blob: 5bcbaf2854da5ff8df108252029b053ccacdd71b [file] [log] [blame]
Guido van Rossumb130dc72000-03-30 23:25:49 +00001/* Hey Emacs, this is -*-C-*-
2 ******************************************************************************
3 * linuxaudiodev.c -- Linux audio device for python.
4 *
5 * Author : Peter Bosch
6 * Created On : Thu Mar 2 21:10:33 2000
7 * Last Modified By: Peter Bosch
8 * Last Modified On: Fri Mar 24 11:27:00 2000
9 * Status : Unknown, Use with caution!
10 *
11 * Unless other notices are present in any part of this file
12 * explicitly claiming copyrights for other people and/or
13 * organizations, the contents of this file is fully copyright
14 * (C) 2000 Peter Bosch, all rights reserved.
15 ******************************************************************************
16 */
17
18#include "Python.h"
19#include "structmember.h"
20
21#ifdef HAVE_UNISTD_H
22#include <unistd.h>
23#endif
24
25#ifdef HAVE_FCNTL_H
26#include <fcntl.h>
27#endif
28
Guido van Rossumb130dc72000-03-30 23:25:49 +000029#include <sys/ioctl.h>
30#include <linux/soundcard.h>
31
32typedef unsigned long uint32_t;
33
34typedef struct {
Fred Drakeda940d82000-07-08 06:05:58 +000035 PyObject_HEAD;
36 int x_fd; /* The open file */
37 int x_icount; /* Input count */
38 int x_ocount; /* Output count */
39 uint32_t x_afmts; /* Supported audio formats */
Guido van Rossumb130dc72000-03-30 23:25:49 +000040} lad_t;
41
42static struct {
Fred Drakeda940d82000-07-08 06:05:58 +000043 int a_bps;
44 uint32_t a_fmt;
Guido van Rossumb130dc72000-03-30 23:25:49 +000045} audio_types[] = {
Fred Drakeda940d82000-07-08 06:05:58 +000046 { 8, AFMT_MU_LAW },
47 { 8, AFMT_U8 },
48 { 8, AFMT_S8 },
49 { 16, AFMT_U16_BE },
50 { 16, AFMT_U16_LE },
51 { 16, AFMT_S16_BE },
52 { 16, AFMT_S16_LE },
Guido van Rossumb130dc72000-03-30 23:25:49 +000053};
54
55
56staticforward PyTypeObject Ladtype;
57
58static PyObject *LinuxAudioError;
59
60static lad_t *
61newladobject(PyObject *arg)
62{
Fred Drakeda940d82000-07-08 06:05:58 +000063 lad_t *xp;
64 int fd, afmts, imode;
65 char *mode;
66 char *basedev;
Guido van Rossumb130dc72000-03-30 23:25:49 +000067
Fred Drakeda940d82000-07-08 06:05:58 +000068 /* Check arg for r/w/rw */
69 if (!PyArg_ParseTuple(arg, "s:open", &mode)) return NULL;
70 if (strcmp(mode, "r") == 0)
71 imode = 0;
72 else if (strcmp(mode, "w") == 0)
73 imode = 1;
74 else {
75 PyErr_SetString(LinuxAudioError, "Mode should be one of 'r', or 'w'");
76 return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +000077 }
Guido van Rossumb130dc72000-03-30 23:25:49 +000078
Fred Drakeda940d82000-07-08 06:05:58 +000079 /* Open the correct device. The base device name comes from the
80 * AUDIODEV environment variable first, then /dev/audio. The
81 * control device tacks "ctl" onto the base device name.
82 */
83 basedev = getenv("AUDIODEV");
84 if (!basedev)
85 basedev = "/dev/dsp";
Guido van Rossumb130dc72000-03-30 23:25:49 +000086
Fred Drakeda940d82000-07-08 06:05:58 +000087 if ((fd = open(basedev, imode)) < 0) {
88 PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
89 return NULL;
90 }
91 if (imode && ioctl(fd, SNDCTL_DSP_NONBLOCK, NULL) < 0) {
92 PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
93 return NULL;
94 }
95 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) < 0) {
96 PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
97 return NULL;
98 }
99 /* Create and initialize the object */
100 if ((xp = PyObject_New(lad_t, &Ladtype)) == NULL) {
101 close(fd);
102 return NULL;
103 }
104 xp->x_fd = fd;
105 xp->x_icount = xp->x_ocount = 0;
106 xp->x_afmts = afmts;
107 return xp;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000108}
109
110static void
111lad_dealloc(lad_t *xp)
112{
Barry Warsaw4ddd8202000-08-18 05:10:45 +0000113 /* if already closed, don't reclose it */
114 if (xp->x_fd != -1)
115 close(xp->x_fd);
Fred Drakeda940d82000-07-08 06:05:58 +0000116 PyObject_Del(xp);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000117}
118
119static PyObject *
120lad_read(lad_t *self, PyObject *args)
121{
Fred Drakeda940d82000-07-08 06:05:58 +0000122 int size, count;
123 char *cp;
124 PyObject *rv;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000125
Fred Drakeda940d82000-07-08 06:05:58 +0000126 if (!PyArg_ParseTuple(args, "i:read", &size))
127 return NULL;
128 rv = PyString_FromStringAndSize(NULL, size);
129 if (rv == NULL)
130 return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000131
Fred Drakeda940d82000-07-08 06:05:58 +0000132 if (!(cp = PyString_AsString(rv))) {
133 Py_DECREF(rv);
134 return NULL;
135 }
136 if ((count = read(self->x_fd, cp, size)) < 0) {
137 PyErr_SetFromErrno(LinuxAudioError);
138 Py_DECREF(rv);
139 return NULL;
140 }
141 self->x_icount += count;
142 return rv;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000143}
144
145static PyObject *
146lad_write(lad_t *self, PyObject *args)
147{
Fred Drakeda940d82000-07-08 06:05:58 +0000148 char *cp;
149 int rv, size;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000150
Fred Drakeda940d82000-07-08 06:05:58 +0000151 if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000152
Fred Drakeda940d82000-07-08 06:05:58 +0000153 while (size > 0) {
154 if ((rv = write(self->x_fd, cp, size)) < 0) {
155 PyErr_SetFromErrno(LinuxAudioError);
156 return NULL;
157 }
158 self->x_ocount += rv;
159 size -= rv;
160 cp += rv;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000161 }
Fred Drakeda940d82000-07-08 06:05:58 +0000162 Py_INCREF(Py_None);
163 return Py_None;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000164}
165
166static PyObject *
167lad_close(lad_t *self, PyObject *args)
168{
Fred Drakeda940d82000-07-08 06:05:58 +0000169 if (!PyArg_ParseTuple(args, ":close")) return NULL;
170 if (self->x_fd >= 0) {
171 close(self->x_fd);
172 self->x_fd = -1;
173 }
174 Py_INCREF(Py_None);
175 return Py_None;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000176}
177
178static PyObject *
179lad_fileno(lad_t *self, PyObject *args)
180{
Fred Drakeda940d82000-07-08 06:05:58 +0000181 if (!PyArg_ParseTuple(args, ":fileno")) return NULL;
182 return PyInt_FromLong(self->x_fd);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000183}
184
185static PyObject *
186lad_setparameters(lad_t *self, PyObject *args)
187{
Fred Drakeda940d82000-07-08 06:05:58 +0000188 int rate, ssize, nchannels, stereo, n, fmt;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000189
Fred Drakeda940d82000-07-08 06:05:58 +0000190 if (!PyArg_ParseTuple(args, "iiii:setparameters",
191 &rate, &ssize, &nchannels, &fmt))
192 return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000193
Fred Drakeda940d82000-07-08 06:05:58 +0000194 if (rate < 0 || ssize < 0 || (nchannels != 1 && nchannels != 2)) {
195 PyErr_SetFromErrno(LinuxAudioError);
196 return NULL;
197 }
198 if (ioctl(self->x_fd, SOUND_PCM_WRITE_RATE, &rate) < 0) {
199 PyErr_SetFromErrno(LinuxAudioError);
200 return NULL;
201 }
202 if (ioctl(self->x_fd, SNDCTL_DSP_SAMPLESIZE, &ssize) < 0) {
203 PyErr_SetFromErrno(LinuxAudioError);
204 return NULL;
205 }
206 stereo = (nchannels == 1)? 0: (nchannels == 2)? 1: -1;
207 if (ioctl(self->x_fd, SNDCTL_DSP_STEREO, &stereo) < 0) {
208 PyErr_SetFromErrno(LinuxAudioError);
209 return NULL;
210 }
211 for (n = 0; n != sizeof(audio_types) / sizeof(audio_types[0]); n++)
212 if (fmt == audio_types[n].a_fmt)
213 break;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000214
Fred Drakeda940d82000-07-08 06:05:58 +0000215 if (n == sizeof(audio_types) / sizeof(audio_types[0]) ||
216 audio_types[n].a_bps != ssize ||
217 (self->x_afmts & audio_types[n].a_fmt) == 0) {
218 PyErr_SetFromErrno(LinuxAudioError);
219 return NULL;
220 }
221 if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &audio_types[n].a_fmt) < 0) {
222 PyErr_SetFromErrno(LinuxAudioError);
223 return NULL;
224 }
225 Py_INCREF(Py_None);
226 return Py_None;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000227}
228
229static int
230_ssize(lad_t *self, int *nchannels, int *ssize)
231{
Fred Drakeda940d82000-07-08 06:05:58 +0000232 int fmt;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000233
Fred Drakeda940d82000-07-08 06:05:58 +0000234 fmt = 0;
235 if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
236 return -errno;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000237
Fred Drakeda940d82000-07-08 06:05:58 +0000238 switch (fmt) {
239 case AFMT_MU_LAW:
240 case AFMT_A_LAW:
241 case AFMT_U8:
242 case AFMT_S8:
243 *ssize = sizeof(char);
244 break;
245 case AFMT_S16_LE:
246 case AFMT_S16_BE:
247 case AFMT_U16_LE:
248 case AFMT_U16_BE:
249 *ssize = sizeof(short);
250 break;
251 case AFMT_MPEG:
252 case AFMT_IMA_ADPCM:
253 default:
254 return -EOPNOTSUPP;
255 }
256 *nchannels = 0;
257 if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, nchannels) < 0)
258 return -errno;
259 return 0;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000260}
261
262
263/* bufsize returns the size of the hardware audio buffer in number
Fred Drakeda940d82000-07-08 06:05:58 +0000264 of samples */
Guido van Rossumb130dc72000-03-30 23:25:49 +0000265static PyObject *
266lad_bufsize(lad_t *self, PyObject *args)
267{
Fred Drakeda940d82000-07-08 06:05:58 +0000268 audio_buf_info ai;
269 int nchannels, ssize;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000270
Fred Drakeda940d82000-07-08 06:05:58 +0000271 if (!PyArg_ParseTuple(args, ":bufsize")) return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000272
Fred Drakeda940d82000-07-08 06:05:58 +0000273 if (_ssize(self, &nchannels, &ssize) < 0) {
274 PyErr_SetFromErrno(LinuxAudioError);
275 return NULL;
276 }
277 if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
278 PyErr_SetFromErrno(LinuxAudioError);
279 return NULL;
280 }
281 return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize));
Guido van Rossumb130dc72000-03-30 23:25:49 +0000282}
283
284/* obufcount returns the number of samples that are available in the
285 hardware for playing */
286static PyObject *
287lad_obufcount(lad_t *self, PyObject *args)
288{
Fred Drakeda940d82000-07-08 06:05:58 +0000289 audio_buf_info ai;
290 int nchannels, ssize;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000291
Fred Drakeda940d82000-07-08 06:05:58 +0000292 if (!PyArg_ParseTuple(args, ":obufcount"))
293 return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000294
Fred Drakeda940d82000-07-08 06:05:58 +0000295 if (_ssize(self, &nchannels, &ssize) < 0) {
296 PyErr_SetFromErrno(LinuxAudioError);
297 return NULL;
298 }
299 if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
300 PyErr_SetFromErrno(LinuxAudioError);
301 return NULL;
302 }
303 return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) /
304 (ssize * nchannels));
Guido van Rossumb130dc72000-03-30 23:25:49 +0000305}
306
307/* obufcount returns the number of samples that can be played without
Fred Drakeda940d82000-07-08 06:05:58 +0000308 blocking */
Guido van Rossumb130dc72000-03-30 23:25:49 +0000309static PyObject *
310lad_obuffree(lad_t *self, PyObject *args)
311{
Fred Drakeda940d82000-07-08 06:05:58 +0000312 audio_buf_info ai;
313 int nchannels, ssize;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000314
Fred Drakeda940d82000-07-08 06:05:58 +0000315 if (!PyArg_ParseTuple(args, ":obuffree"))
316 return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000317
Fred Drakeda940d82000-07-08 06:05:58 +0000318 if (_ssize(self, &nchannels, &ssize) < 0) {
319 PyErr_SetFromErrno(LinuxAudioError);
320 return NULL;
321 }
322 if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
323 PyErr_SetFromErrno(LinuxAudioError);
324 return NULL;
325 }
326 return PyInt_FromLong(ai.bytes / (ssize * nchannels));
Guido van Rossumb130dc72000-03-30 23:25:49 +0000327}
328
329/* Flush the device */
330static PyObject *
331lad_flush(lad_t *self, PyObject *args)
332{
Fred Drakeda940d82000-07-08 06:05:58 +0000333 if (!PyArg_ParseTuple(args, ":flush")) return NULL;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000334
Fred Drakeda940d82000-07-08 06:05:58 +0000335 if (ioctl(self->x_fd, SNDCTL_DSP_SYNC, NULL) < 0) {
336 PyErr_SetFromErrno(LinuxAudioError);
337 return NULL;
338 }
339 Py_INCREF(Py_None);
340 return Py_None;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000341}
342
343static PyMethodDef lad_methods[] = {
Fred Drakeda940d82000-07-08 06:05:58 +0000344 { "read", (PyCFunction)lad_read, METH_VARARGS },
345 { "write", (PyCFunction)lad_write, METH_VARARGS },
346 { "setparameters", (PyCFunction)lad_setparameters, METH_VARARGS },
347 { "bufsize", (PyCFunction)lad_bufsize, METH_VARARGS },
348 { "obufcount", (PyCFunction)lad_obufcount, METH_VARARGS },
349 { "obuffree", (PyCFunction)lad_obuffree, METH_VARARGS },
350 { "flush", (PyCFunction)lad_flush, METH_VARARGS },
351 { "close", (PyCFunction)lad_close, METH_VARARGS },
352 { "fileno", (PyCFunction)lad_fileno, METH_VARARGS },
353 { NULL, NULL} /* sentinel */
Guido van Rossumb130dc72000-03-30 23:25:49 +0000354};
355
356static PyObject *
357lad_getattr(lad_t *xp, char *name)
358{
Fred Drakeda940d82000-07-08 06:05:58 +0000359 return Py_FindMethod(lad_methods, (PyObject *)xp, name);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000360}
361
362static PyTypeObject Ladtype = {
Fred Drakeda940d82000-07-08 06:05:58 +0000363 PyObject_HEAD_INIT(&PyType_Type)
364 0, /*ob_size*/
365 "linux_audio_device", /*tp_name*/
366 sizeof(lad_t), /*tp_size*/
367 0, /*tp_itemsize*/
368 /* methods */
369 (destructor)lad_dealloc, /*tp_dealloc*/
370 0, /*tp_print*/
371 (getattrfunc)lad_getattr, /*tp_getattr*/
372 0, /*tp_setattr*/
373 0, /*tp_compare*/
374 0, /*tp_repr*/
Guido van Rossumb130dc72000-03-30 23:25:49 +0000375};
376
377static PyObject *
378ladopen(PyObject *self, PyObject *args)
379{
Fred Drakeda940d82000-07-08 06:05:58 +0000380 return (PyObject *)newladobject(args);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000381}
382
383static PyMethodDef linuxaudiodev_methods[] = {
Fred Drakeda940d82000-07-08 06:05:58 +0000384 { "open", ladopen, METH_VARARGS },
385 { 0, 0 },
Guido van Rossumb130dc72000-03-30 23:25:49 +0000386};
387
Guido van Rossumb130dc72000-03-30 23:25:49 +0000388void
Thomas Woutersf3f33dc2000-07-21 06:00:07 +0000389initlinuxaudiodev(void)
Guido van Rossumb130dc72000-03-30 23:25:49 +0000390{
Fred Drakeda940d82000-07-08 06:05:58 +0000391 PyObject *m, *d, *x;
Guido van Rossumb130dc72000-03-30 23:25:49 +0000392
Fred Drakeda940d82000-07-08 06:05:58 +0000393 m = Py_InitModule("linuxaudiodev", linuxaudiodev_methods);
394 d = PyModule_GetDict(m);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000395
Fred Drakeda940d82000-07-08 06:05:58 +0000396 LinuxAudioError = PyErr_NewException("linuxaudiodev.error", NULL, NULL);
397 if (LinuxAudioError)
398 PyDict_SetItemString(d, "error", LinuxAudioError);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000399
Fred Drakeda940d82000-07-08 06:05:58 +0000400 x = PyInt_FromLong((long) AFMT_MU_LAW);
401 if (x == NULL || PyDict_SetItemString(d, "AFMT_MU_LAW", x) < 0)
402 goto error;
403 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000404
Fred Drakeda940d82000-07-08 06:05:58 +0000405 x = PyInt_FromLong((long) AFMT_U8);
406 if (x == NULL || PyDict_SetItemString(d, "AFMT_U8", x) < 0)
407 goto error;
408 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000409
Fred Drakeda940d82000-07-08 06:05:58 +0000410 x = PyInt_FromLong((long) AFMT_S8);
411 if (x == NULL || PyDict_SetItemString(d, "AFMT_S8", x) < 0)
412 goto error;
413 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000414
Fred Drakeda940d82000-07-08 06:05:58 +0000415 x = PyInt_FromLong((long) AFMT_U16_BE);
416 if (x == NULL || PyDict_SetItemString(d, "AFMT_U16_BE", x) < 0)
417 goto error;
418 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000419
Fred Drakeda940d82000-07-08 06:05:58 +0000420 x = PyInt_FromLong((long) AFMT_U16_LE);
421 if (x == NULL || PyDict_SetItemString(d, "AFMT_U16_LE", x) < 0)
422 goto error;
423 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000424
Fred Drakeda940d82000-07-08 06:05:58 +0000425 x = PyInt_FromLong((long) AFMT_S16_BE);
426 if (x == NULL || PyDict_SetItemString(d, "AFMT_S16_BE", x) < 0)
427 goto error;
428 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000429
Fred Drakeda940d82000-07-08 06:05:58 +0000430 x = PyInt_FromLong((long) AFMT_S16_LE);
431 if (x == NULL || PyDict_SetItemString(d, "AFMT_S16_LE", x) < 0)
432 goto error;
433 Py_DECREF(x);
Guido van Rossumb130dc72000-03-30 23:25:49 +0000434
Fred Drakeda940d82000-07-08 06:05:58 +0000435 /* Check for errors */
436 if (PyErr_Occurred()) {
437 error:
438 Py_FatalError("can't initialize module linuxaudiodev");
439 }
Guido van Rossumb130dc72000-03-30 23:25:49 +0000440}