[alsa-devel] [BUG] snd_pcm_drop() does not stop the PCM immediately
Hi, The documentation states: " This function stops the PCM immediately. The pending samples on the buffer are ignored. " This does not work for the device "sysdefault" where a piece of the old sound and the new sound overlap, see attached alsadrop1.c testprogram. It is OK with the "default" device which is wired over Pulseaudio, uncomment alsadrop1.c:55 in order to test. The project is here: https://gitlab.com/mseide-msegui/mseuniverse/tree/master/testcase/audio/c/al...
Environment: openSUSE Leap 42.3, see attached alsa-info.tar.gz.
Martin
On Wed, 14 Mar 2018 15:59:07 +0100, Martin Schreiber wrote:
Hi, The documentation states: " This function stops the PCM immediately. The pending samples on the buffer are ignored. " This does not work for the device "sysdefault" where a piece of the old sound and the new sound overlap, see attached alsadrop1.c testprogram. It is OK with the "default" device which is wired over Pulseaudio, uncomment alsadrop1.c:55 in order to test. The project is here: https://gitlab.com/mseide-msegui/mseuniverse/tree/master/testcase/audio/c/al...
Environment: openSUSE Leap 42.3, see attached alsa-info.tar.gz.
It's a best-effort base stopping mechanism with dmix, so it's a sort of expected behavior, unfortunately. Due to its nature of implementation, scratching off the existing data from the mixed buffer isn't so trivial for now.
Takashi
On 03/14/2018 04:13 PM, Takashi Iwai wrote:
It's a best-effort base stopping mechanism with dmix, so it's a sort of expected behavior, unfortunately. Due to its nature of implementation, scratching off the existing data from the mixed buffer isn't so trivial for now.
eSpeakNG has the workaround in pcaudiolib (see outcommented part): " int alsa_object_flush(struct audio_object *object) { struct alsa_object *self = to_alsa_object(object); if (self && self->handle){ snd_pcm_drop(self->handle); } /* if (!self) return 0;
// Using snd_pcm_drop does not discard the audio, so reopen the device // to reset the sound buffer. if (self->is_open) { audio_object_close(object); //this crashes write operation in other thread! return audio_object_open(object, self->format, self->rate, self->channels); } */ return 0; }
" " void alsa_object_close(struct audio_object *object) { struct alsa_object *self = to_alsa_object(object);
if (self->handle) { snd_pcm_close(self->handle); self->handle = NULL; self->is_open = 1; } } " Does snd_pcm_close() "scratching off the existing data from the mixed buffer"? If yes, how could the workaround be made without letting crash pending write operations in separate thread?
Thanks, Martin
On Wed, 14 Mar 2018 16:50:48 +0100, Martin Schreiber wrote:
On 03/14/2018 04:13 PM, Takashi Iwai wrote:
It's a best-effort base stopping mechanism with dmix, so it's a sort of expected behavior, unfortunately. Due to its nature of implementation, scratching off the existing data from the mixed buffer isn't so trivial for now.
eSpeakNG has the workaround in pcaudiolib (see outcommented part): " int alsa_object_flush(struct audio_object *object) { struct alsa_object *self = to_alsa_object(object); if (self && self->handle){ snd_pcm_drop(self->handle); } /* if (!self) return 0;
// Using snd_pcm_drop does not discard the audio, so reopen the device // to reset the sound buffer. if (self->is_open) { audio_object_close(object); //this crashes write operation in other thread! return audio_object_open(object, self->format, self->rate, self->channels); } */ return 0; }
" " void alsa_object_close(struct audio_object *object) { struct alsa_object *self = to_alsa_object(object);
if (self->handle) { snd_pcm_close(self->handle); self->handle = NULL; self->is_open = 1; } } " Does snd_pcm_close() "scratching off the existing data from the mixed buffer"?
It shouldn't. There is no corresponding code in the dmix close path as far as I read again. So, if it really does anything better, it's somewhere rather in the ALSA timer handling, I suppose.
If yes, how could the workaround be made without letting crash pending write operations in separate thread?
Likely no, but please test whether it really makes difference before the final conclusion. If yes, it's worth for further investigation. There can be something I overlooked or forgot, of course, it's a damn old code :)
thanks,
Takashi
On 03/14/2018 05:16 PM, Takashi Iwai wrote:
Does snd_pcm_close() "scratching off the existing data from the mixed buffer"?
It shouldn't. There is no corresponding code in the dmix close path as far as I read again. So, if it really does anything better, it's somewhere rather in the ALSA timer handling, I suppose.
It does better, see attached alsadrop2.c. Now the question is why? And could it be implemented in snd_pcm_drop() too?
Martin
On Wed, 14 Mar 2018 17:39:46 +0100, Martin Schreiber wrote:
On 03/14/2018 05:16 PM, Takashi Iwai wrote:
Does snd_pcm_close() "scratching off the existing data from the mixed buffer"?
It shouldn't. There is no corresponding code in the dmix close path as far as I read again. So, if it really does anything better, it's somewhere rather in the ALSA timer handling, I suppose.
It does better, see attached alsadrop2.c.
Hm, interesting. Could you track down why it makes difference? For example, put a sleep(10) in snd_pcm_dmix_close() at the beginning, so that it stops processing at the entrance of the close callback. If the sample discard still occurs, something else before that point.
Similarly, move sleep(10) call in each step of snd_pcm_dmix_close() and see what really matters.
Now the question is why? And could it be implemented in snd_pcm_drop() too?
Yes, but only if you understand why it differs :)
Takashi
On 03/14/2018 05:49 PM, Takashi Iwai wrote:
It does better, see attached alsadrop2.c.
Hm, interesting. Could you track down why it makes difference?
Difficult for me because I have no clue about Alsa internals. I hope that Fred van Stappen helps out, he is a big Alsa fan. :-)
Martin
participants (2)
-
Martin Schreiber
-
Takashi Iwai