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