[alsa-devel] Intel HDA + HDMI - snd_pcm_drain buggy behaviour.
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:
1. start playback at beginning of file 2. seek to close to the end of the file (snd_pcm_drop() gets called) 3. 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
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
Ok. Never mind. I was under the false impression that snd_pcm_drain would be able to handle partially filled periods. Making sure the last write fills at least a period seemed to have solved the issue.
On Sun, Feb 16, 2014 at 2:26 PM, Sander Jansen s.jansen@gmail.com wrote:
Further investigation on my part I noticed a couple of mistakes I made myself.
- 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
At Sun, 16 Feb 2014 20:52:39 -0600, Sander Jansen wrote:
Ok. Never mind. I was under the false impression that snd_pcm_drain would be able to handle partially filled periods. Making sure the last write fills at least a period seemed to have solved the issue.
Good to hear that you solved the issue by yourself. As you found out, the ALSA core usually doesn't handle the partial period drain.
Takashi
On Sun, Feb 16, 2014 at 2:26 PM, Sander Jansen s.jansen@gmail.com wrote:
Further investigation on my part I noticed a couple of mistakes I made myself.
- 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
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
participants (2)
-
Sander Jansen
-
Takashi Iwai