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