From 6c23f1dd4779119597be634247695d8ef8ea5230 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 23 Feb 2007 10:05:26 +0100 Subject: [PATCH] initial code for alsahcontrol module, missing info and value management --- pyalsa/alsahcontrol.c | 637 ++++++++++++++++++++++++++++++++++++++++++ pyalsa/hctltest1.py | 28 ++ pyalsa/hctltest2.py | 41 +++ setup.py | 7 +- 4 files changed, 712 insertions(+), 1 deletion(-) create mode 100644 pyalsa/alsahcontrol.c create mode 100755 pyalsa/hctltest1.py create mode 100755 pyalsa/hctltest2.py diff --git a/pyalsa/alsahcontrol.c b/pyalsa/alsahcontrol.c new file mode 100644 index 0000000..d81a5a9 --- /dev/null +++ b/pyalsa/alsahcontrol.c @@ -0,0 +1,637 @@ +/* + * Python binding for the ALSA library - Universal Control Layer + * Copyright (c) 2007 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "Python.h" +#include "structmember.h" +#include "frameobject.h" +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#include "sys/poll.h" +#include "stdlib.h" +#include "alsa/asoundlib.h" + +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif +#ifndef Py_RETURN_TRUE +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif +#ifndef Py_RETURN_FALSE +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#endif + +static int element_callback(snd_hctl_elem_t *elem, unsigned int mask); + +static PyObject *module; +#if 0 +static PyObject *buildin; +#endif +static PyInterpreterState *main_interpreter; + +/* + * + */ + +#define PYHCTL(v) (((v) == Py_None) ? NULL : \ + ((struct pyalsahcontrol *)(v))) + +struct pyalsahcontrol { + PyObject_HEAD + snd_hctl_t *handle; +}; + +static inline PyObject *get_bool(int val) +{ + if (val) { + Py_INCREF(Py_True); + return Py_True; + } else { + Py_INCREF(Py_False); + return Py_False; + } +} + +static PyObject * +pyalsahcontrol_getcount(struct pyalsahcontrol *self, void *priv) +{ + return PyLong_FromLong(snd_hctl_get_count(self->handle)); +} + +PyDoc_STRVAR(handlevents__doc__, +"handleEvents() -- Process waiting hcontrol events (and call appropriate callbacks)."); + +static PyObject * +pyalsahcontrol_handleevents(struct pyalsahcontrol *self, PyObject *args) +{ + int err = snd_hctl_handle_events(self->handle); + if (err < 0) + PyErr_Format(PyExc_IOError, + "HControl handle events error: %s", strerror(-err)); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(registerpoll__doc__, +"registerPoll(pollObj) -- Register poll file descriptors."); + +static PyObject * +pyalsahcontrol_registerpoll(struct pyalsahcontrol *self, PyObject *args) +{ + PyObject *pollObj, *reg, *t; + struct pollfd *pfd; + int i, count; + + if (!PyArg_ParseTuple(args, "O", &pollObj)) + return NULL; + + count = snd_hctl_poll_descriptors_count(self->handle); + if (count <= 0) + Py_RETURN_NONE; + pfd = malloc(sizeof(struct pollfd) * count); + if (pfd == NULL) + Py_RETURN_NONE; + count = snd_hctl_poll_descriptors(self->handle, pfd, count); + if (count <= 0) + Py_RETURN_NONE; + + reg = PyObject_GetAttr(pollObj, PyString_InternFromString("register")); + + for (i = 0; i < count; i++) { + t = PyTuple_New(2); + if (t) { + PyTuple_SET_ITEM(t, 0, PyInt_FromLong(pfd[i].fd)); + PyTuple_SET_ITEM(t, 1, PyInt_FromLong(pfd[i].events)); + Py_XDECREF(PyObject_CallObject(reg, t)); + Py_DECREF(t); + } + } + + Py_XDECREF(reg); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(list__doc__, +"list() -- Return a list (tuple) of element IDs in (numid,interface,device,subdevice,name,index) tuple."); + +static PyObject * +pyalsahcontrol_list(struct pyalsahcontrol *self, PyObject *args) +{ + PyObject *t, *v; + int i, count; + snd_hctl_elem_t *elem; + snd_ctl_elem_id_t *id; + + snd_ctl_elem_id_alloca(&id); + count = snd_hctl_get_count(self->handle); + t = PyTuple_New(count); + if (count == 0) + return t; + elem = snd_hctl_first_elem(self->handle); + for (i = 0; i < count; i++) { + v = NULL; + if (elem) { + snd_hctl_elem_get_id(elem, id); + v = PyTuple_New(6); + PyTuple_SET_ITEM(v, 0, PyInt_FromLong(snd_ctl_elem_id_get_numid(id))); + PyTuple_SET_ITEM(v, 1, PyInt_FromLong(snd_ctl_elem_id_get_interface(id))); + PyTuple_SET_ITEM(v, 2, PyInt_FromLong(snd_ctl_elem_id_get_device(id))); + PyTuple_SET_ITEM(v, 3, PyInt_FromLong(snd_ctl_elem_id_get_subdevice(id))); + PyTuple_SET_ITEM(v, 4, PyString_FromString(snd_ctl_elem_id_get_name(id))); + PyTuple_SET_ITEM(v, 5, PyInt_FromLong(snd_ctl_elem_id_get_index(id))); + } + if (v == NULL || elem == NULL) { + v = Py_None; + Py_INCREF(v); + } + PyTuple_SET_ITEM(t, i, v); + elem = snd_hctl_elem_next(elem); + } + return t; +} + +PyDoc_STRVAR(alsahcontrolinit__doc__, +"HControl([name='default'],[mode=0])\n" +" -- Open an ALSA HControl device.\n"); + +static int +pyalsahcontrol_init(struct pyalsahcontrol *pyhctl, PyObject *args, PyObject *kwds) +{ + char *name = "default"; + int mode = 0, err; + + static char * kwlist[] = { "name", "mode", NULL }; + + pyhctl->handle = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si", kwlist, &name, &mode)) + return -1; + + err = snd_hctl_open(&pyhctl->handle, name, mode); + if (err < 0) { + PyErr_Format(PyExc_IOError, + "HControl open error: %s", strerror(-err)); + return -1; + } + + err = snd_hctl_load(pyhctl->handle); + if (err < 0) { + snd_hctl_close(pyhctl->handle); + pyhctl->handle = NULL; + PyErr_Format(PyExc_IOError, + "HControl load error: %s", strerror(-err)); + return -1; + } + + return 0; +} + +static void +pyalsahcontrol_dealloc(struct pyalsahcontrol *self) +{ + if (self->handle != NULL) + snd_hctl_close(self->handle); + + self->ob_type->tp_free(self); +} + +static PyGetSetDef pyalsahcontrol_getseters[] = { + + {"count", (getter)pyalsahcontrol_getcount, NULL, "hcontrol element count", NULL}, + + {NULL} +}; + +static PyMethodDef pyalsahcontrol_methods[] = { + + {"list", (PyCFunction)pyalsahcontrol_list, METH_NOARGS, list__doc__}, + {"handleEvents",(PyCFunction)pyalsahcontrol_handleevents, METH_NOARGS, handlevents__doc__}, + {"registerPoll",(PyCFunction)pyalsahcontrol_registerpoll, METH_VARARGS|METH_KEYWORDS, registerpoll__doc__}, + {NULL} +}; + +static PyTypeObject pyalsahcontrol_type = { + PyObject_HEAD_INIT(0) + tp_name: "alsahcontrol.HControl", + tp_basicsize: sizeof(struct pyalsahcontrol), + tp_dealloc: (destructor)pyalsahcontrol_dealloc, + tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + tp_doc: alsahcontrolinit__doc__, + tp_getset: pyalsahcontrol_getseters, + tp_init: (initproc)pyalsahcontrol_init, + tp_alloc: PyType_GenericAlloc, + tp_new: PyType_GenericNew, + tp_free: PyObject_Del, + tp_methods: pyalsahcontrol_methods, +}; + +/* + * hcontrol element section + */ + +#define PYHCTLELEMENT(v) (((v) == Py_None) ? NULL : \ + ((struct pyalsahcontrolelement *)(v))) + +struct pyalsahcontrolelement { + PyObject_HEAD + PyObject *pyhandle; + PyObject *callback; + snd_hctl_t *handle; + snd_hctl_elem_t *elem; +}; + +static PyObject * +pyalsahcontrolelement_getname(struct pyalsahcontrolelement *pyhelem, void *priv) +{ + return PyString_FromString(snd_hctl_elem_get_name(pyhelem->elem)); +} + +typedef unsigned int (*fcn1)(void *); + +static PyObject * +pyalsahcontrolelement_uint(struct pyalsahcontrolelement *pyhelem, void *fcn) +{ + return PyInt_FromLong(((fcn1)fcn)(pyhelem->elem)); +} + +PyDoc_STRVAR(setcallback__doc__, +"setCallback(callObj) -- Set callback object.\n" +"Note: callObj might have callObj.callback attribute.\n"); + +static PyObject * +pyalsahcontrolelement_setcallback(struct pyalsahcontrolelement *pyhelem, PyObject *args) +{ + PyObject *o; + + if (!PyArg_ParseTuple(args, "O", &o)) + return NULL; + if (o == Py_None) { + Py_XDECREF(pyhelem->callback); + pyhelem->callback = NULL; + snd_hctl_elem_set_callback(pyhelem->elem, NULL); + } else { + Py_INCREF(o); + pyhelem->callback = o; + snd_hctl_elem_set_callback_private(pyhelem->elem, pyhelem); + snd_hctl_elem_set_callback(pyhelem->elem, element_callback); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(elementinit__doc__, +"Element(hctl, numid)\n" +"Element(hctl, interface, device, subdevice, name, index)\n" +"Element(hctl, (interface, device, subdevice, name, index))\n" +" -- Create a hcontrol element object.\n"); + +static int +pyalsahcontrolelement_init(struct pyalsahcontrolelement *pyhelem, PyObject *args, PyObject *kwds) +{ + PyObject *hctl, *first; + char *name = "Default"; + int numid = 0, iface = 0, device = 0, subdevice = 0, index = 0; + snd_ctl_elem_id_t *id; + static char *kwlist1[] = { "hctl", "interface", "device", "subdevice", "name", "index" }; + + snd_ctl_elem_id_alloca(&id); + pyhelem->pyhandle = NULL; + pyhelem->handle = NULL; + pyhelem->elem = NULL; + + if (!PyTuple_Check(args) || PyTuple_Size(args) < 2) { + PyErr_SetString(PyExc_TypeError, "first argument must be alsahcontrol.HControl"); + return -1; + } + first = PyTuple_GetItem(args, 1); + if (PyInt_Check(first)) { + if (!PyArg_ParseTuple(args, "Oi", &hctl, &numid)) + return -1; + snd_ctl_elem_id_set_numid(id, numid); + } else if (PyTuple_Check(first)) { + if (!PyArg_ParseTuple(args, "OO", &hctl, &first)) + return -1; + if (!PyArg_ParseTupleAndKeywords(first, kwds, "|iiisi", kwlist1 + 1, &iface, &device, &subdevice, &name, &index)) + return -1; + goto parse1; + } else { + if (!PyArg_ParseTupleAndKeywords(first, kwds, "O|iiisi", kwlist1, &hctl, &iface, &device, &subdevice, &name, &index)) + return -1; + parse1: + snd_ctl_elem_id_set_interface(id, iface); + snd_ctl_elem_id_set_device(id, device); + snd_ctl_elem_id_set_subdevice(id, subdevice); + snd_ctl_elem_id_set_name(id, name); + snd_ctl_elem_id_set_index(id, index); + } + + if (hctl->ob_type != &pyalsahcontrol_type) { + PyErr_SetString(PyExc_TypeError, "bad type for hctl argument"); + return -1; + } + + pyhelem->pyhandle = hctl; + Py_INCREF(hctl); + pyhelem->handle = PYHCTL(hctl)->handle; + + pyhelem->elem = snd_hctl_find_elem(pyhelem->handle, id); + if (pyhelem->elem == NULL) { + if (numid == 0) + PyErr_Format(PyExc_IOError, "cannot find hcontrol element %i,%i,%i,'%s',%i", iface, device, subdevice, name, index); + else + PyErr_Format(PyExc_IOError, "cannot find hcontrol element numid=%i", numid); + return -1; + } + + return 0; +} + +static void +pyalsahcontrolelement_dealloc(struct pyalsahcontrolelement *self) +{ + if (self->elem) { + Py_XDECREF(self->callback); + snd_hctl_elem_set_callback(self->elem, NULL); + } + if (self->pyhandle) { + Py_XDECREF(self->pyhandle); + } + + self->ob_type->tp_free(self); +} + +static PyGetSetDef pyalsahcontrolelement_getseters[] = { + + {"numid", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element numid", snd_hctl_elem_get_numid}, + {"interface", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element interface", snd_hctl_elem_get_interface}, + {"device", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element device", snd_hctl_elem_get_device}, + {"subdevice", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element subdevice", snd_hctl_elem_get_subdevice}, + {"name", (getter)pyalsahcontrolelement_getname, NULL, "hcontrol element name", NULL}, + {"index", (getter)pyalsahcontrolelement_uint, NULL, "hcontrol element index", snd_hctl_elem_get_index}, + + {NULL} +}; + +static PyMethodDef pyalsahcontrolelement_methods[] = { + + {"setCallback", (PyCFunction)pyalsahcontrolelement_setcallback, METH_VARARGS, setcallback__doc__}, + + {NULL} +}; + +static PyTypeObject pyalsahcontrolelement_type = { + PyObject_HEAD_INIT(0) + tp_name: "alsahcontrol.Element", + tp_basicsize: sizeof(struct pyalsahcontrolelement), + tp_dealloc: (destructor)pyalsahcontrolelement_dealloc, + tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + tp_doc: elementinit__doc__, + tp_getset: pyalsahcontrolelement_getseters, + tp_init: (initproc)pyalsahcontrolelement_init, + tp_alloc: PyType_GenericAlloc, + tp_new: PyType_GenericNew, + tp_free: PyObject_Del, + tp_methods: pyalsahcontrolelement_methods, +}; + +/* + * + */ + +static PyMethodDef pyalsahcontrolparse_methods[] = { + {NULL} +}; + +PyMODINIT_FUNC +initalsahcontrol(void) +{ + PyObject *d, *d1, *l1, *o; + int i; + + if (PyType_Ready(&pyalsahcontrol_type) < 0) + return; + if (PyType_Ready(&pyalsahcontrolelement_type) < 0) + return; + + module = Py_InitModule3("alsahcontrol", pyalsahcontrolparse_methods, "libasound hcontrol wrapper"); + if (module == NULL) + return; + +#if 0 + buildin = PyImport_AddModule("__buildin__"); + if (buildin == NULL) + return; + if (PyObject_SetAttrString(module, "__buildins__", buildin) < 0) + return; +#endif + + Py_INCREF(&pyalsahcontrol_type); + PyModule_AddObject(module, "HControl", (PyObject *)&pyalsahcontrol_type); + + Py_INCREF(&pyalsahcontrolelement_type); + PyModule_AddObject(module, "Element", (PyObject *)&pyalsahcontrolelement_type); + + d = PyModule_GetDict(module); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space1(pname, name) { \ + o = PyInt_FromLong(SND_CTL_ELEM_IFACE_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space1("Card", CARD); + add_space1("HwDep", HWDEP); + add_space1("Mixer", MIXER); + add_space1("PCM", PCM); + add_space1("RawMidi", RAWMIDI); + add_space1("Timer", TIMER); + add_space1("Sequencer", SEQUENCER); + add_space1("Last", LAST); + + PyDict_SetItemString(d, "InterfaceId", d1); + Py_DECREF(d1); + + /* ---- */ + + l1 = PyList_New(0); + + for (i = 0; i <= SND_CTL_ELEM_IFACE_LAST; i++) { + o = PyString_FromString(snd_ctl_elem_iface_name(i)); + PyList_Append(l1, o); + Py_DECREF(o); + } + + PyDict_SetItemString(d, "InterfaceName", l1); + Py_DECREF(l1); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space2(pname, name) { \ + o = PyInt_FromLong(SND_CTL_ELEM_TYPE_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space2("None", NONE); + add_space2("Boolean", BOOLEAN); + add_space2("Integer", INTEGER); + add_space2("Enumeraed", ENUMERATED); + add_space2("Bytes", BYTES); + add_space2("IEC958", IEC958); + add_space2("Integer64", INTEGER64); + add_space2("Last", LAST); + + PyDict_SetItemString(d, "ElementType", d1); + Py_DECREF(d1); + + /* ---- */ + + l1 = PyList_New(0); + + for (i = 0; i <= SND_CTL_ELEM_TYPE_LAST; i++) { + o = PyString_FromString(snd_ctl_elem_type_name(i)); + PyList_Append(l1, o); + Py_DECREF(o); + } + + PyDict_SetItemString(d, "ElementTypeName", l1); + Py_DECREF(l1); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space3(pname, name) { \ + o = PyInt_FromLong(SND_CTL_EVENT_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space3("Element", ELEM); + add_space3("Last", LAST); + + PyDict_SetItemString(d, "EventClass", d1); + Py_DECREF(d1); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space4(pname, name) { \ + o = PyInt_FromLong(SND_CTL_EVENT_MASK_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space4("Value", VALUE); + add_space4("Info", INFO); + add_space4("Add", ADD); + add_space4("TLV", TLV); + + PyDict_SetItemString(d, "EventMask", d1); + Py_DECREF(d1); + + o = PyInt_FromLong(SND_CTL_EVENT_MASK_REMOVE); + PyDict_SetItemString(d, "EventMaskRemove", o); + Py_DECREF(o); + + /* ---- */ + + d1 = PyDict_New(); + +#define add_space5(pname, name) { \ + o = PyInt_FromLong(SND_CTL_##name); \ + PyDict_SetItemString(d1, pname, o); \ + Py_DECREF(o); } + + add_space5("NonBlock", NONBLOCK); + add_space5("Async", ASYNC); + add_space5("ReadOnly", READONLY); + + PyDict_SetItemString(d, "OpenMode", d1); + Py_DECREF(d1); + + /* ---- */ + + main_interpreter = PyThreadState_Get()->interp; + + if (PyErr_Occurred()) + Py_FatalError("Cannot initialize module alsahcontrol"); +} + +/* + * element event callback + */ + +static int element_callback(snd_hctl_elem_t *elem, unsigned int mask) +{ + PyThreadState *tstate, *origstate; + struct pyalsahcontrolelement *pyhelem; + PyObject *o, *t, *r; + int res = 0, inside = 1; + + if (elem == NULL) + return -EINVAL; + pyhelem = snd_hctl_elem_get_callback_private(elem); + if (pyhelem == NULL || pyhelem->callback == NULL) + return -EINVAL; + + tstate = PyThreadState_New(main_interpreter); + origstate = PyThreadState_Swap(tstate); + + o = PyObject_GetAttr(pyhelem->callback, PyString_InternFromString("callback")); + if (!o) { + PyErr_Clear(); + o = pyhelem->callback; + inside = 0; + } + + t = PyTuple_New(2); + if (t) { + if (PyTuple_SET_ITEM(t, 0, (PyObject *)pyhelem)) + Py_INCREF(pyhelem); + PyTuple_SET_ITEM(t, 1, PyInt_FromLong(mask)); + r = PyObject_CallObject(o, t); + Py_DECREF(t); + + if (r) { + if (PyInt_Check(r)) { + res = PyInt_AsLong(o); + } else if (r == Py_None) { + res = 0; + } + Py_DECREF(r); + } else { + PyErr_Print(); + PyErr_Clear(); + res = -EIO; + } + } + if (inside) { + Py_DECREF(o); + } + + PyThreadState_Swap(origstate); + PyThreadState_Delete(tstate); + + return res; +} diff --git a/pyalsa/hctltest1.py b/pyalsa/hctltest1.py new file mode 100755 index 0000000..86badc6 --- /dev/null +++ b/pyalsa/hctltest1.py @@ -0,0 +1,28 @@ +#! /usr/bin/python +# -*- Python -*- + +import alsahcontrol + +print 'InterfaceId:' +print ' ', alsahcontrol.InterfaceId +print 'InterfaceName:' +print ' ', alsahcontrol.InterfaceName +print 'ElementType:' +print ' ', alsahcontrol.ElementType +print 'ElementTypeName:' +print ' ', alsahcontrol.ElementTypeName +print 'EventClass:' +print ' ', alsahcontrol.EventClass +print 'EventMask:' +print ' ', alsahcontrol.EventMask +print 'EventMaskRemove:', alsahcontrol.EventMaskRemove +print ' ', alsahcontrol.OpenMode +print 'EventMaskRemove:', alsahcontrol.OpenMode + +hctl = alsahcontrol.HControl() +print 'Count: ', hctl.count +list = hctl.list() +print 'List:' +print list +element1 = alsahcontrol.Element(hctl, list[0][1:]) +del hctl diff --git a/pyalsa/hctltest2.py b/pyalsa/hctltest2.py new file mode 100755 index 0000000..87dea3d --- /dev/null +++ b/pyalsa/hctltest2.py @@ -0,0 +1,41 @@ +#! /usr/bin/python +# -*- Python -*- + +import select +import alsahcontrol + +def parse_event_mask(events): + if events == 0: + return 'None' + if events == alsahcontrol.EventMaskRemove: + return 'Removed' + s = '' + for i in alsahcontrol.EventMask.keys(): + if events & alsahcontrol.EventMask[i]: + s += '%s ' % i + return s[:-1] + +def event_callback(element, events): + + print 'CALLBACK (DEF)! [%s] %s:%i' % (parse_event_mask(events), element.name, element.index) + + +class MyElementEvent: + + def callback(self, element, events): + print 'CALLBACK (CLASS)! [%s] %s:%i' % (parse_event_mask(events), element.name, element.index) + +hctl = alsahcontrol.HControl() +list = hctl.list() +element1 = alsahcontrol.Element(hctl, list[0][1:]) +element1.setCallback(event_callback) +element2 = alsahcontrol.Element(hctl, list[1][1:]) +element2.setCallback(MyElementEvent()) +print 'Watching (DEF): %s,%i' % (element1.name, element1.index) +print 'Watching (CLASS): %s,%i' % (element2.name, element2.index) +poller = select.poll() +hctl.registerPoll(poller) +while True: + poller.poll() + print 'Poll OK!' + hctl.handleEvents() diff --git a/setup.py b/setup.py index 7f07942..6006b36 100755 --- a/setup.py +++ b/setup.py @@ -16,6 +16,11 @@ setup( include_dirs=[], library_dirs=[], libraries=['asound']), + Extension('pyalsa.alsahcontrol', + ['pyalsa/alsahcontrol.c'], + include_dirs=[], + library_dirs=[], + libraries=['asound']), Extension('pyalsa.alsamixer', ['pyalsa/alsamixer.c'], include_dirs=[], @@ -28,7 +33,7 @@ setup( uname = os.uname() a = 'build/lib.%s-%s-%s' % (uname[0].lower(), uname[4], sys.version[:3]) -for f in ['alsacard.so', 'alsamixer.so']: +for f in ['alsacard.so', 'alsahcontrol.so', 'alsamixer.so']: if not os.path.exists('pyalsa/%s' % f): a = '../build/lib.%s-%s-%s/pyalsa/%s' % (uname[0].lower(), uname[4], sys.version[:3], f) -- 2.47.1