[xiph-commits] r18777 - trunk/ao/src/plugins/alsa
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Mon Jan 21 15:14:27 PST 2013
Author: xiphmont
Date: 2013-01-21 15:14:27 -0800 (Mon, 21 Jan 2013)
New Revision: 18777
Modified:
trunk/ao/src/plugins/alsa/ao_alsa.c
Log:
Implement another Pulse-emulation-specific workaround in ao_alsa;
disable underrun detection for only Pulse plugins to avoid the
'immediate underrrun on stream start' bug:
https://github.com/kinetiknz/cubeb/commit/1aa0058d0729eb85505df104cd1ac072432c6d24
Also tweak the ALSA latency configuration in general; the old code was
'trying too hard' AFAICT.
Modified: trunk/ao/src/plugins/alsa/ao_alsa.c
===================================================================
--- trunk/ao/src/plugins/alsa/ao_alsa.c 2013-01-21 20:47:43 UTC (rev 18776)
+++ trunk/ao/src/plugins/alsa/ao_alsa.c 2013-01-21 23:14:27 UTC (rev 18777)
@@ -40,16 +40,12 @@
#include <ao/ao.h>
#include <ao/plugin.h>
-/* default 25 millisecond buffer */
-#define AO_ALSA_BUFFER_TIME 25000
+/* default 20 millisecond buffer */
+#define AO_ALSA_BUFFER_TIME 20000
-/* the period time is calculated if not given as an option */
-#define AO_ALSA_PERIOD_TIME 0
+/* default 5ms transfer size */
+#define AO_ALSA_PERIOD_TIME 5000
-/* number of samples between interrupts
- * supplying a period_time to ao overrides the use of this */
-#define AO_ALSA_SAMPLE_XFER 256
-
/* set mmap to default if enabled at compile time, otherwise, mmap isn't
the default */
#ifdef USE_ALSA_MMIO
@@ -105,6 +101,12 @@
ao_alsa_writei_t * writei;
snd_pcm_access_t access_mask;
int static_delay;
+
+ /* Local configuration with handle_underrun workaround set for
+ PulseAudio ALSA plugin. Will be NULL if the PA ALSA plugin is not
+ in use or the workaround is not required. Remove this and the
+ associated code once PulseAudio gets fixed. */
+ snd_config_t *local_config;
} ao_alsa_internal;
@@ -217,6 +219,81 @@
return ret;
}
+/* Work around PulseAudio ALSA plugin bug where the PA server forces a
+ higher than requested latency, but the plugin does not update its (and
+ ALSA's) internal state to reflect that, leading to an immediate underrun
+ situation. Inspired by WINE's make_handle_underrun_config.
+ Reference: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-July/053391.html
+ From Mozilla https://github.com/kinetiknz/cubeb/blob/1aa0058d0729eb85505df104cd1ac072432c6d24/src/cubeb_alsa.c
+*/
+static snd_config_t *init_local_config_with_workaround(ao_device *device, char const *name){
+ char pcm_node_name[80];
+ int r;
+ snd_config_t * lconf;
+ snd_config_t * device_node;
+ snd_config_t * type_node;
+ snd_config_t * node;
+ char const * type_string;
+
+ lconf = NULL;
+ snprintf(pcm_node_name,80,"pcm.%s",name);
+
+ if (snd_config == NULL) snd_config_update();
+
+ r = snd_config_copy(&lconf, snd_config);
+ if(r<0){
+ return NULL;
+ }
+
+ r = snd_config_search(lconf, pcm_node_name, &device_node);
+ if (r != 0) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ /* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */
+ r = snd_config_search(device_node, "type", &type_node);
+ if (r != 0) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ r = snd_config_get_string(type_node, &type_string);
+ if (r != 0) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ if (strcmp(type_string, "pulse") != 0) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ /* Don't clobber an explicit existing handle_underrun value, set it only
+ if it doesn't already exist. */
+ r = snd_config_search(device_node, "handle_underrun", &node);
+ if (r != -ENOENT) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ r = snd_config_imake_integer(&node, "handle_underrun", 0);
+ if (r != 0) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ r = snd_config_add(device_node, node);
+ if (r != 0) {
+ snd_config_delete(lconf);
+ return NULL;
+ }
+
+ adebug("PulseAudio ALSA-emulation detected: disabling underrun detection\n");
+ return lconf;
+}
+
+
/* setup alsa data format and buffer geometry */
static inline int alsa_set_hwparams(ao_device *device,
ao_sample_format *format)
@@ -276,11 +353,6 @@
"by the hardware, using %u\n", format->rate, rate);
}
- /* calculate a period time of one half sample time */
- if ((internal->period_time == 0) && (rate > 0))
- internal->period_time =
- 1000000 * AO_ALSA_SAMPLE_XFER / rate;
-
/* set the time per hardware sample transfer */
err = snd_pcm_hw_params_set_period_time_near(internal->pcm_handle,
params, &(internal->period_time), 0);
@@ -320,7 +392,8 @@
static inline int alsa_set_swparams(ao_device *device)
{
ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
- snd_pcm_sw_params_t *params;
+ snd_pcm_sw_params_t *params;
+ snd_pcm_uframes_t boundary;
int err;
/* allocate the software parameter structure */
@@ -333,12 +406,13 @@
return err;
}
+#if 0 /* the below causes more trouble than it cures */
/* allow transfers to start when there is one period */
err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
params, internal->period_size);
if (err < 0){
adebug("snd_pcm_sw_params_set_start_threshold() failed.\n");
- return err;
+ //return err;
}
/* require a minimum of one full transfer in the buffer */
@@ -346,8 +420,9 @@
internal->period_size);
if (err < 0){
adebug("snd_pcm_sw_params_set_avail_min() failed.\n");
- return err;
+ //return err;
}
+#endif
/* do not align transfers; this is obsolete/deprecated in ALSA
1.x where the transfer alignemnt is always 1 (except for
@@ -357,25 +432,25 @@
err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
if (err < 0){
adebug("snd_pcm_sw_params_set_xfer_align() failed.\n");
- return err;
+ //return err;
}
- /* force a work-ahead silence buffer; this is a fix, again for
- VIA 82xx, where non-MMIO transfers will buffer into
- period-size transfers, but the last transfer is usually
- undersized and playback falls off the end of the submitted
- data. */
- {
- snd_pcm_uframes_t boundary;
- err = snd_pcm_sw_params_get_boundary(params,&boundary);
- if (err < 0){
- adebug("snd_pcm_sw_params_get_boundary() failed.\n");
- return err;
- }
+
+ /* get the boundary size */
+ err = snd_pcm_sw_params_get_boundary(params,&boundary);
+ if (err < 0){
+ adebug("snd_pcm_sw_params_get_boundary() failed.\n");
+ }else{
+
+ /* force a work-ahead silence buffer; this is a fix, again for
+ VIA 82xx, where non-MMIO transfers will buffer into
+ period-size transfers, but the last transfer is usually
+ undersized and playback falls off the end of the submitted
+ data. */
err = snd_pcm_sw_params_set_silence_size(internal->pcm_handle, params, boundary);
if (err < 0){
adebug("snd_pcm_sw_params_set_silence_size() failed.\n");
- return err;
+ //return err;
}
}
@@ -405,11 +480,19 @@
adebug("Trying to open ALSA device '%s'\n",dev);
- err = snd_pcm_open(&(internal->pcm_handle), dev,
- SND_PCM_STREAM_PLAYBACK, 0);
+ internal->local_config = init_local_config_with_workaround(device,dev);
+ if(internal->local_config)
+ err = snd_pcm_open_lconf(&(internal->pcm_handle), dev,
+ SND_PCM_STREAM_PLAYBACK, 0, internal->local_config);
+ else
+ err = snd_pcm_open(&(internal->pcm_handle), dev,
+ SND_PCM_STREAM_PLAYBACK, 0);
if(err){
adebug("Unable to open ALSA device '%s'\n",dev);
+ if(internal->local_config)
+ snd_config_delete(internal->local_config);
+ internal->local_config=NULL;
return err;
}
@@ -434,6 +517,9 @@
if(err<0){
adebug("Unable to open ALSA device '%s'\n",dev);
snd_pcm_close(internal->pcm_handle);
+ if(internal->local_config)
+ snd_config_delete(internal->local_config);
+ internal->local_config=NULL;
internal->pcm_handle = NULL;
return err;
}
@@ -443,6 +529,9 @@
if(err<0){
adebug("Unable to open ALSA device '%s'\n",dev);
snd_pcm_close(internal->pcm_handle);
+ if(internal->local_config)
+ snd_config_delete(internal->local_config);
+ internal->local_config=NULL;
internal->pcm_handle = NULL;
return err;
}
@@ -693,6 +782,9 @@
}
}
snd_pcm_close(internal->pcm_handle);
+ if(internal->local_config)
+ snd_config_delete(internal->local_config);
+ internal->local_config=NULL;
internal->pcm_handle=NULL;
}
} else
More information about the commits
mailing list