[alsa-devel] speaker-test stalls
While working with Fernando to get the sis7019 driver working in his buildroot setup, we kept running into a lockup of the PCM stream when using speaker-test. aplay was fine, as was other I finally tracked it down to a combination of uclibc not doing block reads, which led to XRUNs, and what I thought was issue in snd_pcm_lib_write1() when trying to fill up the tail of the PCM buffer with a large write, when there was an intervening small write.
As it turns out, the lockup problem may simply be in speaker-write's sw_params settings -- it calls snd_pcm_sw_params_set_avail_min() to set the minium write to the period size, and snd_pcm_sw_params_set_start_threshold() to start once the buffer has been filled. This doesn't account for odd wave file lengths and XRUNs.
The problem arises when the wave data is not a multiple of the period size, and you get an XRUN when there is less than buffer_size samples remaining in the current loop.
So for example, period size is 8192, buffer is 32768, and the wave file has 71042 samples (Front_Left.wav for speaker-test).
speaker-test will break that into 8 writes of 8192 samples, and one of 5506.
If you get a XRUN in the last 32k of the file, the PCM will be stopped, and prepared, and we'll start loading data into again. Because we have a tail of 5506 samples, we get to the point where the available space is less than our minimum, and then snd_pcm_lib_write1() will wait forever for the available space to be >= runtime->avail_min, even though the channel is stopped.
[snip from a trace, patch to pcm_lib.c attached] writei size 8192 avail 32768 min 8192 xfer 1 state 2 writei size 8192 avail 24576 min 8192 xfer 1 state 2 writei size 5506 avail 16384 min 8192 xfer 1 state 2 writei size 8192 avail 10878 min 8192 xfer 1 state 2 writei size 8192 avail 2686 min 8192 xfer 1 state 2 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192
Assuming that this is desired behavior from the kernel side, then I see three options to fix this in speaker-test: 1) snd_pcm_sw_params_set_avail_min() to 1 sample 2) snd_pcm_sw_params_set_start_threshold() to start when (nperiods - 1) are ready (or be even more aggressive) 3) call snd_pcm_drain() at the end of each loop to clear out the buffer. This won't help if the wave file has fewer samples than the buffer size.
Options 1 or 2 seem to be best.
Thoughts?
Dave
At Sat, 08 Dec 2007 15:58:40 -0500, Dave Dillow wrote:
While working with Fernando to get the sis7019 driver working in his buildroot setup, we kept running into a lockup of the PCM stream when using speaker-test. aplay was fine, as was other I finally tracked it down to a combination of uclibc not doing block reads, which led to XRUNs, and what I thought was issue in snd_pcm_lib_write1() when trying to fill up the tail of the PCM buffer with a large write, when there was an intervening small write.
As it turns out, the lockup problem may simply be in speaker-write's sw_params settings -- it calls snd_pcm_sw_params_set_avail_min() to set the minium write to the period size, and snd_pcm_sw_params_set_start_threshold() to start once the buffer has been filled. This doesn't account for odd wave file lengths and XRUNs.
The problem arises when the wave data is not a multiple of the period size, and you get an XRUN when there is less than buffer_size samples remaining in the current loop.
So for example, period size is 8192, buffer is 32768, and the wave file has 71042 samples (Front_Left.wav for speaker-test).
speaker-test will break that into 8 writes of 8192 samples, and one of 5506.
If you get a XRUN in the last 32k of the file, the PCM will be stopped, and prepared, and we'll start loading data into again. Because we have a tail of 5506 samples, we get to the point where the available space is less than our minimum, and then snd_pcm_lib_write1() will wait forever for the available space to be >= runtime->avail_min, even though the channel is stopped.
[snip from a trace, patch to pcm_lib.c attached] writei size 8192 avail 32768 min 8192 xfer 1 state 2 writei size 8192 avail 24576 min 8192 xfer 1 state 2 writei size 5506 avail 16384 min 8192 xfer 1 state 2 writei size 8192 avail 10878 min 8192 xfer 1 state 2 writei size 8192 avail 2686 min 8192 xfer 1 state 2 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192
Assuming that this is desired behavior from the kernel side, then I see three options to fix this in speaker-test:
- snd_pcm_sw_params_set_avail_min() to 1 sample
- snd_pcm_sw_params_set_start_threshold() to start when (nperiods - 1)
are ready (or be even more aggressive) 3) call snd_pcm_drain() at the end of each loop to clear out the buffer. This won't help if the wave file has fewer samples than the buffer size.
Options 1 or 2 seem to be best.
Thoughts?
Just to be sure: Is it with the latest alsa-lib and alsa-utils from HG?
Takashi
On Thu, 2007-12-13 at 12:04 +0100, Takashi Iwai wrote:
At Sat, 08 Dec 2007 15:58:40 -0500, Dave Dillow wrote:
Assuming that this is desired behavior from the kernel side, then I see three options to fix this in speaker-test:
- snd_pcm_sw_params_set_avail_min() to 1 sample
- snd_pcm_sw_params_set_start_threshold() to start when (nperiods - 1)
are ready (or be even more aggressive) 3) call snd_pcm_drain() at the end of each loop to clear out the buffer. This won't help if the wave file has fewer samples than the buffer size.
Options 1 or 2 seem to be best.
Thoughts?
Just to be sure: Is it with the latest alsa-lib and alsa-utils from HG?
Yes, this is with the latest alsa-lib and alsa-utils -- I did an hg-update to be sure.
Sorry for the delay, I needed to rebuild the buildroot to be sure.
At Sat, 08 Dec 2007 15:58:40 -0500, Dave Dillow wrote:
While working with Fernando to get the sis7019 driver working in his buildroot setup, we kept running into a lockup of the PCM stream when using speaker-test. aplay was fine, as was other I finally tracked it down to a combination of uclibc not doing block reads, which led to XRUNs, and what I thought was issue in snd_pcm_lib_write1() when trying to fill up the tail of the PCM buffer with a large write, when there was an intervening small write.
As it turns out, the lockup problem may simply be in speaker-write's sw_params settings -- it calls snd_pcm_sw_params_set_avail_min() to set the minium write to the period size, and snd_pcm_sw_params_set_start_threshold() to start once the buffer has been filled. This doesn't account for odd wave file lengths and XRUNs.
The problem arises when the wave data is not a multiple of the period size, and you get an XRUN when there is less than buffer_size samples remaining in the current loop.
Hm, it sounds weird. Basically XRUN means that you have *no* data in the buffer while the stream is running. So, when you get XRUN, the data must be empty, no matter which buffer or period size is.
Anyway, could you get the same effect with another driver, e.g. snd-dummy? If it can be easily reproduced, it'll be much easier to track down...
thanks,
Takashi
So for example, period size is 8192, buffer is 32768, and the wave file has 71042 samples (Front_Left.wav for speaker-test).
speaker-test will break that into 8 writes of 8192 samples, and one of 5506.
If you get a XRUN in the last 32k of the file, the PCM will be stopped, and prepared, and we'll start loading data into again. Because we have a tail of 5506 samples, we get to the point where the available space is less than our minimum, and then snd_pcm_lib_write1() will wait forever for the available space to be >= runtime->avail_min, even though the channel is stopped.
[snip from a trace, patch to pcm_lib.c attached] writei size 8192 avail 32768 min 8192 xfer 1 state 2 writei size 8192 avail 24576 min 8192 xfer 1 state 2 writei size 5506 avail 16384 min 8192 xfer 1 state 2 writei size 8192 avail 10878 min 8192 xfer 1 state 2 writei size 8192 avail 2686 min 8192 xfer 1 state 2 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192 writei loop avail 2686 min 8192
Assuming that this is desired behavior from the kernel side, then I see three options to fix this in speaker-test:
- snd_pcm_sw_params_set_avail_min() to 1 sample
- snd_pcm_sw_params_set_start_threshold() to start when (nperiods - 1)
are ready (or be even more aggressive) 3) call snd_pcm_drain() at the end of each loop to clear out the buffer. This won't help if the wave file has fewer samples than the buffer size.
Options 1 or 2 seem to be best.
Thoughts?
Dave
On Fri, Dec 14, 2007 at 04:39:37PM +0100, Takashi Iwai wrote:
At Sat, 08 Dec 2007 15:58:40 -0500, Dave Dillow wrote:
While working with Fernando to get the sis7019 driver working in his buildroot setup, we kept running into a lockup of the PCM stream when using speaker-test. aplay was fine, as was other I finally tracked it down to a combination of uclibc not doing block reads, which led to XRUNs, and what I thought was issue in snd_pcm_lib_write1() when trying to fill up the tail of the PCM buffer with a large write, when there was an intervening small write.
As it turns out, the lockup problem may simply be in speaker-write's sw_params settings -- it calls snd_pcm_sw_params_set_avail_min() to set the minium write to the period size, and snd_pcm_sw_params_set_start_threshold() to start once the buffer has been filled. This doesn't account for odd wave file lengths and XRUNs.
The problem arises when the wave data is not a multiple of the period size, and you get an XRUN when there is less than buffer_size samples remaining in the current loop.
Hm, it sounds weird. Basically XRUN means that you have *no* data in the buffer while the stream is running. So, when you get XRUN, the data must be empty, no matter which buffer or period size is.
Right, the buffer empties, and then the loop in speaker-test::write_buffer() starts filling the buffer again, as expected.
However, the sample data in the wave file is not a multiple of the buffer size, so it does a small write (ie, not period sized) to finish out the file, and the main routine calls back in to do the next loop.
So, you get a pattern (buffer_size is 32768):
write len buffer available before write XRUN happens N/A 8192 32768 8192 24576 5506 16384 8192 10878 8192 2686
Because speaker-test sets avail_min to 8192, and the start threshold to 32768, snd_pcm_lib_write1() will loop forever waiting for 8192 bytes to become available in the buffer. That will never happen, because the XRUN stopped the channel, and we cannot reach the start threshold, as this last write that would do it is the one that blocked.
Anyway, could you get the same effect with another driver, e.g. snd-dummy? If it can be easily reproduced, it'll be much easier to track down...
It won't be easy, as the problem is only present when there is an XRUN in the last 32k (or whatever buffer size is chosen for the hardware) of the input wave file.
I can code up an example if need be, but I've already highlighted the cause --
1) stopped stream 2) start_threshold = buffer_size 3) min_avail = period_size (or more genericaly, > 1) 4) a write pattern that causes there to be less than min_avail room in the buffer for a write
The stream will never start.
Does that make sense, or would it help to code up a example?
Now, this may be desired behaviour from the kernel, and it is just a bug in speaker-test's handling of XRUNs. That's fine, I just wanted to highlight it.
Assuming that this is desired behavior from the kernel side, then I see three options to fix this in speaker-test:
- snd_pcm_sw_params_set_avail_min() to 1 sample
- snd_pcm_sw_params_set_start_threshold() to start when (nperiods - 1)
are ready (or be even more aggressive) 3) call snd_pcm_drain() at the end of each loop to clear out the buffer. This won't help if the wave file has fewer samples than the buffer size.
Options 1 or 2 seem to be best.
At Fri, 14 Dec 2007 12:40:04 -0500, Dave Dillow wrote:
On Fri, Dec 14, 2007 at 04:39:37PM +0100, Takashi Iwai wrote:
At Sat, 08 Dec 2007 15:58:40 -0500, Dave Dillow wrote:
While working with Fernando to get the sis7019 driver working in his buildroot setup, we kept running into a lockup of the PCM stream when using speaker-test. aplay was fine, as was other I finally tracked it down to a combination of uclibc not doing block reads, which led to XRUNs, and what I thought was issue in snd_pcm_lib_write1() when trying to fill up the tail of the PCM buffer with a large write, when there was an intervening small write.
As it turns out, the lockup problem may simply be in speaker-write's sw_params settings -- it calls snd_pcm_sw_params_set_avail_min() to set the minium write to the period size, and snd_pcm_sw_params_set_start_threshold() to start once the buffer has been filled. This doesn't account for odd wave file lengths and XRUNs.
The problem arises when the wave data is not a multiple of the period size, and you get an XRUN when there is less than buffer_size samples remaining in the current loop.
Hm, it sounds weird. Basically XRUN means that you have *no* data in the buffer while the stream is running. So, when you get XRUN, the data must be empty, no matter which buffer or period size is.
Right, the buffer empties, and then the loop in speaker-test::write_buffer() starts filling the buffer again, as expected.
However, the sample data in the wave file is not a multiple of the buffer size, so it does a small write (ie, not period sized) to finish out the file, and the main routine calls back in to do the next loop.
So, you get a pattern (buffer_size is 32768):
write len buffer available before write XRUN happens N/A 8192 32768 8192 24576 5506 16384 8192 10878 8192 2686
Because speaker-test sets avail_min to 8192, and the start threshold to 32768, snd_pcm_lib_write1() will loop forever waiting for 8192 bytes to become available in the buffer. That will never happen, because the XRUN stopped the channel, and we cannot reach the start threshold, as this last write that would do it is the one that blocked.
OK, point taken. It's a problem in the PCM core indeed. The patch below should solve the problem, but it's ad hoc.
Takashi
diff -r 6f193b381db3 core/pcm_lib.c --- a/core/pcm_lib.c Wed Dec 19 12:13:44 2007 +0100 +++ b/core/pcm_lib.c Wed Dec 19 14:36:04 2007 +0100 @@ -1655,8 +1655,11 @@ static snd_pcm_sframes_t snd_pcm_lib_wri if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); avail = snd_pcm_playback_avail(runtime); - if (((avail < runtime->control->avail_min && size > avail) || - (size >= runtime->xfer_align && avail < runtime->xfer_align))) { + if (!avail || + (snd_pcm_running(substream) && + ((avail < runtime->control->avail_min && size > avail) || + (size >= runtime->xfer_align && + avail < runtime->xfer_align)))) { wait_queue_t wait; enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state; long tout;
participants (2)
-
Dave Dillow
-
Takashi Iwai