Further investigation on my part I noticed a couple of mistakes I made myself.
1. snd_pcm_drain() doesn't block in non-blocking mode. I fixed my code to account for this now. 2. snd_pcm_drain() doesn't block indefinitely in blocking mode. I must have accidently put in a infinite loop somewhere myself.
That leaves still with one unresolved issue, which is that calling snd_pcm_drain() does indeed work in both blocking and non-blocking, but I'm still hearing part of the audio that was already played before. I assume this is some data in the ringbuffer that hasn't been overwritten by any new data. I have been able to reproduce this on another PC (Intel G45 chipset) as well (snd_intel_hda as well, but with analog output) so I don't think it's HDMI related.
This is my drain code:
snd_pcm_state_t state = snd_pcm_state(handle); if (state==SND_PCM_STATE_RUNNING) {
/// block while draining //if ((result=snd_pcm_nonblock(handle,0))<0) { // printf("[alsa] failed to set blocking mode. Reason: %s\n",snd_strerror(result)); // return; // }
result=snd_pcm_drain(handle); if (result==-EAGAIN) { printf("[alsa] waiting for drain\n"); while(snd_pcm_state(handle)==SND_PCM_STATE_DRAINING){ FXThread::sleep(500000000); // 50ms } printf("[alsa] drain complete. State: %s\n",snd_pcm_state_name(snd_pcm_state(handle))); } else if (result<0) { printf("[alsa] drain failed. Reason: %s\n",snd_strerror(result)); } else { printf("[alsa] drain complete\n"); } }
Anything else I'm doing wrong?
Thanks,
Sander
On Sat, Feb 15, 2014 at 6:44 PM, Sander Jansen s.jansen@gmail.com wrote:
All,
When I play regular PCM audio through the HDMI that's connected to my amplifier I noticed buggy behaviour when using the snd_pcm_drain() call. From my understanding of ALSA, during playback snd_pcm_drain() normally blocks until the playback buffer is empty.
Here's what I'm experiencing:
a. If the PCM handle is in BLOCKING mode, the snd_pcm_drain() function will block indefinitely (I've waited 30 seconds, before I gave up).
b. In NON-BLOCKING mode, the first call to snd_pcm_drain results in a " Resource temporarily unavailable", subsequent call works but the pcm state has changed to DRAINING and takes about 1 sec to change to SETUP. Even though the audio has less than 0.5 seconds of actual playback left.
So to make it work, I changed my single snd_pcm_drain() call into the following pseudo code: while(state==RUNNING && snd_pcm_drain()<0) { state=snd_pcm_state() }
while(state==DRAINING && sleep(100)){ state=snd_pcm_state() }
Even though this seem to "sort of work", another problem with this approach I've noticed, is that part of the beginning of the playback buffer may be replayed at the end of the drain:
- start playback at beginning of file
- seek to close to the end of the file (snd_pcm_drop() gets called)
- end of file reached, drain gets called, hear the end of the song +
part of the beginning again?
So I'm wondering whether this may be related to the drain issue I've noticed. I've attached the alsa-info.
Thanks,
Sander