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