* [BUG] snd_pcm_drop() does not stop the PCM immediately
@ 2018-03-14 14:59 Martin Schreiber
2018-03-14 15:13 ` Takashi Iwai
0 siblings, 1 reply; 7+ messages in thread
From: Martin Schreiber @ 2018-03-14 14:59 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 552 bytes --]
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/alsadrop
Environment: openSUSE Leap 42.3, see attached alsa-info.tar.gz.
Martin
[-- Attachment #2: alsa-info.tar.gz --]
[-- Type: application/gzip, Size: 5975 bytes --]
[-- Attachment #3: alsadrop1.c --]
[-- Type: text/x-csrc, Size: 2434 bytes --]
//alsadrop1 testcase
// compile with
//gcc -oalsadrop1 -lasound -lpthread -g alsadrop1.c
#include <alsa/asoundlib.h>
#include <pthread.h>
#define samplefrequ 44100
int16_t bufa[samplefrequ]; //1 second f1
int16_t bufb[samplefrequ]; //1 second f2
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* buf;
snd_pcm_t *pcm;
void*
threadexe(void* param){
snd_pcm_sframes_t frameswritten;
int i1,i2,i3;
void* buf1;
i1 = sizeof(bufa)/sizeof(bufa[0]);
frameswritten = 0;
i3 = 0;
while (1){
pthread_mutex_lock(&mutex);
printf("++waitstart\n");
pthread_cond_wait(&cond,&mutex);
printf("!!signaled\n");
buf1 = buf;
pthread_mutex_unlock(&mutex);
frameswritten = snd_pcm_writei(pcm,buf1,i1);
printf("%d %p %d\n",i3,buf1,frameswritten);
i3++;
}
return NULL;
}
int main()
{
int i1,i2;
char* dev;
snd_pcm_hw_params_t *params = NULL;
unsigned int rate = samplefrequ;
snd_pcm_sframes_t frameswritten;
pthread_t thread;
for(i1=0;i1 < samplefrequ;i1++){
bufa[i1] = 0x4000 * (2*((i1 / 40) % 2)-1);
bufb[i1] = 0x4000 * (2*((i1 / 41) % 2)-1);
}
dev = "sysdefault"; //alsa direct ->> overlapping sound
// dev = "default"; //over pulsaudio ->> OK
if (snd_pcm_open(&pcm,dev, SND_PCM_STREAM_PLAYBACK, 0)){
printf("Can not open pcm %s",dev);
goto error;
}
snd_pcm_hw_params_malloc(¶ms);
if (!params){
goto error;
};
if (snd_pcm_hw_params_any(pcm, params)<0){
goto error;
};
if (snd_pcm_hw_params_set_access(pcm,params,SND_PCM_ACCESS_RW_INTERLEAVED)){
goto error;
};
if (snd_pcm_hw_params_set_format(pcm,params,SND_PCM_FORMAT_S16_LE)){
goto error;
};
if (snd_pcm_hw_params_set_rate_near(pcm,params,&rate,0)){
goto error;
};
if (snd_pcm_hw_params_set_channels(pcm,params,1)){
goto error;
};
if (snd_pcm_hw_params(pcm,params)){
goto error;
};
if (snd_pcm_prepare(pcm)){
goto error;
};
snd_pcm_nonblock(pcm,0);
mutex.__data.__kind = PTHREAD_MUTEX_RECURSIVE;
if (pthread_create(&thread,NULL,&threadexe,NULL)){
goto error;
}
while(1){
pthread_mutex_lock(&mutex);
if (buf == bufa){
buf = bufb;
}
else{
buf = bufa;
}
pthread_mutex_unlock(&mutex);
printf("--- %p signal\n",buf);
pthread_cond_signal(&cond);
usleep(700000);
printf("<<<drop\n");
snd_pcm_drop(pcm);
snd_pcm_drain(pcm);
i2 = snd_pcm_prepare(pcm);
printf("<<<prepare %d\n",i2);
}
return 0;
error:
return 1;
}
[-- Attachment #4: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [BUG] snd_pcm_drop() does not stop the PCM immediately
2018-03-14 14:59 [BUG] snd_pcm_drop() does not stop the PCM immediately Martin Schreiber
@ 2018-03-14 15:13 ` Takashi Iwai
2018-03-14 15:50 ` Martin Schreiber
0 siblings, 1 reply; 7+ messages in thread
From: Takashi Iwai @ 2018-03-14 15:13 UTC (permalink / raw)
To: Martin Schreiber; +Cc: alsa-devel
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/alsadrop
>
> 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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [BUG] snd_pcm_drop() does not stop the PCM immediately
2018-03-14 15:13 ` Takashi Iwai
@ 2018-03-14 15:50 ` Martin Schreiber
2018-03-14 16:16 ` Takashi Iwai
0 siblings, 1 reply; 7+ messages in thread
From: Martin Schreiber @ 2018-03-14 15:50 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
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
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [BUG] snd_pcm_drop() does not stop the PCM immediately
2018-03-14 15:50 ` Martin Schreiber
@ 2018-03-14 16:16 ` Takashi Iwai
2018-03-14 16:39 ` Martin Schreiber
0 siblings, 1 reply; 7+ messages in thread
From: Takashi Iwai @ 2018-03-14 16:16 UTC (permalink / raw)
To: Martin Schreiber; +Cc: alsa-devel
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
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [BUG] snd_pcm_drop() does not stop the PCM immediately
2018-03-14 16:16 ` Takashi Iwai
@ 2018-03-14 16:39 ` Martin Schreiber
2018-03-14 16:49 ` Takashi Iwai
0 siblings, 1 reply; 7+ messages in thread
From: Martin Schreiber @ 2018-03-14 16:39 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 461 bytes --]
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
[-- Attachment #2: alsadrop2.c --]
[-- Type: text/x-csrc, Size: 2640 bytes --]
//alsadrop2 testcase
// compile with
//gcc -oalsadrop2 -lasound -lpthread -g alsadrop2.c
#include <alsa/asoundlib.h>
#include <pthread.h>
#define samplefrequ 44100
int16_t bufa[samplefrequ]; //1 second f1
int16_t bufb[samplefrequ]; //1 second f2
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* buf;
snd_pcm_t *pcm;
void*
threadexe(void* param){
snd_pcm_sframes_t frameswritten;
int i1,i2,i3;
void* buf1;
i1 = sizeof(bufa)/sizeof(bufa[0]);
frameswritten = 0;
i3 = 0;
while (1){
pthread_mutex_lock(&mutex);
printf("++waitstart\n");
pthread_cond_wait(&cond,&mutex);
printf("!!signaled\n");
buf1 = buf;
pthread_mutex_unlock(&mutex);
frameswritten = snd_pcm_writei(pcm,buf1,i1);
printf("%d %p %d\n",i3,buf1,frameswritten);
i3++;
}
return NULL;
}
int pcmopen(char* dev){
unsigned int rate = samplefrequ;
snd_pcm_hw_params_t *params = NULL;
snd_pcm_hw_params_malloc(¶ms);
if (snd_pcm_open(&pcm,dev, SND_PCM_STREAM_PLAYBACK, 0)){
printf("Can not open pcm %s",dev);
goto error;
}
if (!params){
goto error;
};
if (snd_pcm_hw_params_any(pcm, params)<0){
goto error;
};
if (snd_pcm_hw_params_set_access(pcm,params,SND_PCM_ACCESS_RW_INTERLEAVED)){
goto error;
};
if (snd_pcm_hw_params_set_format(pcm,params,SND_PCM_FORMAT_S16_LE)){
goto error;
};
if (snd_pcm_hw_params_set_rate_near(pcm,params,&rate,0)){
goto error;
};
if (snd_pcm_hw_params_set_channels(pcm,params,1)){
goto error;
};
if (snd_pcm_hw_params(pcm,params)){
goto error;
};
if (snd_pcm_prepare(pcm)){
goto error;
};
snd_pcm_nonblock(pcm,0);
free(params);
return 0;
error:
return -1;
}
int main()
{
int i1,i2;
char* dev;
snd_pcm_sframes_t frameswritten;
pthread_t thread;
for(i1=0;i1 < samplefrequ;i1++){
bufa[i1] = 0x4000 * (2*((i1 / 40) % 2)-1);
bufb[i1] = 0x4000 * (2*((i1 / 41) % 2)-1);
}
dev = "sysdefault"; //alsa direct ->> overlapping sound
// dev = "default"; //over pulsaudio ->> OK
if (pcmopen(dev)){
goto error;
};
mutex.__data.__kind = PTHREAD_MUTEX_RECURSIVE;
if (pthread_create(&thread,NULL,&threadexe,NULL)){
goto error;
}
while(1){
pthread_mutex_lock(&mutex);
if (buf == bufa){
buf = bufb;
}
else{
buf = bufa;
}
pthread_mutex_unlock(&mutex);
printf("--- %p signal\n",buf);
pthread_cond_signal(&cond);
usleep(700000);
printf("<<<close\n");
snd_pcm_close(pcm);
if (pcmopen(dev)){
goto error;
};
/*
printf("<<<drop\n");
snd_pcm_drop(pcm);
snd_pcm_drain(pcm);
*/
i2 = snd_pcm_prepare(pcm);
printf("<<<prepare %d\n",i2);
}
return 0;
error:
return 1;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [BUG] snd_pcm_drop() does not stop the PCM immediately
2018-03-14 16:39 ` Martin Schreiber
@ 2018-03-14 16:49 ` Takashi Iwai
2018-03-14 16:57 ` Martin Schreiber
0 siblings, 1 reply; 7+ messages in thread
From: Takashi Iwai @ 2018-03-14 16:49 UTC (permalink / raw)
To: Martin Schreiber; +Cc: alsa-devel
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
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2018-03-14 16:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-03-14 14:59 [BUG] snd_pcm_drop() does not stop the PCM immediately Martin Schreiber
2018-03-14 15:13 ` Takashi Iwai
2018-03-14 15:50 ` Martin Schreiber
2018-03-14 16:16 ` Takashi Iwai
2018-03-14 16:39 ` Martin Schreiber
2018-03-14 16:49 ` Takashi Iwai
2018-03-14 16:57 ` Martin Schreiber
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.