summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/lib/libossaudiodev.tex17
-rw-r--r--Lib/test/output/test_ossaudiodev5
-rw-r--r--Lib/test/test_ossaudiodev.py34
-rw-r--r--Modules/ossaudiodev.c80
4 files changed, 101 insertions, 35 deletions
diff --git a/Doc/lib/libossaudiodev.tex b/Doc/lib/libossaudiodev.tex
index 8c8e445..762acb7 100644
--- a/Doc/lib/libossaudiodev.tex
+++ b/Doc/lib/libossaudiodev.tex
@@ -115,7 +115,7 @@ three audio parameters at once. This is more convenient, but may not be
as flexible in all cases.
The audio device objects returned by \function{open()} define the
-following methods:
+following methods and (read-only) attributes:
\begin{methoddesc}[audio device]{close}{}
Explicitly close the audio device. When you are done writing to or
@@ -289,6 +289,21 @@ Returns the number of samples that could be queued into the hardware
buffer to be played without blocking.
\end{methoddesc}
+Audio device objects also support several read-only attributes:
+
+\begin{memberdesc}[audio device]{closed}{}
+Boolean indicating whether the device has been closed.
+\end{memberdesc}
+
+\begin{memberdesc}[audio device]{name}{}
+String containing the name of the device file.
+\end{memberdesc}
+
+\begin{memberdesc}[audio device]{mode}{}
+The I/O mode for the file, either \code{"r"}, \code{"rw"}, or \code{"w"}.
+\end{memberdesc}
+
+
\subsection{Mixer Device Objects \label{mixer-device-objects}}
The mixer object provides two file-like methods:
diff --git a/Lib/test/output/test_ossaudiodev b/Lib/test/output/test_ossaudiodev
index 6903012..9f55afa 100644
--- a/Lib/test/output/test_ossaudiodev
+++ b/Lib/test/output/test_ossaudiodev
@@ -1,6 +1,3 @@
test_ossaudiodev
playing test sound file...
-elapsed time: 2.9 sec
-setparameters: got OSSAudioError as expected
-setparameters: got OSSAudioError as expected
-setparameters: got OSSAudioError as expected
+elapsed time: 3.1 sec
diff --git a/Lib/test/test_ossaudiodev.py b/Lib/test/test_ossaudiodev.py
index 3067c03..f668eb4 100644
--- a/Lib/test/test_ossaudiodev.py
+++ b/Lib/test/test_ossaudiodev.py
@@ -56,6 +56,19 @@ def play_sound_file(data, rate, ssize, nchannels):
dsp.getptr()
dsp.fileno()
+ # Make sure the read-only attributes work.
+ assert dsp.closed is False, "dsp.closed is not False"
+ assert dsp.name == "/dev/dsp"
+ assert dsp.mode == 'w', "bad dsp.mode: %r" % dsp.mode
+
+ # And make sure they're really read-only.
+ for attr in ('closed', 'name', 'mode'):
+ try:
+ setattr(dsp, attr, 42)
+ raise RuntimeError("dsp.%s not read-only" % attr)
+ except TypeError:
+ pass
+
# set parameters based on .au file headers
dsp.setparameters(AFMT_S16_NE, nchannels, rate)
t1 = time.time()
@@ -65,9 +78,7 @@ def play_sound_file(data, rate, ssize, nchannels):
t2 = time.time()
print "elapsed time: %.1f sec" % (t2-t1)
-def test_setparameters():
- dsp = ossaudiodev.open("w")
-
+def test_setparameters(dsp):
# Two configurations for testing:
# config1 (8-bit, mono, 8 kHz) should work on even the most
# ancient and crufty sound card, but maybe not on special-
@@ -96,11 +107,16 @@ def test_setparameters():
assert result == (fmt, channels, rate), \
"setparameters%r: returned %r" % (config + result)
+def test_bad_setparameters(dsp):
+
# Now try some configurations that are presumably bogus: eg. 300
# channels currently exceeds even Hollywood's ambitions, and
# negative sampling rate is utter nonsense. setparameters() should
# accept these in non-strict mode, returning something other than
# was requested, but should barf in strict mode.
+ fmt = AFMT_S16_NE
+ rate = 44100
+ channels = 2
for config in [(fmt, 300, rate), # ridiculous nchannels
(fmt, -5, rate), # impossible nchannels
(fmt, channels, -50), # impossible rate
@@ -119,6 +135,16 @@ def test_setparameters():
def test():
(data, rate, ssize, nchannels) = read_sound_file(findfile('audiotest.au'))
play_sound_file(data, rate, ssize, nchannels)
- test_setparameters()
+
+ dsp = ossaudiodev.open("w")
+ try:
+ test_setparameters(dsp)
+
+ # Disabled because it fails under Linux 2.6 with ALSA's OSS
+ # emulation layer.
+ #test_bad_setparameters(dsp)
+ finally:
+ dsp.close()
+ assert dsp.closed is True, "dsp.closed is not True"
test()
diff --git a/Modules/ossaudiodev.c b/Modules/ossaudiodev.c
index 047355f..43bd92b 100644
--- a/Modules/ossaudiodev.c
+++ b/Modules/ossaudiodev.c
@@ -46,11 +46,12 @@ typedef unsigned long uint32_t;
typedef struct {
PyObject_HEAD;
- int fd; /* The open file */
- int mode; /* file mode */
- int icount; /* Input count */
- int ocount; /* Output count */
- uint32_t afmts; /* Audio formats supported by hardware */
+ 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 {
@@ -74,7 +75,7 @@ newossobject(PyObject *arg)
{
oss_audio_t *self;
int fd, afmts, imode;
- char *basedev = NULL;
+ char *devicename = NULL;
char *mode = NULL;
/* Two ways to call open():
@@ -82,11 +83,11 @@ newossobject(PyObject *arg)
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", &basedev, &mode))
+ if (!PyArg_ParseTuple(arg, "s|s:open", &devicename, &mode))
return NULL;
if (mode == NULL) { /* only one arg supplied */
- mode = basedev;
- basedev = NULL;
+ mode = devicename;
+ devicename = NULL;
}
if (strcmp(mode, "r") == 0)
@@ -102,18 +103,18 @@ newossobject(PyObject *arg)
/* Open the correct device: either the 'device' argument,
or the AUDIODEV environment variable, or "/dev/dsp". */
- if (basedev == NULL) { /* called with one arg */
- basedev = getenv("AUDIODEV");
- if (basedev == NULL) /* $AUDIODEV not set */
- basedev = "/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(basedev, imode|O_NONBLOCK)) == -1) {
- PyErr_SetFromErrnoWithFilename(PyExc_IOError, basedev);
+ if ((fd = open(devicename, imode|O_NONBLOCK)) == -1) {
+ PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
@@ -121,12 +122,12 @@ newossobject(PyObject *arg)
expected write() semantics. */
if (fcntl(fd, F_SETFL, 0) == -1) {
close(fd);
- PyErr_SetFromErrnoWithFilename(PyExc_IOError, basedev);
+ PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) {
- PyErr_SetFromErrnoWithFilename(PyExc_IOError, basedev);
+ PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
/* Create and initialize the object */
@@ -134,6 +135,7 @@ newossobject(PyObject *arg)
close(fd);
return NULL;
}
+ self->devicename = devicename;
self->fd = fd;
self->mode = imode;
self->icount = self->ocount = 0;
@@ -158,22 +160,22 @@ oss_dealloc(oss_audio_t *self)
static oss_mixer_t *
newossmixerobject(PyObject *arg)
{
- char *basedev = NULL;
+ char *devicename = NULL;
int fd;
oss_mixer_t *self;
- if (!PyArg_ParseTuple(arg, "|s", &basedev)) {
+ if (!PyArg_ParseTuple(arg, "|s", &devicename)) {
return NULL;
}
- if (basedev == NULL) {
- basedev = getenv("MIXERDEV");
- if (basedev == NULL) /* MIXERDEV not set */
- basedev = "/dev/mixer";
+ if (devicename == NULL) {
+ devicename = getenv("MIXERDEV");
+ if (devicename == NULL) /* MIXERDEV not set */
+ devicename = "/dev/mixer";
}
- if ((fd = open(basedev, O_RDWR)) == -1) {
- PyErr_SetFromErrnoWithFilename(PyExc_IOError, basedev);
+ if ((fd = open(devicename, O_RDWR)) == -1) {
+ PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL;
}
@@ -827,7 +829,33 @@ static PyMethodDef oss_mixer_methods[] = {
static PyObject *
oss_getattr(oss_audio_t *self, char *name)
{
- return Py_FindMethod(oss_methods, (PyObject *)self, 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 *