[Etoys] Patch to fix sound delay issue

Takashi Yamamiya tak at metatoys.org
Fri Dec 8 09:14:28 EST 2006


Hello Yoshiki,

I fixed this problem. The reason of this issue was the delay
buffer was overflowed if under run happened repeatedly.
I tested it on my machine.
Please test it again.

Thank you,
- Takashi

> Yoshiki Ohshima wrote:
>>   Takashi,
>>
>>   The attached vm-sound-ALSA does shorten the delay when I play sound
>> from PianoKeyboard, but for a longer sound, it doesn't work as
>> expected.  The buffer underrun seems to be happening a lot, and also I
>> might guess that the index to fill the buffer may be wrong.
>>
>>   Now you have one, try
>>
>>   SampledSound stereoBachFugue play
-------------- next part --------------
A non-text attachment was scrubbed...
Name: vm-sound-ALSA.gz
Type: application/gzip
Size: 12575 bytes
Desc: not available
Url : http://mailman.laptop.org/pipermail/etoys/attachments/20061208/862a3ee6/vm-sound-ALSA.bin
-------------- next part --------------
Index: platforms/unix/vm-sound-ALSA/sqUnixSoundALSA.c
===================================================================
--- platforms/unix/vm-sound-ALSA/sqUnixSoundALSA.c	(revision 1594)
+++ platforms/unix/vm-sound-ALSA/sqUnixSoundALSA.c	(working copy)
@@ -56,6 +56,8 @@
 static void sigio_save(void);
 static void sigio_restore(void);
 
+#define MIN(x,y) ((x) < (y)) ? (x) : (y)
+#define MAX(x,y) ((x) > (y)) ? (x) : (y)
 
 /* output */
 
@@ -67,8 +69,10 @@
 static snd_async_handler_t	*output_handler= 0;
 static int			 output_semaphore= 0;
 static int			 output_channels= 0;
-static int			 output_buffer_frames_size= 0;
 static int			 output_buffer_frames_available= 0;
+static snd_pcm_uframes_t	 output_buffer_period_size= 0;
+static snd_pcm_uframes_t	 output_buffer_size= 0;
+static double			 max_delay_frames= 0;
 
 static void output_callback(snd_async_handler_t *handler)
 {
@@ -92,7 +96,6 @@
   int			 err;
   snd_pcm_hw_params_t	*hwparams;
   snd_pcm_sw_params_t	*swparams;
-  snd_pcm_uframes_t	 frames;
   unsigned int		 uval;
   int			 dir;
 
@@ -109,8 +112,8 @@
   snd_pcm_hw_params_set_channels(output_handle, hwparams, output_channels);
   uval= samplesPerSec;
   snd_pcm_hw_params_set_rate_near(output_handle, hwparams, &uval, &dir);
-  frames= frameCount;
-  snd_pcm_hw_params_set_period_size_near(output_handle, hwparams, &frames, &dir);
+  output_buffer_period_size= frameCount;
+  snd_pcm_hw_params_set_period_size_near(output_handle, hwparams, &output_buffer_period_size, &dir);
   snd(pcm_hw_params(output_handle, hwparams), "sound_Start: snd_pcm_hw_params");
 
   snd_pcm_sw_params_alloca(&swparams);
@@ -120,8 +123,9 @@
   snd(pcm_sw_params_set_xfer_align(output_handle, swparams, 1), "sound_Start: snd_pcm_sw_params_set_xfer_align");
   snd(pcm_sw_params(output_handle, swparams), "sound_Start: snd_pcm_sw_params");
 
-  output_buffer_frames_size= frameCount;
+  snd(pcm_hw_params_get_buffer_size(hwparams, &output_buffer_size), "sound_Start: pcm_hw_params_get_buffer_size");
   output_buffer_frames_available= 1;
+  max_delay_frames= output_buffer_period_size * 2; /* set initial delay frames */
 
   snd(pcm_nonblock(output_handle, 1), "sound_Start: snd_pcm_nonblock");
   snd(async_add_pcm_handler(&output_handler, output_handle, output_callback, 0), "soundStart: snd_add_pcm_handler");
@@ -152,17 +156,34 @@
   return 1;
 }
 
+/* Answers periods frame size, or zero if the delay is over. */
+
 static sqInt sound_AvailableSpace(void)
 {
-  if (output_handle)
-    {
-      int count = snd_pcm_avail_update(output_handle);
-      if (count >= 0)
-	return count;
-      fprintf(stderr, "sound_AvailableSpace: snd_pcm_avail_update: %s\n", snd_strerror(count));
-      snd_pcm_prepare(output_handle);
-    }
-  return 0;
+  snd_pcm_sframes_t delay;    /* distance to playback point (in frames) */
+  snd_pcm_state_t   state;    /* current state of the stream */
+  sqInt             avail= 0; /* available space for the answer (in bytes) */
+
+  if (!output_handle) return 0;
+
+  snd_pcm_delay(output_handle, &delay);
+  state= snd_pcm_state (output_handle);
+
+  /* if underrun causes, max delay is loosened */
+  if (state == SND_PCM_STATE_XRUN) {
+    max_delay_frames=
+      MIN(max_delay_frames * 1.5, output_buffer_size - output_buffer_period_size);
+  }
+
+  /* if the state is not running, new sound is needed bacause nobody can
+     signal the semaphore. */
+  if (delay <= max_delay_frames || state != SND_PCM_STATE_RUNNING) {
+    avail= output_buffer_period_size;
+    max_delay_frames= MAX(max_delay_frames * 0.9995, output_buffer_period_size);
+  }
+  fprintf(stderr, "delay=%i, ans_avail=%i, state=%i, real_delay=%.1fms\n",
+	  (int) delay, avail, state, 1000 * max_delay_frames / 22050);
+  return avail * output_channels * 2; /* bytes */
 }
 
 static sqInt  sound_InsertSamplesFromLeadTime(sqInt frameCount, sqInt srcBufPtr, sqInt samplesOfLeadTime)	FAIL(frameCount)
@@ -231,7 +252,6 @@
   snd_pcm_hw_params_t	*hwparams;
   snd_pcm_sw_params_t	*swparams;
   snd_pcm_uframes_t	 frames;
-  unsigned int		 uval;
   int			 dir;
 
   if (input_handle) sound_StopRecording();
@@ -261,6 +281,7 @@
   snd(pcm_nonblock(input_handle, 1), "sound_StartRecording: snd_pcm_nonblock");
   snd(async_add_pcm_handler(&input_handler, input_handle, input_callback, 0), "sound_StartRecording: snd_add_pcm_handler");
   snd(pcm_start(input_handle), "sound_StartRecording: snd_pcm_start");
+  return 1;
 }
 
 static double sound_GetRecordingSampleRate(void)


More information about the Etoys mailing list