]> granicus.if.org Git - python/commitdiff
SF #818006: merge from release24-maint branch: add useful read-only
authorGreg Ward <gward@python.net>
Mon, 7 Mar 2005 01:41:11 +0000 (01:41 +0000)
committerGreg Ward <gward@python.net>
Mon, 7 Mar 2005 01:41:11 +0000 (01:41 +0000)
attributes to oss_audio_device object: 'closed', 'name', and 'mode'.

Doc/lib/libossaudiodev.tex
Lib/test/output/test_ossaudiodev
Lib/test/test_ossaudiodev.py
Modules/ossaudiodev.c

index 8c8e445bb26b49bd4272c71a667b773017ae79b3..762acb766dae139e097fb48dc0c3a1d448fd973f 100644 (file)
@@ -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:
index 6903012134ab5485ad595b77dac62f7306d1c38d..9f55afa4cb3309ba49bc3f3f50a15354170a5ffc 100644 (file)
@@ -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
index 3067c03de0dd4ab2c9c34b3cc9c70ab0580bf431..f668eb41d7ed07a5c641095e8071c87240e43125 100644 (file)
@@ -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()
index 047355fb784d5c724c5cf0afa658871b95832d00..43bd92b53be0b430d4a4954f2450a9a7fbd9115c 100644 (file)
@@ -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 *