[Vm-dev] [PATCH 1/3] ALSA: correctly handle -ESTRPIPE

Daniel Drake dsd at laptop.org
Wed Mar 27 18:11:43 UTC 2013


When ALSA produces -ESTRPIPE, it means that the sound subsystem is suspended,
and the client should resume it if it wants playback to continue. See
http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html#pcm_errors
and sample code:
http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html

Fixes a sound failure (and huge log spam) after suspend/resume with
sound playback enabled.

Index: Squeak-4.10.2.2614-src-no-mp3/unix/vm-sound-ALSA/sqUnixSoundALSA.c
===================================================================
--- Squeak-4.10.2.2614-src-no-mp3.orig/unix/vm-sound-ALSA/sqUnixSoundALSA.c
+++ Squeak-4.10.2.2614-src-no-mp3/unix/vm-sound-ALSA/sqUnixSoundALSA.c
@@ -200,28 +200,44 @@ static sqInt  sound_InsertSamplesFromLea
 
 static sqInt  sound_PlaySamplesFromAtLength(sqInt frameCount, void *srcBufPtr, sqInt startIndex)
 {
-  if (output_handle)
-    {
-      void *samples= srcBufPtr + startIndex * output_channels * 2;
-      int   count=   snd_pcm_writei(output_handle, samples, frameCount);
-      if (count < frameCount / 2)
-	{
-	  output_buffer_frames_available= 0;
-	}
-      if (count < 0)
-	{
-	  if (count == -EPIPE)    /* underrun */
-	    {
-	      int err;
-	      snd(pcm_prepare(output_handle), "sound_PlaySamples: snd_pcm_prepare");
-	      return 0;
-	    }
-	  fprintf(stderr, "snd_pcm_writei returned %i\n", count);
-	  return 0;
-	}
-      return count;
+  if (!output_handle)
+  {
+    success(false);
+    return 0;
+  }
+
+  void *samples= srcBufPtr + startIndex * output_channels * 2;
+  int   count=   snd_pcm_writei(output_handle, samples, frameCount);
+  if (count < frameCount / 2)
+    output_buffer_frames_available= 0;
+
+  if (count >= 0)
+    return count;
+
+  if (count != -EPIPE & count != -ESTRPIPE)
+  {
+    fprintf(stderr, "snd_pcm_writei returned %i\n", count);
+    return 0;
+  }
+
+  int err;
+  if (count == -EPIPE) {          /* under-run */
+    err = snd_pcm_prepare (output_handle);
+    if (err < 0)
+	  printf("Can't recover from underrun, prepare failed: %s", snd_strerror (err));
+    return 0;
+  } else if (count == -ESTRPIPE) {
+    while ((err = snd_pcm_resume (output_handle)) == -EAGAIN)
+      sleep(1);           /* wait until the suspend flag is released */
+
+    if (err < 0) {
+      err = snd_pcm_prepare (output_handle);
+      if (err < 0)
+		printf("Can't recover from suspend, prepare failed: %s", snd_strerror (err));
     }
-  success(false);
+    return 0;
+  }
+
   return 0;
 }
 
@@ -307,13 +323,28 @@ static sqInt sound_RecordSamplesIntoAtLe
       int   frameCount= ((bufferSizeInBytes / 2) - startSliceIndex) / input_channels;
       int   count=      snd_pcm_readi(input_handle, samples, frameCount);
       if (count < 0)
-	{    
-	  if (count == -EPIPE)
-	    snd_pcm_prepare(input_handle);
-	  else if (count != -EAGAIN)
-	    fprintf(stderr, "snd_pcm_readi returned %i\n", count);
-	  return 0;
-	}
+	  {
+		int err;
+		if (count == -EPIPE) {          /* under-run */
+		  err = snd_pcm_prepare (input_handle);
+		  if (err < 0)
+			printf("Can't recover from underrun, prepare failed: %s", snd_strerror (err));
+		  return 0;
+		} else if (count == -ESTRPIPE) {
+		  while ((err = snd_pcm_resume (input_handle)) == -EAGAIN)
+			sleep(1);           /* wait until the suspend flag is released */
+
+		  if (err < 0) {
+			err = snd_pcm_prepare (input_handle);
+			if (err < 0)
+			  printf("Can't recover from suspend, prepare failed: %s", snd_strerror (err));
+		  }
+		  return 0;
+		}
+
+		return 0;
+	  }
+
       return count * input_channels;
     }
   success(false);


More information about the Vm-dev mailing list