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