[pulseaudio-commits] 9 commits - doc/stream_restore_fallback_table_example.table src/Makefile.am src/modules src/pulse src/pulsecore src/tests

Colin Guthrie colin at kemper.freedesktop.org
Sat Oct 1 05:26:20 PDT 2011


 doc/stream_restore_fallback_table_example.table |   13 +++
 src/Makefile.am                                 |    6 +
 src/modules/echo-cancel/module-echo-cancel.c    |    8 -
 src/modules/module-combine-sink.c               |    3 
 src/modules/module-equalizer-sink.c             |    4 
 src/modules/module-ladspa-sink.c                |    2 
 src/modules/module-loopback.c                   |    3 
 src/modules/module-null-sink.c                  |    2 
 src/modules/module-stream-restore.c             |   97 +++++++++++++++++++++++-
 src/modules/module-virtual-sink.c               |    2 
 src/modules/module-virtual-source.c             |    4 
 src/modules/rtp/module-rtp-recv.c               |    3 
 src/modules/rtp/module-rtp-send.c               |    3 
 src/pulse/context.c                             |    2 
 src/pulse/stream.c                              |    3 
 src/pulse/version.h.in                          |    2 
 src/pulsecore/memblockq.c                       |   15 ++-
 src/pulsecore/memblockq.h                       |   11 +-
 src/pulsecore/play-memchunk.c                   |    2 
 src/pulsecore/protocol-esound.c                 |    6 -
 src/pulsecore/protocol-http.c                   |    3 
 src/pulsecore/protocol-native.c                 |   12 ++
 src/pulsecore/protocol-simple.c                 |    6 -
 src/pulsecore/sink-input.c                      |   24 +++--
 src/pulsecore/sink.c                            |   87 ++++++++++++++++++++-
 src/pulsecore/sound-file-stream.c               |    2 
 src/pulsecore/source-output.c                   |    6 -
 src/pulsecore/svolume_mmx.c                     |    4 
 src/pulsecore/svolume_sse.c                     |    4 
 src/tests/memblockq-test.c                      |    7 +
 30 files changed, 288 insertions(+), 58 deletions(-)

New commits:
commit b0d9c78f3ea8b1183b8a89239153f752b4376eec
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Wed Sep 28 09:50:26 2011 +0200

    Make pulse build with clang again
    
    The casts are not supported there.

diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c
index ae2cf05..87d29e8 100644
--- a/src/pulsecore/svolume_mmx.c
+++ b/src/pulsecore/svolume_mmx.c
@@ -153,7 +153,7 @@ static void pa_volume_s16ne_mmx(int16_t *samples, int32_t *volumes, unsigned cha
 
         : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
 #if defined (__i386__)
-        : "m" ((pa_reg_x86)channels)
+        : "m" (channels)
 #else
         : "r" ((pa_reg_x86)channels)
 #endif
@@ -232,7 +232,7 @@ static void pa_volume_s16re_mmx(int16_t *samples, int32_t *volumes, unsigned cha
 
         : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
 #if defined (__i386__)
-        : "m" ((pa_reg_x86)channels)
+        : "m" (channels)
 #else
         : "r" ((pa_reg_x86)channels)
 #endif
diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c
index 6a73270..99a1adb 100644
--- a/src/pulsecore/svolume_sse.c
+++ b/src/pulsecore/svolume_sse.c
@@ -152,7 +152,7 @@ static void pa_volume_s16ne_sse2(int16_t *samples, int32_t *volumes, unsigned ch
 
         : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
 #if defined (__i386__)
-        : "m" ((pa_reg_x86)channels)
+        : "m" (channels)
 #else
         : "r" ((pa_reg_x86)channels)
 #endif
@@ -244,7 +244,7 @@ static void pa_volume_s16re_sse2(int16_t *samples, int32_t *volumes, unsigned ch
 
         : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
 #if defined (__i386__)
-        : "m" ((pa_reg_x86)channels)
+        : "m" (channels)
 #else
         : "r" ((pa_reg_x86)channels)
 #endif

commit cb9ebeffa06ea63415a5f4af349f8c8c921e6673
Author: Sudarshan Bisht <sudarshan.bisht at nokia.com>
Date:   Fri Sep 30 12:49:54 2011 +0300

    null-sink: Set latency range at the time of initialization of module.
    
    At the time of module initialization latency range is being set so that the null-sink
    would be aware of its limitations with latencies.

diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index 10868f5..454bd3e 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -315,6 +315,8 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    pa_sink_set_latency_range(u->sink, 0, BLOCK_USEC);
+
     pa_sink_put(u->sink);
 
     pa_modargs_free(ma);

commit 0f363d252c23142644f311387a2de5f063c34312
Author: Daniel Mack <daniel at caiaq.de>
Date:   Thu Sep 29 13:25:12 2011 +0200

    osx: don't build the once-test binary on OS X
    
    This patch was already added earlier with commit ID 2f86ba4f, but the
    changes got reverted by commit 3adc43b ("win32: Make once-test work").
    
    However, this still doesn't work on OSX as here, pthread is in general
    available, but the barrier APIs aren't.

diff --git a/src/Makefile.am b/src/Makefile.am
index 7f547cd..fdb2e99 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -244,7 +244,6 @@ TESTS = \
 
 TESTS_norun = \
 		mcalign-test \
-		once-test \
 		pacat-simple \
 		parec-simple \
 		extended-test \
@@ -262,6 +261,11 @@ TESTS += \
 		usergroup-test
 endif
 
+if !OS_IS_DARWIN
+TESTS_norun += \
+		once-test
+endif
+
 if HAVE_SIGXCPU
 TESTS_norun += \
 		cpulimit-test \

commit 8d0e9c05a51e6550dd07e25136504d67c9b47657
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Sep 30 17:09:29 2011 +0300

    doc: Add an example stream-restore fallback table file.

diff --git a/doc/stream_restore_fallback_table_example.table b/doc/stream_restore_fallback_table_example.table
new file mode 100644
index 0000000..0a4ade0
--- /dev/null
+++ b/doc/stream_restore_fallback_table_example.table
@@ -0,0 +1,13 @@
+# This is an example fallback table file for module-stream-restore.
+# Lines starting with '#' or ';' are regarded as comments and ignored.
+# Empty lines are allowed.
+#
+# Each non-comment and non-empty line defines the default volume
+# for one stream-restore database key. For example:
+
+sink-input-by-media-role:phone -4.2
+
+# That line sets the volume of sink inputs with media role "phone"
+# to -4.2 dB (relative to the sink volume), if the
+# "sink-input-by-media-role:phone" key doesn't already exist in the
+# stream-restore database. Positive dB values are not allowed.

commit 188c91b514804d48de6257e72640ef8ff8e8e830
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Sat Oct 1 12:16:35 2011 +0100

    stream-restore: Support a simple fallback volume table
    
    The purpose of this patch is to make it possible to configure stream volumes
    before pulseaudio is run for the first time. This is useful, for example, in
    embedded products where the default volumes have to be sensible already in
    the first boot.

diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index 4d0686f..fe7708b 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -68,17 +68,24 @@ PA_MODULE_USAGE(
         "restore_volume=<Save/restore volumes?> "
         "restore_muted=<Save/restore muted states?> "
         "on_hotplug=<When new device becomes available, recheck streams?> "
-        "on_rescue=<When device becomes unavailable, recheck streams?>");
+        "on_rescue=<When device becomes unavailable, recheck streams?> "
+        "fallback_table=<filename>");
 
 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
 
+#define DEFAULT_FALLBACK_FILE PA_DEFAULT_CONFIG_DIR"/stream-restore.table"
+#define DEFAULT_FALLBACK_FILE_USER "stream-restore.table"
+
+#define WHITESPACE "\n\r \t"
+
 static const char* const valid_modargs[] = {
     "restore_device",
     "restore_volume",
     "restore_muted",
     "on_hotplug",
     "on_rescue",
+    "fallback_table",
     NULL
 };
 
@@ -1800,7 +1807,88 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc
     return PA_HOOK_OK;
 }
 
-#define EXT_VERSION 1
+static int fill_db(struct userdata *u, const char *filename) {
+    FILE *f;
+    int n = 0;
+    int ret = -1;
+    char *fn = NULL;
+
+    pa_assert(u);
+
+    if (filename)
+        f = fopen(fn = pa_xstrdup(filename), "r");
+    else
+        f = pa_open_config_file(DEFAULT_FALLBACK_FILE, DEFAULT_FALLBACK_FILE_USER, NULL, &fn);
+
+    if (!f) {
+        if (filename)
+            pa_log("Failed to open %s: %s", filename, pa_cstrerror(errno));
+        else
+            ret = 0;
+
+        goto finish;
+    }
+
+    while (!feof(f)) {
+        char ln[256];
+        char *d, *v;
+        double db;
+
+        if (!fgets(ln, sizeof(ln), f))
+            break;
+
+        n++;
+
+        pa_strip_nl(ln);
+
+        if (!*ln || ln[0] == '#' || ln[0] == ';')
+            continue;
+
+        d = ln+strcspn(ln, WHITESPACE);
+        v = d+strspn(d, WHITESPACE);
+
+        if (!*v) {
+            pa_log("[%s:%u] failed to parse line - too few words", fn, n);
+            goto finish;
+        }
+
+        *d = 0;
+        if (pa_atod(v, &db) >= 0) {
+            if (db <= 0.0) {
+                pa_datum key, data;
+                struct entry e;
+
+                pa_zero(e);
+                e.version = ENTRY_VERSION;
+                e.volume_valid = TRUE;
+                pa_cvolume_set(&e.volume, 1, pa_sw_volume_from_dB(db));
+                pa_channel_map_init_mono(&e.channel_map);
+
+                key.data = (void *) ln;
+                key.size = strlen(ln);
+
+                data.data = (void *) &e;
+                data.size = sizeof(e);
+
+                if (pa_database_set(u->database, &key, &data, FALSE) == 0)
+                    pa_log_debug("Setting %s to %0.2f dB.", ln, db);
+            } else
+                pa_log_warn("[%s:%u] Positive dB values are not allowed, not setting entry %s.", fn, n, ln);
+        } else
+            pa_log_warn("[%s:%u] Couldn't parse '%s' as a double, not setting entry %s.", fn, n, v, ln);
+    }
+
+    trigger_save(u);
+    ret = 0;
+
+finish:
+    if (f)
+        fclose(f);
+
+    pa_xfree(fn);
+
+    return ret;
+}
 
 static void entry_apply(struct userdata *u, const char *name, struct entry *e) {
     pa_sink_input *si;
@@ -1942,6 +2030,8 @@ PA_GCC_UNUSED static void stream_restore_dump_database(struct userdata *u) {
 }
 #endif
 
+#define EXT_VERSION 1
+
 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
     struct userdata *u;
     uint32_t command;
@@ -2280,6 +2370,9 @@ int pa__init(pa_module*m) {
     pa_log_info("Successfully opened database file '%s'.", fname);
     pa_xfree(fname);
 
+    if (fill_db(u, pa_modargs_get_value(ma, "fallback_table", NULL)) < 0)
+        goto fail;
+
 #ifdef HAVE_DBUS
     u->dbus_protocol = pa_dbus_protocol_get(u->core);
     u->dbus_entries = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);

commit 666261ece8cfa9b5458a1c1358b7ae4b9682b6a5
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Sep 29 18:54:03 2011 +0300

    memblockq: Improve debuggability by storing a name and a sample spec.
    
    These are not used for anything at this point, but this
    makes it easy to add ad-hoc debug prints that show the
    memblockq name and to convert between bytes and usecs.

diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 6c7828f..7e0dcef 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -1608,10 +1608,10 @@ int pa__init(pa_module*m) {
 
     pa_sink_input_get_silence(u->sink_input, &silence);
 
-    u->source_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0,
-        pa_frame_size(&source_ss), 1, 1, 0, &silence);
-    u->sink_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0,
-        pa_frame_size(&sink_ss), 1, 1, 0, &silence);
+    u->source_memblockq = pa_memblockq_new("module-echo-cancel source_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0,
+        &source_ss, 1, 1, 0, &silence);
+    u->sink_memblockq = pa_memblockq_new("module-echo-cancel sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0,
+        &sink_ss, 1, 1, 0, &silence);
 
     pa_memblock_unref(silence.memblock);
 
diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c
index 8bdc5b7..dec2279 100644
--- a/src/modules/module-combine-sink.c
+++ b/src/modules/module-combine-sink.c
@@ -897,10 +897,11 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) {
     o->outq = pa_asyncmsgq_new(0);
     o->sink = sink;
     o->memblockq = pa_memblockq_new(
+            "module-combine-sink output memblockq",
             0,
             MEMBLOCKQ_MAXLENGTH,
             MEMBLOCKQ_MAXLENGTH,
-            pa_frame_size(&u->sink->sample_spec),
+            &u->sink->sample_spec,
             1,
             0,
             0,
diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c
index e0587fe..46bd0d7 100644
--- a/src/modules/module-equalizer-sink.c
+++ b/src/modules/module-equalizer-sink.c
@@ -1207,8 +1207,8 @@ int pa__init(pa_module*m) {
     }
     u->sink->userdata = u;
 
-    u->input_q = pa_memblockq_new(0,  MEMBLOCKQ_MAXLENGTH, 0, fs, 1, 1, 0, &u->sink->silence);
-    u->output_q = pa_memblockq_new(0,  MEMBLOCKQ_MAXLENGTH, 0, fs, 1, 1, 0, NULL);
+    u->input_q = pa_memblockq_new("module-equalizer-sink input_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &u->sink->silence);
+    u->output_q = pa_memblockq_new("module-equalizer-sink output_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
     u->output_buffer = NULL;
     u->output_buffer_length = 0;
     u->output_buffer_max_length = 0;
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index 7d81e0d..be05715 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -529,7 +529,7 @@ int pa__init(pa_module*m) {
     u = pa_xnew0(struct userdata, 1);
     u->module = m;
     m->userdata = u;
-    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+    u->memblockq = pa_memblockq_new("module-ladspa-sink memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
     u->max_ladspaport_count = 1; /*to avoid division by zero etc. in pa__done when failing before this value has been set*/
     u->channels = 0;
     u->input = NULL;
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 627a16f..5291258 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -806,10 +806,11 @@ int pa__init(pa_module *m) {
 
     pa_sink_input_get_silence(u->sink_input, &silence);
     u->memblockq = pa_memblockq_new(
+            "module-loopback memblockq",
             0,                      /* idx */
             MEMBLOCKQ_MAXLENGTH,    /* maxlength */
             MEMBLOCKQ_MAXLENGTH,    /* tlength */
-            pa_frame_size(&ss),     /* base */
+            &ss,                    /* sample_spec */
             0,                      /* prebuf */
             0,                      /* minreq */
             0,                      /* maxrewind */
diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index dd3de86..e7c476e 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -614,7 +614,7 @@ int pa__init(pa_module*m) {
     u->sink->input_to_master = u->sink_input;
 
     pa_sink_input_get_silence(u->sink_input, &silence);
-    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, &silence);
+    u->memblockq = pa_memblockq_new("module-virtual-sink memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
     pa_memblock_unref(silence.memblock);
 
     /* (9) INITIALIZE ANYTHING ELSE YOU NEED HERE */
diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c
index 00a4b65..bf07580 100644
--- a/src/modules/module-virtual-source.c
+++ b/src/modules/module-virtual-source.c
@@ -548,7 +548,7 @@ int pa__init(pa_module*m) {
     }
     u->module = m;
     m->userdata = u;
-    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+    u->memblockq = pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
     if (!u->memblockq) {
         pa_log("Failed to create source memblockq.");
         goto fail;
@@ -659,7 +659,7 @@ int pa__init(pa_module*m) {
             pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
         }
 
-        u->sink_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+        u->sink_memblockq = pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
         if (!u->sink_memblockq) {
             pa_sink_new_data_done(&sink_data);
             pa_log("Failed to create sink memblockq.");
diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c
index 7025c15..9d86805 100644
--- a/src/modules/rtp/module-rtp-recv.c
+++ b/src/modules/rtp/module-rtp-recv.c
@@ -556,10 +556,11 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in
         s->intended_latency = s->sink_latency*2;
 
     s->memblockq = pa_memblockq_new(
+            "module-rtp-recv memblockq",
             0,
             MEMBLOCKQ_MAXLENGTH,
             MEMBLOCKQ_MAXLENGTH,
-            pa_frame_size(&s->sink_input->sample_spec),
+            &s->sink_input->sample_spec,
             pa_usec_to_bytes(s->intended_latency - s->sink_latency, &s->sink_input->sample_spec),
             0,
             0,
diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c
index 7131629..6502664 100644
--- a/src/modules/rtp/module-rtp-send.c
+++ b/src/modules/rtp/module-rtp-send.c
@@ -348,10 +348,11 @@ int pa__init(pa_module*m) {
     u->source_output = o;
 
     u->memblockq = pa_memblockq_new(
+            "module-rtp-send memblockq",
             0,
             MEMBLOCKQ_MAXLENGTH,
             MEMBLOCKQ_MAXLENGTH,
-            pa_frame_size(&ss),
+            &ss,
             1,
             0,
             0,
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index ec88bf1..3bf2d96 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1140,10 +1140,11 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag,
         pa_assert(!s->record_memblockq);
 
         s->record_memblockq = pa_memblockq_new(
+                "client side record memblockq",
                 0,
                 s->buffer_attr.maxlength,
                 0,
-                pa_frame_size(&s->sample_spec),
+                &s->sample_spec,
                 1,
                 0,
                 0,
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index 3e1f7bc..2bee0a2 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -54,13 +54,16 @@ struct pa_memblockq {
     pa_memchunk silence;
     pa_mcalign *mcalign;
     int64_t missing, requested;
+    char *name;
+    pa_sample_spec sample_spec;
 };
 
 pa_memblockq* pa_memblockq_new(
+        const char *name,
         int64_t idx,
         size_t maxlength,
         size_t tlength,
-        size_t base,
+        const pa_sample_spec *sample_spec,
         size_t prebuf,
         size_t minreq,
         size_t maxrewind,
@@ -68,18 +71,21 @@ pa_memblockq* pa_memblockq_new(
 
     pa_memblockq* bq;
 
-    pa_assert(base > 0);
+    pa_assert(sample_spec);
+    pa_assert(name);
 
     bq = pa_xnew(pa_memblockq, 1);
+    bq->name = pa_xstrdup(name);
     bq->blocks = bq->blocks_tail = NULL;
     bq->current_read = bq->current_write = NULL;
     bq->n_blocks = 0;
 
-    bq->base = base;
+    bq->sample_spec = *sample_spec;
+    bq->base = pa_frame_size(sample_spec);
     bq->read_index = bq->write_index = idx;
 
     pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
-                 (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq, (unsigned long) maxrewind);
+                 (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) bq->base, (unsigned long) prebuf, (unsigned long) minreq, (unsigned long) maxrewind);
 
     bq->missing = bq->requested = 0;
     bq->maxlength = bq->tlength = bq->prebuf = bq->minreq = bq->maxrewind = 0;
@@ -116,6 +122,7 @@ void pa_memblockq_free(pa_memblockq* bq) {
     if (bq->mcalign)
         pa_mcalign_free(bq->mcalign);
 
+    pa_xfree(bq->name);
     pa_xfree(bq);
 }
 
diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h
index 8d1f137..08c0bf0 100644
--- a/src/pulsecore/memblockq.h
+++ b/src/pulsecore/memblockq.h
@@ -40,6 +40,8 @@ typedef struct pa_memblockq pa_memblockq;
 
 /* Parameters:
 
+   - name:      name for debugging purposes
+
    - idx:       start value for both read and write index
 
    - maxlength: maximum length of queue. If more data is pushed into
@@ -47,9 +49,9 @@ typedef struct pa_memblockq pa_memblockq;
 
    - tlength:   the target length of the queue. Pass 0 for the default.
 
-   - base:      a base value for all metrics. Only multiples of this value
-                are popped from the queue or should be pushed into
-                it. Must not be 0.
+   - ss:        Sample spec describing the queue contents. Only multiples
+                of the frame size as implied by the sample spec are
+                popped from the queue or should be pushed into it.
 
    - prebuf:    If the queue runs empty wait until this many bytes are in
                 queue again before passing the first byte out. If set
@@ -65,10 +67,11 @@ typedef struct pa_memblockq pa_memblockq;
    - silence:   return this memchunk when reading uninitialized data
 */
 pa_memblockq* pa_memblockq_new(
+        const char *name,
         int64_t idx,
         size_t maxlength,
         size_t tlength,
-        size_t base,
+        const pa_sample_spec *sample_spec,
         size_t prebuf,
         size_t minreq,
         size_t maxrewind,
diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c
index ee25958..26a2bcc 100644
--- a/src/pulsecore/play-memchunk.c
+++ b/src/pulsecore/play-memchunk.c
@@ -50,7 +50,7 @@ int pa_play_memchunk(
     pa_assert(chunk);
 
     pa_silence_memchunk_get(&sink->core->silence_cache, sink->core->mempool, &silence, ss, 0);
-    q = pa_memblockq_new(0, chunk->length, 0, pa_frame_size(ss), 1, 1, 0, &silence);
+    q = pa_memblockq_new("pa_play_memchunk() q", 0, chunk->length, 0, ss, 1, 1, 0, &silence);
     pa_memblock_unref(silence.memblock);
 
     pa_assert_se(pa_memblockq_push(q, chunk) >= 0);
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 5527c30..4e1c56c 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -436,10 +436,11 @@ static int esd_proto_stream_play(connection *c, esd_proto_t request, const void
     l = (size_t) ((double) pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS);
     pa_sink_input_get_silence(c->sink_input, &silence);
     c->input_memblockq = pa_memblockq_new(
+            "esound protocol connection input_memblockq",
             0,
             l,
             l,
-            pa_frame_size(&ss),
+            &ss,
             (size_t) -1,
             l/PLAYBACK_BUFFER_FRAGMENTS,
             0,
@@ -534,10 +535,11 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi
 
     l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS);
     c->output_memblockq = pa_memblockq_new(
+            "esound protocol connection output_memblockq",
             0,
             l,
             l,
-            pa_frame_size(&ss),
+            &ss,
             1,
             0,
             0,
diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c
index d085e61..d745634 100644
--- a/src/pulsecore/protocol-http.c
+++ b/src/pulsecore/protocol-http.c
@@ -584,10 +584,11 @@ static void handle_listen_prefix(struct connection *c, const char *source_name)
 
     l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS);
     c->output_memblockq = pa_memblockq_new(
+            "http protocol connection output_memblockq",
             0,
             l,
             0,
-            pa_frame_size(&ss),
+            &ss,
             1,
             0,
             0,
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index e871478..0ee4ead 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -646,6 +646,7 @@ static record_stream* record_stream_new(
     record_stream *s;
     pa_source_output *source_output = NULL;
     pa_source_output_new_data data;
+    char *memblockq_name;
 
     pa_assert(c);
     pa_assert(ss);
@@ -708,15 +709,18 @@ static record_stream* record_stream_new(
 
     fix_record_buffer_attr_pre(s);
 
+    memblockq_name = pa_sprintf_malloc("native protocol record stream memblockq [%u]", s->source_output->index);
     s->memblockq = pa_memblockq_new(
+            memblockq_name,
             0,
             s->buffer_attr.maxlength,
             0,
-            pa_frame_size(&source_output->sample_spec),
+            &source_output->sample_spec,
             1,
             0,
             0,
             NULL);
+    pa_xfree(memblockq_name);
 
     pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
     fix_record_buffer_attr_post(s);
@@ -1068,6 +1072,7 @@ static playback_stream* playback_stream_new(
     uint32_t idx;
     int64_t start_index;
     pa_sink_input_new_data data;
+    char *memblockq_name;
 
     pa_assert(c);
     pa_assert(ss);
@@ -1163,15 +1168,18 @@ static playback_stream* playback_stream_new(
     fix_playback_buffer_attr(s);
 
     pa_sink_input_get_silence(sink_input, &silence);
+    memblockq_name = pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s->sink_input->index);
     s->memblockq = pa_memblockq_new(
+            memblockq_name,
             start_index,
             s->buffer_attr.maxlength,
             s->buffer_attr.tlength,
-            pa_frame_size(&sink_input->sample_spec),
+            &sink_input->sample_spec,
             s->buffer_attr.prebuf,
             s->buffer_attr.minreq,
             0,
             &silence);
+    pa_xfree(memblockq_name);
     pa_memblock_unref(silence.memblock);
 
     pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 978339d..8d8f5b8 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -560,10 +560,11 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp
         l = (size_t) ((double) pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS);
         pa_sink_input_get_silence(c->sink_input, &silence);
         c->input_memblockq = pa_memblockq_new(
+                "simple protocol connection input_memblockq",
                 0,
                 l,
                 l,
-                pa_frame_size(&o->sample_spec),
+                &o->sample_spec,
                 (size_t) -1,
                 l/PLAYBACK_BUFFER_FRAGMENTS,
                 0,
@@ -611,10 +612,11 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp
 
         l = (size_t) (pa_bytes_per_second(&o->sample_spec)*RECORD_BUFFER_SECONDS);
         c->output_memblockq = pa_memblockq_new(
+                "simple protocol connection output_memblockq",
                 0,
                 l,
                 0,
-                pa_frame_size(&o->sample_spec),
+                &o->sample_spec,
                 1,
                 0,
                 0,
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 15944f4..5146a9d 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -242,6 +242,7 @@ int pa_sink_input_new(
     pa_channel_map original_cm;
     int r;
     char *pt;
+    char *memblockq_name;
     pa_sample_spec ss;
     pa_channel_map map;
 
@@ -481,21 +482,24 @@ int pa_sink_input_new(
     i->thread_info.playing_for = 0;
     i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
+    pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
+    pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
+
+    if (i->client)
+        pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0);
+
+    memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
     i->thread_info.render_memblockq = pa_memblockq_new(
+            memblockq_name,
             0,
             MEMBLOCKQ_MAXLENGTH,
             0,
-            pa_frame_size(&i->sink->sample_spec),
+            &i->sink->sample_spec,
             0,
             1,
             0,
             &i->sink->silence);
-
-    pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
-    pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
-
-    if (i->client)
-        pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0);
+    pa_xfree(memblockq_name);
 
     pt = pa_proplist_to_string_sep(i->proplist, "\n    ");
     pa_log_info("Created input %u \"%s\" on %s with sample spec %s and channel map %s\n    %s",
@@ -1643,6 +1647,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 
     /* Replace resampler and render queue */
     if (new_resampler != i->thread_info.resampler) {
+        char *memblockq_name;
 
         if (i->thread_info.resampler)
             pa_resampler_free(i->thread_info.resampler);
@@ -1650,15 +1655,18 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 
         pa_memblockq_free(i->thread_info.render_memblockq);
 
+        memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
         i->thread_info.render_memblockq = pa_memblockq_new(
+                memblockq_name,
                 0,
                 MEMBLOCKQ_MAXLENGTH,
                 0,
-                pa_frame_size(&i->sink->sample_spec),
+                &i->sink->sample_spec,
                 0,
                 1,
                 0,
                 &i->sink->silence);
+        pa_xfree(memblockq_name);
         i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
     }
 
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index 96b5fb8..24d3314 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -320,7 +320,7 @@ int pa_play_file(
     u->sink_input->userdata = u;
 
     pa_sink_input_get_silence(u->sink_input, &silence);
-    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, &silence);
+    u->memblockq = pa_memblockq_new("sound-file-stream memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
     pa_memblock_unref(silence.memblock);
 
     pa_sink_input_put(u->sink_input);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 1e08a03..ea0e760 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -443,10 +443,11 @@ int pa_source_output_new(
     o->thread_info.direct_on_input = o->direct_on_input;
 
     o->thread_info.delay_memblockq = pa_memblockq_new(
+            "source output delay_memblockq",
             0,
             MEMBLOCKQ_MAXLENGTH,
             0,
-            pa_frame_size(&o->source->sample_spec),
+            &o->source->sample_spec,
             0,
             1,
             0,
@@ -1433,10 +1434,11 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
         pa_memblockq_free(o->thread_info.delay_memblockq);
 
         o->thread_info.delay_memblockq = pa_memblockq_new(
+                "source output delay_memblockq",
                 0,
                 MEMBLOCKQ_MAXLENGTH,
                 0,
-                pa_frame_size(&o->source->sample_spec),
+                &o->source->sample_spec,
                 0,
                 1,
                 0,
diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c
index b6c6003..085d70e 100644
--- a/src/tests/memblockq-test.c
+++ b/src/tests/memblockq-test.c
@@ -76,6 +76,11 @@ int main(int argc, char *argv[]) {
     pa_memblockq *bq;
     pa_memchunk chunk1, chunk2, chunk3, chunk4;
     pa_memchunk silence;
+    pa_sample_spec ss = {
+        .format = PA_SAMPLE_S16LE,
+        .rate = 48000,
+        .channels = 1
+    };
 
     pa_log_set_level(PA_LOG_DEBUG);
 
@@ -86,7 +91,7 @@ int main(int argc, char *argv[]) {
     silence.index = 0;
     silence.length = pa_memblock_get_length(silence.memblock);
 
-    bq = pa_memblockq_new(0, 200, 10, 2, 4, 4, 40, &silence);
+    bq = pa_memblockq_new("test memblockq", 0, 200, 10, &ss, 4, 4, 40, &silence);
     assert(bq);
 
     chunk1.memblock = pa_memblock_new_fixed(p, (char*) "11", 2, 1);

commit 4d930f19f93d1823e6aa28c2b990d2ca3ff8a9ba
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Sep 29 18:54:02 2011 +0300

    sink: Add some comments about the rewind handling during stream moves.

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index a2642b4..53cab32 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -2403,6 +2403,46 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
                 pa_usec_t usec = 0;
                 size_t sink_nbytes, total_nbytes;
 
+                /* The old sink probably has some audio from this
+                 * stream in its buffer. We want to "take it back" as
+                 * much as possible and play it to the new sink. We
+                 * don't know at this point how much the old sink can
+                 * rewind. We have to pick something, and that
+                 * something is the full latency of the old sink here.
+                 * So we rewind the stream buffer by the sink latency
+                 * amount, which may be more than what we should
+                 * rewind. This can result in a chunk of audio being
+                 * played both to the old sink and the new sink.
+                 *
+                 * FIXME: Fix this code so that we don't have to make
+                 * guesses about how much the sink will actually be
+                 * able to rewind. If someone comes up with a solution
+                 * for this, something to note is that the part of the
+                 * latency that the old sink couldn't rewind should
+                 * ideally be compensated after the stream has moved
+                 * to the new sink by adding silence. The new sink
+                 * most likely can't start playing the moved stream
+                 * immediately, and that gap should be removed from
+                 * the "compensation silence" (at least at the time of
+                 * writing this, the move finish code will actually
+                 * already take care of dropping the new sink's
+                 * unrewindable latency, so taking into account the
+                 * unrewindable latency of the old sink is the only
+                 * problem).
+                 *
+                 * The render_memblockq contents are discarded,
+                 * because when the sink changes, the format of the
+                 * audio stored in the render_memblockq may change
+                 * too, making the stored audio invalid. FIXME:
+                 * However, the read and write indices are moved back
+                 * the same amount, so if they are not the same now,
+                 * they won't be the same after the rewind either. If
+                 * the write index of the render_memblockq is ahead of
+                 * the read index, then the render_memblockq will feed
+                 * the new sink some silence first, which it shouldn't
+                 * do. The write index should be flushed to be the
+                 * same as the read index. */
+
                 /* Get the latency of the sink */
                 usec = pa_sink_get_latency_within_thread(s);
                 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
@@ -2456,6 +2496,24 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
                 pa_usec_t usec = 0;
                 size_t nbytes;
 
+                /* In the ideal case the new sink would start playing
+                 * the stream immediately. That requires the sink to
+                 * be able to rewind all of its latency, which usually
+                 * isn't possible, so there will probably be some gap
+                 * before the moved stream becomes audible. We then
+                 * have two possibilities: 1) start playing the stream
+                 * from where it is now, or 2) drop the unrewindable
+                 * latency of the sink from the stream. With option 1
+                 * we won't lose any audio but the stream will have a
+                 * pause. With option 2 we may lose some audio but the
+                 * stream time will be somewhat in sync with the wall
+                 * clock. Lennart seems to have chosen option 2 (one
+                 * of the reasons might have been that option 1 is
+                 * actually much harder to implement), so we drop the
+                 * latency of the new sink from the moved stream and
+                 * hope that the sink will undo most of that in the
+                 * rewind. */
+
                 /* Get the latency of the sink */
                 usec = pa_sink_get_latency_within_thread(s);
                 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);

commit 307911c72e905633660a4fd84b75113c92299613
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Sep 29 18:54:01 2011 +0300

    sink: Move updating the requested latency after the rewind request when finishing a stream move.

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 05b08aa..a2642b4 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -2330,6 +2330,18 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
              * slow start, i.e. need some time to buffer client
              * samples before beginning streaming. */
 
+            /* FIXME: Actually rewinding should be requested before
+             * updating the sink requested latency, because updating
+             * the requested latency updates also max_rewind of the
+             * sink. Now consider this: a sink has a 10 s buffer and
+             * nobody has requested anything less. Then a new stream
+             * appears while the sink buffer is full. The new stream
+             * requests e.g. 100 ms latency. That request is forwarded
+             * to the sink, so now max_rewind is 100 ms. When a rewind
+             * is requested, the sink will only rewind 100 ms, and the
+             * new stream will have to wait about 10 seconds before it
+             * becomes audible. */
+
             /* In flat volume mode we need to update the volume as
              * well */
             return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
@@ -2440,12 +2452,6 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
             if (i->attach)
                 i->attach(i);
 
-            if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
-                pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
-
-            pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
-            pa_sink_input_update_max_request(i, s->thread_info.max_request);
-
             if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
                 pa_usec_t usec = 0;
                 size_t nbytes;
@@ -2461,6 +2467,17 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
                 pa_sink_request_rewind(s, nbytes);
             }
 
+            /* Updating the requested sink latency has to be done
+             * after the sink rewind request, not before, because
+             * otherwise the sink may limit the rewind amount
+             * needlessly. */
+
+            if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
+                pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
+
+            pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
+            pa_sink_input_update_max_request(i, s->thread_info.max_request);
+
             return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
         }
 

commit 7563e0bbb54fbac54e77f3a62d9761a70f3a559c
Author: Colin Guthrie <colin at mageia.org>
Date:   Sat Oct 1 12:03:44 2011 +0100

    libpulse: Always return a three part version number in API calls.
    
    For both the headers and the library we should provide clean, three part
    strings as this has been what we've previously done in the past
    and some external systems apparently rely on this format. While it's not
    something we've officially commented on before, there is no real advantage
    to us to change it so let's not try to tidy things up too much
    considering some third party apps (e.g. Skype) seem to dislike a two
    part version string.

diff --git a/src/pulse/context.c b/src/pulse/context.c
index 25d04a1..af144aa 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1281,7 +1281,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su
 }
 
 const char* pa_get_library_version(void) {
-    return PACKAGE_VERSION;
+    return pa_get_headers_version();
 }
 
 const char* pa_context_get_server(pa_context *c) {
diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in
index 7e00c5e..1be4c75 100644
--- a/src/pulse/version.h.in
+++ b/src/pulse/version.h.in
@@ -35,7 +35,7 @@ PA_C_DECL_BEGIN
 /** Return the version of the header files. Keep in mind that this is
 a macro and not a function, so it is impossible to get the pointer of
 it. */
-#define pa_get_headers_version() ("@PACKAGE_VERSION@")
+#define pa_get_headers_version() ("@PA_MAJOR at .@PA_MINOR at .0")
 
 /** Return the version of the library the current application is
  * linked to. */



More information about the pulseaudio-commits mailing list