[xiph-commits] r18779 - in trunk/ao: . doc src/plugins/alsa src/plugins/pulse

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Mon Jan 21 20:41:11 PST 2013


Author: xiphmont
Date: 2013-01-21 20:41:11 -0800 (Mon, 21 Jan 2013)
New Revision: 18779

Modified:
   trunk/ao/configure.ac
   trunk/ao/doc/drivers.html
   trunk/ao/src/plugins/alsa/ao_alsa.c
   trunk/ao/src/plugins/pulse/Makefile.am
   trunk/ao/src/plugins/pulse/ao_pulse.c
Log:
Further tweaking of latency setup in ALSA; set default period_time ot 1/4 of buffer time
Add latency management the Pulse plugin, along with "buffer_time" option
Add drain() bug workaround to pulse ao_plugin_close(); should eliminate the long wait on teardown



Modified: trunk/ao/configure.ac
===================================================================
--- trunk/ao/configure.ac	2013-01-22 02:35:11 UTC (rev 18778)
+++ trunk/ao/configure.ac	2013-01-22 04:41:11 UTC (rev 18779)
@@ -452,9 +452,8 @@
 if test "x$BUILD_PULSE" = "xyes" ; then
     PKG_CHECK_MODULES(PULSE, [ libpulse-simple >= 0.9 ],
 	[have_pulse=yes],[have_pulse=no])
-    AC_SUBST(PULSE_LIBS)
-    AC_SUBST(PULSE_CFLAGS)
 fi
+AC_SUBST(PULSE_LIBS)
 
 AM_CONDITIONAL(HAVE_PULSE,test "x$have_pulse" = xyes)
 

Modified: trunk/ao/doc/drivers.html
===================================================================
--- trunk/ao/doc/drivers.html	2013-01-22 02:35:11 UTC (rev 18778)
+++ trunk/ao/doc/drivers.html	2013-01-22 04:41:11 UTC (rev 18779)
@@ -245,6 +245,7 @@
 <p>
 <b>Option keys:</b>
 <ul>
+<li>"buffer_time" - Override the default hardware buffer size (in milliseconds).
 <li>"dev" - (see 'Standard Driver Options' above). This maps to a specific Pulse sink; it may be specified by Pulse sink name, or by number.
 <li>"id" - (see 'Standard Driver Options' above). Maps to a specific pulse sink number.
 <li>"server" - Specifies Pulseaudio server to use.

Modified: trunk/ao/src/plugins/alsa/ao_alsa.c
===================================================================
--- trunk/ao/src/plugins/alsa/ao_alsa.c	2013-01-22 02:35:11 UTC (rev 18778)
+++ trunk/ao/src/plugins/alsa/ao_alsa.c	2013-01-22 04:41:11 UTC (rev 18779)
@@ -43,8 +43,8 @@
 /* default 20 millisecond buffer */
 #define AO_ALSA_BUFFER_TIME 20000
 
-/* default 5ms transfer size */
-#define AO_ALSA_PERIOD_TIME 5000
+/* default we be calculated to be 1/4 of the buffer time */
+#define AO_ALSA_PERIOD_TIME 0
 
 /* set mmap to default if enabled at compile time, otherwise, mmap isn't
    the default */
@@ -353,7 +353,18 @@
                 "by the hardware, using %u\n", format->rate, rate);
 	}
 
+	/* set the length of the hardware sample buffer in microseconds */
+	err = snd_pcm_hw_params_set_buffer_time_near(internal->pcm_handle,
+			params, &(internal->buffer_time), 0);
+	if (err < 0){
+          adebug("snd_pcm_hw_params_set_buffer_time_near() failed.\n");
+          return err;
+        }
+
 	/* set the time per hardware sample transfer */
+        if(internal->period_time==0)
+          internal->period_time=internal->buffer_time/4;
+
 	err = snd_pcm_hw_params_set_period_time_near(internal->pcm_handle,
 			params, &(internal->period_time), 0);
 	if (err < 0){
@@ -361,14 +372,6 @@
           return err;
         }
 
-	/* set the length of the hardware sample buffer in microseconds */
-	err = snd_pcm_hw_params_set_buffer_time_near(internal->pcm_handle,
-			params, &(internal->buffer_time), 0);
-	if (err < 0){
-          adebug("snd_pcm_hw_params_set_buffer_time_near() failed.\n");
-          return err;
-        }
-
 	/* commit the params structure to the hardware via ALSA */
 	err = snd_pcm_hw_params(internal->pcm_handle, params);
 	if (err < 0){
@@ -773,7 +776,6 @@
                   /* something went wrong; fall back */
                   snd_pcm_drain(internal->pcm_handle);
                 }else{
-                  fprintf(stderr,"s=%f(%d)",s,(int)sframes);
                   if(s>0){
                     struct timespec sleep,wake;
                     sleep.tv_sec = (int)s;

Modified: trunk/ao/src/plugins/pulse/Makefile.am
===================================================================
--- trunk/ao/src/plugins/pulse/Makefile.am	2013-01-22 02:35:11 UTC (rev 18778)
+++ trunk/ao/src/plugins/pulse/Makefile.am	2013-01-22 04:41:11 UTC (rev 18779)
@@ -19,9 +19,8 @@
 libdir = $(plugindir)
 lib_LTLIBRARIES = $(pulseltlibs)
 
-libpulse_la_LDFLAGS= @PLUGIN_LDFLAGS@
-libpulse_la_SOURCES=$(pulsesources)
-libpulse_la_LIBADD=$(AM_LIBADD) $(PULSE_LIBS)
-libpulse_la_CFLAGS=$(AM_CFLAGS) $(PULSE_CFLAGS)
+libpulse_la_LDFLAGS = @PLUGIN_LDFLAGS@
+libpulse_la_LIBADD = @PULSE_LIBS@
+libpulse_la_SOURCES = $(pulsesources)
 
 EXTRA_DIST = ao_pulse.c

Modified: trunk/ao/src/plugins/pulse/ao_pulse.c
===================================================================
--- trunk/ao/src/plugins/pulse/ao_pulse.c	2013-01-22 02:35:11 UTC (rev 18778)
+++ trunk/ao/src/plugins/pulse/ao_pulse.c	2013-01-22 04:41:11 UTC (rev 18779)
@@ -40,6 +40,8 @@
 #include <ao/ao.h>
 #include <ao/plugin.h>
 
+#define AO_PULSE_BUFFER_TIME 20000
+
 /* Unfortunately libao doesn't allow "const" for these structures... */
 static char * ao_pulse_options[] = {
     "server",
@@ -51,6 +53,7 @@
     "matrix",
     "debug",
     "client_name"
+    "buffer_time"
 };
 
 static ao_info ao_pulse_info = {
@@ -68,6 +71,8 @@
 typedef struct ao_pulse_internal {
     struct pa_simple *simple;
     char *server, *sink, *client_name;
+    pa_usec_t static_delay;
+    pa_usec_t buffer_time;
 } ao_pulse_internal;
 
 /* Yes, this is very ugly, but required nonetheless... */
@@ -142,6 +147,7 @@
     internal->server = NULL;
     internal->sink = NULL;
     internal->client_name = NULL;
+    internal->buffer_time = AO_PULSE_BUFFER_TIME;
 
     device->internal = internal;
     device->output_matrix_order = AO_OUTPUT_MATRIX_PERMUTABLE;
@@ -167,6 +173,8 @@
     } else if (!strcmp(key, "client_name")) {
         free(internal->client_name);
         internal->client_name = strdup(value);
+    }else if (!strcmp(key, "buffer_time")){
+      internal->buffer_time = atoi(value) * 1000;
     } else
         return 0;
 
@@ -178,6 +186,7 @@
     ao_pulse_internal *internal;
     struct pa_sample_spec ss;
     struct pa_channel_map map;
+    struct pa_buffer_attr battr;
     size_t allocated = 128;
 
     assert(device && device->internal && format);
@@ -246,14 +255,25 @@
       }
     }
 
+    /* buffering attributes */
+    battr.prebuf = battr.minreq = battr.fragsize = -1;
+
+    battr.tlength = (int)(internal->buffer_time * format->rate) / 1000000 *
+      ((format->bits+7)/8) + device->output_channels;
+    battr.minreq = battr.tlength/4;
+    battr.maxlength = battr.tlength+battr.minreq;
+
     internal->simple = pa_simple_new(internal->server, t, PA_STREAM_PLAYBACK,
                                      internal->sink, t2, &ss,
-                                     (device->input_map ? &map : NULL), NULL, NULL);
+                                     (device->input_map ? &map : NULL), &battr, NULL);
     if (!internal->simple)
         return 0;
 
     device->driver_byte_format = AO_FMT_NATIVE;
 
+    internal->static_delay = pa_simple_get_latency(internal->simple, NULL);
+    if(internal->static_delay<0) internal->static_delay = 0;
+
     return 1;
 }
 
@@ -270,7 +290,32 @@
     ao_pulse_internal *internal = (ao_pulse_internal *) device->internal;
 
     if(internal->simple){
-      pa_simple_drain(internal->simple, NULL);
+
+      /* this is a PulseAudio ALSA bug workaround;
+         pa_simple_drain() always takes about 2 seconds, even if
+         there's nothing to drain.  Rather than wait for no
+         reason, determine the current playback depth, wait
+         that long, then kill the stream.  Remove this code
+         once Pulse gets fixed. */
+
+      pa_usec_t us = pa_simple_get_latency(internal->simple, NULL);
+      if(us<0 || us>1000000){
+        pa_simple_drain(internal->simple, NULL);
+      }else{
+        us -= internal->static_delay;
+        if(us>0){
+          struct timespec sleep,wake;
+          sleep.tv_sec = (int)(us/1000000);
+          sleep.tv_nsec = (us-sleep.tv_sec*1000000)*1000;
+          while(nanosleep(&sleep,&wake)<0){
+            if(errno==EINTR)
+              sleep=wake;
+            else
+              break;
+          }
+        }
+      }
+
       pa_simple_free(internal->simple);
       internal->simple = NULL;
     }



More information about the commits mailing list