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