Modify framebuffer and NGA framebuffer to read screen size from board model dtb file. Optimise memory usuage of frame buffer
Add example minigui application with hooks to profiler (which writes results to S:\). Modified NGA framebuffer to run its own dfc queue at high priority
/*
* ossaudiodev -- Python interface to the OSS (Open Sound System) API.
* This is the standard audio API for Linux and some
* flavours of BSD [XXX which ones?]; it is also available
* for a wide range of commercial Unices.
*
* Originally written by Peter Bosch, March 2000, as linuxaudiodev.
*
* Renamed to ossaudiodev and rearranged/revised/hacked up
* by Greg Ward <gward@python.net>, November 2002.
* Mixer interface by Nicholas FitzRoy-Dale <wzdd@lardcave.net>, Dec 2002.
*
* (c) 2000 Peter Bosch. All Rights Reserved.
* (c) 2002 Gregory P. Ward. All Rights Reserved.
* (c) 2002 Python Software Foundation. All Rights Reserved.
*
* XXX need a license statement
*
* $Id: ossaudiodev.c 64048 2008-06-09 04:58:54Z gregory.p.smith $
*/
#include "Python.h"
#include "structmember.h"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#define O_RDONLY 00
#define O_WRONLY 01
#endif
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#if defined(linux)
#ifndef HAVE_STDINT_H
typedef unsigned long uint32_t;
#endif
#elif defined(__FreeBSD__)
# ifndef SNDCTL_DSP_CHANNELS
# define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS
# endif
#endif
typedef struct {
PyObject_HEAD
char *devicename; /* name of the device file */
int fd; /* file descriptor */
int mode; /* file mode (O_RDONLY, etc.) */
int icount; /* input count */
int ocount; /* output count */
uint32_t afmts; /* audio formats supported by hardware */
} oss_audio_t;
typedef struct {
PyObject_HEAD
int fd; /* The open mixer device */
} oss_mixer_t;
static PyTypeObject OSSAudioType;
static PyTypeObject OSSMixerType;
static PyObject *OSSAudioError;
/* ----------------------------------------------------------------------
* DSP object initialization/deallocation
*/
static oss_audio_t *
newossobject(PyObject *arg)
{
oss_audio_t *self;
int fd, afmts, imode;
char *devicename = NULL;
char *mode = NULL;
/* Two ways to call open():
open(device, mode) (for consistency with builtin open())
open(mode) (for backwards compatibility)
because the *first* argument is optional, parsing args is
a wee bit tricky. */
if (!PyArg_ParseTuple(arg, "s|s:open", &devicename, &mode))
return NULL;
if (mode == NULL) { /* only one arg supplied */
mode = devicename;
devicename = NULL;
}
if (strcmp(mode, "r") == 0)
imode = O_RDONLY;
else if (strcmp(mode, "w") == 0)
imode = O_WRONLY;
else if (strcmp(mode, "rw") == 0)
imode = O_RDWR;
else {
PyErr_SetString(OSSAudioError, "mode must be 'r', 'w', or 'rw'");
return NULL;
}
/* Open the correct device: either the 'device' argument,
or the AUDIODEV environment variable, or "/dev/dsp". */
if (devicename == NULL) { /* called with one arg */
devicename = getenv("AUDIODEV");
if (devicename == NULL) /* $AUDIODEV not set */
devicename = "/dev/dsp";
}
/* Open with O_NONBLOCK to avoid hanging on devices that only allow
one open at a time. This does *not* affect later I/O; OSS
provides a special ioctl() for non-blocking read/write, which is
exposed via oss_nonblock() below. */
if ((fd = open(devicename, imode|O_NONBLOCK)) == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
/* And (try to) put it back in blocking mode so we get the
expected write() semantics. */
if (fcntl(fd, F_SETFL, 0) == -1) {
close(fd);
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
/* Create and initialize the object */
if ((self = PyObject_New(oss_audio_t, &OSSAudioType)) == NULL) {
close(fd);
return NULL;
}
self->devicename = devicename;
self->fd = fd;
self->mode = imode;
self->icount = self->ocount = 0;
self->afmts = afmts;
return self;
}
static void
oss_dealloc(oss_audio_t *self)
{
/* if already closed, don't reclose it */
if (self->fd != -1)
close(self->fd);
PyObject_Del(self);
}
/* ----------------------------------------------------------------------
* Mixer object initialization/deallocation
*/
static oss_mixer_t *
newossmixerobject(PyObject *arg)
{
char *devicename = NULL;
int fd;
oss_mixer_t *self;
if (!PyArg_ParseTuple(arg, "|s", &devicename)) {
return NULL;
}
if (devicename == NULL) {
devicename = getenv("MIXERDEV");
if (devicename == NULL) /* MIXERDEV not set */
devicename = "/dev/mixer";
}
if ((fd = open(devicename, O_RDWR)) == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) {
close(fd);
return NULL;
}
self->fd = fd;
return self;
}
static void
oss_mixer_dealloc(oss_mixer_t *self)
{
/* if already closed, don't reclose it */
if (self->fd != -1)
close(self->fd);
PyObject_Del(self);
}
/* Methods to wrap the OSS ioctls. The calling convention is pretty
simple:
nonblock() -> ioctl(fd, SNDCTL_DSP_NONBLOCK)
fmt = setfmt(fmt) -> ioctl(fd, SNDCTL_DSP_SETFMT, &fmt)
etc.
*/
/* ----------------------------------------------------------------------
* Helper functions
*/
/* _do_ioctl_1() is a private helper function used for the OSS ioctls --
SNDCTL_DSP_{SETFMT,CHANNELS,SPEED} -- that that are called from C
like this:
ioctl(fd, SNDCTL_DSP_cmd, &arg)
where arg is the value to set, and on return the driver sets arg to
the value that was actually set. Mapping this to Python is obvious:
arg = dsp.xxx(arg)
*/
static PyObject *
_do_ioctl_1(int fd, PyObject *args, char *fname, int cmd)
{
char argfmt[33] = "i:";
int arg;
assert(strlen(fname) <= 30);
strcat(argfmt, fname);
if (!PyArg_ParseTuple(args, argfmt, &arg))
return NULL;
if (ioctl(fd, cmd, &arg) == -1)
return PyErr_SetFromErrno(PyExc_IOError);
return PyInt_FromLong(arg);
}
/* _do_ioctl_1_internal() is a wrapper for ioctls that take no inputs
but return an output -- ie. we need to pass a pointer to a local C
variable so the driver can write its output there, but from Python
all we see is the return value. For example,
SOUND_MIXER_READ_DEVMASK returns a bitmask of available mixer
devices, but does not use the value of the parameter passed-in in any
way.
*/
static PyObject *
_do_ioctl_1_internal(int fd, PyObject *args, char *fname, int cmd)
{
char argfmt[32] = ":";
int arg = 0;
assert(strlen(fname) <= 30);
strcat(argfmt, fname);
if (!PyArg_ParseTuple(args, argfmt, &arg))
return NULL;
if (ioctl(fd, cmd, &arg) == -1)
return PyErr_SetFromErrno(PyExc_IOError);
return PyInt_FromLong(arg);
}
/* _do_ioctl_0() is a private helper for the no-argument ioctls:
SNDCTL_DSP_{SYNC,RESET,POST}. */
static PyObject *
_do_ioctl_0(int fd, PyObject *args, char *fname, int cmd)
{
char argfmt[32] = ":";
int rv;
assert(strlen(fname) <= 30);
strcat(argfmt, fname);
if (!PyArg_ParseTuple(args, argfmt))
return NULL;
/* According to hannu@opensound.com, all three of the ioctls that
use this function can block, so release the GIL. This is
especially important for SYNC, which can block for several
seconds. */
Py_BEGIN_ALLOW_THREADS
rv = ioctl(fd, cmd, 0);
Py_END_ALLOW_THREADS
if (rv == -1)
return PyErr_SetFromErrno(PyExc_IOError);
Py_INCREF(Py_None);
return Py_None;
}
/* ----------------------------------------------------------------------
* Methods of DSP objects (OSSAudioType)
*/
static PyObject *
oss_nonblock(oss_audio_t *self, PyObject *unused)
{
/* Hmmm: it doesn't appear to be possible to return to blocking
mode once we're in non-blocking mode! */
if (ioctl(self->fd, SNDCTL_DSP_NONBLOCK, NULL) == -1)
return PyErr_SetFromErrno(PyExc_IOError);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
oss_setfmt(oss_audio_t *self, PyObject *args)
{
return _do_ioctl_1(self->fd, args, "setfmt", SNDCTL_DSP_SETFMT);
}
static PyObject *
oss_getfmts(oss_audio_t *self, PyObject *unused)
{
int mask;
if (ioctl(self->fd, SNDCTL_DSP_GETFMTS, &mask) == -1)
return PyErr_SetFromErrno(PyExc_IOError);
return PyInt_FromLong(mask);
}
static PyObject *
oss_channels(oss_audio_t *self, PyObject *args)
{
return _do_ioctl_1(self->fd, args, "channels", SNDCTL_DSP_CHANNELS);
}
static PyObject *
oss_speed(oss_audio_t *self, PyObject *args)
{
return _do_ioctl_1(self->fd, args, "speed", SNDCTL_DSP_SPEED);
}
static PyObject *
oss_sync(oss_audio_t *self, PyObject *args)
{
return _do_ioctl_0(self->fd, args, "sync", SNDCTL_DSP_SYNC);
}
static PyObject *
oss_reset(oss_audio_t *self, PyObject *args)
{
return _do_ioctl_0(self->fd, args, "reset", SNDCTL_DSP_RESET);
}
static PyObject *
oss_post(oss_audio_t *self, PyObject *args)
{
return _do_ioctl_0(self->fd, args, "post", SNDCTL_DSP_POST);
}
/* Regular file methods: read(), write(), close(), etc. as well
as one convenience method, writeall(). */
static PyObject *
oss_read(oss_audio_t *self, PyObject *args)
{
int size, count;
char *cp;
PyObject *rv;
if (!PyArg_ParseTuple(args, "i:read", &size))
return NULL;
rv = PyString_FromStringAndSize(NULL, size);
if (rv == NULL)
return NULL;
cp = PyString_AS_STRING(rv);
Py_BEGIN_ALLOW_THREADS
count = read(self->fd, cp, size);
Py_END_ALLOW_THREADS
if (count < 0) {
PyErr_SetFromErrno(PyExc_IOError);
Py_DECREF(rv);
return NULL;
}
self->icount += count;
_PyString_Resize(&rv, count);
return rv;
}
static PyObject *
oss_write(oss_audio_t *self, PyObject *args)
{
char *cp;
int rv, size;
if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
rv = write(self->fd, cp, size);
Py_END_ALLOW_THREADS
if (rv == -1) {
return PyErr_SetFromErrno(PyExc_IOError);
} else {
self->ocount += rv;
}
return PyInt_FromLong(rv);
}
static PyObject *
oss_writeall(oss_audio_t *self, PyObject *args)
{
char *cp;
int rv, size;
fd_set write_set_fds;
int select_rv;
/* NB. writeall() is only useful in non-blocking mode: according to
Guenter Geiger <geiger@xdv.org> on the linux-audio-dev list
(http://eca.cx/lad/2002/11/0380.html), OSS guarantees that
write() in blocking mode consumes the whole buffer. In blocking
mode, the behaviour of write() and writeall() from Python is
indistinguishable. */
if (!PyArg_ParseTuple(args, "s#:write", &cp, &size))
return NULL;
/* use select to wait for audio device to be available */
FD_ZERO(&write_set_fds);
FD_SET(self->fd, &write_set_fds);
while (size > 0) {
Py_BEGIN_ALLOW_THREADS
select_rv = select(self->fd+1, NULL, &write_set_fds, NULL, NULL);
Py_END_ALLOW_THREADS
assert(select_rv != 0); /* no timeout, can't expire */
if (select_rv == -1)
return PyErr_SetFromErrno(PyExc_IOError);
Py_BEGIN_ALLOW_THREADS
rv = write(self->fd, cp, size);
Py_END_ALLOW_THREADS
if (rv == -1) {
if (errno == EAGAIN) { /* buffer is full, try again */
errno = 0;
continue;
} else /* it's a real error */
return PyErr_SetFromErrno(PyExc_IOError);
} else { /* wrote rv bytes */
self->ocount += rv;
size -= rv;
cp += rv;
}
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
oss_close(oss_audio_t *self, PyObject *unused)
{
if (self->fd >= 0) {
Py_BEGIN_ALLOW_THREADS
close(self->fd);
Py_END_ALLOW_THREADS
self->fd = -1;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
oss_fileno(oss_audio_t *self, PyObject *unused)
{
return PyInt_FromLong(self->fd);
}
/* Convenience methods: these generally wrap a couple of ioctls into one
common task. */
static PyObject *
oss_setparameters(oss_audio_t *self, PyObject *args)
{
int wanted_fmt, wanted_channels, wanted_rate, strict=0;
int fmt, channels, rate;
PyObject * rv; /* return tuple (fmt, channels, rate) */
if (!PyArg_ParseTuple(args, "iii|i:setparameters",
&wanted_fmt, &wanted_channels, &wanted_rate,
&strict))
return NULL;
fmt = wanted_fmt;
if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) == -1) {
return PyErr_SetFromErrno(PyExc_IOError);
}
if (strict && fmt != wanted_fmt) {
return PyErr_Format
(OSSAudioError,
"unable to set requested format (wanted %d, got %d)",
wanted_fmt, fmt);
}
channels = wanted_channels;
if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
return PyErr_SetFromErrno(PyExc_IOError);
}
if (strict && channels != wanted_channels) {
return PyErr_Format
(OSSAudioError,
"unable to set requested channels (wanted %d, got %d)",
wanted_channels, channels);
}
rate = wanted_rate;
if (ioctl(self->fd, SNDCTL_DSP_SPEED, &rate) == -1) {
return PyErr_SetFromErrno(PyExc_IOError);
}
if (strict && rate != wanted_rate) {
return PyErr_Format
(OSSAudioError,
"unable to set requested rate (wanted %d, got %d)",
wanted_rate, rate);
}
/* Construct the return value: a (fmt, channels, rate) tuple that
tells what the audio hardware was actually set to. */
rv = PyTuple_New(3);
if (rv == NULL)
return NULL;
PyTuple_SET_ITEM(rv, 0, PyInt_FromLong(fmt));
PyTuple_SET_ITEM(rv, 1, PyInt_FromLong(channels));
PyTuple_SET_ITEM(rv, 2, PyInt_FromLong(rate));
return rv;
}
static int
_ssize(oss_audio_t *self, int *nchannels, int *ssize)
{
int fmt;
fmt = 0;
if (ioctl(self->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 = 1; /* 8 bit formats: 1 byte */
break;
case AFMT_S16_LE:
case AFMT_S16_BE:
case AFMT_U16_LE:
case AFMT_U16_BE:
*ssize = 2; /* 16 bit formats: 2 byte */
break;
case AFMT_MPEG:
case AFMT_IMA_ADPCM:
default:
return -EOPNOTSUPP;
}
if (ioctl(self->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 *
oss_bufsize(oss_audio_t *self, PyObject *unused)
{
audio_buf_info ai;
int nchannels=0, ssize=0;
if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
PyErr_SetFromErrno(PyExc_IOError);
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 *
oss_obufcount(oss_audio_t *self, PyObject *unused)
{
audio_buf_info ai;
int nchannels=0, ssize=0;
if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
PyErr_SetFromErrno(PyExc_IOError);
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 *
oss_obuffree(oss_audio_t *self, PyObject *unused)
{
audio_buf_info ai;
int nchannels=0, ssize=0;
if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
return PyInt_FromLong(ai.bytes / (ssize * nchannels));
}
static PyObject *
oss_getptr(oss_audio_t *self, PyObject *unused)
{
count_info info;
int req;
if (self->mode == O_RDONLY)
req = SNDCTL_DSP_GETIPTR;
else
req = SNDCTL_DSP_GETOPTR;
if (ioctl(self->fd, req, &info) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
return Py_BuildValue("iii", info.bytes, info.blocks, info.ptr);
}
/* ----------------------------------------------------------------------
* Methods of mixer objects (OSSMixerType)
*/
static PyObject *
oss_mixer_close(oss_mixer_t *self, PyObject *unused)
{
if (self->fd >= 0) {
close(self->fd);
self->fd = -1;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
oss_mixer_fileno(oss_mixer_t *self, PyObject *unused)
{
return PyInt_FromLong(self->fd);
}
/* Simple mixer interface methods */
static PyObject *
oss_mixer_controls(oss_mixer_t *self, PyObject *args)
{
return _do_ioctl_1_internal(self->fd, args, "controls",
SOUND_MIXER_READ_DEVMASK);
}
static PyObject *
oss_mixer_stereocontrols(oss_mixer_t *self, PyObject *args)
{
return _do_ioctl_1_internal(self->fd, args, "stereocontrols",
SOUND_MIXER_READ_STEREODEVS);
}
static PyObject *
oss_mixer_reccontrols(oss_mixer_t *self, PyObject *args)
{
return _do_ioctl_1_internal(self->fd, args, "reccontrols",
SOUND_MIXER_READ_RECMASK);
}
static PyObject *
oss_mixer_get(oss_mixer_t *self, PyObject *args)
{
int channel, volume;
/* Can't use _do_ioctl_1 because of encoded arg thingy. */
if (!PyArg_ParseTuple(args, "i:get", &channel))
return NULL;
if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) {
PyErr_SetString(OSSAudioError, "Invalid mixer channel specified.");
return NULL;
}
if (ioctl(self->fd, MIXER_READ(channel), &volume) == -1)
return PyErr_SetFromErrno(PyExc_IOError);
return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8);
}
static PyObject *
oss_mixer_set(oss_mixer_t *self, PyObject *args)
{
int channel, volume, leftVol, rightVol;
/* Can't use _do_ioctl_1 because of encoded arg thingy. */
if (!PyArg_ParseTuple(args, "i(ii):set", &channel, &leftVol, &rightVol))
return NULL;
if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) {
PyErr_SetString(OSSAudioError, "Invalid mixer channel specified.");
return NULL;
}
if (leftVol < 0 || rightVol < 0 || leftVol > 100 || rightVol > 100) {
PyErr_SetString(OSSAudioError, "Volumes must be between 0 and 100.");
return NULL;
}
volume = (rightVol << 8) | leftVol;
if (ioctl(self->fd, MIXER_WRITE(channel), &volume) == -1)
return PyErr_SetFromErrno(PyExc_IOError);
return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8);
}
static PyObject *
oss_mixer_get_recsrc(oss_mixer_t *self, PyObject *args)
{
return _do_ioctl_1_internal(self->fd, args, "get_recsrc",
SOUND_MIXER_READ_RECSRC);
}
static PyObject *
oss_mixer_set_recsrc(oss_mixer_t *self, PyObject *args)
{
return _do_ioctl_1(self->fd, args, "set_recsrc",
SOUND_MIXER_WRITE_RECSRC);
}
/* ----------------------------------------------------------------------
* Method tables and other bureaucracy
*/
static PyMethodDef oss_methods[] = {
/* Regular file methods */
{ "read", (PyCFunction)oss_read, METH_VARARGS },
{ "write", (PyCFunction)oss_write, METH_VARARGS },
{ "writeall", (PyCFunction)oss_writeall, METH_VARARGS },
{ "close", (PyCFunction)oss_close, METH_NOARGS },
{ "fileno", (PyCFunction)oss_fileno, METH_NOARGS },
/* Simple ioctl wrappers */
{ "nonblock", (PyCFunction)oss_nonblock, METH_NOARGS },
{ "setfmt", (PyCFunction)oss_setfmt, METH_VARARGS },
{ "getfmts", (PyCFunction)oss_getfmts, METH_NOARGS },
{ "channels", (PyCFunction)oss_channels, METH_VARARGS },
{ "speed", (PyCFunction)oss_speed, METH_VARARGS },
{ "sync", (PyCFunction)oss_sync, METH_VARARGS },
{ "reset", (PyCFunction)oss_reset, METH_VARARGS },
{ "post", (PyCFunction)oss_post, METH_VARARGS },
/* Convenience methods -- wrap a couple of ioctls together */
{ "setparameters", (PyCFunction)oss_setparameters, METH_VARARGS },
{ "bufsize", (PyCFunction)oss_bufsize, METH_NOARGS },
{ "obufcount", (PyCFunction)oss_obufcount, METH_NOARGS },
{ "obuffree", (PyCFunction)oss_obuffree, METH_NOARGS },
{ "getptr", (PyCFunction)oss_getptr, METH_NOARGS },
/* Aliases for backwards compatibility */
{ "flush", (PyCFunction)oss_sync, METH_VARARGS },
{ NULL, NULL} /* sentinel */
};
static PyMethodDef oss_mixer_methods[] = {
/* Regular file method - OSS mixers are ioctl-only interface */
{ "close", (PyCFunction)oss_mixer_close, METH_NOARGS },
{ "fileno", (PyCFunction)oss_mixer_fileno, METH_NOARGS },
/* Simple ioctl wrappers */
{ "controls", (PyCFunction)oss_mixer_controls, METH_VARARGS },
{ "stereocontrols", (PyCFunction)oss_mixer_stereocontrols, METH_VARARGS},
{ "reccontrols", (PyCFunction)oss_mixer_reccontrols, METH_VARARGS},
{ "get", (PyCFunction)oss_mixer_get, METH_VARARGS },
{ "set", (PyCFunction)oss_mixer_set, METH_VARARGS },
{ "get_recsrc", (PyCFunction)oss_mixer_get_recsrc, METH_VARARGS },
{ "set_recsrc", (PyCFunction)oss_mixer_set_recsrc, METH_VARARGS },
{ NULL, NULL}
};
static PyObject *
oss_getattr(oss_audio_t *self, char *name)
{
PyObject * rval = NULL;
if (strcmp(name, "closed") == 0) {
rval = (self->fd == -1) ? Py_True : Py_False;
Py_INCREF(rval);
}
else if (strcmp(name, "name") == 0) {
rval = PyString_FromString(self->devicename);
}
else if (strcmp(name, "mode") == 0) {
/* No need for a "default" in this switch: from newossobject(),
self->mode can only be one of these three values. */
switch(self->mode) {
case O_RDONLY:
rval = PyString_FromString("r");
break;
case O_RDWR:
rval = PyString_FromString("rw");
break;
case O_WRONLY:
rval = PyString_FromString("w");
break;
}
}
else {
rval = Py_FindMethod(oss_methods, (PyObject *)self, name);
}
return rval;
}
static PyObject *
oss_mixer_getattr(oss_mixer_t *self, char *name)
{
return Py_FindMethod(oss_mixer_methods, (PyObject *)self, name);
}
static PyTypeObject OSSAudioType = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"ossaudiodev.oss_audio_device", /*tp_name*/
sizeof(oss_audio_t), /*tp_size*/
0, /*tp_itemsize*/
/* methods */
(destructor)oss_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)oss_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
};
static PyTypeObject OSSMixerType = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"ossaudiodev.oss_mixer_device", /*tp_name*/
sizeof(oss_mixer_t), /*tp_size*/
0, /*tp_itemsize*/
/* methods */
(destructor)oss_mixer_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)oss_mixer_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
};
static PyObject *
ossopen(PyObject *self, PyObject *args)
{
return (PyObject *)newossobject(args);
}
static PyObject *
ossopenmixer(PyObject *self, PyObject *args)
{
return (PyObject *)newossmixerobject(args);
}
static PyMethodDef ossaudiodev_methods[] = {
{ "open", ossopen, METH_VARARGS },
{ "openmixer", ossopenmixer, METH_VARARGS },
{ 0, 0 },
};
#define _EXPORT_INT(mod, name) \
if (PyModule_AddIntConstant(mod, #name, (long) (name)) == -1) return;
static char *control_labels[] = SOUND_DEVICE_LABELS;
static char *control_names[] = SOUND_DEVICE_NAMES;
static int
build_namelists (PyObject *module)
{
PyObject *labels;
PyObject *names;
PyObject *s;
int num_controls;
int i;
num_controls = sizeof(control_labels) / sizeof(control_labels[0]);
assert(num_controls == sizeof(control_names) / sizeof(control_names[0]));
labels = PyList_New(num_controls);
names = PyList_New(num_controls);
if (labels == NULL || names == NULL)
goto error2;
for (i = 0; i < num_controls; i++) {
s = PyString_FromString(control_labels[i]);
if (s == NULL)
goto error2;
PyList_SET_ITEM(labels, i, s);
s = PyString_FromString(control_names[i]);
if (s == NULL)
goto error2;
PyList_SET_ITEM(names, i, s);
}
if (PyModule_AddObject(module, "control_labels", labels) == -1)
goto error2;
if (PyModule_AddObject(module, "control_names", names) == -1)
goto error1;
return 0;
error2:
Py_XDECREF(labels);
error1:
Py_XDECREF(names);
return -1;
}
void
initossaudiodev(void)
{
PyObject *m;
m = Py_InitModule("ossaudiodev", ossaudiodev_methods);
if (m == NULL)
return;
OSSAudioError = PyErr_NewException("ossaudiodev.OSSAudioError",
NULL, NULL);
if (OSSAudioError) {
/* Each call to PyModule_AddObject decrefs it; compensate: */
Py_INCREF(OSSAudioError);
Py_INCREF(OSSAudioError);
PyModule_AddObject(m, "error", OSSAudioError);
PyModule_AddObject(m, "OSSAudioError", OSSAudioError);
}
/* Build 'control_labels' and 'control_names' lists and add them
to the module. */
if (build_namelists(m) == -1) /* XXX what to do here? */
return;
/* Expose the audio format numbers -- essential! */
_EXPORT_INT(m, AFMT_QUERY);
_EXPORT_INT(m, AFMT_MU_LAW);
_EXPORT_INT(m, AFMT_A_LAW);
_EXPORT_INT(m, AFMT_IMA_ADPCM);
_EXPORT_INT(m, AFMT_U8);
_EXPORT_INT(m, AFMT_S16_LE);
_EXPORT_INT(m, AFMT_S16_BE);
_EXPORT_INT(m, AFMT_S8);
_EXPORT_INT(m, AFMT_U16_LE);
_EXPORT_INT(m, AFMT_U16_BE);
_EXPORT_INT(m, AFMT_MPEG);
#ifdef AFMT_AC3
_EXPORT_INT(m, AFMT_AC3);
#endif
#ifdef AFMT_S16_NE
_EXPORT_INT(m, AFMT_S16_NE);
#endif
#ifdef AFMT_U16_NE
_EXPORT_INT(m, AFMT_U16_NE);
#endif
#ifdef AFMT_S32_LE
_EXPORT_INT(m, AFMT_S32_LE);
#endif
#ifdef AFMT_S32_BE
_EXPORT_INT(m, AFMT_S32_BE);
#endif
#ifdef AFMT_MPEG
_EXPORT_INT(m, AFMT_MPEG);
#endif
/* Expose the sound mixer device numbers. */
_EXPORT_INT(m, SOUND_MIXER_NRDEVICES);
_EXPORT_INT(m, SOUND_MIXER_VOLUME);
_EXPORT_INT(m, SOUND_MIXER_BASS);
_EXPORT_INT(m, SOUND_MIXER_TREBLE);
_EXPORT_INT(m, SOUND_MIXER_SYNTH);
_EXPORT_INT(m, SOUND_MIXER_PCM);
_EXPORT_INT(m, SOUND_MIXER_SPEAKER);
_EXPORT_INT(m, SOUND_MIXER_LINE);
_EXPORT_INT(m, SOUND_MIXER_MIC);
_EXPORT_INT(m, SOUND_MIXER_CD);
_EXPORT_INT(m, SOUND_MIXER_IMIX);
_EXPORT_INT(m, SOUND_MIXER_ALTPCM);
_EXPORT_INT(m, SOUND_MIXER_RECLEV);
_EXPORT_INT(m, SOUND_MIXER_IGAIN);
_EXPORT_INT(m, SOUND_MIXER_OGAIN);
_EXPORT_INT(m, SOUND_MIXER_LINE1);
_EXPORT_INT(m, SOUND_MIXER_LINE2);
_EXPORT_INT(m, SOUND_MIXER_LINE3);
#ifdef SOUND_MIXER_DIGITAL1
_EXPORT_INT(m, SOUND_MIXER_DIGITAL1);
#endif
#ifdef SOUND_MIXER_DIGITAL2
_EXPORT_INT(m, SOUND_MIXER_DIGITAL2);
#endif
#ifdef SOUND_MIXER_DIGITAL3
_EXPORT_INT(m, SOUND_MIXER_DIGITAL3);
#endif
#ifdef SOUND_MIXER_PHONEIN
_EXPORT_INT(m, SOUND_MIXER_PHONEIN);
#endif
#ifdef SOUND_MIXER_PHONEOUT
_EXPORT_INT(m, SOUND_MIXER_PHONEOUT);
#endif
#ifdef SOUND_MIXER_VIDEO
_EXPORT_INT(m, SOUND_MIXER_VIDEO);
#endif
#ifdef SOUND_MIXER_RADIO
_EXPORT_INT(m, SOUND_MIXER_RADIO);
#endif
#ifdef SOUND_MIXER_MONITOR
_EXPORT_INT(m, SOUND_MIXER_MONITOR);
#endif
/* Expose all the ioctl numbers for masochists who like to do this
stuff directly. */
_EXPORT_INT(m, SNDCTL_COPR_HALT);
_EXPORT_INT(m, SNDCTL_COPR_LOAD);
_EXPORT_INT(m, SNDCTL_COPR_RCODE);
_EXPORT_INT(m, SNDCTL_COPR_RCVMSG);
_EXPORT_INT(m, SNDCTL_COPR_RDATA);
_EXPORT_INT(m, SNDCTL_COPR_RESET);
_EXPORT_INT(m, SNDCTL_COPR_RUN);
_EXPORT_INT(m, SNDCTL_COPR_SENDMSG);
_EXPORT_INT(m, SNDCTL_COPR_WCODE);
_EXPORT_INT(m, SNDCTL_COPR_WDATA);
#ifdef SNDCTL_DSP_BIND_CHANNEL
_EXPORT_INT(m, SNDCTL_DSP_BIND_CHANNEL);
#endif
_EXPORT_INT(m, SNDCTL_DSP_CHANNELS);
_EXPORT_INT(m, SNDCTL_DSP_GETBLKSIZE);
_EXPORT_INT(m, SNDCTL_DSP_GETCAPS);
#ifdef SNDCTL_DSP_GETCHANNELMASK
_EXPORT_INT(m, SNDCTL_DSP_GETCHANNELMASK);
#endif
_EXPORT_INT(m, SNDCTL_DSP_GETFMTS);
_EXPORT_INT(m, SNDCTL_DSP_GETIPTR);
_EXPORT_INT(m, SNDCTL_DSP_GETISPACE);
#ifdef SNDCTL_DSP_GETODELAY
_EXPORT_INT(m, SNDCTL_DSP_GETODELAY);
#endif
_EXPORT_INT(m, SNDCTL_DSP_GETOPTR);
_EXPORT_INT(m, SNDCTL_DSP_GETOSPACE);
#ifdef SNDCTL_DSP_GETSPDIF
_EXPORT_INT(m, SNDCTL_DSP_GETSPDIF);
#endif
_EXPORT_INT(m, SNDCTL_DSP_GETTRIGGER);
_EXPORT_INT(m, SNDCTL_DSP_MAPINBUF);
_EXPORT_INT(m, SNDCTL_DSP_MAPOUTBUF);
_EXPORT_INT(m, SNDCTL_DSP_NONBLOCK);
_EXPORT_INT(m, SNDCTL_DSP_POST);
#ifdef SNDCTL_DSP_PROFILE
_EXPORT_INT(m, SNDCTL_DSP_PROFILE);
#endif
_EXPORT_INT(m, SNDCTL_DSP_RESET);
_EXPORT_INT(m, SNDCTL_DSP_SAMPLESIZE);
_EXPORT_INT(m, SNDCTL_DSP_SETDUPLEX);
_EXPORT_INT(m, SNDCTL_DSP_SETFMT);
_EXPORT_INT(m, SNDCTL_DSP_SETFRAGMENT);
#ifdef SNDCTL_DSP_SETSPDIF
_EXPORT_INT(m, SNDCTL_DSP_SETSPDIF);
#endif
_EXPORT_INT(m, SNDCTL_DSP_SETSYNCRO);
_EXPORT_INT(m, SNDCTL_DSP_SETTRIGGER);
_EXPORT_INT(m, SNDCTL_DSP_SPEED);
_EXPORT_INT(m, SNDCTL_DSP_STEREO);
_EXPORT_INT(m, SNDCTL_DSP_SUBDIVIDE);
_EXPORT_INT(m, SNDCTL_DSP_SYNC);
_EXPORT_INT(m, SNDCTL_FM_4OP_ENABLE);
_EXPORT_INT(m, SNDCTL_FM_LOAD_INSTR);
_EXPORT_INT(m, SNDCTL_MIDI_INFO);
_EXPORT_INT(m, SNDCTL_MIDI_MPUCMD);
_EXPORT_INT(m, SNDCTL_MIDI_MPUMODE);
_EXPORT_INT(m, SNDCTL_MIDI_PRETIME);
_EXPORT_INT(m, SNDCTL_SEQ_CTRLRATE);
_EXPORT_INT(m, SNDCTL_SEQ_GETINCOUNT);
_EXPORT_INT(m, SNDCTL_SEQ_GETOUTCOUNT);
#ifdef SNDCTL_SEQ_GETTIME
_EXPORT_INT(m, SNDCTL_SEQ_GETTIME);
#endif
_EXPORT_INT(m, SNDCTL_SEQ_NRMIDIS);
_EXPORT_INT(m, SNDCTL_SEQ_NRSYNTHS);
_EXPORT_INT(m, SNDCTL_SEQ_OUTOFBAND);
_EXPORT_INT(m, SNDCTL_SEQ_PANIC);
_EXPORT_INT(m, SNDCTL_SEQ_PERCMODE);
_EXPORT_INT(m, SNDCTL_SEQ_RESET);
_EXPORT_INT(m, SNDCTL_SEQ_RESETSAMPLES);
_EXPORT_INT(m, SNDCTL_SEQ_SYNC);
_EXPORT_INT(m, SNDCTL_SEQ_TESTMIDI);
_EXPORT_INT(m, SNDCTL_SEQ_THRESHOLD);
#ifdef SNDCTL_SYNTH_CONTROL
_EXPORT_INT(m, SNDCTL_SYNTH_CONTROL);
#endif
#ifdef SNDCTL_SYNTH_ID
_EXPORT_INT(m, SNDCTL_SYNTH_ID);
#endif
_EXPORT_INT(m, SNDCTL_SYNTH_INFO);
_EXPORT_INT(m, SNDCTL_SYNTH_MEMAVL);
#ifdef SNDCTL_SYNTH_REMOVESAMPLE
_EXPORT_INT(m, SNDCTL_SYNTH_REMOVESAMPLE);
#endif
_EXPORT_INT(m, SNDCTL_TMR_CONTINUE);
_EXPORT_INT(m, SNDCTL_TMR_METRONOME);
_EXPORT_INT(m, SNDCTL_TMR_SELECT);
_EXPORT_INT(m, SNDCTL_TMR_SOURCE);
_EXPORT_INT(m, SNDCTL_TMR_START);
_EXPORT_INT(m, SNDCTL_TMR_STOP);
_EXPORT_INT(m, SNDCTL_TMR_TEMPO);
_EXPORT_INT(m, SNDCTL_TMR_TIMEBASE);
}