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