• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Hey Emacs, this is -*-C-*-
2  ******************************************************************************
3  * linuxaudiodev.c -- Linux audio device for python.
4  *
5  * Author          : Peter Bosch
6  * Created On      : Thu Mar  2 21:10:33 2000
7  * Status          : Unknown, Use with caution!
8  *
9  * Unless other notices are present in any part of this file
10  * explicitly claiming copyrights for other people and/or
11  * organizations, the contents of this file is fully copyright
12  * (C) 2000 Peter Bosch, all rights reserved.
13  ******************************************************************************
14  */
15 
16 #include "Python.h"
17 #include "structmember.h"
18 
19 #ifdef HAVE_FCNTL_H
20 #include <fcntl.h>
21 #else
22 #define O_RDONLY 00
23 #define O_WRONLY 01
24 #endif
25 
26 
27 #include <sys/ioctl.h>
28 #if defined(linux)
29 #include <linux/soundcard.h>
30 
31 #ifndef HAVE_STDINT_H
32 typedef unsigned long uint32_t;
33 #endif
34 
35 #elif defined(__FreeBSD__)
36 #include <machine/soundcard.h>
37 
38 #ifndef SNDCTL_DSP_CHANNELS
39 #define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS
40 #endif
41 
42 #endif
43 
44 typedef struct {
45     PyObject_HEAD
46     int         x_fd;           /* The open file */
47     int         x_mode;           /* file mode */
48     int         x_icount;       /* Input count */
49     int         x_ocount;       /* Output count */
50     uint32_t    x_afmts;        /* Audio formats supported by hardware*/
51 } lad_t;
52 
53 /* XXX several format defined in soundcard.h are not supported,
54    including _NE (native endian) options and S32 options
55 */
56 
57 static struct {
58     int         a_bps;
59     uint32_t    a_fmt;
60     char       *a_name;
61 } audio_types[] = {
62     {  8,       AFMT_MU_LAW, "logarithmic mu-law 8-bit audio" },
63     {  8,       AFMT_A_LAW,  "logarithmic A-law 8-bit audio" },
64     {  8,       AFMT_U8,     "linear unsigned 8-bit audio" },
65     {  8,       AFMT_S8,     "linear signed 8-bit audio" },
66     { 16,       AFMT_U16_BE, "linear unsigned 16-bit big-endian audio" },
67     { 16,       AFMT_U16_LE, "linear unsigned 16-bit little-endian audio" },
68     { 16,       AFMT_S16_BE, "linear signed 16-bit big-endian audio" },
69     { 16,       AFMT_S16_LE, "linear signed 16-bit little-endian audio" },
70     { 16,       AFMT_S16_NE, "linear signed 16-bit native-endian audio" },
71 };
72 
73 static int n_audio_types = sizeof(audio_types) / sizeof(audio_types[0]);
74 
75 static PyTypeObject Ladtype;
76 
77 static PyObject *LinuxAudioError;
78 
79 static lad_t *
newladobject(PyObject * arg)80 newladobject(PyObject *arg)
81 {
82     lad_t *xp;
83     int fd, afmts, imode;
84     char *basedev = NULL;
85     char *mode = NULL;
86 
87     /* Two ways to call linuxaudiodev.open():
88          open(device, mode) (for consistency with builtin open())
89          open(mode)         (for backwards compatibility)
90        because the *first* argument is optional, parsing args is
91        a wee bit tricky. */
92     if (!PyArg_ParseTuple(arg, "s|s:open", &basedev, &mode))
93        return NULL;
94     if (mode == NULL) {                 /* only one arg supplied */
95        mode = basedev;
96        basedev = NULL;
97     }
98 
99     if (strcmp(mode, "r") == 0)
100         imode = O_RDONLY;
101     else if (strcmp(mode, "w") == 0)
102         imode = O_WRONLY;
103     else {
104         PyErr_SetString(LinuxAudioError, "mode should be 'r' or 'w'");
105         return NULL;
106     }
107 
108     /* Open the correct device.  The base device name comes from the
109      * AUDIODEV environment variable first, then /dev/dsp.  The
110      * control device tacks "ctl" onto the base device name.
111      *
112      * Note that the only difference between /dev/audio and /dev/dsp
113      * is that the former uses logarithmic mu-law encoding and the
114      * latter uses 8-bit unsigned encoding.
115      */
116 
117     if (basedev == NULL) {              /* called with one arg */
118        basedev = getenv("AUDIODEV");
119        if (basedev == NULL)             /* $AUDIODEV not set */
120           basedev = "/dev/dsp";
121     }
122 
123     if ((fd = open(basedev, imode)) == -1) {
124         PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
125         return NULL;
126     }
127     if (imode == O_WRONLY && ioctl(fd, SNDCTL_DSP_NONBLOCK, NULL) == -1) {
128         PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
129         return NULL;
130     }
131     if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) {
132         PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
133         return NULL;
134     }
135     /* Create and initialize the object */
136     if ((xp = PyObject_New(lad_t, &Ladtype)) == NULL) {
137         close(fd);
138         return NULL;
139     }
140     xp->x_fd = fd;
141     xp->x_mode = imode;
142     xp->x_icount = xp->x_ocount = 0;
143     xp->x_afmts  = afmts;
144     return xp;
145 }
146 
147 static void
lad_dealloc(lad_t * xp)148 lad_dealloc(lad_t *xp)
149 {
150     /* if already closed, don't reclose it */
151     if (xp->x_fd != -1)
152         close(xp->x_fd);
153     PyObject_Del(xp);
154 }
155 
156 static PyObject *
lad_read(lad_t * self,PyObject * args)157 lad_read(lad_t *self, PyObject *args)
158 {
159     int size, count;
160     char *cp;
161     PyObject *rv;
162 
163     if (!PyArg_ParseTuple(args, "i:read", &size))
164         return NULL;
165     rv = PyString_FromStringAndSize(NULL, size);
166     if (rv == NULL)
167         return NULL;
168     cp = PyString_AS_STRING(rv);
169     if ((count = read(self->x_fd, cp, size)) < 0) {
170         PyErr_SetFromErrno(LinuxAudioError);
171         Py_DECREF(rv);
172         return NULL;
173     }
174     self->x_icount += count;
175     _PyString_Resize(&rv, count);
176     return rv;
177 }
178 
179 static PyObject *
lad_write(lad_t * self,PyObject * args)180 lad_write(lad_t *self, PyObject *args)
181 {
182     char *cp;
183     int rv, size;
184     fd_set write_set_fds;
185     struct timeval tv;
186     int select_retval;
187 
188     if (!PyArg_ParseTuple(args, "s#:write", &cp, &size))
189         return NULL;
190 
191     /* use select to wait for audio device to be available */
192     FD_ZERO(&write_set_fds);
193     FD_SET(self->x_fd, &write_set_fds);
194     tv.tv_sec = 4; /* timeout values */
195     tv.tv_usec = 0;
196 
197     while (size > 0) {
198       select_retval = select(self->x_fd+1, NULL, &write_set_fds, NULL, &tv);
199       tv.tv_sec = 1; tv.tv_usec = 0; /* willing to wait this long next time*/
200       if (select_retval) {
201         if ((rv = write(self->x_fd, cp, size)) == -1) {
202           if (errno != EAGAIN) {
203             PyErr_SetFromErrno(LinuxAudioError);
204             return NULL;
205           } else {
206             errno = 0; /* EAGAIN: buffer is full, try again */
207           }
208         } else {
209           self->x_ocount += rv;
210           size -= rv;
211           cp += rv;
212         }
213       } else {
214         /* printf("Not able to write to linux audio device within %ld seconds\n", tv.tv_sec); */
215         PyErr_SetFromErrno(LinuxAudioError);
216         return NULL;
217       }
218     }
219     Py_INCREF(Py_None);
220     return Py_None;
221 }
222 
223 static PyObject *
lad_close(lad_t * self,PyObject * unused)224 lad_close(lad_t *self, PyObject *unused)
225 {
226     if (self->x_fd >= 0) {
227         close(self->x_fd);
228         self->x_fd = -1;
229     }
230     Py_RETURN_NONE;
231 }
232 
233 static PyObject *
lad_fileno(lad_t * self,PyObject * unused)234 lad_fileno(lad_t *self, PyObject *unused)
235 {
236     return PyInt_FromLong(self->x_fd);
237 }
238 
239 static PyObject *
lad_setparameters(lad_t * self,PyObject * args)240 lad_setparameters(lad_t *self, PyObject *args)
241 {
242     int rate, ssize, nchannels, n, fmt, emulate=0;
243 
244     if (!PyArg_ParseTuple(args, "iiii|i:setparameters",
245                           &rate, &ssize, &nchannels, &fmt, &emulate))
246         return NULL;
247 
248     if (rate < 0) {
249         PyErr_Format(PyExc_ValueError, "expected rate >= 0, not %d",
250                      rate);
251         return NULL;
252     }
253     if (ssize < 0) {
254         PyErr_Format(PyExc_ValueError, "expected sample size >= 0, not %d",
255                      ssize);
256         return NULL;
257     }
258     if (nchannels != 1 && nchannels != 2) {
259         PyErr_Format(PyExc_ValueError, "nchannels must be 1 or 2, not %d",
260                      nchannels);
261         return NULL;
262     }
263 
264     for (n = 0; n < n_audio_types; n++)
265         if (fmt == audio_types[n].a_fmt)
266             break;
267     if (n == n_audio_types) {
268         PyErr_Format(PyExc_ValueError, "unknown audio encoding: %d", fmt);
269         return NULL;
270     }
271     if (audio_types[n].a_bps != ssize) {
272         PyErr_Format(PyExc_ValueError,
273                      "for %s, expected sample size %d, not %d",
274                      audio_types[n].a_name, audio_types[n].a_bps, ssize);
275         return NULL;
276     }
277 
278     if (emulate == 0) {
279         if ((self->x_afmts & audio_types[n].a_fmt) == 0) {
280             PyErr_Format(PyExc_ValueError,
281                          "%s format not supported by device",
282                          audio_types[n].a_name);
283             return NULL;
284         }
285     }
286     if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT,
287               &audio_types[n].a_fmt) == -1) {
288         PyErr_SetFromErrno(LinuxAudioError);
289         return NULL;
290     }
291     if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1) {
292         PyErr_SetFromErrno(LinuxAudioError);
293         return NULL;
294     }
295     if (ioctl(self->x_fd, SNDCTL_DSP_SPEED, &rate) == -1) {
296         PyErr_SetFromErrno(LinuxAudioError);
297         return NULL;
298     }
299 
300     Py_INCREF(Py_None);
301     return Py_None;
302 }
303 
304 static int
_ssize(lad_t * self,int * nchannels,int * ssize)305 _ssize(lad_t *self, int *nchannels, int *ssize)
306 {
307     int fmt;
308 
309     fmt = 0;
310     if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
311         return -errno;
312 
313     switch (fmt) {
314     case AFMT_MU_LAW:
315     case AFMT_A_LAW:
316     case AFMT_U8:
317     case AFMT_S8:
318         *ssize = sizeof(char);
319         break;
320     case AFMT_S16_LE:
321     case AFMT_S16_BE:
322     case AFMT_U16_LE:
323     case AFMT_U16_BE:
324         *ssize = sizeof(short);
325         break;
326     case AFMT_MPEG:
327     case AFMT_IMA_ADPCM:
328     default:
329         return -EOPNOTSUPP;
330     }
331     if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, nchannels) < 0)
332         return -errno;
333     return 0;
334 }
335 
336 
337 /* bufsize returns the size of the hardware audio buffer in number
338    of samples */
339 static PyObject *
lad_bufsize(lad_t * self,PyObject * unused)340 lad_bufsize(lad_t *self, PyObject *unused)
341 {
342     audio_buf_info ai;
343     int nchannels=0, ssize=0;
344 
345     if (_ssize(self, &nchannels, &ssize) < 0 || !ssize || !nchannels) {
346         PyErr_SetFromErrno(LinuxAudioError);
347         return NULL;
348     }
349     if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
350         PyErr_SetFromErrno(LinuxAudioError);
351         return NULL;
352     }
353     return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize));
354 }
355 
356 /* obufcount returns the number of samples that are available in the
357    hardware for playing */
358 static PyObject *
lad_obufcount(lad_t * self,PyObject * unused)359 lad_obufcount(lad_t *self, PyObject *unused)
360 {
361     audio_buf_info ai;
362     int nchannels=0, ssize=0;
363 
364     if (_ssize(self, &nchannels, &ssize) < 0 || !ssize || !nchannels) {
365         PyErr_SetFromErrno(LinuxAudioError);
366         return NULL;
367     }
368     if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
369         PyErr_SetFromErrno(LinuxAudioError);
370         return NULL;
371     }
372     return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) /
373                           (ssize * nchannels));
374 }
375 
376 /* obufcount returns the number of samples that can be played without
377    blocking */
378 static PyObject *
lad_obuffree(lad_t * self,PyObject * unused)379 lad_obuffree(lad_t *self, PyObject *unused)
380 {
381     audio_buf_info ai;
382     int nchannels=0, ssize=0;
383 
384     if (_ssize(self, &nchannels, &ssize) < 0 || !ssize || !nchannels) {
385         PyErr_SetFromErrno(LinuxAudioError);
386         return NULL;
387     }
388     if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
389         PyErr_SetFromErrno(LinuxAudioError);
390         return NULL;
391     }
392     return PyInt_FromLong(ai.bytes / (ssize * nchannels));
393 }
394 
395 /* Flush the device */
396 static PyObject *
lad_flush(lad_t * self,PyObject * unused)397 lad_flush(lad_t *self, PyObject *unused)
398 {
399     if (ioctl(self->x_fd, SNDCTL_DSP_SYNC, NULL) == -1) {
400         PyErr_SetFromErrno(LinuxAudioError);
401         return NULL;
402     }
403     Py_RETURN_NONE;
404 }
405 
406 static PyObject *
lad_getptr(lad_t * self,PyObject * unused)407 lad_getptr(lad_t *self, PyObject *unused)
408 {
409     count_info info;
410     int req;
411 
412     if (self->x_mode == O_RDONLY)
413         req = SNDCTL_DSP_GETIPTR;
414     else
415         req = SNDCTL_DSP_GETOPTR;
416     if (ioctl(self->x_fd, req, &info) == -1) {
417         PyErr_SetFromErrno(LinuxAudioError);
418         return NULL;
419     }
420     return Py_BuildValue("iii", info.bytes, info.blocks, info.ptr);
421 }
422 
423 static PyMethodDef lad_methods[] = {
424     { "read",           (PyCFunction)lad_read, METH_VARARGS },
425     { "write",          (PyCFunction)lad_write, METH_VARARGS },
426     { "setparameters",  (PyCFunction)lad_setparameters, METH_VARARGS },
427     { "bufsize",        (PyCFunction)lad_bufsize, METH_VARARGS },
428     { "obufcount",      (PyCFunction)lad_obufcount, METH_NOARGS },
429     { "obuffree",       (PyCFunction)lad_obuffree, METH_NOARGS },
430     { "flush",          (PyCFunction)lad_flush, METH_NOARGS },
431     { "close",          (PyCFunction)lad_close, METH_NOARGS },
432     { "fileno",         (PyCFunction)lad_fileno, METH_NOARGS },
433     { "getptr",         (PyCFunction)lad_getptr, METH_NOARGS },
434     { NULL,             NULL}           /* sentinel */
435 };
436 
437 static PyObject *
lad_getattr(lad_t * xp,char * name)438 lad_getattr(lad_t *xp, char *name)
439 {
440     return Py_FindMethod(lad_methods, (PyObject *)xp, name);
441 }
442 
443 static PyTypeObject Ladtype = {
444     PyVarObject_HEAD_INIT(&PyType_Type, 0)
445     "linuxaudiodev.linux_audio_device", /*tp_name*/
446     sizeof(lad_t),              /*tp_size*/
447     0,                          /*tp_itemsize*/
448     /* methods */
449     (destructor)lad_dealloc,    /*tp_dealloc*/
450     0,                          /*tp_print*/
451     (getattrfunc)lad_getattr,   /*tp_getattr*/
452     0,                          /*tp_setattr*/
453     0,                          /*tp_compare*/
454     0,                          /*tp_repr*/
455 };
456 
457 static PyObject *
ladopen(PyObject * self,PyObject * args)458 ladopen(PyObject *self, PyObject *args)
459 {
460     return (PyObject *)newladobject(args);
461 }
462 
463 static PyMethodDef linuxaudiodev_methods[] = {
464     { "open", ladopen, METH_VARARGS },
465     { 0, 0 },
466 };
467 
468 void
initlinuxaudiodev(void)469 initlinuxaudiodev(void)
470 {
471     PyObject *m;
472 
473     if (PyErr_WarnPy3k("the linuxaudiodev module has been removed in "
474                     "Python 3.0; use the ossaudiodev module instead", 2) < 0)
475         return;
476 
477     m = Py_InitModule("linuxaudiodev", linuxaudiodev_methods);
478     if (m == NULL)
479         return;
480 
481     LinuxAudioError = PyErr_NewException("linuxaudiodev.error", NULL, NULL);
482     if (LinuxAudioError)
483         PyModule_AddObject(m, "error", LinuxAudioError);
484 
485     if (PyModule_AddIntConstant(m, "AFMT_MU_LAW", (long)AFMT_MU_LAW) == -1)
486         return;
487     if (PyModule_AddIntConstant(m, "AFMT_A_LAW", (long)AFMT_A_LAW) == -1)
488         return;
489     if (PyModule_AddIntConstant(m, "AFMT_U8", (long)AFMT_U8) == -1)
490         return;
491     if (PyModule_AddIntConstant(m, "AFMT_S8", (long)AFMT_S8) == -1)
492         return;
493     if (PyModule_AddIntConstant(m, "AFMT_U16_BE", (long)AFMT_U16_BE) == -1)
494         return;
495     if (PyModule_AddIntConstant(m, "AFMT_U16_LE", (long)AFMT_U16_LE) == -1)
496         return;
497     if (PyModule_AddIntConstant(m, "AFMT_S16_BE", (long)AFMT_S16_BE) == -1)
498         return;
499     if (PyModule_AddIntConstant(m, "AFMT_S16_LE", (long)AFMT_S16_LE) == -1)
500         return;
501     if (PyModule_AddIntConstant(m, "AFMT_S16_NE", (long)AFMT_S16_NE) == -1)
502         return;
503 
504     return;
505 }
506