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