blob: 393df05bd6349a0b1e86cf6fba7bf865620dc66f [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 {
35 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 */
40} lad_t;
41
42static struct {
43 int a_bps;
44 uint32_t a_fmt;
45} audio_types[] = {
46 { 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 },
53};
54
55
56staticforward PyTypeObject Ladtype;
57
58static PyObject *LinuxAudioError;
59
60static lad_t *
61newladobject(PyObject *arg)
62{
63 lad_t *xp;
64 int fd, afmts, imode;
65 char *mode;
66 char *basedev;
67 char *ctldev;
68 char *opendev;
69
70 /* Check arg for r/w/rw */
71 if (!PyArg_ParseTuple(arg, "s", &mode)) return NULL;
72 if (strcmp(mode, "r") == 0)
73 imode = 0;
74 else if (strcmp(mode, "w") == 0)
75 imode = 1;
76 else {
77 PyErr_SetString(LinuxAudioError, "Mode should be one of 'r', or 'w'");
78 return NULL;
79 }
80
81 /* Open the correct device. The base device name comes from the
82 * AUDIODEV environment variable first, then /dev/audio. The
83 * control device tacks "ctl" onto the base device name.
84 */
85 basedev = getenv("AUDIODEV");
86 if (!basedev)
87 basedev = "/dev/dsp";
88
89 if ((fd = open(basedev, imode)) < 0) {
90 PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
91 return NULL;
92 }
93
94 if (imode) {
95 if (ioctl(fd, SNDCTL_DSP_NONBLOCK, NULL) < 0) {
96 PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
97 return NULL;
98 }
99 }
100
101 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) < 0) {
102 PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev);
103 return NULL;
104 }
105
106 /* Create and initialize the object */
107 if ((xp = PyObject_NEW(lad_t, &Ladtype)) == NULL) {
108 close(fd);
109 return NULL;
110 }
111 xp->x_fd = fd;
112 xp->x_icount = xp->x_ocount = 0;
113 xp->x_afmts = afmts;
114 return xp;
115}
116
117static void
118lad_dealloc(lad_t *xp)
119{
120 close(xp->x_fd);
121 PyMem_DEL(xp);
122}
123
124static PyObject *
125lad_read(lad_t *self, PyObject *args)
126{
127 int size, count;
128 char *cp;
129 PyObject *rv;
130
131 if (!PyArg_ParseTuple(args, "i", &size)) return NULL;
132 rv = PyString_FromStringAndSize(NULL, size);
133 if (rv == NULL) return NULL;
134
135 if (!(cp = PyString_AsString(rv))) {
136 Py_DECREF(rv);
137 return NULL;
138 }
139
140 if ((count = read(self->x_fd, cp, size)) < 0) {
141 PyErr_SetFromErrno(LinuxAudioError);
142 Py_DECREF(rv);
143 return NULL;
144 }
145
146 self->x_icount += count;
147 return rv;
148}
149
150static PyObject *
151lad_write(lad_t *self, PyObject *args)
152{
153 char *cp;
154 int rv, size;
155
156 if (!PyArg_ParseTuple(args, "s#", &cp, &size)) return NULL;
157
158 while (size > 0) {
159 if ((rv = write(self->x_fd, cp, size)) < 0) {
160 PyErr_SetFromErrno(LinuxAudioError);
161 return NULL;
162 }
163 self->x_ocount += rv;
164 size -= rv;
165 cp += rv;
166 }
167 Py_INCREF(Py_None);
168 return Py_None;
169}
170
171static PyObject *
172lad_close(lad_t *self, PyObject *args)
173{
174 if (!PyArg_ParseTuple(args, "")) return NULL;
175 if (self->x_fd >= 0) {
176 close(self->x_fd);
177 self->x_fd = -1;
178 }
179 Py_INCREF(Py_None);
180 return Py_None;
181}
182
183static PyObject *
184lad_fileno(lad_t *self, PyObject *args)
185{
186 if (!PyArg_ParseTuple(args, "")) return NULL;
187 return PyInt_FromLong(self->x_fd);
188}
189
190static PyObject *
191lad_setparameters(lad_t *self, PyObject *args)
192{
193 int rate, ssize, nchannels, stereo, n, fmt;
194
195 if (!PyArg_ParseTuple(args, "iiii", &rate, &ssize, &nchannels, &fmt))
196 return NULL;
197
198 if (rate < 0 || ssize < 0 || (nchannels != 1 && nchannels != 2)) {
199 PyErr_SetFromErrno(LinuxAudioError);
200 return NULL;
201 }
202
203 if (ioctl(self->x_fd, SOUND_PCM_WRITE_RATE, &rate) < 0) {
204 PyErr_SetFromErrno(LinuxAudioError);
205 return NULL;
206 }
207
208 if (ioctl(self->x_fd, SNDCTL_DSP_SAMPLESIZE, &ssize) < 0) {
209 PyErr_SetFromErrno(LinuxAudioError);
210 return NULL;
211 }
212
213 stereo = (nchannels == 1)? 0: (nchannels == 2)? 1: -1;
214 if (ioctl(self->x_fd, SNDCTL_DSP_STEREO, &stereo) < 0) {
215 PyErr_SetFromErrno(LinuxAudioError);
216 return NULL;
217 }
218
219 for (n = 0; n != sizeof(audio_types) / sizeof(audio_types[0]); n++)
220 if (fmt == audio_types[n].a_fmt)
221 break;
222
223 if (n == sizeof(audio_types) / sizeof(audio_types[0]) ||
224 audio_types[n].a_bps != ssize ||
225 (self->x_afmts & audio_types[n].a_fmt) == 0) {
226 PyErr_SetFromErrno(LinuxAudioError);
227 return NULL;
228 }
229
230 if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &audio_types[n].a_fmt) < 0) {
231 PyErr_SetFromErrno(LinuxAudioError);
232 return NULL;
233 }
234
235 Py_INCREF(Py_None);
236 return Py_None;
237}
238
239static int
240_ssize(lad_t *self, int *nchannels, int *ssize)
241{
242 int fmt;
243
244 fmt = 0;
245 if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
246 return -errno;
247
248 switch (fmt) {
249 case AFMT_MU_LAW:
250 case AFMT_A_LAW:
251 case AFMT_U8:
252 case AFMT_S8:
253 *ssize = sizeof(char);
254 break;
255 case AFMT_S16_LE:
256 case AFMT_S16_BE:
257 case AFMT_U16_LE:
258 case AFMT_U16_BE:
259 *ssize = sizeof(short);
260 break;
261 case AFMT_MPEG:
262 case AFMT_IMA_ADPCM:
263 default:
264 return -EOPNOTSUPP;
265 }
266
267 *nchannels = 0;
268 if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, nchannels) < 0)
269 return -errno;
270 return 0;
271}
272
273
274/* bufsize returns the size of the hardware audio buffer in number
275 of samples */
276static PyObject *
277lad_bufsize(lad_t *self, PyObject *args)
278{
279 audio_buf_info ai;
280 int nchannels, ssize;
281
282 if (!PyArg_ParseTuple(args, "")) return NULL;
283
284 if (_ssize(self, &nchannels, &ssize) < 0) {
285 PyErr_SetFromErrno(LinuxAudioError);
286 return NULL;
287 }
288
289 if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
290 PyErr_SetFromErrno(LinuxAudioError);
291 return NULL;
292 }
293
294 return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize));
295}
296
297/* obufcount returns the number of samples that are available in the
298 hardware for playing */
299static PyObject *
300lad_obufcount(lad_t *self, PyObject *args)
301{
302 audio_buf_info ai;
303 int nchannels, ssize;
304
305 if (!PyArg_ParseTuple(args, "")) return NULL;
306
307 if (_ssize(self, &nchannels, &ssize) < 0) {
308 PyErr_SetFromErrno(LinuxAudioError);
309 return NULL;
310 }
311
312 if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
313 PyErr_SetFromErrno(LinuxAudioError);
314 return NULL;
315 }
316
317 return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) /
318 (ssize * nchannels));
319}
320
321/* obufcount returns the number of samples that can be played without
322 blocking */
323static PyObject *
324lad_obuffree(lad_t *self, PyObject *args)
325{
326 audio_buf_info ai;
327 int nchannels, ssize;
328
329 if (!PyArg_ParseTuple(args, "")) return NULL;
330
331 if (_ssize(self, &nchannels, &ssize) < 0) {
332 PyErr_SetFromErrno(LinuxAudioError);
333 return NULL;
334 }
335
336 if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
337 PyErr_SetFromErrno(LinuxAudioError);
338 return NULL;
339 }
340
341 return PyInt_FromLong(ai.bytes / (ssize * nchannels));
342}
343
344/* Flush the device */
345static PyObject *
346lad_flush(lad_t *self, PyObject *args)
347{
348 if (!PyArg_ParseTuple(args, "")) return NULL;
349
350 if (ioctl(self->x_fd, SNDCTL_DSP_SYNC, NULL) < 0) {
351 PyErr_SetFromErrno(LinuxAudioError);
352 return NULL;
353 }
354
355 Py_INCREF(Py_None);
356 return Py_None;
357}
358
359static PyMethodDef lad_methods[] = {
360 { "read", (PyCFunction)lad_read, 1 },
361 { "write", (PyCFunction)lad_write, 1 },
362 { "setparameters", (PyCFunction)lad_setparameters, 1 },
363 { "bufsize", (PyCFunction)lad_bufsize, 1 },
364 { "obufcount", (PyCFunction)lad_obufcount, 1 },
365 { "obuffree", (PyCFunction)lad_obuffree, 1 },
366 { "flush", (PyCFunction)lad_flush, 1 },
367 { "close", (PyCFunction)lad_close, 1 },
368 { "fileno", (PyCFunction)lad_fileno, 1 },
369 { NULL, NULL} /* sentinel */
370};
371
372static PyObject *
373lad_getattr(lad_t *xp, char *name)
374{
375 return Py_FindMethod(lad_methods, (PyObject *)xp, name);
376}
377
378static PyTypeObject Ladtype = {
379 PyObject_HEAD_INIT(&PyType_Type)
380 0, /*ob_size*/
381 "linux_audio_device", /*tp_name*/
382 sizeof(lad_t), /*tp_size*/
383 0, /*tp_itemsize*/
384 /* methods */
385 (destructor)lad_dealloc, /*tp_dealloc*/
386 0, /*tp_print*/
387 (getattrfunc)lad_getattr, /*tp_getattr*/
388 0, /*tp_setattr*/
389 0, /*tp_compare*/
390 0, /*tp_repr*/
391};
392
393static PyObject *
394ladopen(PyObject *self, PyObject *args)
395{
396 return (PyObject *)newladobject(args);
397}
398
399static PyMethodDef linuxaudiodev_methods[] = {
400 { "open", ladopen, 1 },
401 { 0, 0 },
402};
403
404static int
405ins(PyObject *d, char *symbol, long value)
406{
407 PyObject* v = PyInt_FromLong(value);
408 if (!v || PyDict_SetItemString(d, symbol, v) < 0)
409 return -1; /* triggers fatal error */
410
411 Py_DECREF(v);
412 return 0;
413}
414void
415initlinuxaudiodev()
416{
417 PyObject *m, *d, *x;
418
419 m = Py_InitModule("linuxaudiodev", linuxaudiodev_methods);
420 d = PyModule_GetDict(m);
421
422 LinuxAudioError = PyErr_NewException("linuxaudiodev.error", NULL, NULL);
423 if (LinuxAudioError)
424 PyDict_SetItemString(d, "error", LinuxAudioError);
425
426 x = PyInt_FromLong((long) AFMT_MU_LAW);
427 if (x == NULL || PyDict_SetItemString(d, "AFMT_MU_LAW", x) < 0)
428 goto error;
429 Py_DECREF(x);
430
431 x = PyInt_FromLong((long) AFMT_U8);
432 if (x == NULL || PyDict_SetItemString(d, "AFMT_U8", x) < 0)
433 goto error;
434 Py_DECREF(x);
435
436 x = PyInt_FromLong((long) AFMT_S8);
437 if (x == NULL || PyDict_SetItemString(d, "AFMT_S8", x) < 0)
438 goto error;
439 Py_DECREF(x);
440
441 x = PyInt_FromLong((long) AFMT_U16_BE);
442 if (x == NULL || PyDict_SetItemString(d, "AFMT_U16_BE", x) < 0)
443 goto error;
444 Py_DECREF(x);
445
446 x = PyInt_FromLong((long) AFMT_U16_LE);
447 if (x == NULL || PyDict_SetItemString(d, "AFMT_U16_LE", x) < 0)
448 goto error;
449 Py_DECREF(x);
450
451 x = PyInt_FromLong((long) AFMT_S16_BE);
452 if (x == NULL || PyDict_SetItemString(d, "AFMT_S16_BE", x) < 0)
453 goto error;
454 Py_DECREF(x);
455
456 x = PyInt_FromLong((long) AFMT_S16_LE);
457 if (x == NULL || PyDict_SetItemString(d, "AFMT_S16_LE", x) < 0)
458 goto error;
459 Py_DECREF(x);
460
461 /* Check for errors */
462 if (PyErr_Occurred()) {
463 error:
464 Py_FatalError("can't initialize module linuxaudiodev");
465 }
466}