• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ossaudiodev -- Python interface to the OSS (Open Sound System) API.
3  *                This is the standard audio API for Linux and some
4  *                flavours of BSD [XXX which ones?]; it is also available
5  *                for a wide range of commercial Unices.
6  *
7  * Originally written by Peter Bosch, March 2000, as linuxaudiodev.
8  *
9  * Renamed to ossaudiodev and rearranged/revised/hacked up
10  * by Greg Ward <gward@python.net>, November 2002.
11  * Mixer interface by Nicholas FitzRoy-Dale <wzdd@lardcave.net>, Dec 2002.
12  *
13  * (c) 2000 Peter Bosch.  All Rights Reserved.
14  * (c) 2002 Gregory P. Ward.  All Rights Reserved.
15  * (c) 2002 Python Software Foundation.  All Rights Reserved.
16  *
17  * XXX need a license statement
18  *
19  * $Id$
20  */
21 
22 #include "Python.h"
23 #include "structmember.h"
24 
25 #ifdef HAVE_FCNTL_H
26 #include <fcntl.h>
27 #else
28 #define O_RDONLY 00
29 #define O_WRONLY 01
30 #endif
31 
32 #include <sys/ioctl.h>
33 #include <sys/soundcard.h>
34 
35 #if defined(linux)
36 
37 #ifndef HAVE_STDINT_H
38 typedef unsigned long uint32_t;
39 #endif
40 
41 #elif defined(__FreeBSD__)
42 
43 # ifndef SNDCTL_DSP_CHANNELS
44 #  define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS
45 # endif
46 
47 #endif
48 
49 typedef struct {
50     PyObject_HEAD
51     char    *devicename;              /* name of the device file */
52     int      fd;                      /* file descriptor */
53     int      mode;                    /* file mode (O_RDONLY, etc.) */
54     int      icount;                  /* input count */
55     int      ocount;                  /* output count */
56     uint32_t afmts;                   /* audio formats supported by hardware */
57 } oss_audio_t;
58 
59 typedef struct {
60     PyObject_HEAD
61     int      fd;                      /* The open mixer device */
62 } oss_mixer_t;
63 
64 
65 static PyTypeObject OSSAudioType;
66 static PyTypeObject OSSMixerType;
67 
68 static PyObject *OSSAudioError;
69 
70 
71 /* ----------------------------------------------------------------------
72  * DSP object initialization/deallocation
73  */
74 
75 static oss_audio_t *
newossobject(PyObject * arg)76 newossobject(PyObject *arg)
77 {
78     oss_audio_t *self;
79     int fd, afmts, imode;
80     char *devicename = NULL;
81     char *mode = NULL;
82 
83     /* Two ways to call open():
84          open(device, mode) (for consistency with builtin open())
85          open(mode)         (for backwards compatibility)
86        because the *first* argument is optional, parsing args is
87        a wee bit tricky. */
88     if (!PyArg_ParseTuple(arg, "s|s:open", &devicename, &mode))
89        return NULL;
90     if (mode == NULL) {                 /* only one arg supplied */
91        mode = devicename;
92        devicename = NULL;
93     }
94 
95     if (strcmp(mode, "r") == 0)
96         imode = O_RDONLY;
97     else if (strcmp(mode, "w") == 0)
98         imode = O_WRONLY;
99     else if (strcmp(mode, "rw") == 0)
100         imode = O_RDWR;
101     else {
102         PyErr_SetString(OSSAudioError, "mode must be 'r', 'w', or 'rw'");
103         return NULL;
104     }
105 
106     /* Open the correct device: either the 'device' argument,
107        or the AUDIODEV environment variable, or "/dev/dsp". */
108     if (devicename == NULL) {              /* called with one arg */
109        devicename = getenv("AUDIODEV");
110        if (devicename == NULL)             /* $AUDIODEV not set */
111           devicename = "/dev/dsp";
112     }
113 
114     /* Open with O_NONBLOCK to avoid hanging on devices that only allow
115        one open at a time.  This does *not* affect later I/O; OSS
116        provides a special ioctl() for non-blocking read/write, which is
117        exposed via oss_nonblock() below. */
118     if ((fd = open(devicename, imode|O_NONBLOCK)) == -1) {
119         PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
120         return NULL;
121     }
122 
123     /* And (try to) put it back in blocking mode so we get the
124        expected write() semantics. */
125     if (fcntl(fd, F_SETFL, 0) == -1) {
126         close(fd);
127         PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
128         return NULL;
129     }
130 
131     if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) {
132         close(fd);
133         PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
134         return NULL;
135     }
136     /* Create and initialize the object */
137     if ((self = PyObject_New(oss_audio_t, &OSSAudioType)) == NULL) {
138         close(fd);
139         return NULL;
140     }
141     self->devicename = devicename;
142     self->fd = fd;
143     self->mode = imode;
144     self->icount = self->ocount = 0;
145     self->afmts  = afmts;
146     return self;
147 }
148 
149 static void
oss_dealloc(oss_audio_t * self)150 oss_dealloc(oss_audio_t *self)
151 {
152     /* if already closed, don't reclose it */
153     if (self->fd != -1)
154         close(self->fd);
155     PyObject_Del(self);
156 }
157 
158 
159 /* ----------------------------------------------------------------------
160  * Mixer object initialization/deallocation
161  */
162 
163 static oss_mixer_t *
newossmixerobject(PyObject * arg)164 newossmixerobject(PyObject *arg)
165 {
166     char *devicename = NULL;
167     int fd;
168     oss_mixer_t *self;
169 
170     if (!PyArg_ParseTuple(arg, "|s", &devicename)) {
171         return NULL;
172     }
173 
174     if (devicename == NULL) {
175         devicename = getenv("MIXERDEV");
176         if (devicename == NULL)            /* MIXERDEV not set */
177             devicename = "/dev/mixer";
178     }
179 
180     if ((fd = open(devicename, O_RDWR)) == -1) {
181         PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
182         return NULL;
183     }
184 
185     if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) {
186         close(fd);
187         return NULL;
188     }
189 
190     self->fd = fd;
191 
192     return self;
193 }
194 
195 static void
oss_mixer_dealloc(oss_mixer_t * self)196 oss_mixer_dealloc(oss_mixer_t *self)
197 {
198     /* if already closed, don't reclose it */
199     if (self->fd != -1)
200         close(self->fd);
201     PyObject_Del(self);
202 }
203 
204 
205 /* Methods to wrap the OSS ioctls.  The calling convention is pretty
206    simple:
207      nonblock()        -> ioctl(fd, SNDCTL_DSP_NONBLOCK)
208      fmt = setfmt(fmt) -> ioctl(fd, SNDCTL_DSP_SETFMT, &fmt)
209      etc.
210 */
211 
212 
213 /* ----------------------------------------------------------------------
214  * Helper functions
215  */
216 
217 /* _do_ioctl_1() is a private helper function used for the OSS ioctls --
218    SNDCTL_DSP_{SETFMT,CHANNELS,SPEED} -- that are called from C
219    like this:
220      ioctl(fd, SNDCTL_DSP_cmd, &arg)
221 
222    where arg is the value to set, and on return the driver sets arg to
223    the value that was actually set.  Mapping this to Python is obvious:
224      arg = dsp.xxx(arg)
225 */
226 static PyObject *
_do_ioctl_1(int fd,PyObject * args,char * fname,int cmd)227 _do_ioctl_1(int fd, PyObject *args, char *fname, int cmd)
228 {
229     char argfmt[33] = "i:";
230     int arg;
231 
232     assert(strlen(fname) <= 30);
233     strcat(argfmt, fname);
234     if (!PyArg_ParseTuple(args, argfmt, &arg))
235         return NULL;
236 
237     if (ioctl(fd, cmd, &arg) == -1)
238         return PyErr_SetFromErrno(PyExc_IOError);
239     return PyInt_FromLong(arg);
240 }
241 
242 
243 /* _do_ioctl_1_internal() is a wrapper for ioctls that take no inputs
244    but return an output -- ie. we need to pass a pointer to a local C
245    variable so the driver can write its output there, but from Python
246    all we see is the return value.  For example,
247    SOUND_MIXER_READ_DEVMASK returns a bitmask of available mixer
248    devices, but does not use the value of the parameter passed-in in any
249    way.
250 */
251 static PyObject *
_do_ioctl_1_internal(int fd,PyObject * args,char * fname,int cmd)252 _do_ioctl_1_internal(int fd, PyObject *args, char *fname, int cmd)
253 {
254     char argfmt[32] = ":";
255     int arg = 0;
256 
257     assert(strlen(fname) <= 30);
258     strcat(argfmt, fname);
259     if (!PyArg_ParseTuple(args, argfmt, &arg))
260         return NULL;
261 
262     if (ioctl(fd, cmd, &arg) == -1)
263         return PyErr_SetFromErrno(PyExc_IOError);
264     return PyInt_FromLong(arg);
265 }
266 
267 
268 
269 /* _do_ioctl_0() is a private helper for the no-argument ioctls:
270    SNDCTL_DSP_{SYNC,RESET,POST}. */
271 static PyObject *
_do_ioctl_0(int fd,PyObject * args,char * fname,int cmd)272 _do_ioctl_0(int fd, PyObject *args, char *fname, int cmd)
273 {
274     char argfmt[32] = ":";
275     int rv;
276 
277     assert(strlen(fname) <= 30);
278     strcat(argfmt, fname);
279     if (!PyArg_ParseTuple(args, argfmt))
280         return NULL;
281 
282     /* According to hannu@opensound.com, all three of the ioctls that
283        use this function can block, so release the GIL.  This is
284        especially important for SYNC, which can block for several
285        seconds. */
286     Py_BEGIN_ALLOW_THREADS
287     rv = ioctl(fd, cmd, 0);
288     Py_END_ALLOW_THREADS
289 
290     if (rv == -1)
291         return PyErr_SetFromErrno(PyExc_IOError);
292     Py_INCREF(Py_None);
293     return Py_None;
294 }
295 
296 
297 /* ----------------------------------------------------------------------
298  * Methods of DSP objects (OSSAudioType)
299  */
300 
301 static PyObject *
oss_nonblock(oss_audio_t * self,PyObject * unused)302 oss_nonblock(oss_audio_t *self, PyObject *unused)
303 {
304     /* Hmmm: it doesn't appear to be possible to return to blocking
305        mode once we're in non-blocking mode! */
306     if (ioctl(self->fd, SNDCTL_DSP_NONBLOCK, NULL) == -1)
307         return PyErr_SetFromErrno(PyExc_IOError);
308     Py_INCREF(Py_None);
309     return Py_None;
310 }
311 
312 static PyObject *
oss_setfmt(oss_audio_t * self,PyObject * args)313 oss_setfmt(oss_audio_t *self, PyObject *args)
314 {
315     return _do_ioctl_1(self->fd, args, "setfmt", SNDCTL_DSP_SETFMT);
316 }
317 
318 static PyObject *
oss_getfmts(oss_audio_t * self,PyObject * unused)319 oss_getfmts(oss_audio_t *self, PyObject *unused)
320 {
321     int mask;
322     if (ioctl(self->fd, SNDCTL_DSP_GETFMTS, &mask) == -1)
323         return PyErr_SetFromErrno(PyExc_IOError);
324     return PyInt_FromLong(mask);
325 }
326 
327 static PyObject *
oss_channels(oss_audio_t * self,PyObject * args)328 oss_channels(oss_audio_t *self, PyObject *args)
329 {
330     return _do_ioctl_1(self->fd, args, "channels", SNDCTL_DSP_CHANNELS);
331 }
332 
333 static PyObject *
oss_speed(oss_audio_t * self,PyObject * args)334 oss_speed(oss_audio_t *self, PyObject *args)
335 {
336     return _do_ioctl_1(self->fd, args, "speed", SNDCTL_DSP_SPEED);
337 }
338 
339 static PyObject *
oss_sync(oss_audio_t * self,PyObject * args)340 oss_sync(oss_audio_t *self, PyObject *args)
341 {
342     return _do_ioctl_0(self->fd, args, "sync", SNDCTL_DSP_SYNC);
343 }
344 
345 static PyObject *
oss_reset(oss_audio_t * self,PyObject * args)346 oss_reset(oss_audio_t *self, PyObject *args)
347 {
348     return _do_ioctl_0(self->fd, args, "reset", SNDCTL_DSP_RESET);
349 }
350 
351 static PyObject *
oss_post(oss_audio_t * self,PyObject * args)352 oss_post(oss_audio_t *self, PyObject *args)
353 {
354     return _do_ioctl_0(self->fd, args, "post", SNDCTL_DSP_POST);
355 }
356 
357 
358 /* Regular file methods: read(), write(), close(), etc. as well
359    as one convenience method, writeall(). */
360 
361 static PyObject *
oss_read(oss_audio_t * self,PyObject * args)362 oss_read(oss_audio_t *self, PyObject *args)
363 {
364     int size, count;
365     char *cp;
366     PyObject *rv;
367 
368     if (!PyArg_ParseTuple(args, "i:read", &size))
369         return NULL;
370     rv = PyString_FromStringAndSize(NULL, size);
371     if (rv == NULL)
372         return NULL;
373     cp = PyString_AS_STRING(rv);
374 
375     Py_BEGIN_ALLOW_THREADS
376     count = read(self->fd, cp, size);
377     Py_END_ALLOW_THREADS
378 
379     if (count < 0) {
380         PyErr_SetFromErrno(PyExc_IOError);
381         Py_DECREF(rv);
382         return NULL;
383     }
384     self->icount += count;
385     _PyString_Resize(&rv, count);
386     return rv;
387 }
388 
389 static PyObject *
oss_write(oss_audio_t * self,PyObject * args)390 oss_write(oss_audio_t *self, PyObject *args)
391 {
392     char *cp;
393     int rv, size;
394 
395     if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) {
396         return NULL;
397     }
398 
399     Py_BEGIN_ALLOW_THREADS
400     rv = write(self->fd, cp, size);
401     Py_END_ALLOW_THREADS
402 
403     if (rv == -1) {
404         return PyErr_SetFromErrno(PyExc_IOError);
405     } else {
406         self->ocount += rv;
407     }
408     return PyInt_FromLong(rv);
409 }
410 
411 static PyObject *
oss_writeall(oss_audio_t * self,PyObject * args)412 oss_writeall(oss_audio_t *self, PyObject *args)
413 {
414     char *cp;
415     int rv, size;
416     fd_set write_set_fds;
417     int select_rv;
418 
419     /* NB. writeall() is only useful in non-blocking mode: according to
420        Guenter Geiger <geiger@xdv.org> on the linux-audio-dev list
421        (http://eca.cx/lad/2002/11/0380.html), OSS guarantees that
422        write() in blocking mode consumes the whole buffer.  In blocking
423        mode, the behaviour of write() and writeall() from Python is
424        indistinguishable. */
425 
426     if (!PyArg_ParseTuple(args, "s#:write", &cp, &size))
427         return NULL;
428 
429     if (!_PyIsSelectable_fd(self->fd)) {
430         PyErr_SetString(PyExc_ValueError,
431                         "file descriptor out of range for select");
432         return NULL;
433     }
434     /* use select to wait for audio device to be available */
435     FD_ZERO(&write_set_fds);
436     FD_SET(self->fd, &write_set_fds);
437 
438     while (size > 0) {
439         Py_BEGIN_ALLOW_THREADS
440         select_rv = select(self->fd+1, NULL, &write_set_fds, NULL, NULL);
441         Py_END_ALLOW_THREADS
442         assert(select_rv != 0);         /* no timeout, can't expire */
443         if (select_rv == -1)
444             return PyErr_SetFromErrno(PyExc_IOError);
445 
446         Py_BEGIN_ALLOW_THREADS
447         rv = write(self->fd, cp, size);
448         Py_END_ALLOW_THREADS
449         if (rv == -1) {
450             if (errno == EAGAIN) {      /* buffer is full, try again */
451                 errno = 0;
452                 continue;
453             } else                      /* it's a real error */
454                 return PyErr_SetFromErrno(PyExc_IOError);
455         } else {                        /* wrote rv bytes */
456             self->ocount += rv;
457             size -= rv;
458             cp += rv;
459         }
460     }
461     Py_INCREF(Py_None);
462     return Py_None;
463 }
464 
465 static PyObject *
oss_close(oss_audio_t * self,PyObject * unused)466 oss_close(oss_audio_t *self, PyObject *unused)
467 {
468     if (self->fd >= 0) {
469         Py_BEGIN_ALLOW_THREADS
470         close(self->fd);
471         Py_END_ALLOW_THREADS
472         self->fd = -1;
473     }
474     Py_INCREF(Py_None);
475     return Py_None;
476 }
477 
478 static PyObject *
oss_fileno(oss_audio_t * self,PyObject * unused)479 oss_fileno(oss_audio_t *self, PyObject *unused)
480 {
481     return PyInt_FromLong(self->fd);
482 }
483 
484 
485 /* Convenience methods: these generally wrap a couple of ioctls into one
486    common task. */
487 
488 static PyObject *
oss_setparameters(oss_audio_t * self,PyObject * args)489 oss_setparameters(oss_audio_t *self, PyObject *args)
490 {
491     int wanted_fmt, wanted_channels, wanted_rate, strict=0;
492     int fmt, channels, rate;
493 
494     if (!PyArg_ParseTuple(args, "iii|i:setparameters",
495                           &wanted_fmt, &wanted_channels, &wanted_rate,
496                           &strict))
497         return NULL;
498 
499     fmt = wanted_fmt;
500     if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) == -1) {
501         return PyErr_SetFromErrno(PyExc_IOError);
502     }
503     if (strict && fmt != wanted_fmt) {
504         return PyErr_Format
505             (OSSAudioError,
506              "unable to set requested format (wanted %d, got %d)",
507              wanted_fmt, fmt);
508     }
509 
510     channels = wanted_channels;
511     if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
512         return PyErr_SetFromErrno(PyExc_IOError);
513     }
514     if (strict && channels != wanted_channels) {
515         return PyErr_Format
516             (OSSAudioError,
517              "unable to set requested channels (wanted %d, got %d)",
518              wanted_channels, channels);
519     }
520 
521     rate = wanted_rate;
522     if (ioctl(self->fd, SNDCTL_DSP_SPEED, &rate) == -1) {
523         return PyErr_SetFromErrno(PyExc_IOError);
524     }
525     if (strict && rate != wanted_rate) {
526         return PyErr_Format
527             (OSSAudioError,
528              "unable to set requested rate (wanted %d, got %d)",
529              wanted_rate, rate);
530     }
531 
532     /* Construct the return value: a (fmt, channels, rate) tuple that
533        tells what the audio hardware was actually set to. */
534     return Py_BuildValue("(iii)", fmt, channels, rate);
535 }
536 
537 static int
_ssize(oss_audio_t * self,int * nchannels,int * ssize)538 _ssize(oss_audio_t *self, int *nchannels, int *ssize)
539 {
540     int fmt;
541 
542     fmt = 0;
543     if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
544         return -errno;
545 
546     switch (fmt) {
547     case AFMT_MU_LAW:
548     case AFMT_A_LAW:
549     case AFMT_U8:
550     case AFMT_S8:
551         *ssize = 1;                     /* 8 bit formats: 1 byte */
552         break;
553     case AFMT_S16_LE:
554     case AFMT_S16_BE:
555     case AFMT_U16_LE:
556     case AFMT_U16_BE:
557         *ssize = 2;                     /* 16 bit formats: 2 byte */
558         break;
559     case AFMT_MPEG:
560     case AFMT_IMA_ADPCM:
561     default:
562         return -EOPNOTSUPP;
563     }
564     if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, nchannels) < 0)
565         return -errno;
566     return 0;
567 }
568 
569 
570 /* bufsize returns the size of the hardware audio buffer in number
571    of samples */
572 static PyObject *
oss_bufsize(oss_audio_t * self,PyObject * unused)573 oss_bufsize(oss_audio_t *self, PyObject *unused)
574 {
575     audio_buf_info ai;
576     int nchannels=0, ssize=0;
577 
578     if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
579         PyErr_SetFromErrno(PyExc_IOError);
580         return NULL;
581     }
582     if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
583         PyErr_SetFromErrno(PyExc_IOError);
584         return NULL;
585     }
586     return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize));
587 }
588 
589 /* obufcount returns the number of samples that are available in the
590    hardware for playing */
591 static PyObject *
oss_obufcount(oss_audio_t * self,PyObject * unused)592 oss_obufcount(oss_audio_t *self, PyObject *unused)
593 {
594     audio_buf_info ai;
595     int nchannels=0, ssize=0;
596 
597     if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
598         PyErr_SetFromErrno(PyExc_IOError);
599         return NULL;
600     }
601     if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
602         PyErr_SetFromErrno(PyExc_IOError);
603         return NULL;
604     }
605     return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) /
606                           (ssize * nchannels));
607 }
608 
609 /* obufcount returns the number of samples that can be played without
610    blocking */
611 static PyObject *
oss_obuffree(oss_audio_t * self,PyObject * unused)612 oss_obuffree(oss_audio_t *self, PyObject *unused)
613 {
614     audio_buf_info ai;
615     int nchannels=0, ssize=0;
616 
617     if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
618         PyErr_SetFromErrno(PyExc_IOError);
619         return NULL;
620     }
621     if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
622         PyErr_SetFromErrno(PyExc_IOError);
623         return NULL;
624     }
625     return PyInt_FromLong(ai.bytes / (ssize * nchannels));
626 }
627 
628 static PyObject *
oss_getptr(oss_audio_t * self,PyObject * unused)629 oss_getptr(oss_audio_t *self, PyObject *unused)
630 {
631     count_info info;
632     int req;
633 
634     if (self->mode == O_RDONLY)
635         req = SNDCTL_DSP_GETIPTR;
636     else
637         req = SNDCTL_DSP_GETOPTR;
638     if (ioctl(self->fd, req, &info) == -1) {
639         PyErr_SetFromErrno(PyExc_IOError);
640         return NULL;
641     }
642     return Py_BuildValue("iii", info.bytes, info.blocks, info.ptr);
643 }
644 
645 
646 /* ----------------------------------------------------------------------
647  * Methods of mixer objects (OSSMixerType)
648  */
649 
650 static PyObject *
oss_mixer_close(oss_mixer_t * self,PyObject * unused)651 oss_mixer_close(oss_mixer_t *self, PyObject *unused)
652 {
653     if (self->fd >= 0) {
654         close(self->fd);
655         self->fd = -1;
656     }
657     Py_INCREF(Py_None);
658     return Py_None;
659 }
660 
661 static PyObject *
oss_mixer_fileno(oss_mixer_t * self,PyObject * unused)662 oss_mixer_fileno(oss_mixer_t *self, PyObject *unused)
663 {
664     return PyInt_FromLong(self->fd);
665 }
666 
667 /* Simple mixer interface methods */
668 
669 static PyObject *
oss_mixer_controls(oss_mixer_t * self,PyObject * args)670 oss_mixer_controls(oss_mixer_t *self, PyObject *args)
671 {
672     return _do_ioctl_1_internal(self->fd, args, "controls",
673         SOUND_MIXER_READ_DEVMASK);
674 }
675 
676 static PyObject *
oss_mixer_stereocontrols(oss_mixer_t * self,PyObject * args)677 oss_mixer_stereocontrols(oss_mixer_t *self, PyObject *args)
678 {
679     return _do_ioctl_1_internal(self->fd, args, "stereocontrols",
680         SOUND_MIXER_READ_STEREODEVS);
681 }
682 
683 static PyObject *
oss_mixer_reccontrols(oss_mixer_t * self,PyObject * args)684 oss_mixer_reccontrols(oss_mixer_t *self, PyObject *args)
685 {
686     return _do_ioctl_1_internal(self->fd, args, "reccontrols",
687         SOUND_MIXER_READ_RECMASK);
688 }
689 
690 static PyObject *
oss_mixer_get(oss_mixer_t * self,PyObject * args)691 oss_mixer_get(oss_mixer_t *self, PyObject *args)
692 {
693     int channel, volume;
694 
695     /* Can't use _do_ioctl_1 because of encoded arg thingy. */
696     if (!PyArg_ParseTuple(args, "i:get", &channel))
697         return NULL;
698 
699     if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) {
700         PyErr_SetString(OSSAudioError, "Invalid mixer channel specified.");
701         return NULL;
702     }
703 
704     if (ioctl(self->fd, MIXER_READ(channel), &volume) == -1)
705         return PyErr_SetFromErrno(PyExc_IOError);
706 
707     return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8);
708 }
709 
710 static PyObject *
oss_mixer_set(oss_mixer_t * self,PyObject * args)711 oss_mixer_set(oss_mixer_t *self, PyObject *args)
712 {
713     int channel, volume, leftVol, rightVol;
714 
715     /* Can't use _do_ioctl_1 because of encoded arg thingy. */
716     if (!PyArg_ParseTuple(args, "i(ii):set", &channel, &leftVol, &rightVol))
717         return NULL;
718 
719     if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) {
720         PyErr_SetString(OSSAudioError, "Invalid mixer channel specified.");
721         return NULL;
722     }
723 
724     if (leftVol < 0 || rightVol < 0 || leftVol > 100 || rightVol > 100) {
725         PyErr_SetString(OSSAudioError, "Volumes must be between 0 and 100.");
726         return NULL;
727     }
728 
729     volume = (rightVol << 8) | leftVol;
730 
731     if (ioctl(self->fd, MIXER_WRITE(channel), &volume) == -1)
732         return PyErr_SetFromErrno(PyExc_IOError);
733 
734     return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8);
735 }
736 
737 static PyObject *
oss_mixer_get_recsrc(oss_mixer_t * self,PyObject * args)738 oss_mixer_get_recsrc(oss_mixer_t *self, PyObject *args)
739 {
740     return _do_ioctl_1_internal(self->fd, args, "get_recsrc",
741         SOUND_MIXER_READ_RECSRC);
742 }
743 
744 static PyObject *
oss_mixer_set_recsrc(oss_mixer_t * self,PyObject * args)745 oss_mixer_set_recsrc(oss_mixer_t *self, PyObject *args)
746 {
747     return _do_ioctl_1(self->fd, args, "set_recsrc",
748         SOUND_MIXER_WRITE_RECSRC);
749 }
750 
751 
752 /* ----------------------------------------------------------------------
753  * Method tables and other bureaucracy
754  */
755 
756 static PyMethodDef oss_methods[] = {
757     /* Regular file methods */
758     { "read",           (PyCFunction)oss_read, METH_VARARGS },
759     { "write",          (PyCFunction)oss_write, METH_VARARGS },
760     { "writeall",       (PyCFunction)oss_writeall, METH_VARARGS },
761     { "close",          (PyCFunction)oss_close, METH_NOARGS },
762     { "fileno",         (PyCFunction)oss_fileno, METH_NOARGS },
763 
764     /* Simple ioctl wrappers */
765     { "nonblock",       (PyCFunction)oss_nonblock, METH_NOARGS },
766     { "setfmt",         (PyCFunction)oss_setfmt, METH_VARARGS },
767     { "getfmts",        (PyCFunction)oss_getfmts, METH_NOARGS },
768     { "channels",       (PyCFunction)oss_channels, METH_VARARGS },
769     { "speed",          (PyCFunction)oss_speed, METH_VARARGS },
770     { "sync",           (PyCFunction)oss_sync, METH_VARARGS },
771     { "reset",          (PyCFunction)oss_reset, METH_VARARGS },
772     { "post",           (PyCFunction)oss_post, METH_VARARGS },
773 
774     /* Convenience methods -- wrap a couple of ioctls together */
775     { "setparameters",  (PyCFunction)oss_setparameters, METH_VARARGS },
776     { "bufsize",        (PyCFunction)oss_bufsize, METH_NOARGS },
777     { "obufcount",      (PyCFunction)oss_obufcount, METH_NOARGS },
778     { "obuffree",       (PyCFunction)oss_obuffree, METH_NOARGS },
779     { "getptr",         (PyCFunction)oss_getptr, METH_NOARGS },
780 
781     /* Aliases for backwards compatibility */
782     { "flush",          (PyCFunction)oss_sync, METH_VARARGS },
783 
784     { NULL,             NULL}           /* sentinel */
785 };
786 
787 static PyMethodDef oss_mixer_methods[] = {
788     /* Regular file method - OSS mixers are ioctl-only interface */
789     { "close",          (PyCFunction)oss_mixer_close, METH_NOARGS },
790     { "fileno",         (PyCFunction)oss_mixer_fileno, METH_NOARGS },
791 
792     /* Simple ioctl wrappers */
793     { "controls",       (PyCFunction)oss_mixer_controls, METH_VARARGS },
794     { "stereocontrols", (PyCFunction)oss_mixer_stereocontrols, METH_VARARGS},
795     { "reccontrols",    (PyCFunction)oss_mixer_reccontrols, METH_VARARGS},
796     { "get",            (PyCFunction)oss_mixer_get, METH_VARARGS },
797     { "set",            (PyCFunction)oss_mixer_set, METH_VARARGS },
798     { "get_recsrc",     (PyCFunction)oss_mixer_get_recsrc, METH_VARARGS },
799     { "set_recsrc",     (PyCFunction)oss_mixer_set_recsrc, METH_VARARGS },
800 
801     { NULL,             NULL}
802 };
803 
804 static PyObject *
oss_getattr(oss_audio_t * self,char * name)805 oss_getattr(oss_audio_t *self, char *name)
806 {
807     PyObject * rval = NULL;
808     if (strcmp(name, "closed") == 0) {
809         rval = (self->fd == -1) ? Py_True : Py_False;
810         Py_INCREF(rval);
811     }
812     else if (strcmp(name, "name") == 0) {
813         rval = PyString_FromString(self->devicename);
814     }
815     else if (strcmp(name, "mode") == 0) {
816         /* No need for a "default" in this switch: from newossobject(),
817            self->mode can only be one of these three values. */
818         switch(self->mode) {
819             case O_RDONLY:
820                 rval = PyString_FromString("r");
821                 break;
822             case O_RDWR:
823                 rval = PyString_FromString("rw");
824                 break;
825             case O_WRONLY:
826                 rval = PyString_FromString("w");
827                 break;
828         }
829     }
830     else {
831         rval = Py_FindMethod(oss_methods, (PyObject *)self, name);
832     }
833     return rval;
834 }
835 
836 static PyObject *
oss_mixer_getattr(oss_mixer_t * self,char * name)837 oss_mixer_getattr(oss_mixer_t *self, char *name)
838 {
839     return Py_FindMethod(oss_mixer_methods, (PyObject *)self, name);
840 }
841 
842 static PyTypeObject OSSAudioType = {
843     PyVarObject_HEAD_INIT(&PyType_Type, 0)
844     "ossaudiodev.oss_audio_device", /*tp_name*/
845     sizeof(oss_audio_t),        /*tp_size*/
846     0,                          /*tp_itemsize*/
847     /* methods */
848     (destructor)oss_dealloc,    /*tp_dealloc*/
849     0,                          /*tp_print*/
850     (getattrfunc)oss_getattr,   /*tp_getattr*/
851     0,                          /*tp_setattr*/
852     0,                          /*tp_compare*/
853     0,                          /*tp_repr*/
854 };
855 
856 static PyTypeObject OSSMixerType = {
857     PyVarObject_HEAD_INIT(&PyType_Type, 0)
858     "ossaudiodev.oss_mixer_device", /*tp_name*/
859     sizeof(oss_mixer_t),            /*tp_size*/
860     0,                              /*tp_itemsize*/
861     /* methods */
862     (destructor)oss_mixer_dealloc,  /*tp_dealloc*/
863     0,                              /*tp_print*/
864     (getattrfunc)oss_mixer_getattr, /*tp_getattr*/
865     0,                              /*tp_setattr*/
866     0,                              /*tp_compare*/
867     0,                              /*tp_repr*/
868 };
869 
870 
871 static PyObject *
ossopen(PyObject * self,PyObject * args)872 ossopen(PyObject *self, PyObject *args)
873 {
874     return (PyObject *)newossobject(args);
875 }
876 
877 static PyObject *
ossopenmixer(PyObject * self,PyObject * args)878 ossopenmixer(PyObject *self, PyObject *args)
879 {
880     return (PyObject *)newossmixerobject(args);
881 }
882 
883 static PyMethodDef ossaudiodev_methods[] = {
884     { "open", ossopen, METH_VARARGS },
885     { "openmixer", ossopenmixer, METH_VARARGS },
886     { 0, 0 },
887 };
888 
889 
890 #define _EXPORT_INT(mod, name) \
891   if (PyModule_AddIntConstant(mod, #name, (long) (name)) == -1) return;
892 
893 
894 static char *control_labels[] = SOUND_DEVICE_LABELS;
895 static char *control_names[] = SOUND_DEVICE_NAMES;
896 
897 
898 static int
build_namelists(PyObject * module)899 build_namelists (PyObject *module)
900 {
901     PyObject *labels;
902     PyObject *names;
903     PyObject *s;
904     int num_controls;
905     int i;
906 
907     num_controls = sizeof(control_labels) / sizeof(control_labels[0]);
908     assert(num_controls == sizeof(control_names) / sizeof(control_names[0]));
909 
910     labels = PyList_New(num_controls);
911     names = PyList_New(num_controls);
912     if (labels == NULL || names == NULL)
913         goto error2;
914     for (i = 0; i < num_controls; i++) {
915         s = PyString_FromString(control_labels[i]);
916         if (s == NULL)
917             goto error2;
918         PyList_SET_ITEM(labels, i, s);
919 
920         s = PyString_FromString(control_names[i]);
921         if (s == NULL)
922             goto error2;
923         PyList_SET_ITEM(names, i, s);
924     }
925 
926     if (PyModule_AddObject(module, "control_labels", labels) == -1)
927         goto error2;
928     if (PyModule_AddObject(module, "control_names", names) == -1)
929         goto error1;
930 
931     return 0;
932 
933 error2:
934     Py_XDECREF(labels);
935 error1:
936     Py_XDECREF(names);
937     return -1;
938 }
939 
940 
941 void
initossaudiodev(void)942 initossaudiodev(void)
943 {
944     PyObject *m;
945 
946     m = Py_InitModule("ossaudiodev", ossaudiodev_methods);
947     if (m == NULL)
948 	return;
949 
950     OSSAudioError = PyErr_NewException("ossaudiodev.OSSAudioError",
951 				       NULL, NULL);
952     if (OSSAudioError) {
953         /* Each call to PyModule_AddObject decrefs it; compensate: */
954         Py_INCREF(OSSAudioError);
955         Py_INCREF(OSSAudioError);
956         PyModule_AddObject(m, "error", OSSAudioError);
957         PyModule_AddObject(m, "OSSAudioError", OSSAudioError);
958     }
959 
960     /* Build 'control_labels' and 'control_names' lists and add them
961        to the module. */
962     if (build_namelists(m) == -1)       /* XXX what to do here? */
963         return;
964 
965     /* Expose the audio format numbers -- essential! */
966     _EXPORT_INT(m, AFMT_QUERY);
967     _EXPORT_INT(m, AFMT_MU_LAW);
968     _EXPORT_INT(m, AFMT_A_LAW);
969     _EXPORT_INT(m, AFMT_IMA_ADPCM);
970     _EXPORT_INT(m, AFMT_U8);
971     _EXPORT_INT(m, AFMT_S16_LE);
972     _EXPORT_INT(m, AFMT_S16_BE);
973     _EXPORT_INT(m, AFMT_S8);
974     _EXPORT_INT(m, AFMT_U16_LE);
975     _EXPORT_INT(m, AFMT_U16_BE);
976     _EXPORT_INT(m, AFMT_MPEG);
977 #ifdef AFMT_AC3
978     _EXPORT_INT(m, AFMT_AC3);
979 #endif
980 #ifdef AFMT_S16_NE
981     _EXPORT_INT(m, AFMT_S16_NE);
982 #endif
983 #ifdef AFMT_U16_NE
984     _EXPORT_INT(m, AFMT_U16_NE);
985 #endif
986 #ifdef AFMT_S32_LE
987     _EXPORT_INT(m, AFMT_S32_LE);
988 #endif
989 #ifdef AFMT_S32_BE
990     _EXPORT_INT(m, AFMT_S32_BE);
991 #endif
992 #ifdef AFMT_MPEG
993     _EXPORT_INT(m, AFMT_MPEG);
994 #endif
995 
996     /* Expose the sound mixer device numbers. */
997     _EXPORT_INT(m, SOUND_MIXER_NRDEVICES);
998     _EXPORT_INT(m, SOUND_MIXER_VOLUME);
999     _EXPORT_INT(m, SOUND_MIXER_BASS);
1000     _EXPORT_INT(m, SOUND_MIXER_TREBLE);
1001     _EXPORT_INT(m, SOUND_MIXER_SYNTH);
1002     _EXPORT_INT(m, SOUND_MIXER_PCM);
1003     _EXPORT_INT(m, SOUND_MIXER_SPEAKER);
1004     _EXPORT_INT(m, SOUND_MIXER_LINE);
1005     _EXPORT_INT(m, SOUND_MIXER_MIC);
1006     _EXPORT_INT(m, SOUND_MIXER_CD);
1007     _EXPORT_INT(m, SOUND_MIXER_IMIX);
1008     _EXPORT_INT(m, SOUND_MIXER_ALTPCM);
1009     _EXPORT_INT(m, SOUND_MIXER_RECLEV);
1010     _EXPORT_INT(m, SOUND_MIXER_IGAIN);
1011     _EXPORT_INT(m, SOUND_MIXER_OGAIN);
1012     _EXPORT_INT(m, SOUND_MIXER_LINE1);
1013     _EXPORT_INT(m, SOUND_MIXER_LINE2);
1014     _EXPORT_INT(m, SOUND_MIXER_LINE3);
1015 #ifdef SOUND_MIXER_DIGITAL1
1016     _EXPORT_INT(m, SOUND_MIXER_DIGITAL1);
1017 #endif
1018 #ifdef SOUND_MIXER_DIGITAL2
1019     _EXPORT_INT(m, SOUND_MIXER_DIGITAL2);
1020 #endif
1021 #ifdef SOUND_MIXER_DIGITAL3
1022     _EXPORT_INT(m, SOUND_MIXER_DIGITAL3);
1023 #endif
1024 #ifdef SOUND_MIXER_PHONEIN
1025     _EXPORT_INT(m, SOUND_MIXER_PHONEIN);
1026 #endif
1027 #ifdef SOUND_MIXER_PHONEOUT
1028     _EXPORT_INT(m, SOUND_MIXER_PHONEOUT);
1029 #endif
1030 #ifdef SOUND_MIXER_VIDEO
1031     _EXPORT_INT(m, SOUND_MIXER_VIDEO);
1032 #endif
1033 #ifdef SOUND_MIXER_RADIO
1034     _EXPORT_INT(m, SOUND_MIXER_RADIO);
1035 #endif
1036 #ifdef SOUND_MIXER_MONITOR
1037     _EXPORT_INT(m, SOUND_MIXER_MONITOR);
1038 #endif
1039 
1040     /* Expose all the ioctl numbers for masochists who like to do this
1041        stuff directly. */
1042     _EXPORT_INT(m, SNDCTL_COPR_HALT);
1043     _EXPORT_INT(m, SNDCTL_COPR_LOAD);
1044     _EXPORT_INT(m, SNDCTL_COPR_RCODE);
1045     _EXPORT_INT(m, SNDCTL_COPR_RCVMSG);
1046     _EXPORT_INT(m, SNDCTL_COPR_RDATA);
1047     _EXPORT_INT(m, SNDCTL_COPR_RESET);
1048     _EXPORT_INT(m, SNDCTL_COPR_RUN);
1049     _EXPORT_INT(m, SNDCTL_COPR_SENDMSG);
1050     _EXPORT_INT(m, SNDCTL_COPR_WCODE);
1051     _EXPORT_INT(m, SNDCTL_COPR_WDATA);
1052 #ifdef SNDCTL_DSP_BIND_CHANNEL
1053     _EXPORT_INT(m, SNDCTL_DSP_BIND_CHANNEL);
1054 #endif
1055     _EXPORT_INT(m, SNDCTL_DSP_CHANNELS);
1056     _EXPORT_INT(m, SNDCTL_DSP_GETBLKSIZE);
1057     _EXPORT_INT(m, SNDCTL_DSP_GETCAPS);
1058 #ifdef SNDCTL_DSP_GETCHANNELMASK
1059     _EXPORT_INT(m, SNDCTL_DSP_GETCHANNELMASK);
1060 #endif
1061     _EXPORT_INT(m, SNDCTL_DSP_GETFMTS);
1062     _EXPORT_INT(m, SNDCTL_DSP_GETIPTR);
1063     _EXPORT_INT(m, SNDCTL_DSP_GETISPACE);
1064 #ifdef SNDCTL_DSP_GETODELAY
1065     _EXPORT_INT(m, SNDCTL_DSP_GETODELAY);
1066 #endif
1067     _EXPORT_INT(m, SNDCTL_DSP_GETOPTR);
1068     _EXPORT_INT(m, SNDCTL_DSP_GETOSPACE);
1069 #ifdef SNDCTL_DSP_GETSPDIF
1070     _EXPORT_INT(m, SNDCTL_DSP_GETSPDIF);
1071 #endif
1072     _EXPORT_INT(m, SNDCTL_DSP_GETTRIGGER);
1073     _EXPORT_INT(m, SNDCTL_DSP_MAPINBUF);
1074     _EXPORT_INT(m, SNDCTL_DSP_MAPOUTBUF);
1075     _EXPORT_INT(m, SNDCTL_DSP_NONBLOCK);
1076     _EXPORT_INT(m, SNDCTL_DSP_POST);
1077 #ifdef SNDCTL_DSP_PROFILE
1078     _EXPORT_INT(m, SNDCTL_DSP_PROFILE);
1079 #endif
1080     _EXPORT_INT(m, SNDCTL_DSP_RESET);
1081     _EXPORT_INT(m, SNDCTL_DSP_SAMPLESIZE);
1082     _EXPORT_INT(m, SNDCTL_DSP_SETDUPLEX);
1083     _EXPORT_INT(m, SNDCTL_DSP_SETFMT);
1084     _EXPORT_INT(m, SNDCTL_DSP_SETFRAGMENT);
1085 #ifdef SNDCTL_DSP_SETSPDIF
1086     _EXPORT_INT(m, SNDCTL_DSP_SETSPDIF);
1087 #endif
1088     _EXPORT_INT(m, SNDCTL_DSP_SETSYNCRO);
1089     _EXPORT_INT(m, SNDCTL_DSP_SETTRIGGER);
1090     _EXPORT_INT(m, SNDCTL_DSP_SPEED);
1091     _EXPORT_INT(m, SNDCTL_DSP_STEREO);
1092     _EXPORT_INT(m, SNDCTL_DSP_SUBDIVIDE);
1093     _EXPORT_INT(m, SNDCTL_DSP_SYNC);
1094     _EXPORT_INT(m, SNDCTL_FM_4OP_ENABLE);
1095     _EXPORT_INT(m, SNDCTL_FM_LOAD_INSTR);
1096     _EXPORT_INT(m, SNDCTL_MIDI_INFO);
1097     _EXPORT_INT(m, SNDCTL_MIDI_MPUCMD);
1098     _EXPORT_INT(m, SNDCTL_MIDI_MPUMODE);
1099     _EXPORT_INT(m, SNDCTL_MIDI_PRETIME);
1100     _EXPORT_INT(m, SNDCTL_SEQ_CTRLRATE);
1101     _EXPORT_INT(m, SNDCTL_SEQ_GETINCOUNT);
1102     _EXPORT_INT(m, SNDCTL_SEQ_GETOUTCOUNT);
1103 #ifdef SNDCTL_SEQ_GETTIME
1104     _EXPORT_INT(m, SNDCTL_SEQ_GETTIME);
1105 #endif
1106     _EXPORT_INT(m, SNDCTL_SEQ_NRMIDIS);
1107     _EXPORT_INT(m, SNDCTL_SEQ_NRSYNTHS);
1108     _EXPORT_INT(m, SNDCTL_SEQ_OUTOFBAND);
1109     _EXPORT_INT(m, SNDCTL_SEQ_PANIC);
1110     _EXPORT_INT(m, SNDCTL_SEQ_PERCMODE);
1111     _EXPORT_INT(m, SNDCTL_SEQ_RESET);
1112     _EXPORT_INT(m, SNDCTL_SEQ_RESETSAMPLES);
1113     _EXPORT_INT(m, SNDCTL_SEQ_SYNC);
1114     _EXPORT_INT(m, SNDCTL_SEQ_TESTMIDI);
1115     _EXPORT_INT(m, SNDCTL_SEQ_THRESHOLD);
1116 #ifdef SNDCTL_SYNTH_CONTROL
1117     _EXPORT_INT(m, SNDCTL_SYNTH_CONTROL);
1118 #endif
1119 #ifdef SNDCTL_SYNTH_ID
1120     _EXPORT_INT(m, SNDCTL_SYNTH_ID);
1121 #endif
1122     _EXPORT_INT(m, SNDCTL_SYNTH_INFO);
1123     _EXPORT_INT(m, SNDCTL_SYNTH_MEMAVL);
1124 #ifdef SNDCTL_SYNTH_REMOVESAMPLE
1125     _EXPORT_INT(m, SNDCTL_SYNTH_REMOVESAMPLE);
1126 #endif
1127     _EXPORT_INT(m, SNDCTL_TMR_CONTINUE);
1128     _EXPORT_INT(m, SNDCTL_TMR_METRONOME);
1129     _EXPORT_INT(m, SNDCTL_TMR_SELECT);
1130     _EXPORT_INT(m, SNDCTL_TMR_SOURCE);
1131     _EXPORT_INT(m, SNDCTL_TMR_START);
1132     _EXPORT_INT(m, SNDCTL_TMR_STOP);
1133     _EXPORT_INT(m, SNDCTL_TMR_TEMPO);
1134     _EXPORT_INT(m, SNDCTL_TMR_TIMEBASE);
1135 }
1136