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