Hello everyone,
I've ran into some issues while writing a wrapper around alsaloop. It's possible to make it fall into infinite loops of silence. Here is how to trigger one such loop:
alsaloop -C cloop -P Audio -t 100000 -v... & # Read attached asoundrc sleep 2 mpc play pkill -STOP -x alsaloop; sleep 0.1; pkill -CONT -x alsaloop
On the great majority of times, this happens:
... pool took 68171us playback hw:Audio/capture cloop: pollfds handle playback hw:Audio: delay 2160 / 38400 / 0 capture cloop: delay 15120 / 38400 / 0 playback hw:Audio/capture cloop: prevents = 0x4, crevents = 0x0 playback hw:Audio/capture cloop: queued 5040/18000 samples playback hw:Audio: end delay 5040 / 38400 / 0 capture cloop: end delay 18000 / 38400 / 0 playback hw:Audio/capture cloop: processing time 69us pool took 192670us playback hw:Audio/capture cloop: pollfds handle playback hw:Audio: delay error: Broken pipe / 38400 / 0 capture cloop: delay 8400 / 38400 / 0 playback hw:Audio/capture cloop: prevents = 0xc, crevents = 0x1 underrun for playback hw:Audio playback hw:Audio/capture cloop: xrun sync 0 1 sync: cdelay=18000(18000), pdelay=9600(9600), fill=4800 (delay=27600), src_out=0 sync: cbufcount=9600, pbufcount=9600 sync: capt stop removed 9600 samples playback hw:Audio/capture cloop: xrun sync 0 1 sync: cdelay=18000(18000), pdelay=0(0), fill=4800 (delay=18000), src_out=0 sync: cbufcount=0, pbufcount=0 sync: capt stop removed 0 samples playback hw:Audio/capture cloop: xrun sync 0 1 sync: cdelay=18000(18000), pdelay=0(0), fill=4800 (delay=18000), src_out=0 sync: cbufcount=0, pbufcount=0 sync: capt stop removed 0 samples playback hw:Audio/capture cloop: xrun sync 0 1 ...
Moving outwards, some observations,
* `remove_samples()` falls into `if (loop->play->buf == loop->capt->buf)`, which is what decides to always remove 0 samples after some point (as seen in output).
* cdelay (from `snd_pcm_delay(capt->handle, &cdelay)`) is consistently 18000, meaning that `delay1 > fill` in `xrun_sync()` will always be true as `fill` is fixed during the run. If one forces this check to fail (by setting cdelay to 0), alsaloop recovers, with no audible delay compared to what's being played back.
* It is this code that leads to `xrun()` in the first place:
if (avail == -EPIPE) { if ((err = xrun(lhandle)) < 0)
* The issue is hinted even earlier, as after
err = snd_pcm_poll_descriptors_revents(play->handle, fds, play->pollfd_count, &prevents);
`(prevents & POLLERR)` is true.
* Depending on when STOP is sent, the same sometimes holds true after `thread_job1`'s
err = poll(pfds, j, wake);
on `pfds[i].revents`.
I am not sure what the correct way of fixing this is, especially because I couldn't figure out why `snd_pcm_delay` returns this specific value. I can only guess it is related to aloop.
Other ways of throwing alsaloop into infinite loops is unplugging a soundcard that it's using (I believe it should exit in this case) and suspending/resuming the system. I haven't gone through the codepaths in those cases carefully yet, but I'm interested in fixing them eventually.
Please let me know if I can provide more useful output, Dimitri
[alsa-info.sh]http://www.alsa-project.org/db/?f=89eb0056b0876a3b4fb377c39d5bc81405a308a7