Subject: Re: /dev/sound, non-blocking IO, and select
To: None <tech-kern@netbsd.org>
From: Alan Post <apost@recalcitrant.org>
List: tech-kern
Date: 04/07/2005 12:59:37
In article <1112877023.538.20.camel@localhost>, Jared D. McNeill wrote:
>
> The read is never returning for me (even if I turn off O_NONBLOCK).
> Something strange is going on here.
>
> I can 'dd if=/dev/sound1 of=/dev/null ...' and 'cat /dev/sound1' without
> a problem, but reads in this application are hanging.
Have you tried using /dev/audio1 instead of /dev/sound1? The
initialization code paths are slightly different for /dev/audio and
/dev/sound in audio.c.
> Here's basically what I'm doing for setup:
> dev->fd = open(dev_name, O_RDWR, O_NONBLOCK);
> [...]
> if (ioctl(dev->fd, AUDIO_GETINFO, &oinfo) < 0) {
> [...]
> }
> AUDIO_INITINFO(&dev->info);
> dev->info.play.sample_rate = dev->info.record.sample_rate = 8000;
> dev->info.play.channels = dev->info.record.channels = 1;
> dev->info.play.precision = dev->info.record.precision = 16;
> dev->info.play.encoding = dev->info.record.encoding =
> AUDIO_ENCODING_SLINEAR_LE;
> dev->info.play.gain = dev->info.record.gain = oinfo.play.gain;
> dev->info.play.port = dev->info.record.port = oinfo.play.port;
> dev->info.play.balance = dev->info.record.balance =
> oinfo.play.balance;
> dev->info.monitor_gain = oinfo.monitor_gain;
> dev->info.mode = AUMODE_PLAY | AUMODE_RECORD;
> if (ioctl(dev->fd, AUDIO_SETINFO, &dev->info) < 0) {
> [...]
> }
If you want to do full duplex, you should also do an AUDIO_SETFD
between the open and the SETINFO:
int is_full_duplex = 1;
if ( -1 == ioctl( afd, AUDIO_SETFD, &is_full_duplex )) die( "ioctl" );
In my application, I don't open the device O_NONBLOCK. Also, I set
the blocksize in the SETINFO. Note also that if you aren't changing
values in the audioinfo struct, you can leave them initialized by
AUDIO_INITINFO -- the SETINFO ioctl will recognize such values as
"don't change" (see audiosetinfo() in audio.c). Finally, it can be
instructive to do a GETINFO after your SETINFO, and see what you end
up with, as the settings you send in SETINFO are really just a
request, and the hardware decides what it's capable of.
Also, if you want low-latency, I recommend:
* Recording: if you read as soon as data is available, the kernel
buffer won't fill up
* Playing: if you set:
info.hiwat = 2;
info.lowat = 1;
then writing will block after the play buffer holds
2*blocksize, and allow writing again after flushing
1*blocksize to the hardware.
My audio device is:
auich0 at pci0 dev 31 function 5: i82801AA (ICH) AC-97 Audio
auich0: interrupting at irq 9
auich0: Analog Devices AD1881 codec; headphone, Analog Devices Phat Stereo
auich0: measured ac97 link rate at 47999 Hz, will use 48000 Hz
audio0 at auich0: full duplex, mmap, independent
HTH.
Alan