1/*
2 *  Mixer Interface - python binding simple abstact module
3 *  Copyright (c) 2007 by Jaroslav Kysela <perex@perex.cz>
4 *
5 *
6 *   This library is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU Lesser General Public License as
8 *   published by the Free Software Foundation; either version 2.1 of
9 *   the License, or (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU Lesser General Public License for more details.
15 *
16 *   You should have received a copy of the GNU Lesser General Public
17 *   License along with this library; if not, write to the Free Software
18 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 *
20 */
21
22#include "Python.h"
23#include <stddef.h>
24#include <limits.h>
25#include "config.h"
26#include "asoundlib.h"
27#include "mixer_abst.h"
28
29#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
30#pragma GCC diagnostic ignored "-Wstrict-aliasing"
31#endif
32
33struct python_priv {
34	int py_initialized;
35	PyObject *py_event_func;
36	PyObject *py_mdict;
37	PyObject *py_mixer;
38};
39
40#define SCRIPT "smixer/python/main.py"
41
42struct pymelem {
43	PyObject_HEAD
44	sm_selem_t selem;
45	PyObject *py_mixer;
46	snd_mixer_elem_t *melem;
47};
48
49struct pymixer {
50	PyObject_HEAD
51	snd_mixer_class_t *class;
52	snd_mixer_t *mixer;
53	PyObject *mdict;
54	int hctl_count;
55	void **hctl;
56	int helem_count;
57	void **helem;
58	int melem_count;
59	void **melem;
60};
61
62static PyInterpreterState *main_interpreter;
63
64#if PY_MAJOR_VERSION >= 3
65  #define PyInt_FromLong PyLong_FromLong
66#endif
67
68static inline int get_long(PyObject *o, long *val)
69{
70#if PY_MAJOR_VERSION < 3
71        if (PyInt_Check(o)) {
72                *val = PyInt_AsLong(o);
73                return 0;
74        }
75#endif
76        if (PyLong_Check(o)) {
77                *val = PyLong_AsLong(o);
78                return 0;
79        }
80        return 1;
81}
82
83static inline PyObject *InternFromString(const char *name)
84{
85#if PY_MAJOR_VERSION < 3
86        return PyString_InternFromString(name);
87#else
88        return PyUnicode_InternFromString(name);
89#endif
90}
91
92static void *get_C_ptr(PyObject *obj, const char *attr)
93{
94	PyObject *o;
95	long val;
96
97	o = PyObject_GetAttr(obj, InternFromString(attr));
98	if (!o) {
99		PyErr_Format(PyExc_TypeError, "missing '%s' attribute", attr);
100		return NULL;
101	}
102	if (get_long(o, &val)) {
103		PyErr_Format(PyExc_TypeError, "'%s' attribute is not Int or Long", attr);
104		return NULL;
105	}
106	return (void *)val;
107}
108
109static struct pymelem *melem_to_pymelem(snd_mixer_elem_t *elem)
110{
111	return (struct pymelem *)((char *)snd_mixer_elem_get_private(elem) - offsetof(struct pymelem, selem));
112}
113
114static int pcall(struct pymelem *pymelem, const char *attr, PyObject *args, PyObject **_res)
115{
116	PyObject *obj = (PyObject *)pymelem, *res;
117	long xres = 0;
118
119	if (_res)
120		*_res = NULL;
121	obj = PyObject_GetAttr(obj, InternFromString(attr));
122	if (!obj) {
123		PyErr_Format(PyExc_TypeError, "missing '%s' attribute", attr);
124		PyErr_Print();
125		PyErr_Clear();
126		Py_DECREF(args);
127		return -EIO;
128	}
129	res = PyObject_CallObject(obj, args);
130	Py_XDECREF(args);
131	if (res == NULL) {
132		PyErr_Print();
133		PyErr_Clear();
134		return -EIO;
135	}
136	if (_res && PyTuple_Check(res)) {
137		*_res = res;
138		res = PyTuple_GetItem(res, 0);
139	}
140	if (PyLong_Check(res)) {
141		xres = PyLong_AsLong(res);
142#if PY_MAJOR_VERSION < 3
143	} else if (PyInt_Check(res)) {
144		xres = PyInt_AsLong(res);
145#endif
146	} else if (res == Py_None) {
147		xres = 0;
148	} else if (PyBool_Check(res)) {
149		xres = res == Py_True;
150	} else {
151		PyErr_Format(PyExc_TypeError, "wrong result from '%s'!", attr);
152		PyErr_Print();
153		PyErr_Clear();
154		Py_DECREF(res);
155		if (_res)
156			*_res = NULL;
157		return -EIO;
158	}
159	if (_res && *_res)
160		return xres;
161	Py_DECREF(res);
162	return xres;
163}
164
165static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
166{
167	PyObject *obj1;
168	struct pymelem *pymelem = melem_to_pymelem(elem);
169	char *s, fcn[32] = "opsIs";
170	int res, xdir = 1, xval = 0;
171
172	switch (cmd) {
173	case SM_OPS_IS_ACTIVE: 	s = "Active"; xdir = 0; break;
174	case SM_OPS_IS_MONO:	s = "Mono"; break;
175	case SM_OPS_IS_CHANNEL:	s = "Channel"; xval = 1; break;
176	case SM_OPS_IS_ENUMERATED: s = "Enumerated"; xdir = val == 1; break;
177	case SM_OPS_IS_ENUMCNT:	s = "EnumCnt"; break;
178	default:
179		return 1;
180	}
181	strcat(fcn, s);
182
183	obj1 = PyTuple_New(xdir + xval);
184	if (xdir) {
185		PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
186		if (xval)
187			PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(val));
188	}
189	res = pcall(pymelem, fcn, obj1, NULL);
190	return res < 0 ? 0 : res;
191}
192
193static int get_x_range_ops(snd_mixer_elem_t *elem, int dir,
194                           long *min, long *max, const char *attr)
195{
196	PyObject *obj1, *t1, *t2, *res;
197	struct pymelem *pymelem = melem_to_pymelem(elem);
198	int err;
199
200	obj1 = PyTuple_New(1);
201	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
202	err = pcall(pymelem, attr, obj1, &res);
203	if (err >= 0) {
204		t1 = PyTuple_GetItem(res, 1);
205		t2 = PyTuple_GetItem(res, 2);
206		if (PyLong_Check(t1) && PyLong_Check(t2)) {
207			*min = PyLong_AsLong(PyTuple_GetItem(res, 1));
208			*max = PyLong_AsLong(PyTuple_GetItem(res, 2));
209			err = 0;
210#if PY_MAJOR_VERSION < 3
211		} else if (PyInt_Check(t1) && PyInt_Check(t2)) {
212			*min = PyInt_AsLong(PyTuple_GetItem(res, 1));
213			*max = PyInt_AsLong(PyTuple_GetItem(res, 2));
214			err = 0;
215#endif
216		} else {
217			PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)");
218			PyErr_Print();
219			PyErr_Clear();
220			err = -EIO;
221		}
222	}
223	Py_XDECREF(res);
224	return err;
225}
226
227static int get_range_ops(snd_mixer_elem_t *elem, int dir,
228                         long *min, long *max)
229{
230	return get_x_range_ops(elem, dir, min, max, "opsGetRange");
231}
232
233static int set_range_ops(snd_mixer_elem_t *elem, int dir,
234                         long min, long max)
235{
236	PyObject *obj1;
237	struct pymelem *pymelem = melem_to_pymelem(elem);
238
239	obj1 = PyTuple_New(3);
240	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
241	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(min));
242	PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(max));
243	return pcall(pymelem, "opsGetRange", obj1, NULL);
244}
245
246static int get_x_ops(snd_mixer_elem_t *elem, int dir,
247                     long channel, long *value,
248                     const char *attr)
249{
250	PyObject *obj1, *t1, *res;
251	struct pymelem *pymelem = melem_to_pymelem(elem);
252	int err;
253
254	obj1 = PyTuple_New(2);
255	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
256	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel));
257	err = pcall(pymelem, attr, obj1, &res);
258	if (err >= 0) {
259		t1 = PyTuple_GetItem(res, 1);
260		if (PyLong_Check(t1)) {
261			*value = PyLong_AsLong(t1);
262			err = 0;
263#if PY_MAJOR_VERSION < 3
264		} else if (PyInt_Check(t1)) {
265			*value = PyInt_AsLong(t1);
266			err = 0;
267#endif
268		} else {
269			PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)");
270			PyErr_Print();
271			PyErr_Clear();
272			err = -EIO;
273		}
274	}
275	Py_XDECREF(res);
276	return err;
277}
278
279static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
280			  snd_mixer_selem_channel_id_t channel, long *value)
281{
282	return get_x_ops(elem, dir, channel, value, "opsGetVolume");
283}
284
285static int get_switch_ops(snd_mixer_elem_t *elem, int dir,
286                          snd_mixer_selem_channel_id_t channel, int *value)
287{
288	long value1;
289	int res;
290	res = get_x_ops(elem, dir, channel, &value1, "opsGetSwitch");
291	*value = value1;
292	return res;
293}
294
295static int ask_vol_dB_ops(snd_mixer_elem_t *elem,
296			  int dir,
297			  long value,
298			  long *dbValue)
299{
300	return get_x_ops(elem, dir, value, dbValue, "opsGetVolDB");
301}
302
303static int ask_dB_vol_ops(snd_mixer_elem_t *elem,
304			  int dir,
305			  long value,
306			  long *dbValue,
307			  int xdir)
308{
309	PyObject *obj1, *t1, *res;
310	struct pymelem *pymelem = melem_to_pymelem(elem);
311	int err;
312
313	obj1 = PyTuple_New(3);
314	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
315	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(value));
316	PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(xdir));
317	err = pcall(pymelem, "opsGetDBVol", obj1, &res);
318	if (err >= 0) {
319		t1 = PyTuple_GetItem(res, 1);
320		if (PyLong_Check(t1)) {
321			*dbValue = PyLong_AsLong(t1);
322			err = 0;
323#if PY_MAJOR_VERSION < 3
324		} else if (PyInt_Check(t1)) {
325			*dbValue = PyInt_AsLong(t1);
326			err = 0;
327#endif
328		} else {
329			PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)");
330			PyErr_Print();
331			PyErr_Clear();
332			err = -EIO;
333		}
334	}
335	Py_XDECREF(res);
336	return err;
337}
338
339static int get_dB_ops(snd_mixer_elem_t *elem,
340                      int dir,
341                      snd_mixer_selem_channel_id_t channel,
342                      long *value)
343{
344	return get_x_ops(elem, dir, channel, value, "opsGetDB");
345}
346
347static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir,
348                            long *min, long *max)
349{
350	return get_x_range_ops(elem, dir, min, max, "opsGetDBRange");
351}
352
353static int set_volume_ops(snd_mixer_elem_t *elem, int dir,
354                          snd_mixer_selem_channel_id_t channel, long value)
355{
356	PyObject *obj1;
357	struct pymelem *pymelem = melem_to_pymelem(elem);
358
359	obj1 = PyTuple_New(3);
360	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
361	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel));
362	PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(value));
363	return pcall(pymelem, "opsSetVolume", obj1, NULL);
364}
365
366static int set_switch_ops(snd_mixer_elem_t *elem, int dir,
367                          snd_mixer_selem_channel_id_t channel, int value)
368{
369	PyObject *obj1;
370	struct pymelem *pymelem = melem_to_pymelem(elem);
371
372	obj1 = PyTuple_New(3);
373	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
374	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel));
375	PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(value));
376	return pcall(pymelem, "opsSetSwitch", obj1, NULL);
377}
378
379static int set_dB_ops(snd_mixer_elem_t *elem, int dir,
380                      snd_mixer_selem_channel_id_t channel,
381                      long db_gain, int xdir)
382{
383	PyObject *obj1;
384	struct pymelem *pymelem = melem_to_pymelem(elem);
385
386	obj1 = PyTuple_New(4);
387	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir));
388	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel));
389	PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(db_gain));
390	PyTuple_SET_ITEM(obj1, 3, PyInt_FromLong(xdir));
391	return pcall(pymelem, "opsSetDB", obj1, NULL);
392}
393
394static int enum_item_name_ops(snd_mixer_elem_t *elem,
395                              unsigned int item,
396                              size_t maxlen, char *buf)
397{
398	PyObject *obj1, *obj2, *t1, *res;
399	struct pymelem *pymelem = melem_to_pymelem(elem);
400	int err;
401	unsigned int len;
402	char *s;
403
404	obj1 = PyTuple_New(1);
405	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(item));
406	err = pcall(pymelem, "opsGetEnumItemName", obj1, &res);
407	if (err >= 0) {
408		t1 = PyTuple_GetItem(res, 1);
409		if (PyUnicode_Check(t1)) {
410			obj2 = PyUnicode_AsEncodedString(t1, "utf-8", "strict");
411			if (obj2) {
412				s = PyBytes_AsString(obj2);
413				len = strlen(s);
414				if (maxlen - 1 > len)
415					len = maxlen - 1;
416				memcpy(buf, s, len);
417				buf[len] = '\0';
418				Py_DECREF(obj2);
419			} else {
420				goto errlbl;
421			}
422#if PY_MAJOR_VERSION < 3
423		} else if (PyString_Check(t1)) {
424			s = PyString_AsString(t1);
425			len = strlen(s);
426			if (maxlen - 1 > len)
427				len = maxlen - 1;
428			memcpy(buf, s, len);
429			buf[len] = '\0';
430#endif
431		} else {
432errlbl:
433			PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)");
434			PyErr_Print();
435			PyErr_Clear();
436			err = -EIO;
437		}
438	}
439	Py_XDECREF(res);
440	return err;
441}
442
443static int get_enum_item_ops(snd_mixer_elem_t *elem,
444                             snd_mixer_selem_channel_id_t channel,
445                             unsigned int *itemp)
446{
447	PyObject *obj1, *t1, *res;
448	struct pymelem *pymelem = melem_to_pymelem(elem);
449	int err;
450
451	obj1 = PyTuple_New(1);
452	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(channel));
453	err = pcall(pymelem, "opsGetEnumItem", obj1, &res);
454	if (err >= 0) {
455		t1 = PyTuple_GetItem(res, 1);
456		if (PyLong_Check(t1)) {
457			*itemp = PyLong_AsLong(t1);
458			err = 0;
459#if PY_MAJOR_VERSION < 3
460		} else if (PyInt_Check(t1)) {
461			*itemp = PyInt_AsLong(t1);
462			err = 0;
463#endif
464		} else {
465			PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)");
466			PyErr_Print();
467			PyErr_Clear();
468			err = -EIO;
469		}
470	}
471	Py_XDECREF(res);
472	return err;
473}
474
475static int set_enum_item_ops(snd_mixer_elem_t *elem,
476                             snd_mixer_selem_channel_id_t channel,
477                             unsigned int item)
478{
479	PyObject *obj1;
480	struct pymelem *pymelem = melem_to_pymelem(elem);
481
482	obj1 = PyTuple_New(2);
483	PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(channel));
484	PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(item));
485	return pcall(pymelem, "opsSetEnumItem", obj1, NULL);
486}
487
488static struct sm_elem_ops simple_python_ops = {
489        .is             = is_ops,
490        .get_range      = get_range_ops,
491        .get_dB_range   = get_dB_range_ops,
492        .set_range      = set_range_ops,
493        .ask_vol_dB	= ask_vol_dB_ops,
494        .ask_dB_vol	= ask_dB_vol_ops,
495        .get_volume     = get_volume_ops,
496        .get_dB         = get_dB_ops,
497        .set_volume     = set_volume_ops,
498        .set_dB         = set_dB_ops,
499        .get_switch     = get_switch_ops,
500        .set_switch     = set_switch_ops,
501        .enum_item_name = enum_item_name_ops,
502        .get_enum_item  = get_enum_item_ops,
503        .set_enum_item  = set_enum_item_ops
504};
505
506static void selem_free(snd_mixer_elem_t *elem)
507{
508	sm_selem_t *simple = snd_mixer_elem_get_private(elem);
509
510	if (simple->id) {
511		snd_mixer_selem_id_free(simple->id);
512		simple->id = NULL;
513	}
514}
515
516static PyObject *
517pymelem_cap(struct pymelem *pymelem ATTRIBUTE_UNUSED, void *priv)
518{
519	return PyInt_FromLong((long)priv);
520}
521
522static PyObject *
523pymelem_get_caps(struct pymelem *pymelem, void *priv ATTRIBUTE_UNUSED)
524{
525	return PyInt_FromLong(pymelem->selem.caps);
526}
527
528static PyObject *
529pymelem_get_name(struct pymelem *pymelem, void *priv ATTRIBUTE_UNUSED)
530{
531	return PyUnicode_FromString(snd_mixer_selem_id_get_name(pymelem->selem.id));
532}
533
534static PyObject *
535pymelem_get_index(struct pymelem *pymelem, void *priv ATTRIBUTE_UNUSED)
536{
537	return PyInt_FromLong(snd_mixer_selem_id_get_index(pymelem->selem.id));
538}
539
540static int
541pymelem_set_caps(struct pymelem *pymelem, PyObject *val, void *priv ATTRIBUTE_UNUSED)
542{
543	if (PyLong_Check(val)) {
544		pymelem->selem.caps = PyLong_AsLong(val);
545		return 0;
546	}
547#if PY_MAJOR_VERSION < 3
548	if (PyInt_Check(val)) {
549		pymelem->selem.caps = PyInt_AsLong(val);
550		return 0;
551	}
552#endif
553	PyErr_SetString(PyExc_TypeError, "The last attribute value must be an integer");
554	return -1;
555}
556
557static PyObject *
558pymelem_ignore(struct pymelem *pymelem ATTRIBUTE_UNUSED, PyObject *args ATTRIBUTE_UNUSED)
559{
560	Py_RETURN_NONE;
561}
562
563static PyObject *
564pymelem_ignore1(struct pymelem *pymelem ATTRIBUTE_UNUSED, PyObject *args ATTRIBUTE_UNUSED)
565{
566	Py_RETURN_TRUE;
567}
568
569static PyObject *
570pymelem_error(struct pymelem *pymelem ATTRIBUTE_UNUSED, PyObject *args ATTRIBUTE_UNUSED)
571{
572	return PyInt_FromLong(-EIO);
573}
574
575static PyObject *
576pymelem_attach(struct pymelem *pymelem, PyObject *args)
577{
578	PyObject *obj;
579	snd_hctl_elem_t *helem;
580	int err;
581
582	if (!PyArg_ParseTuple(args, "O", &obj))
583		return NULL;
584	helem = (snd_hctl_elem_t *)get_C_ptr(obj, "get_C_helem");
585	if (helem == NULL)
586		return NULL;
587	err = snd_mixer_elem_attach(pymelem->melem, helem);
588	if (err < 0) {
589		PyErr_Format(PyExc_RuntimeError, "Cannot attach hcontrol element to mixer element: %s", snd_strerror(err));
590		return NULL;
591	}
592	Py_RETURN_NONE;
593}
594
595static PyObject *
596pymelem_detach(struct pymelem *pymelem, PyObject *args)
597{
598	PyObject *obj;
599	snd_hctl_elem_t *helem;
600	int err;
601
602	if (!PyArg_ParseTuple(args, "O", &obj))
603		return NULL;
604	helem = (snd_hctl_elem_t *)get_C_ptr(obj, "get_C_helem");
605	if (helem == NULL)
606		return NULL;
607	err = snd_mixer_elem_detach(pymelem->melem, helem);
608	if (err < 0) {
609		PyErr_Format(PyExc_RuntimeError, "Cannot detach hcontrol element to mixer element: %s", snd_strerror(err));
610		return NULL;
611	}
612	Py_RETURN_NONE;
613}
614
615static PyObject *
616pymelem_event_info(struct pymelem *pymelem, PyObject *args)
617{
618	if (!PyArg_ParseTuple(args, ""))
619		return NULL;
620	return PyInt_FromLong(snd_mixer_elem_info(pymelem->melem));
621}
622
623static PyObject *
624pymelem_event_value(struct pymelem *pymelem, PyObject *args)
625{
626	if (!PyArg_ParseTuple(args, ""))
627		return NULL;
628	return PyInt_FromLong(snd_mixer_elem_value(pymelem->melem));
629}
630
631static int
632pymelem_init(struct pymelem *pymelem, PyObject *args, PyObject *kwds ATTRIBUTE_UNUSED)
633{
634	char *name;
635	long index, weight;
636	snd_mixer_selem_id_t *id;
637	int err;
638
639	if (!PyArg_ParseTuple(args, "Osii", &pymelem->py_mixer, &name, &index, &weight))
640		return -1;
641	memset(&pymelem->selem, 0, sizeof(pymelem->selem));
642	if (snd_mixer_selem_id_malloc(&id))
643		return -1;
644	snd_mixer_selem_id_set_name(id, name);
645	snd_mixer_selem_id_set_index(id, index);
646	pymelem->selem.id = id;
647	pymelem->selem.ops = &simple_python_ops;
648	err = snd_mixer_elem_new(&pymelem->melem, SND_MIXER_ELEM_SIMPLE,
649				 weight, &pymelem->selem, selem_free);
650	if (err < 0) {
651		snd_mixer_selem_id_free(id);
652		return -1;
653	}
654	return 0;
655}
656
657static void
658pymelem_dealloc(struct pymelem *self)
659{
660	selem_free(self->melem);
661}
662
663static PyGetSetDef pymelem_getseters[] = {
664	{"CAP_GVOLUME", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_GVOLUME},
665	{"CAP_GSWITCH", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_GSWITCH},
666	{"CAP_PVOLUME", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PVOLUME},
667	{"CAP_PVOLUME_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PVOLUME_JOIN},
668	{"CAP_PSWITCH", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PSWITCH},
669	{"CAP_PSWITCH_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PSWITCH_JOIN},
670	{"CAP_CVOLUME", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CVOLUME},
671	{"CAP_CVOLUME_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CVOLUME_JOIN},
672	{"CAP_CSWITCH", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CSWITCH},
673	{"CAP_CSWITCH_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CSWITCH_JOIN},
674	{"CAP_CSWITCH_EXCL", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CSWITCH_EXCL},
675	{"CAP_PENUM", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PENUM},
676	{"CAP_CENUM", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CENUM},
677
678	{"caps", (getter)pymelem_get_caps, (setter)pymelem_set_caps, NULL, NULL},
679
680	{"name", (getter)pymelem_get_name, NULL, NULL, NULL},
681	{"index", (getter)pymelem_get_index, NULL, NULL, NULL},
682
683	{NULL,NULL,NULL,NULL,NULL}
684};
685
686static PyMethodDef pymelem_methods[] = {
687	{"attach", (PyCFunction)pymelem_attach, METH_VARARGS, NULL},
688	{"detach", (PyCFunction)pymelem_detach, METH_VARARGS, NULL},
689
690	/* "default" functions - no functionality */
691	{"opsIsActive", (PyCFunction)pymelem_ignore1, METH_VARARGS, NULL},
692	{"opsIsMono", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL},
693	{"opsIsChannel", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL},
694	{"opsIsEnumerated", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL},
695	{"opsIsEnumCnt", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL},
696
697	{"opsGetDB", (PyCFunction)pymelem_error, METH_VARARGS, NULL},
698
699	{"eventInfo", (PyCFunction)pymelem_event_info, METH_VARARGS, NULL},
700	{"eventValue", (PyCFunction)pymelem_event_value, METH_VARARGS, NULL},
701
702	{NULL,NULL,0,NULL}
703};
704
705static PyTypeObject pymelem_type = {
706        PyVarObject_HEAD_INIT(NULL, 0)
707        tp_name:        "smixer_python.InternalMElement",
708        tp_basicsize:   sizeof(struct pymelem),
709        tp_dealloc:     (destructor)pymelem_dealloc,
710        tp_flags:       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
711        tp_doc:         NULL /* mixerinit__doc__ */,
712        tp_getset:      pymelem_getseters,
713        tp_init:        (initproc)pymelem_init,
714        tp_alloc:       PyType_GenericAlloc,
715        tp_new:         PyType_GenericNew,
716        tp_free:        PyObject_Del,
717        tp_methods:     pymelem_methods,
718};
719
720static PyObject *
721pymixer_attach_hctl(struct pymixer *pymixer, PyObject *args)
722{
723	PyObject *obj;
724	snd_hctl_t *hctl;
725	void **hctls;
726	int err;
727
728	if (!PyArg_ParseTuple(args, "O", &obj))
729		return NULL;
730	hctl = (snd_hctl_t *)get_C_ptr(obj, "get_C_hctl");
731	if (hctl == NULL)
732		return NULL;
733	err = snd_mixer_attach_hctl(pymixer->mixer, hctl);
734	if (err < 0) {
735		PyErr_Format(PyExc_RuntimeError, "Cannot attach hctl: %s", snd_strerror(err));
736		return NULL;
737	}
738	hctls = realloc(pymixer->hctl, sizeof(void *) * (pymixer->hctl_count+1) * 2);
739	if (hctls == NULL) {
740		PyErr_SetString(PyExc_RuntimeError, "No enough memory");
741		return NULL;
742	}
743	pymixer->hctl = hctls;
744	pymixer->hctl[pymixer->hctl_count*2] = (void *)hctl;
745	pymixer->hctl[pymixer->hctl_count*2+1] = (void *)obj;
746	pymixer->hctl_count++;
747	Py_INCREF(obj);
748	Py_RETURN_NONE;
749}
750
751static PyObject *
752pymixer_register(struct pymixer *pymixer, PyObject *args)
753{
754	int err;
755
756	if (!PyArg_ParseTuple(args, ""))
757		return NULL;
758	err = snd_mixer_class_register(pymixer->class, pymixer->mixer);
759	if (err < 0) {
760		PyErr_Format(PyExc_RuntimeError, "Cannot register mixer: %s", snd_strerror(err));
761		return NULL;
762	}
763	Py_RETURN_NONE;
764}
765
766static PyObject *
767pymixer_melement_new(struct pymixer *pymixer, PyObject *args)
768{
769	PyObject *obj, *obj1, *obj2;
770	char *class, *name;
771	long index, weight;
772
773	if (!PyArg_ParseTuple(args, "ssii", &class, &name, &index, &weight))
774		return NULL;
775	obj = PyDict_GetItemString(pymixer->mdict, class);
776	if (obj) {
777		obj1 = PyTuple_New(4);
778		PyTuple_SET_ITEM(obj1, 0, (PyObject *)pymixer);
779		Py_INCREF((PyObject *)pymixer);
780		PyTuple_SET_ITEM(obj1, 1, PyUnicode_FromString(name));
781		PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(index));
782		PyTuple_SET_ITEM(obj1, 3, PyInt_FromLong(weight));
783		obj2 = PyObject_CallObject(obj, obj1);
784		Py_XDECREF(obj1);
785		if (obj2) {
786			struct pymelem *pymelem = (struct pymelem *)obj2;
787			void **melems = realloc(pymixer->melem, sizeof(void *) * (pymixer->melem_count + 1) * 2);
788			if (melems == NULL) {
789				Py_DECREF(obj2);
790				return NULL;
791			}
792			melems[pymixer->melem_count*2] = pymelem->melem;
793			melems[pymixer->melem_count*2+1] = obj2;
794			Py_INCREF(obj2);
795			pymixer->melem = melems;
796			pymixer->melem_count++;
797		}
798	} else {
799		PyErr_Format(PyExc_RuntimeError, "Cannot find class '%s'", class);
800		return NULL;
801	}
802	return obj2;
803}
804
805static PyObject *
806pymixer_melement_add(struct pymixer *pymixer, PyObject *args)
807{
808	PyObject *obj;
809	struct pymelem *pymelem;
810	int err;
811
812	if (!PyArg_ParseTuple(args, "O", &obj))
813		return NULL;
814	pymelem = (struct pymelem *)obj;
815	err = snd_mixer_elem_add(pymelem->melem, pymixer->class);
816	if (err < 0) {
817		PyErr_Format(PyExc_RuntimeError, "Cannot add mixer element: %s", snd_strerror(err));
818		return NULL;
819	}
820	Py_RETURN_NONE;
821}
822
823static int
824pymixer_init(struct pymixer *pymixer, PyObject *args, PyObject *kwds ATTRIBUTE_UNUSED)
825{
826	long class, mixer;
827
828	if (!PyArg_ParseTuple(args, "iiO", &class, &mixer, &pymixer->mdict))
829		return -1;
830	pymixer->class = (snd_mixer_class_t *)class;
831	pymixer->mixer = (snd_mixer_t *)mixer;
832	pymixer->hctl_count = 0;
833	pymixer->hctl = NULL;
834	pymixer->helem_count = 0;
835	pymixer->helem = NULL;
836	pymixer->melem_count = 0;
837	pymixer->melem = NULL;
838	return 0;
839}
840
841static void
842pymixer_free(struct pymixer *self)
843{
844	int idx;
845
846	for (idx = 0; idx < self->hctl_count; idx++) {
847		snd_mixer_detach_hctl(self->mixer, self->hctl[idx*2]);
848		Py_DECREF((PyObject *)self->hctl[idx*2+1]);
849	}
850	if (self->hctl)
851		free(self->hctl);
852	self->hctl_count = 0;
853	self->hctl = NULL;
854	for (idx = 0; idx < self->helem_count; idx++)
855		Py_DECREF((PyObject *)self->helem[idx*2+1]);
856	if (self->helem)
857		free(self->helem);
858	self->helem_count = 0;
859	self->helem = NULL;
860	for (idx = 0; idx < self->melem_count; idx++)
861		Py_DECREF((PyObject *)self->melem[idx*2+1]);
862	if (self->melem)
863		free(self->melem);
864	self->melem_count = 0;
865	self->melem = NULL;
866}
867
868static void
869pymixer_dealloc(struct pymixer *self)
870{
871	pymixer_free(self);
872}
873
874static PyGetSetDef pymixer_getseters[] = {
875	{NULL,NULL,NULL,NULL,NULL}
876};
877
878static PyMethodDef pymixer_methods[] = {
879	{"attachHCtl", (PyCFunction)pymixer_attach_hctl, METH_VARARGS, NULL},
880	{"register", (PyCFunction)pymixer_register, METH_VARARGS, NULL},
881	{"newMElement", (PyCFunction)pymixer_melement_new, METH_VARARGS, NULL},
882	{"addMElement", (PyCFunction)pymixer_melement_add, METH_VARARGS, NULL},
883	{NULL,NULL,0,NULL}
884};
885
886static PyTypeObject pymixer_type = {
887        PyVarObject_HEAD_INIT(NULL, 0)
888        tp_name:        "smixer_python.InternalMixer",
889        tp_basicsize:   sizeof(struct pymixer),
890        tp_dealloc:     (destructor)pymixer_dealloc,
891        tp_flags:       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
892        tp_doc:         NULL /* mixerinit__doc__ */,
893        tp_getset:      pymixer_getseters,
894        tp_init:        (initproc)pymixer_init,
895        tp_alloc:       PyType_GenericAlloc,
896        tp_new:         PyType_GenericNew,
897        tp_free:        PyObject_Del,
898        tp_methods:     pymixer_methods,
899};
900
901static PyMethodDef python_methods[] = {
902	{NULL, NULL, 0, NULL}
903};
904
905static PyObject *new_helem(struct python_priv *priv, snd_hctl_elem_t *helem)
906{
907	PyObject *obj, *py_hctl = NULL, *obj1, *obj2;
908	snd_hctl_t *hctl = snd_hctl_elem_get_hctl(helem);
909	struct pymixer *pymixer = (struct pymixer *)priv->py_mixer;
910	int idx;
911
912	for (idx = 0; idx < pymixer->hctl_count; idx++) {
913		if (pymixer->hctl[idx] == hctl) {
914			py_hctl = pymixer->hctl[idx*2+1];
915			break;
916		}
917	}
918	if (py_hctl == NULL)
919		return NULL;
920	obj = PyDict_GetItemString(priv->py_mdict, "HElement");
921	if (obj) {
922		obj1 = PyTuple_New(3);
923		PyTuple_SET_ITEM(obj1, 0, py_hctl);
924		Py_INCREF(py_hctl);
925		PyTuple_SET_ITEM(obj1, 1, PyFloat_FromDouble(1));
926		PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong((long)helem));
927		obj2 = PyObject_CallObject(obj, obj1);
928		if (obj2 == NULL) {
929			PyErr_Print();
930			PyErr_Clear();
931		}
932		Py_XDECREF(obj1);
933	} else {
934		SNDERR("Unable to create InternalMixer object");
935		return NULL;
936	}
937	if (obj2) {
938		struct pymixer *pymixer = (struct pymixer *)priv->py_mixer;
939		void **helems = realloc(pymixer->helem, sizeof(void *) * (pymixer->helem_count + 1) * 2);
940		if (helems == NULL) {
941			Py_DECREF(obj2);
942			return NULL;
943		}
944		helems[pymixer->helem_count*2] = helem;
945		helems[pymixer->helem_count*2+1] = obj2;
946		Py_INCREF(obj2);
947		pymixer->helem = helems;
948		pymixer->helem_count++;
949	}
950	return obj2;
951}
952
953static PyObject *find_helem(struct python_priv *priv, snd_hctl_elem_t *helem)
954{
955	struct pymixer *pymixer = (struct pymixer *)priv->py_mixer;
956	int idx;
957
958	for (idx = 0; idx < pymixer->helem_count; idx++) {
959		if (pymixer->helem[idx*2] == helem)
960			return (PyObject *)pymixer->helem[idx*2+1];
961	}
962	return NULL;
963}
964
965static PyObject *find_melem(struct python_priv *priv, snd_mixer_elem_t *melem)
966{
967	struct pymixer *pymixer = (struct pymixer *)priv->py_mixer;
968	int idx;
969
970	for (idx = 0; idx < pymixer->melem_count; idx++) {
971		if (pymixer->melem[idx*2] == melem)
972			return (PyObject *)pymixer->melem[idx*2+1];
973	}
974	return NULL;
975}
976
977int alsa_mixer_simple_event(snd_mixer_class_t *class, unsigned int mask,
978			    snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
979{
980	struct python_priv *priv = snd_mixer_sbasic_get_private(class);
981	PyThreadState *tstate;
982	PyObject *t, *o, *r;
983	int res = -ENOMEM;
984
985	tstate = PyThreadState_New(main_interpreter);
986	PyThreadState_Swap(tstate);
987
988        t = PyTuple_New(3);
989        if (t) {
990        	PyTuple_SET_ITEM(t, 0, (PyObject *)PyInt_FromLong(mask));
991        	o = find_helem(priv, helem);
992	        if (mask & SND_CTL_EVENT_MASK_ADD) {
993	        	if (o == NULL)
994        			o = new_helem(priv, helem);
995		}
996        	if (o == NULL)
997        		return 0;
998		PyTuple_SET_ITEM(t, 1, o);
999		Py_INCREF(o);
1000        	o = melem ? find_melem(priv, melem) : Py_None;
1001		PyTuple_SET_ITEM(t, 2, o);
1002		Py_INCREF(o);
1003		r = PyObject_CallObject(priv->py_event_func, t);
1004		Py_DECREF(t);
1005		if (r) {
1006			if (PyLong_Check(r)) {
1007				res = PyLong_AsLong(r);
1008#if PY_MAJOR_VERSION < 3
1009			} else if (PyInt_Check(r)) {
1010				res = PyInt_AsLong(r);
1011#endif
1012			} else if (r == Py_None) {
1013				res = 0;
1014			}
1015			Py_DECREF(r);
1016		} else {
1017			PyErr_Print();
1018			PyErr_Clear();
1019			res = -EIO;
1020		}
1021	}
1022
1023	return res;
1024}
1025
1026static void alsa_mixer_simple_free(snd_mixer_class_t *class)
1027{
1028	struct python_priv *priv = snd_mixer_sbasic_get_private(class);
1029
1030	if (priv->py_mixer) {
1031		pymixer_free((struct pymixer *)priv->py_mixer);
1032		Py_DECREF(priv->py_mixer);
1033	}
1034	if (priv->py_initialized) {
1035		Py_XDECREF(priv->py_event_func);
1036		Py_Finalize();
1037	}
1038	free(priv);
1039}
1040
1041static int alsa_mixer_simple_pyinit(struct python_priv *priv,
1042                                    PyObject *py_mod,
1043                                    FILE *fp,
1044				    const char *file,
1045				    snd_mixer_class_t *class,
1046				    snd_mixer_t *mixer,
1047				    const char *device)
1048{
1049	PyObject *obj, *obj1, *obj2, *mdict;
1050
1051	mdict = priv->py_mdict = PyModule_GetDict(py_mod);
1052	obj = PyUnicode_FromString(file);
1053	if (obj)
1054		PyDict_SetItemString(mdict, "__file__", obj);
1055	Py_XDECREF(obj);
1056	obj = PyUnicode_FromString(device);
1057	if (obj)
1058		PyDict_SetItemString(mdict, "device", obj);
1059	Py_XDECREF(obj);
1060	Py_INCREF(&pymelem_type);
1061	Py_INCREF(&pymixer_type);
1062	PyModule_AddObject(py_mod, "InternalMElement", (PyObject *)&pymelem_type);
1063	PyModule_AddObject(py_mod, "InternalMixer", (PyObject *)&pymixer_type);
1064	obj = PyDict_GetItemString(mdict, "InternalMixer");
1065	if (obj) {
1066		obj1 = PyTuple_New(3);
1067		PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong((long)class));
1068		PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong((long)mixer));
1069		PyTuple_SET_ITEM(obj1, 2, mdict);
1070		Py_INCREF(mdict);
1071		obj2 = PyObject_CallObject(obj, obj1);
1072		Py_XDECREF(obj1);
1073		PyDict_SetItemString(mdict, "mixer", obj2);
1074		priv->py_mixer = obj2;
1075	} else {
1076		SNDERR("Unable to create InternalMixer object");
1077		return -EIO;
1078	}
1079
1080	obj = PyRun_FileEx(fp, file, Py_file_input, mdict, mdict, 1);
1081	if (obj == NULL)
1082		PyErr_Print();
1083	Py_XDECREF(obj);
1084	priv->py_event_func = PyDict_GetItemString(mdict, "event");
1085	if (priv->py_event_func == NULL) {
1086		SNDERR("Unable to find python function 'event'");
1087		return -EIO;
1088	}
1089	return 0;
1090}
1091
1092#if PY_MAJOR_VERSION >= 3
1093static struct PyModuleDef smixer_python_module = {
1094        PyModuleDef_HEAD_INIT,
1095        "smixer_python",
1096        NULL,
1097        0,
1098        python_methods,
1099        NULL,
1100        NULL,
1101        NULL,
1102        NULL
1103};
1104#endif
1105
1106int alsa_mixer_simple_finit(snd_mixer_class_t *class,
1107			    snd_mixer_t *mixer,
1108			    const char *device)
1109{
1110	struct python_priv *priv;
1111	FILE *fp;
1112	const char *file;
1113	PyObject *obj, *py_mod;
1114	char path[PATH_MAX];
1115
1116	priv = calloc(1, sizeof(*priv));
1117	if (priv == NULL)
1118		return -ENOMEM;
1119
1120	snd_mixer_sbasic_set_private(class, priv);
1121	snd_mixer_sbasic_set_private_free(class, alsa_mixer_simple_free);
1122
1123	file = getenv("ALSA_MIXER_SIMPLE_MPYTHON");
1124	if (file == NULL) {
1125		snd_dlpath(path, sizeof(path), SCRIPT);
1126		file = path;
1127	}
1128
1129	fp = fopen(file, "r");
1130	if (fp == NULL) {
1131		SNDERR("Unable to find python module '%s'", file);
1132		return -ENODEV;
1133	}
1134
1135	Py_Initialize();
1136	if (PyType_Ready(&pymelem_type) < 0 ||
1137	    PyType_Ready(&pymixer_type) < 0) {
1138		fclose(fp);
1139		return -EIO;
1140	}
1141#if PY_MAJOR_VERSION < 3
1142	Py_InitModule("smixer_python", python_methods);
1143#else
1144	PyModule_Create(&smixer_python_module);
1145#endif
1146	priv->py_initialized = 1;
1147	main_interpreter = PyThreadState_Get()->interp;
1148	obj = PyImport_GetModuleDict();
1149	py_mod = PyDict_GetItemString(obj, "__main__");
1150	if (py_mod)
1151		alsa_mixer_simple_pyinit(priv, py_mod, fp, file, class, mixer, device);
1152	return 0;
1153}
1154