diff options
author | Guido van Rossum <guido@python.org> | 2000-03-31 16:56:32 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2000-03-31 16:56:32 (GMT) |
commit | 8de16932d0d401a5ef9ac32f746b6d451aa62012 (patch) | |
tree | e2328b2909eedf33b3f64c2b616432130b754b3d /Modules/linuxaudiodev.c | |
parent | 1027e3fde9b9cb6eb470cc13e48fbd2208658b32 (diff) | |
download | cpython-8de16932d0d401a5ef9ac32f746b6d451aa62012.zip cpython-8de16932d0d401a5ef9ac32f746b6d451aa62012.tar.gz cpython-8de16932d0d401a5ef9ac32f746b6d451aa62012.tar.bz2 |
This module's name should be linuxaudio*dev*.c
Diffstat (limited to 'Modules/linuxaudiodev.c')
-rw-r--r-- | Modules/linuxaudiodev.c | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/Modules/linuxaudiodev.c b/Modules/linuxaudiodev.c new file mode 100644 index 0000000..393df05 --- /dev/null +++ b/Modules/linuxaudiodev.c @@ -0,0 +1,466 @@ +/* Hey Emacs, this is -*-C-*- + ****************************************************************************** + * linuxaudiodev.c -- Linux audio device for python. + * + * Author : Peter Bosch + * Created On : Thu Mar 2 21:10:33 2000 + * Last Modified By: Peter Bosch + * Last Modified On: Fri Mar 24 11:27:00 2000 + * Status : Unknown, Use with caution! + * + * Unless other notices are present in any part of this file + * explicitly claiming copyrights for other people and/or + * organizations, the contents of this file is fully copyright + * (C) 2000 Peter Bosch, all rights reserved. + ****************************************************************************** + */ + +#include "Python.h" +#include "structmember.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#include <sys/ioctl.h> +#include <linux/soundcard.h> + +typedef unsigned long uint32_t; + +typedef struct { + PyObject_HEAD; + int x_fd; /* The open file */ + int x_icount; /* Input count */ + int x_ocount; /* Output count */ + uint32_t x_afmts; /* Supported audio formats */ +} lad_t; + +static struct { + int a_bps; + uint32_t a_fmt; +} audio_types[] = { + { 8, AFMT_MU_LAW }, + { 8, AFMT_U8 }, + { 8, AFMT_S8 }, + { 16, AFMT_U16_BE }, + { 16, AFMT_U16_LE }, + { 16, AFMT_S16_BE }, + { 16, AFMT_S16_LE }, +}; + + +staticforward PyTypeObject Ladtype; + +static PyObject *LinuxAudioError; + +static lad_t * +newladobject(PyObject *arg) +{ + lad_t *xp; + int fd, afmts, imode; + char *mode; + char *basedev; + char *ctldev; + char *opendev; + + /* Check arg for r/w/rw */ + if (!PyArg_ParseTuple(arg, "s", &mode)) return NULL; + if (strcmp(mode, "r") == 0) + imode = 0; + else if (strcmp(mode, "w") == 0) + imode = 1; + else { + PyErr_SetString(LinuxAudioError, "Mode should be one of 'r', or 'w'"); + return NULL; + } + + /* Open the correct device. The base device name comes from the + * AUDIODEV environment variable first, then /dev/audio. The + * control device tacks "ctl" onto the base device name. + */ + basedev = getenv("AUDIODEV"); + if (!basedev) + basedev = "/dev/dsp"; + + if ((fd = open(basedev, imode)) < 0) { + PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev); + return NULL; + } + + if (imode) { + if (ioctl(fd, SNDCTL_DSP_NONBLOCK, NULL) < 0) { + PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev); + return NULL; + } + } + + if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) < 0) { + PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev); + return NULL; + } + + /* Create and initialize the object */ + if ((xp = PyObject_NEW(lad_t, &Ladtype)) == NULL) { + close(fd); + return NULL; + } + xp->x_fd = fd; + xp->x_icount = xp->x_ocount = 0; + xp->x_afmts = afmts; + return xp; +} + +static void +lad_dealloc(lad_t *xp) +{ + close(xp->x_fd); + PyMem_DEL(xp); +} + +static PyObject * +lad_read(lad_t *self, PyObject *args) +{ + int size, count; + char *cp; + PyObject *rv; + + if (!PyArg_ParseTuple(args, "i", &size)) return NULL; + rv = PyString_FromStringAndSize(NULL, size); + if (rv == NULL) return NULL; + + if (!(cp = PyString_AsString(rv))) { + Py_DECREF(rv); + return NULL; + } + + if ((count = read(self->x_fd, cp, size)) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + Py_DECREF(rv); + return NULL; + } + + self->x_icount += count; + return rv; +} + +static PyObject * +lad_write(lad_t *self, PyObject *args) +{ + char *cp; + int rv, size; + + if (!PyArg_ParseTuple(args, "s#", &cp, &size)) return NULL; + + while (size > 0) { + if ((rv = write(self->x_fd, cp, size)) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + self->x_ocount += rv; + size -= rv; + cp += rv; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +lad_close(lad_t *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + if (self->x_fd >= 0) { + close(self->x_fd); + self->x_fd = -1; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +lad_fileno(lad_t *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return PyInt_FromLong(self->x_fd); +} + +static PyObject * +lad_setparameters(lad_t *self, PyObject *args) +{ + int rate, ssize, nchannels, stereo, n, fmt; + + if (!PyArg_ParseTuple(args, "iiii", &rate, &ssize, &nchannels, &fmt)) + return NULL; + + if (rate < 0 || ssize < 0 || (nchannels != 1 && nchannels != 2)) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + if (ioctl(self->x_fd, SOUND_PCM_WRITE_RATE, &rate) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + if (ioctl(self->x_fd, SNDCTL_DSP_SAMPLESIZE, &ssize) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + stereo = (nchannels == 1)? 0: (nchannels == 2)? 1: -1; + if (ioctl(self->x_fd, SNDCTL_DSP_STEREO, &stereo) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + for (n = 0; n != sizeof(audio_types) / sizeof(audio_types[0]); n++) + if (fmt == audio_types[n].a_fmt) + break; + + if (n == sizeof(audio_types) / sizeof(audio_types[0]) || + audio_types[n].a_bps != ssize || + (self->x_afmts & audio_types[n].a_fmt) == 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &audio_types[n].a_fmt) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static int +_ssize(lad_t *self, int *nchannels, int *ssize) +{ + int fmt; + + fmt = 0; + if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + return -errno; + + switch (fmt) { + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + *ssize = sizeof(char); + break; + case AFMT_S16_LE: + case AFMT_S16_BE: + case AFMT_U16_LE: + case AFMT_U16_BE: + *ssize = sizeof(short); + break; + case AFMT_MPEG: + case AFMT_IMA_ADPCM: + default: + return -EOPNOTSUPP; + } + + *nchannels = 0; + if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, nchannels) < 0) + return -errno; + return 0; +} + + +/* bufsize returns the size of the hardware audio buffer in number + of samples */ +static PyObject * +lad_bufsize(lad_t *self, PyObject *args) +{ + audio_buf_info ai; + int nchannels, ssize; + + if (!PyArg_ParseTuple(args, "")) return NULL; + + if (_ssize(self, &nchannels, &ssize) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize)); +} + +/* obufcount returns the number of samples that are available in the + hardware for playing */ +static PyObject * +lad_obufcount(lad_t *self, PyObject *args) +{ + audio_buf_info ai; + int nchannels, ssize; + + if (!PyArg_ParseTuple(args, "")) return NULL; + + if (_ssize(self, &nchannels, &ssize) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) / + (ssize * nchannels)); +} + +/* obufcount returns the number of samples that can be played without + blocking */ +static PyObject * +lad_obuffree(lad_t *self, PyObject *args) +{ + audio_buf_info ai; + int nchannels, ssize; + + if (!PyArg_ParseTuple(args, "")) return NULL; + + if (_ssize(self, &nchannels, &ssize) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + return PyInt_FromLong(ai.bytes / (ssize * nchannels)); +} + +/* Flush the device */ +static PyObject * +lad_flush(lad_t *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + + if (ioctl(self->x_fd, SNDCTL_DSP_SYNC, NULL) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef lad_methods[] = { + { "read", (PyCFunction)lad_read, 1 }, + { "write", (PyCFunction)lad_write, 1 }, + { "setparameters", (PyCFunction)lad_setparameters, 1 }, + { "bufsize", (PyCFunction)lad_bufsize, 1 }, + { "obufcount", (PyCFunction)lad_obufcount, 1 }, + { "obuffree", (PyCFunction)lad_obuffree, 1 }, + { "flush", (PyCFunction)lad_flush, 1 }, + { "close", (PyCFunction)lad_close, 1 }, + { "fileno", (PyCFunction)lad_fileno, 1 }, + { NULL, NULL} /* sentinel */ +}; + +static PyObject * +lad_getattr(lad_t *xp, char *name) +{ + return Py_FindMethod(lad_methods, (PyObject *)xp, name); +} + +static PyTypeObject Ladtype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "linux_audio_device", /*tp_name*/ + sizeof(lad_t), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)lad_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)lad_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyObject * +ladopen(PyObject *self, PyObject *args) +{ + return (PyObject *)newladobject(args); +} + +static PyMethodDef linuxaudiodev_methods[] = { + { "open", ladopen, 1 }, + { 0, 0 }, +}; + +static int +ins(PyObject *d, char *symbol, long value) +{ + PyObject* v = PyInt_FromLong(value); + if (!v || PyDict_SetItemString(d, symbol, v) < 0) + return -1; /* triggers fatal error */ + + Py_DECREF(v); + return 0; +} +void +initlinuxaudiodev() +{ + PyObject *m, *d, *x; + + m = Py_InitModule("linuxaudiodev", linuxaudiodev_methods); + d = PyModule_GetDict(m); + + LinuxAudioError = PyErr_NewException("linuxaudiodev.error", NULL, NULL); + if (LinuxAudioError) + PyDict_SetItemString(d, "error", LinuxAudioError); + + x = PyInt_FromLong((long) AFMT_MU_LAW); + if (x == NULL || PyDict_SetItemString(d, "AFMT_MU_LAW", x) < 0) + goto error; + Py_DECREF(x); + + x = PyInt_FromLong((long) AFMT_U8); + if (x == NULL || PyDict_SetItemString(d, "AFMT_U8", x) < 0) + goto error; + Py_DECREF(x); + + x = PyInt_FromLong((long) AFMT_S8); + if (x == NULL || PyDict_SetItemString(d, "AFMT_S8", x) < 0) + goto error; + Py_DECREF(x); + + x = PyInt_FromLong((long) AFMT_U16_BE); + if (x == NULL || PyDict_SetItemString(d, "AFMT_U16_BE", x) < 0) + goto error; + Py_DECREF(x); + + x = PyInt_FromLong((long) AFMT_U16_LE); + if (x == NULL || PyDict_SetItemString(d, "AFMT_U16_LE", x) < 0) + goto error; + Py_DECREF(x); + + x = PyInt_FromLong((long) AFMT_S16_BE); + if (x == NULL || PyDict_SetItemString(d, "AFMT_S16_BE", x) < 0) + goto error; + Py_DECREF(x); + + x = PyInt_FromLong((long) AFMT_S16_LE); + if (x == NULL || PyDict_SetItemString(d, "AFMT_S16_LE", x) < 0) + goto error; + Py_DECREF(x); + + /* Check for errors */ + if (PyErr_Occurred()) { + error: + Py_FatalError("can't initialize module linuxaudiodev"); + } +} |