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