Summary:ASTERISK-01290: [patch] using select() with alsa console drivers is unreliable, unless snd_pcm_poll_descriptors_revents() is called after it.
Reporter:jcdutton (jcdutton)Labels:
Date Opened:2004-03-25 12:50:37.000-0600Date Closed:2011-06-07 14:04:40
Versions:Frequency of
Environment:Attachments:( 0) chan_alsa.c
( 1) chan_alsa.c
( 2) chan_alsa.c.diff
Description:one cannot rely on ast_select() when polling alsa file descriptors.
Example of problems:
int ast_waitfor(struct ast_channel *c, int ms)
might never return, even if there is data to read from the sound device.


snd_pcm_poll_descriptors();  <- Currently done.
ast_select();  <- Currently done.
snd_pcm_poll_descriptors_revents()  <- decode the results of the select.

The last step is not performed in the current asterix code.
Instead select macros are used, like FD_ISSET.

Depending on the alsa sound setup, this problem may or may not present itself.

I suggest that if some part of asterisk needs to do a select or poll on the audio input/output, it should instead call a thread safe function pointer, and have the poll testing code in the ./channels/chan_xxx.c driver instead of ./channel.c.

The current asterisk code does not look very SMP or thread safe either.
Comments:By: jcdutton (jcdutton) 2004-03-29 14:15:27.000-0600

I have made some progress, and will be posting a new chan_alsa.c which gets round the problems described above soon.
I have full duplex low latency currently working, I just need to add in ringing/busy etc. notifications.

By: antonverburg (antonverburg) 2004-04-01 03:05:03.000-0600

Can you upload your new chan_alsa.c already? I am verry interested in using alsa at the console, maybe I can do something to finish it.

By: jcdutton (jcdutton) 2004-04-01 20:26:20.000-0600

New version of chan_alsa.c which should close this bug.

Correctly records and playback sound to mic and speakers.

By: jcdutton (jcdutton) 2004-04-03 10:09:58.000-0600

Uploaded a new file, with a few log messages removed.
It also fixes a bug in the dial command so that in call dial commands now work.
It also fixes a race problem during some hangup situations.

By: Brian West (bkw918) 2004-04-03 10:47:41.000-0600

diff -u please

By: jcdutton (jcdutton) 2004-04-03 11:20:18.000-0600

As you can see, the diff file is almost bigger than the .c file, which is why I did not bother posting the .diff before.
It is very much different from the current chan_alsa.c in cvs because I had to re-write most of it.
It probably still needs tuning, but works quite reliably here now.

By: antonverburg (antonverburg) 2004-04-06 10:05:42

I have tested this new alsachannel with RH6.2. Works fine. Only one point; it consumes more CPU-power than the oss channel. Don't know why...

By: jcdutton (jcdutton) 2004-04-06 10:26:34

How much more CPU power?
This is probably due to period sizes.
The OSS driver uses period sizes or 1024 or 2048 samples, but the alsa one uses 160 samples.
So, the card is interrupting the CPU every 160 samples with the alsa driver.
The advantage of all this, is that the alsa driver has better latency than the oss driver.
The extra cpu time should only be used during an actual call. Can you check that?
Note that a SB Live and Audigy cannot do capture of 160 samples, but instead uses 384 samples. The SB Live and Audigy can do 160 samples playback. So, the SB will have slightly higher latency than say for example a motherboard based intel card.

By: antonverburg (antonverburg) 2004-04-06 11:08:04

Alsa consumes almost twice as much as OSS. Yes, CPU-time is consumed during a call. I have moved that periodsize from 160 to 320. Didn't help me much. I am going to try it out with 1024 samples now. Over that, maybe it's interesting to put a nanosleep in  sound_capture()t? We could make an option in alsa.conf, for setting this sleep to 0 for better latency, and increase the pause for less CPU-usage? I am using * in an embeded system, for that reason CPU-usage is important for me...

By: antonverburg (antonverburg) 2004-04-06 11:11:24

Yes, bringing periodsize to 1024 helps a bit: going from 25% to 19. Comes closer to OSS (12%). Using 2048 is not posible. Sound is disorted in packets, and you can only hear huh-huh-huh.

Some other idea's to improve speed;
- It grabs now 16-bit integers. Is there a posibility to make it work on 8-bit? I tried that changing  SND_PCM_FORMAT_S16_LE to SND_PCM_FORMAT_S8, but that didn't work.
- Can I bring down the sample frequence of alsa? I tried to put  DESIRED_RATE to 4000, but Alsa does not accept that.

edited on: 04-06-04 10:16

By: antonverburg (antonverburg) 2004-04-07 11:19:23

Hm, looking to the source of chan_alsa.c and chan_oss.c there is one big difference; alsa delivers 16-bit integers to the gsm-encoder, oss 8-bit. I think that's the main problem. I can push down CPU-usage using a usleep between grabbing of frames. In combination with a periodsize of 1024, this brings my CPU-usage to a minimum of 16%.

Until now, I was using the gsm-codec. When I switched to ulaw/alaw, alsa was better than oss. Using total 8% (5% encoding, 3% decoding). ADPCM does also a good job; 10% total. Using oss for this, requires always at least 14%. These codecs convert the 16-bit integers to 8bit.

So the only problem is, that alsa uses 16-bit integers. If we do not like this, we could convert them maybe before delivering to the encoder. If this is no problem, the driver is OK, and should be added to CVS. In my opinion it can even be added, to the semi-stable release, because it fixes the not-working microphone.

By: jcdutton (jcdutton) 2004-04-07 11:45:03

adding usleep is pointless.
We do:
poll()    <- Waits while using no cpu.
snd_pcm_readi() in blocks of 160 samples, but more if more are waiting.
back to poll()

As your test with ulaw/alaw shows, alsa is actually better than oss cpu wise, so the cpu % is therefore caused by the gsm codec and not alsa at all.
As gsm <-> alaw/ulaw is the most common conversion in telco land, we could change the capture/playback format to ulaw/alaw, or even change it to a /etc/asterisk/alsa.conf setting.
Alsa can handle the following sample formats, for every sound card: -
Recognized sample formats are: S8 U8 S16_LE S16_BE U16_LE U16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BE FLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BE IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM SPECIAL S24_3LE S24_3BE U24_3LE U24_3BE S20_3LE S20_3BE U20_3LE U20_3BE S18_3LE S18_3BE U18_3LE

So, alsa supports MU_LAW, A_LAW and even GSM directly.
I will make it a alsa.conf config item, and post a new patch.

By: antonverburg (antonverburg) 2004-04-07 17:09:54

Yep good idea. Like I told before, I tried already to change SND_PCM_FORMAT_S16_LE to SND_PCM_FORMAT_S8, but that didn't work.  Tomorrow moring I will have some time again, so I will have a look at it (don't know if it delivers much interesting, I am only a beginner, but learning every day ;) It would be realy cool if we could use the native encoder of Alsa, because in that case, it's very easy to make use of hardware encoding support in some soundcards! If Alsa supports the hardware encoding we have not to care :)

Shouldn't it be a good idea to use the format that Asterisk asks for a connection? Then we do not need to use an option in alsa.conf. If Asterisk asks for a connection with GSM codec, chan_alsa.so should try to use GSM codec, etc.

By: antonverburg (antonverburg) 2004-04-08 05:56:44

Hm, I have been playing a bit with arecord. It seems that not all codecs are suported in Alsa now. You can find the currently supported codecs in aplay.c, in function begin_wave. These are suported: SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S16_LE,  SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S24_LE and SND_PCM_FORMAT_S24_3LE. Over that, it depends on your hardware if Alsa can use these codecs. For example, using the microphone of my webcam, I can't use the 8bit option. I think thats also the reason that I cannot use 8bits for the GSM codec, and thats the reason that OSS-gsm is CPU-wise cheaper.

Currently, I tried to install another PC104 soundcard, but there are some problems. If this soundcard works, I should be able to run Alsa with GSM in 8bit-mode.

<<edit; ai, I was wrong. ulaw is supported, but not in 'wav' mode. 'au' mode should be used. Going to test it... >>

edited on: 04-08-04 04:51

By: antonverburg (antonverburg) 2004-04-08 06:09:28

OK, using the -t option for arecord, you can specify the fileformat. If using -t raw, I can grab sound with alaw/ulaw encoding. This is because my soundcard (SB16) suports it. Using my USB-cam microphone, I cannot use alaw/ulaw, only S16_LE is available. So the available encoder depends from the available hardware... Interesting point?

By: antonverburg (antonverburg) 2004-04-09 11:15:13

At least I have my soundcart working... But now ther occurs another problem. If I give a not-valid and not existing input/output device name in alsa.conf, asterisk does some unexpected things; runs around telling me that I have to use "STOP NOW" to stop Asterisk. If I give a valid devicename (default, declared in ~/.asoundrc  ) Asterisk hangs when loading chan_alsa.so. I realy do not know why. Seems if asterisk cannot connect to the soundcard. I can grab sound with arecord and play with aplay, so it shouldn't be a problem...

Some aditional info:


pcm.!default {
       type hw
       card 0
ctl.!default {
       type hw
       card 0



Options for my soundcard (Isa PnP PC104 card with es1869 chip)

alias snd-card-0 snd-es18xx
options snd-es18xx port=0x220 irq=5 dma1=1  index=0

I used isapnptools to set the irq, dma's and port of my audiocard.

By: antonverburg (antonverburg) 2004-04-09 11:33:04

Here is where it goes wrong; In function soundcard_init(void), after intitializing the capture device (  alsa.capture_handle = alsa_card_init(&alsa, indevname, SND_PCM_STREAM_CAPTURE);) asterisk is unable to initialize also the playback device (                                                                                                                                                                                                                                                                                          alsa.playback_handle = alsa_card_init(&alsa, outdevname, SND_PCM_STREAM_PLAYBACK);). During the initializing of the card, asterisk stays waiting forever until the card is initialized.

By: antonverburg (antonverburg) 2004-04-09 11:49:40

Hm, adding the option dma2=0 to my /etc/modules.conf solved the problem. But now aplay and arecord do not work any more... Well, not a problem of asterisk, nah?

By: jcdutton (jcdutton) 2004-04-14 13:27:47

Do not use any of these patches.