[pulseaudio-discuss] Couple problems when using 0.9.11 and fixes

Jyri Sarha lepbtetfmvbz at spammotel.com
Thu Sep 4 04:56:17 PDT 2008


Hi,
	I found couple of problems when upgrading to pulseaduio 0.9.11. The 
both are related to a case when tsched turned off on alsa-sink. First, 
problem appears when trying the select a specific number fragment with
module-alsa-sink parameters, for instance this:

load-module module-alsa-sink device=hw:0 rate=44100 fragment_size=882 fragments=2 tsched=0

The above produces three fragments of 588 bytes each. The actual bug
appears to be in alsa-lib, but it can be by-passed without breaking
things when alsa-lib gets fixed. To do that apply
fix_incremented_number_of_fragments.patch.

The other problem appears when trying to use alsa-sink with tsched=0 on a 
slow CPU. After writing a set of samples to device alsa-sink checks whether
there is room to write some more samples. On a slow CPU there is always room
for couple of samples more and alsa-sink keeps busy looping in the write
function. "parameter_to_set_minimum_write_size.patch" adds a parameter to 
module-alsa-sink to set the minimum number of samples to write on device,
setting this parameter to a reasonable value fixes the above problem,
like this:

load-module module-alsa-sink device=hw:0 rate=44100 fragment_size=882 fragments=2 tsched=0 hwbuf_min_frames_to_write=32

Alsa-source would need a similar patch too. In the end I decided
to forward port the old alsa- sink and source from 0.9.10 to 0.9.11,
because they seem to work more reliably and generate much less load, when
fragment-size and number of fragments is pushed to the minimum and 
tsched is not used. I can post those patches too if anybody is interested.

Cheers,
	Jyri


===File ~/fix_incremented_number_of_fragments.patch=========
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index 8abf834..64b4eff 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -369,12 +369,15 @@ int pa_alsa_set_hw_params(
         goto finish;
 
     if (_periods > 0) {
-        dir = 1;
-        if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
-            dir = -1;
-            if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
-                goto finish;
-        }
+	dir = 0;
+	if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
+	    dir = 1;
+	    if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
+		dir = -1;
+		if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
+		    goto finish;
+	    }
+	}
     }
 
     if (_period_size > 0)
============================================================

===File ~/parameter_to_set_minimum_write_size.patch=========
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index 8e66f79..0135a0b 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -69,7 +69,8 @@ PA_MODULE_USAGE(
         "tsched=<enable system timer based scheduling mode?> "
         "tsched_buffer_size=<buffer size when using timer based scheduling> "
         "tsched_buffer_watermark=<lower fill watermark> "
-        "mixer_reset=<reset hw volume and mute settings to sane defaults when falling back to software?>");
+        "mixer_reset=<reset hw volume and mute settings to sane defaults when falling back to software?>"
+	"hwbuf_min_frames_to_write=<minimum number of available frames in hwbuf to fill>");
 
 static const char* const valid_modargs[] = {
     "sink_name",
@@ -86,6 +87,7 @@ static const char* const valid_modargs[] = {
     "tsched_buffer_size",
     "tsched_buffer_watermark",
     "mixer_reset",
+    "hwbuf_min_frames_to_write",
     NULL
 };
 
@@ -132,6 +134,7 @@ struct userdata {
     uint64_t since_start;
 
     snd_pcm_sframes_t hwbuf_unused_frames;
+    snd_pcm_sframes_t hwbuf_min_frames_to_write;
 };
 
 static void fix_tsched_watermark(struct userdata *u) {
@@ -278,7 +281,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
             if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > process_usec+max_sleep_usec/2)
                 break;
 
-        if (PA_UNLIKELY(n <= u->hwbuf_unused_frames))
+        if (PA_UNLIKELY(n <= u->hwbuf_min_frames_to_write || n <= u->hwbuf_unused_frames))
             break;
 
         n -= u->hwbuf_unused_frames;
@@ -390,7 +393,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec) {
             if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > process_usec+max_sleep_usec/2)
                 break;
 
-        if (PA_UNLIKELY(n <= u->hwbuf_unused_frames))
+        if (PA_UNLIKELY(n <= u->hwbuf_min_frames_to_write || n <= u->hwbuf_unused_frames))
             break;
 
         n -= u->hwbuf_unused_frames;
@@ -1103,6 +1106,7 @@ int pa__init(pa_module*m) {
     pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, mixer_reset = TRUE;
     pa_usec_t usec;
     pa_sink_new_data data;
+    int32_t hwbuf_min_frames_to_write = 0;
 
     snd_pcm_info_alloca(&pcm_info);
 
@@ -1162,6 +1166,11 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (pa_modargs_get_value_s32(ma, "hwbuf_min_frames_to_write", &hwbuf_min_frames_to_write) < 0) {
+        pa_log("Failed to parse hwbuf_min_frames_to_write argument");
+	goto fail;
+    }
+
     u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
@@ -1316,6 +1325,7 @@ int pa__init(pa_module*m) {
     u->fragment_size = frag_size = period_frames * frame_size;
     u->nfragments = nfrags;
     u->hwbuf_size = u->fragment_size * nfrags;
+    u->hwbuf_min_frames_to_write = hwbuf_min_frames_to_write;
     u->hwbuf_unused_frames = 0;
     u->tsched_watermark = tsched_watermark;
     u->frame_index = 0;
============================================================



More information about the pulseaudio-discuss mailing list