
Back at work on the ossaudiodev docs for a few minutes. Documenting an API is always a great opportunity to clean it up, and the ossaudiodev.open() function has a weird interface right now. From the current docs: """ open([device, ] mode) Open an audio device and return an OSS audio device object. This object supports many file-like methods, such as read(), write(), and fileno() (although there are subtle differences between conventional Unix read/write semantics and those of OSS audio devices). It also supports a number of audio-specific methods; see below for the complete list of methods. Note the unusual calling syntax: the first argument is optional, and the second is required. This is a historical artifact for compatibility with the older linuxaudiodev module which ossaudiodev supersedes. device is the audio device filename to use. If it is not specified, this module first looks in the environment variable AUDIODEV for a device to use. If not found, it falls back to /dev/dsp. mode is one of 'r' for read-only (record) access, 'w' for write-only (playback) access and 'rw' for both. Since many soundcards only allow one process to have the recorder or player open at a time it is a good idea to open the device only for the activity needed. Further, some soundcards are half-duplex: they can be opened for reading or writing, but not both at once. """ The historical background is that in linuxaudiodev prior to Python 2.3, it was *impossible* to specify the device file to open -- you had to do something like this: os.environ['AUDIODEV'] = "/dev/dsp2" dsp = linuxaudiodev.open("w") Fixing that wart is what led me to create ossaudiodev in the first place. Cleaning up the remaining ugliness in ossaudiodev.open() brings things nicely full-circle. Anyways, since the module has been renamed, who cares about backwards compatibility with linuxaudiodev? I'd like to change the open() interface to: open(device, mode) where both are required. (Most use of the audio device is for playback, not recording. But a default mode of "w" goes counter to expectations. So I think 'mode' should be required.) This would also mean getting rid of the $AUDIODEV check in ossaudiodev.c. Less C code is a good thing, unless of course it leads to lots of redundant Python code all over the world. Finally, for consistency I should also change openmixer() to require a 'device' argument (currently, it does the same thing, but hardcodes "/dev/mixer" and checks $MIXERDEVICE). Of course, this will lead people to hardcode "/dev/dsp" (and/or "/dev/mixer") into their Python audio scripts. That's bad if other OSS-using operating systems have different names for the standard audio devices. Do they? But it's certainly no *worse* than the situation for C programmers, who have to assume "/dev/dsp" as a default -- the open(2) system call certainly doesn't let you get away with leaving the filename out. And besides, "/dev/dsp" is already hard-coded into ossaudiodev.c, so if that's inappropriate on certain operating systems, somebody's going to lose already. Thoughts? Greg -- Greg Ward <gward@python.net> http://www.gerg.ca/ Sure, I'm paranoid... but am I paranoid ENOUGH?

Back at work on the ossaudiodev docs for a few minutes.
Great! I wonder if you have any thoughts on why running test_ossaudiodev hangs when run on Linux Red Hat 7.3? I'm currently using a 2.4.18-24.7.x kernel. I have no idea what other info would be useful to debug this. Regarding the changes you propose, I was going to vote +1 on all, but I realize I'm not a user so my vote should only count as epsilon. --Guido van Rossum (home page: http://www.python.org/~guido/)

On 11 March 2003, Guido van Rossum said:
The most obvious cause is that some other process has the audio device open, and your audio {hardware, device driver} only allows one at a time. If you're running one of those newfangled GUI environments like KDE or GNOME, it's quite likely that the esound or aRTSd (however you spell it) daemon started when you logged in, and is thus blocking all access to your /dev/dsp. This sucks, but IMHO it's not ossaudiodev's job to know about esound and similar. One way to test this is to take your system down to single-user (or at least a console-only, no-X11 runlevel) and then try running test_ossaudiodev. Hmmm, it looks like calling open() with O_NONBLOCK helps. I know this does *not* affect later read()/write() -- there's a special ioctl() for non-blocking read/write -- but it *does* appear to fix blocking open(). At least for me it turned a second open() attempt on the same device from "hang" to "IOError: [Errno 16] Device or resource busy: '/dev/dsp2'". Try this patch; if it works I'll check it in: --- Modules/ossaudiodev.c 10 Mar 2003 03:17:06 -0000 1.24 +++ Modules/ossaudiodev.c 11 Mar 2003 15:56:24 -0000 @@ -131,7 +131,7 @@ basedev = "/dev/dsp"; } - if ((fd = open(basedev, imode)) == -1) { + if ((fd = open(basedev, imode|O_NONBLOCK)) == -1) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, basedev); return NULL; } test_ossaudiodev.py will still need fixing to handle the EBUSY error, but at least this should prevent hanging on open(). Greg -- Greg Ward <gward@python.net> http://www.gerg.ca/ Hand me a pair of leather pants and a CASIO keyboard -- I'm living for today!

[Greg]
Hm, but I *do* hear some sound coming out of the speaker: a quiet, sped-up squeaky version of the "nobody expects the spanish inquisition" soundclip that test_linuxaudiodev also used to play. (The latter now crashes for me with "linuxaudiodev.error: (0, 'Error')".)
I tried this at runlevel 1, and the symptoms are identical: some squeaks, then it hangs.
Yes, it fixes the hang. Please check it in! The sample is still played at too high a speed, but maybe that's expected? --Guido van Rossum (home page: http://www.python.org/~guido/)

On 11 March 2003, Guido van Rossum said:
Yes, it fixes the hang. Please check it in!
OK, done.
The sample is still played at too high a speed, but maybe that's expected?
No, definitely not. On my system, it sounds the same as it has with linuxaudiodev for quite a while, and the same as it did with sunaudiodev on my old Sun box at CNRI before that. *Maybe* there's something wrong with how setparameters() initializes the audio device. Try this patch and see how it goes: --- Lib/test/test_ossaudiodev.py 14 Feb 2003 19:29:22 -0000 1.4 +++ Lib/test/test_ossaudiodev.py 11 Mar 2003 21:42:31 -0000 @@ -52,8 +52,10 @@ a.fileno() # set parameters based on .au file headers - a.setparameters(rate, 16, nchannels, fmt) - a.write(data) + a.setfmt(fmt) + a.channels(nchannels) + a.speed(rate) + a.writeall(data) a.flush() a.close() Hmmm, I just noticed that setting O_NONBLOCK at open() time *does* have an effect -- I needed to change that write() to writeall() in order to hear the whole test sound. Uh-oh. Greg -- Greg Ward <gward@python.net> http://www.gerg.ca/ "... but in the town it was well known that when they got home their fat and psychopathic wives would thrash them to within inches of their lives ..."

Back at work on the ossaudiodev docs for a few minutes.
Great! I wonder if you have any thoughts on why running test_ossaudiodev hangs when run on Linux Red Hat 7.3? I'm currently using a 2.4.18-24.7.x kernel. I have no idea what other info would be useful to debug this. Regarding the changes you propose, I was going to vote +1 on all, but I realize I'm not a user so my vote should only count as epsilon. --Guido van Rossum (home page: http://www.python.org/~guido/)

On 11 March 2003, Guido van Rossum said:
The most obvious cause is that some other process has the audio device open, and your audio {hardware, device driver} only allows one at a time. If you're running one of those newfangled GUI environments like KDE or GNOME, it's quite likely that the esound or aRTSd (however you spell it) daemon started when you logged in, and is thus blocking all access to your /dev/dsp. This sucks, but IMHO it's not ossaudiodev's job to know about esound and similar. One way to test this is to take your system down to single-user (or at least a console-only, no-X11 runlevel) and then try running test_ossaudiodev. Hmmm, it looks like calling open() with O_NONBLOCK helps. I know this does *not* affect later read()/write() -- there's a special ioctl() for non-blocking read/write -- but it *does* appear to fix blocking open(). At least for me it turned a second open() attempt on the same device from "hang" to "IOError: [Errno 16] Device or resource busy: '/dev/dsp2'". Try this patch; if it works I'll check it in: --- Modules/ossaudiodev.c 10 Mar 2003 03:17:06 -0000 1.24 +++ Modules/ossaudiodev.c 11 Mar 2003 15:56:24 -0000 @@ -131,7 +131,7 @@ basedev = "/dev/dsp"; } - if ((fd = open(basedev, imode)) == -1) { + if ((fd = open(basedev, imode|O_NONBLOCK)) == -1) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, basedev); return NULL; } test_ossaudiodev.py will still need fixing to handle the EBUSY error, but at least this should prevent hanging on open(). Greg -- Greg Ward <gward@python.net> http://www.gerg.ca/ Hand me a pair of leather pants and a CASIO keyboard -- I'm living for today!

[Greg]
Hm, but I *do* hear some sound coming out of the speaker: a quiet, sped-up squeaky version of the "nobody expects the spanish inquisition" soundclip that test_linuxaudiodev also used to play. (The latter now crashes for me with "linuxaudiodev.error: (0, 'Error')".)
I tried this at runlevel 1, and the symptoms are identical: some squeaks, then it hangs.
Yes, it fixes the hang. Please check it in! The sample is still played at too high a speed, but maybe that's expected? --Guido van Rossum (home page: http://www.python.org/~guido/)

On 11 March 2003, Guido van Rossum said:
Yes, it fixes the hang. Please check it in!
OK, done.
The sample is still played at too high a speed, but maybe that's expected?
No, definitely not. On my system, it sounds the same as it has with linuxaudiodev for quite a while, and the same as it did with sunaudiodev on my old Sun box at CNRI before that. *Maybe* there's something wrong with how setparameters() initializes the audio device. Try this patch and see how it goes: --- Lib/test/test_ossaudiodev.py 14 Feb 2003 19:29:22 -0000 1.4 +++ Lib/test/test_ossaudiodev.py 11 Mar 2003 21:42:31 -0000 @@ -52,8 +52,10 @@ a.fileno() # set parameters based on .au file headers - a.setparameters(rate, 16, nchannels, fmt) - a.write(data) + a.setfmt(fmt) + a.channels(nchannels) + a.speed(rate) + a.writeall(data) a.flush() a.close() Hmmm, I just noticed that setting O_NONBLOCK at open() time *does* have an effect -- I needed to change that write() to writeall() in order to hear the whole test sound. Uh-oh. Greg -- Greg Ward <gward@python.net> http://www.gerg.ca/ "... but in the town it was well known that when they got home their fat and psychopathic wives would thrash them to within inches of their lives ..."
participants (4)
-
Anthony Baxter
-
Arne Koewing
-
Greg Ward
-
Guido van Rossum