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