[alsa-devel] handling of underrunning snd_pcm_writei
Hi,
I AM trying to convert an internal app from oss to alsa and is trying to grok the alsa API and the examples I can find.
I would like to ask some questions to avoid guessing and making wrong assumptions. Feel free to redirect me to where I should have found the answer myself.
http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gf13067c0eb... says about snd_pcm_writei:
Returns: a positive number of frames actually written otherwise a negative error code ... Return values: ... -EPIPE an underrun occurred ... The count of bytes can be less only if a signal or underrun occurred.
So what is returned in case of underrun? Error code or count of bytes?
Should snd_pcm_recover always be used to get the byte count after -EPIPE? snd_pcm_recover is neither mentioned in the link above nor in http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html , so I don't feel confident about that.
And is it measured in "positive number of frames actually written" or "count of bytes"?
It surprises me that snd_pcm_writei shows non-blocking behaviour in case of underruns and don't use all the offered data. I would guess that it either blocked and enjoyed the data it finally got, or that it gave an error and didn't take any data at all. But if this is how it is, then ... that is how it is ;-)
/Mads
using alsa-lib-1.0.21-3.fc11.i586 alsa-plugins-pulseaudio-1.0.21-2.fc11.i586
On 11/11/2009 05:50 PM, Mads Kiilerich wrote:
http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gf13067c0eb... says about snd_pcm_writei:
Returns: a positive number of frames actually written otherwise a negative error code ... Return values: ... -EPIPE an underrun occurred ... The count of bytes can be less only if a signal or underrun occurred.
...
It surprises me that snd_pcm_writei shows non-blocking behaviour in case of underruns and don't use all the offered data. I would guess that it either blocked and enjoyed the data it finally got, or that it gave an error and didn't take any data at all. But if this is how it is, then ... that is how it is ;-)
Ok, experiments indicates that the documented blocking behaviour only applies in SND_PCM_STATE_RUNNING. snd_pcm_writei apparently behaves non-blocking in SND_PCM_STATE_PREPARED. I can see how that kind of makes sense - I just didn't expect that. Is that correctly understood?
/Mads
At Wed, 11 Nov 2009 17:50:12 +0100, Mads Kiilerich wrote:
Returns: a positive number of frames actually written otherwise a negative error code ... Return values: ... -EPIPE an underrun occurred ... The count of bytes can be less only if a signal or underrun occurred.
So what is returned in case of underrun? Error code or count of bytes?
First it returns the actually written frames, then -EPIPE. But, it might return -EPIPE first, depending on the plugin, I guess.
Should snd_pcm_recover always be used to get the byte count after -EPIPE? snd_pcm_recover is neither mentioned in the link above nor in http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html , so I don't feel confident about that.
Yes, snd_pcm_recover() is *recommended*. You can write the recovery routine by yourself. The function isn't referred here just because it's relatively new. Better to be documented, indeed.
And is it measured in "positive number of frames actually written" or "count of bytes"?
Frames. Should be corrected.
For both fixes, a patch from contributors is always welcome ;)
It surprises me that snd_pcm_writei shows non-blocking behaviour in case of underruns and don't use all the offered data. I would guess that it either blocked and enjoyed the data it finally got, or that it gave an error and didn't take any data at all. But if this is how it is, then ... that is how it is ;-)
It's because the XRUN isn't recovered automatically but the operation stops. It's analogous to a disk-full error.
thanks,
Takashi
On 11/12/2009 08:12 AM, Takashi Iwai wrote:
Yes, snd_pcm_recover() is *recommended*. You can write the recovery routine by yourself. The function isn't referred here just because it's relatively new. Better to be documented, indeed.
Thanks a lot for you answer, Takashi. That was very helpful.
But when I hack pcm_min.c to log the state at the beginning of the loop and then enforces an underrun by pausing the program then it sometimes locks up:
$ ./pcm_min state 2 SND_PCM_STATE_PREPARED state 2 SND_PCM_STATE_PREPARED Short write (expected 16384, wrote 7616) state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING [ctrl-s ... waiting for silence ... ctrl q] ALSA lib pcm.c:7234:(snd_pcm_recover) underrun occured state 2 SND_PCM_STATE_PREPARED state 2 SND_PCM_STATE_PREPARED state 3 SND_PCM_STATE_RUNNING [hanging in snd_pcm_writei]
It seems like pcm_min.cs use of snd_pcm_recover isn't enough to recover fully? The playback never gets started again, so the async writes in PREPARED succeeds, but the first blocking write hangs waiting forever? What is missing?
It also surprises me that the last PREPARED write isn't a short write. Why is that?
Regards, Mads
On 11/12/2009 01:10 PM, Mads Kiilerich wrote:
On 11/12/2009 08:12 AM, Takashi Iwai wrote:
Yes, snd_pcm_recover() is *recommended*. You can write the recovery routine by yourself. The function isn't referred here just because it's relatively new. Better to be documented, indeed.
Thanks a lot for you answer, Takashi. That was very helpful.
But when I hack pcm_min.c to log the state at the beginning of the loop and then enforces an underrun by pausing the program then it sometimes locks up:
$ ./pcm_min state 2 SND_PCM_STATE_PREPARED state 2 SND_PCM_STATE_PREPARED Short write (expected 16384, wrote 7616) state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING [ctrl-s ... waiting for silence ... ctrl q] ALSA lib pcm.c:7234:(snd_pcm_recover) underrun occured state 2 SND_PCM_STATE_PREPARED state 2 SND_PCM_STATE_PREPARED state 3 SND_PCM_STATE_RUNNING [hanging in snd_pcm_writei]
It seems like pcm_min.cs use of snd_pcm_recover isn't enough to recover fully? The playback never gets started again, so the async writes in PREPARED succeeds, but the first blocking write hangs waiting forever? What is missing?
It seems like the lockup always happens in SND_PCM_STATE_RUNNING after snd_pcm_avail_update has reported values > 9000. Usually it returns < 8000.
Any idea?
/Mads
At Thu, 12 Nov 2009 15:01:15 +0100, Mads Kiilerich wrote:
On 11/12/2009 01:10 PM, Mads Kiilerich wrote:
On 11/12/2009 08:12 AM, Takashi Iwai wrote:
Yes, snd_pcm_recover() is *recommended*. You can write the recovery routine by yourself. The function isn't referred here just because it's relatively new. Better to be documented, indeed.
Thanks a lot for you answer, Takashi. That was very helpful.
But when I hack pcm_min.c to log the state at the beginning of the loop and then enforces an underrun by pausing the program then it sometimes locks up:
$ ./pcm_min state 2 SND_PCM_STATE_PREPARED state 2 SND_PCM_STATE_PREPARED Short write (expected 16384, wrote 7616) state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING state 3 SND_PCM_STATE_RUNNING [ctrl-s ... waiting for silence ... ctrl q] ALSA lib pcm.c:7234:(snd_pcm_recover) underrun occured state 2 SND_PCM_STATE_PREPARED state 2 SND_PCM_STATE_PREPARED state 3 SND_PCM_STATE_RUNNING [hanging in snd_pcm_writei]
It seems like pcm_min.cs use of snd_pcm_recover isn't enough to recover fully? The playback never gets started again, so the async writes in PREPARED succeeds, but the first blocking write hangs waiting forever? What is missing?
It seems like the lockup always happens in SND_PCM_STATE_RUNNING after snd_pcm_avail_update has reported values > 9000. Usually it returns < 8000.
Hm, not now, as I've been too busy for other things. Will take a look at this issue later.
thanks,
Takashi
participants (2)
-
Mads Kiilerich
-
Takashi Iwai