[Bug 692953] alsa modules are silent or noisy after several hours of use

GStreamer (bugzilla.gnome.org) bugzilla at gnome.org
Tue Sep 10 16:59:39 PDT 2013


https://bugzilla.gnome.org/show_bug.cgi?id=692953
  GStreamer | gst-plugins-base | 1.0.9

--- Comment #132 from Thomas DEBESSE <thomas.debesse at rcf.fr> 2013-09-10 23:59:30 UTC ---
Remember Comment #42, we have logged this:

1:39:18.548386467 26625 0x7f8b2c003a30 DEBUG                   alsa
gstalsasink.c:1014:gst_alsasink_write:<alsasink0> wait error, -32

##############################################################################

I found that in gst-plugins-base/ext/alsa/gstalsasink.c:

---8<-------------------------------------------------------------------------
static gint
> gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
> {
>   GstAlsaSink *alsa;
>   gint err;
>   gint cptr;
>   gint16 *ptr = data;
> 
>   alsa = GST_ALSA_SINK (asink);
> 
>   if (alsa->iec958 && alsa->need_swap) {
>     guint i;
> 
>     GST_DEBUG_OBJECT (asink, "swapping bytes");
>     for (i = 0; i < length / 2; i++) {
>       ptr[i] = GUINT16_SWAP_LE_BE (ptr[i]);
>     }
>   }
> 
>   GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length);
> 
>   cptr = length / alsa->bpf;
> 
>   GST_ALSA_SINK_LOCK (asink);
>   while (cptr > 0) {
>     /* start by doing a blocking wait for free space. Set the timeout
>      * to 4 times the period time */
>     err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000));
>     if (err < 0) {
>       GST_DEBUG_OBJECT (asink, "wait error, %d", err);
>     } else {
>       GST_DELAY_SINK_LOCK (asink);
>       err = snd_pcm_writei (alsa->handle, ptr, cptr);
>       GST_DELAY_SINK_UNLOCK (asink);
>     }
> 
>     GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr);
>     if (err < 0) {
>       GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err));
>       if (err == -EAGAIN) {
>         continue;
>       } else if (err == -ENODEV) {
>         goto device_disappeared;
>       } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
>         goto write_error;
>       }
>       continue;
>     }
> 
>     ptr += snd_pcm_frames_to_bytes (alsa->handle, err);
>     cptr -= err;
>   }
>   GST_ALSA_SINK_UNLOCK (asink);
> 
>   return length - (cptr * alsa->bpf);
> 
> write_error:
>   {
>     GST_ALSA_SINK_UNLOCK (asink);
>     return length;              /* skip one period */
>   }
> device_disappeared:
>   {
>     GST_ELEMENT_ERROR (asink, RESOURCE, WRITE,
>         (_("Error outputting to audio device. "
>                 "The device has been disconnected.")), (NULL));
>     goto write_error;
>   }
> }
---8<-------------------------------------------------------------------------

Perhaps the bug is somewhere here ?

In comparison we have that in gst-plugins-base/ext/alsa/gstalsasrc.c:

---8<-------------------------------------------------------------------------
> static guint
> gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length,
>     GstClockTime * timestamp)
> {
>   GstAlsaSrc *alsa;
>   gint err;
>   gint cptr;
>   gint16 *ptr;
> 
>   alsa = GST_ALSA_SRC (asrc);
> 
>   cptr = length / alsa->bpf;
>   ptr = data;
> 
>   GST_ALSA_SRC_LOCK (asrc);
>   while (cptr > 0) {
>     if ((err = snd_pcm_readi (alsa->handle, ptr, cptr)) < 0) {
>       if (err == -EAGAIN) {
>         GST_DEBUG_OBJECT (asrc, "Read error: %s", snd_strerror (err));
>         continue;
>       } else if (err == -ENODEV) {
>         goto device_disappeared;
>       } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
>         goto read_error;
>       }
>       continue;
>     }
> 
>     ptr += err * alsa->channels;
>     cptr -= err;
>   }
>   GST_ALSA_SRC_UNLOCK (asrc);
> 
>   /* if driver timestamps are enabled we need to return this here */
>   if (alsa->driver_timestamps && timestamp)
>     *timestamp = gst_alsasrc_get_timestamp (alsa);
> 
>   return length - (cptr * alsa->bpf);
> 
> read_error:
>   {
>     GST_ALSA_SRC_UNLOCK (asrc);
>     return length;              /* skip one period */
>   }
> device_disappeared:
>   {
>     GST_ELEMENT_ERROR (asrc, RESOURCE, READ,
>         (_("Error recording from audio device. "
>                 "The device has been disconnected.")), (NULL));
>     GST_ALSA_SRC_UNLOCK (asrc);
>     return (guint) - 1;
>   }
> }
---8<-------------------------------------------------------------------------

##############################################################################

There is two notable difference between them.

The first notable difference is:

in gstalsasrc.c:

> while (cptr > 0) {
>   /* some code */
>   ptr += err * alsa->channels;
>   cptr -= err;
> }

in gstalsasink.c:

> while (cptr > 0) {
>   /* some code */
>   ptr += snd_pcm_frames_to_bytes (alsa->handle, err);
>   cptr -= err;
> }

I do not know if this is normal and if this is the expected operation.

The second notable difference is:

in gstalsasrc.c, err is always assigned like that:

> err = snd_pcm_readi (alsa->handle, ptr, cptr)

in gstalsasink.c, err can be assigned in two ways:

> err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000));

or, if err >= 0:

> err = snd_pcm_writei (alsa->handle, ptr, cptr);

##############################################################################

There is another noticeable thing !

We read in gstalsasink.c:

> err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000));

And this the snd_pcm_wait code in alsa-lib/src/pcm/pcm.c:

> int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
> {
> 	if (!snd_pcm_may_wait_for_avail_min(pcm, snd_pcm_mmap_avail(pcm))) {
> 		/* check more precisely */
> 		switch (snd_pcm_state(pcm)) {
> 		case SND_PCM_STATE_XRUN:
> 			return -EPIPE;
> 		case SND_PCM_STATE_SUSPENDED:
> 			return -ESTRPIPE;
> 		case SND_PCM_STATE_DISCONNECTED:
> 			return -ENODEV;
> 		default:
> 			return 1;
> 		}
> 	}
> 	return snd_pcm_wait_nocheck(pcm, timeout);
> }

snd_pcm_wait can return -EPIPE in case of SND_PCM_STATE_XRUN
We can remember that EPIPE is 32.

In gst-plugins-base/ext/alsa/gstalsasink.c we can see that -EPIPE is not
handled:

>     if (err < 0) {
>       GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err));
>       if (err == -EAGAIN) {
>         continue;
>       } else if (err == -ENODEV) {
>         goto device_disappeared;
>       } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
>         goto write_error;
>       }
>       continue;
>     }

There is no "if (err == -EPIPE)" at all.

In case of "alsasrc ! alsasink" pipeline, when the alsasink get -EPIPE, this is
the alsasrc module that catch this error and complains:

1:39:18.548478614 26625 0x7f8b2c003630 DEBUG                   alsa
gstalsasrc.c:808:xrun_recovery:<alsasrc0> xrun recovery -32: Erreur inconnue
-32

Does anyone have an idea?

-- 
Configure bugmail: https://bugzilla.gnome.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.


More information about the gstreamer-bugs mailing list