(root)/
Python-3.11.7/
Modules/
ossaudiodev.c
       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
      48  typedef 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  
      59  typedef 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  
      69  typedef struct {
      70      PyObject_HEAD
      71      int      fd;                      /* The open mixer device */
      72  } oss_mixer_t;
      73  
      74  
      75  static PyTypeObject OSSAudioType;
      76  static PyTypeObject OSSMixerType;
      77  
      78  static PyObject *OSSAudioError;
      79  
      80  
      81  /* ----------------------------------------------------------------------
      82   * DSP object initialization/deallocation
      83   */
      84  
      85  static oss_audio_t *
      86  newossobject(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  
     158  static void
     159  oss_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  
     172  static oss_mixer_t *
     173  newossmixerobject(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  
     203  static void
     204  oss_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   */
     228  static 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  */
     249  static 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  */
     274  static 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}. */
     294  static 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  
     323  static PyObject *
     324  oss_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  
     336  static PyObject *
     337  oss_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  
     345  static PyObject *
     346  oss_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  
     358  static PyObject *
     359  oss_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  
     367  static PyObject *
     368  oss_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  
     376  static PyObject *
     377  oss_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  
     385  static PyObject *
     386  oss_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  
     394  static PyObject *
     395  oss_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  
     407  static PyObject *
     408  oss_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  
     434  static PyObject *
     435  oss_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  
     456  static PyObject *
     457  oss_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  
     523  static PyObject *
     524  oss_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  
     535  static PyObject *
     536  oss_self(PyObject *self, PyObject *unused)
     537  {
     538      Py_INCREF(self);
     539      return self;
     540  }
     541  
     542  static PyObject *
     543  oss_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  
     554  static PyObject *
     555  oss_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  
     567  static PyObject *
     568  oss_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  
     619  static 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 */
     654  static PyObject *
     655  oss_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 */
     676  static PyObject *
     677  oss_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 */
     699  static PyObject *
     700  oss_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  
     719  static PyObject *
     720  oss_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  
     744  static PyObject *
     745  oss_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  
     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_OSError);
     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_OSError);
     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 PyMemberDef oss_members[] = {
     930      {"name", T_STRING, offsetof(oss_audio_t, devicename), READONLY, NULL},
     931      {NULL}
     932  };
     933  
     934  static PyObject *
     935  oss_closed_getter(oss_audio_t *self, void *closure)
     936  {
     937      return PyBool_FromLong(self->fd == -1);
     938  }
     939  
     940  static PyObject *
     941  oss_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  
     960  static 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  
     966  static 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  
    1000  static 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  
    1033  static PyObject *
    1034  ossopen(PyObject *self, PyObject *args)
    1035  {
    1036      return (PyObject *)newossobject(args);
    1037  }
    1038  
    1039  static PyObject *
    1040  ossopenmixer(PyObject *self, PyObject *args)
    1041  {
    1042      return (PyObject *)newossmixerobject(args);
    1043  }
    1044  
    1045  static 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  
    1056  static char *control_labels[] = SOUND_DEVICE_LABELS;
    1057  static char *control_names[] = SOUND_DEVICE_NAMES;
    1058  
    1059  
    1060  static int
    1061  build_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  
    1095  error2:
    1096      Py_XDECREF(labels);
    1097  error1:
    1098      Py_XDECREF(names);
    1099      return -1;
    1100  }
    1101  
    1102  
    1103  static 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  
    1115  PyMODINIT_FUNC
    1116  PyInit_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  }