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