Blame SOURCES/0003-combine-sink-add-support-for-DYNAMIC_LATENCY.patch

4bc40d
From 12ef9f32c15604f958a4b913d8f45685dd284ff8 Mon Sep 17 00:00:00 2001
4bc40d
From: Wim Taymans <wim.taymans@gmail.com>
4bc40d
Date: Tue, 10 Jun 2014 21:38:28 +0200
4bc40d
Subject: [PATCH 3/7] combine-sink: add support for DYNAMIC_LATENCY
4bc40d
4bc40d
Mark the sink as DYNAMIC_LATENCY and implement update_sink_latency_range
4bc40d
on its sink-input to collect the combined latency range of all sinks.
4bc40d
4bc40d
Implement update_requested_latency on the sink to configure the final
4bc40d
latency by combining the sink-input requested latencies. This makes us
4bc40d
honour the client latency request.
4bc40d
4bc40d
Also add more debug log.
4bc40d
4bc40d
Fixes https://bugs.freedesktop.org/show_bug.cgi?id=47899
4bc40d
---
4bc40d
 src/modules/module-combine-sink.c | 142 ++++++++++++++++++++++++++++----------
4bc40d
 1 file changed, 107 insertions(+), 35 deletions(-)
4bc40d
4bc40d
diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c
4bc40d
index 2730891..cf318c5 100644
4bc40d
--- a/src/modules/module-combine-sink.c
4bc40d
+++ b/src/modules/module-combine-sink.c
4bc40d
@@ -104,7 +104,8 @@ struct output {
4bc40d
 
4bc40d
     /* For communication of the stream parameters to the sink thread */
4bc40d
     pa_atomic_t max_request;
4bc40d
-    pa_atomic_t requested_latency;
4bc40d
+    pa_atomic_t max_latency;
4bc40d
+    pa_atomic_t min_latency;
4bc40d
 
4bc40d
     PA_LLIST_FIELDS(struct output);
4bc40d
 };
4bc40d
@@ -131,6 +132,8 @@ struct userdata {
4bc40d
     pa_resample_method_t resample_method;
4bc40d
 
4bc40d
     pa_usec_t block_usec;
4bc40d
+    pa_usec_t default_min_latency;
4bc40d
+    pa_usec_t default_max_latency;
4bc40d
 
4bc40d
     pa_idxset* outputs; /* managed in main context */
4bc40d
 
4bc40d
@@ -150,11 +153,12 @@ enum {
4bc40d
     SINK_MESSAGE_NEED,
4bc40d
     SINK_MESSAGE_UPDATE_LATENCY,
4bc40d
     SINK_MESSAGE_UPDATE_MAX_REQUEST,
4bc40d
-    SINK_MESSAGE_UPDATE_REQUESTED_LATENCY
4bc40d
+    SINK_MESSAGE_UPDATE_LATENCY_RANGE
4bc40d
 };
4bc40d
 
4bc40d
 enum {
4bc40d
     SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
4bc40d
+    SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY
4bc40d
 };
4bc40d
 
4bc40d
 static void output_disable(struct output *o);
4bc40d
@@ -463,35 +467,44 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
4bc40d
         return;
4bc40d
 
4bc40d
     pa_atomic_store(&o->max_request, (int) nbytes);
4bc40d
+    pa_log_debug("Sink input update max request %lu", (unsigned long) nbytes);
4bc40d
     pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
4bc40d
 }
4bc40d
 
4bc40d
 /* Called from thread context */
4bc40d
-static void sink_input_update_sink_requested_latency_cb(pa_sink_input *i) {
4bc40d
+static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
4bc40d
     struct output *o;
4bc40d
-    pa_usec_t c;
4bc40d
+    pa_usec_t min, max, fix;
4bc40d
 
4bc40d
     pa_assert(i);
4bc40d
 
4bc40d
     pa_sink_input_assert_ref(i);
4bc40d
     pa_assert_se(o = i->userdata);
4bc40d
 
4bc40d
-    c = pa_sink_get_requested_latency_within_thread(i->sink);
4bc40d
-
4bc40d
-    if (c == (pa_usec_t) -1)
4bc40d
-        c = i->sink->thread_info.max_latency;
4bc40d
+    fix = i->sink->thread_info.fixed_latency;
4bc40d
+    if (fix > 0) {
4bc40d
+        min = fix;
4bc40d
+        max = fix;
4bc40d
+    } else {
4bc40d
+        min = i->sink->thread_info.min_latency;
4bc40d
+        max = i->sink->thread_info.max_latency;
4bc40d
+    }
4bc40d
 
4bc40d
-    if (pa_atomic_load(&o->requested_latency) == (int) c)
4bc40d
+    if ((pa_atomic_load(&o->min_latency) == (int) min) &&
4bc40d
+        (pa_atomic_load(&o->max_latency) == (int) max))
4bc40d
         return;
4bc40d
 
4bc40d
-    pa_atomic_store(&o->requested_latency, (int) c);
4bc40d
-    pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL);
4bc40d
+    pa_atomic_store(&o->min_latency, (int) min);
4bc40d
+    pa_atomic_store(&o->max_latency, (int) max);
4bc40d
+    pa_log_debug("Sink input update latency range %lu %lu", (unsigned long) min, (unsigned long) max);
4bc40d
+    pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_LATENCY_RANGE, NULL, 0, NULL, NULL);
4bc40d
 }
4bc40d
 
4bc40d
 /* Called from I/O thread context */
4bc40d
 static void sink_input_attach_cb(pa_sink_input *i) {
4bc40d
     struct output *o;
4bc40d
-    pa_usec_t c;
4bc40d
+    pa_usec_t fix, min, max;
4bc40d
+    size_t nbytes;
4bc40d
 
4bc40d
     pa_sink_input_assert_ref(i);
4bc40d
     pa_assert_se(o = i->userdata);
4bc40d
@@ -511,10 +524,20 @@ static void sink_input_attach_cb(pa_sink_input *i) {
4bc40d
 
4bc40d
     pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
4bc40d
 
4bc40d
-    pa_atomic_store(&o->max_request, (int) pa_sink_input_get_max_request(i));
4bc40d
+    nbytes = pa_sink_input_get_max_request(i);
4bc40d
+    pa_atomic_store(&o->max_request, (int) nbytes);
4bc40d
+    pa_log_debug("attach max request %lu", (unsigned long) nbytes);
4bc40d
 
4bc40d
-    c = pa_sink_get_requested_latency_within_thread(i->sink);
4bc40d
-    pa_atomic_store(&o->requested_latency, (int) (c == (pa_usec_t) -1 ? 0 : c));
4bc40d
+    fix = i->sink->thread_info.fixed_latency;
4bc40d
+    if (fix > 0) {
4bc40d
+        min = max = fix;
4bc40d
+    } else {
4bc40d
+        min = i->sink->thread_info.min_latency;
4bc40d
+        max = i->sink->thread_info.max_latency;
4bc40d
+    }
4bc40d
+    pa_atomic_store(&o->min_latency, (int) min);
4bc40d
+    pa_atomic_store(&o->max_latency, (int) max);
4bc40d
+    pa_log_debug("attach latency range %lu %lu", (unsigned long) min, (unsigned long) max);
4bc40d
 
4bc40d
     /* We register the output. That means that the sink will start to pass data to
4bc40d
      * this output. */
4bc40d
@@ -541,6 +564,7 @@ static void sink_input_detach_cb(pa_sink_input *i) {
4bc40d
         pa_rtpoll_item_free(o->outq_rtpoll_item_write);
4bc40d
         o->outq_rtpoll_item_write = NULL;
4bc40d
     }
4bc40d
+
4bc40d
 }
4bc40d
 
4bc40d
 /* Called from main context */
4bc40d
@@ -578,6 +602,14 @@ static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64
4bc40d
                 pa_memblockq_flush_write(o->memblockq, TRUE);
4bc40d
 
4bc40d
             return 0;
4bc40d
+
4bc40d
+        case SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: {
4bc40d
+            pa_usec_t latency = (pa_usec_t) offset;
4bc40d
+
4bc40d
+            pa_sink_input_set_requested_latency_within_thread(o->sink_input, latency);
4bc40d
+
4bc40d
+            return 0;
4bc40d
+        }
4bc40d
     }
4bc40d
 
4bc40d
     return pa_sink_input_process_msg(obj, code, data, offset, chunk);
4bc40d
@@ -666,31 +698,42 @@ static void update_max_request(struct userdata *u) {
4bc40d
     if (max_request <= 0)
4bc40d
         max_request = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
4bc40d
 
4bc40d
+    pa_log_debug("Sink update max request %lu", (unsigned long) max_request);
4bc40d
     pa_sink_set_max_request_within_thread(u->sink, max_request);
4bc40d
 }
4bc40d
 
4bc40d
 /* Called from IO context */
4bc40d
-static void update_fixed_latency(struct userdata *u) {
4bc40d
-    pa_usec_t fixed_latency = 0;
4bc40d
+static void update_latency_range(struct userdata *u) {
4bc40d
+    pa_usec_t min_latency = 0, max_latency = (pa_usec_t) -1;
4bc40d
     struct output *o;
4bc40d
 
4bc40d
     pa_assert(u);
4bc40d
     pa_sink_assert_io_context(u->sink);
4bc40d
 
4bc40d
-    /* Collects the requested_latency values of all streams and sets
4bc40d
-     * the largest one as fixed_latency locally */
4bc40d
-
4bc40d
+    /* Collects the latency_range values of all streams and sets
4bc40d
+     * the max of min and min of max locally */
4bc40d
     PA_LLIST_FOREACH(o, u->thread_info.active_outputs) {
4bc40d
-        pa_usec_t rl = (size_t) pa_atomic_load(&o->requested_latency);
4bc40d
+        pa_usec_t min = (size_t) pa_atomic_load(&o->min_latency);
4bc40d
+        pa_usec_t max = (size_t) pa_atomic_load(&o->max_latency);
4bc40d
 
4bc40d
-        if (rl > fixed_latency)
4bc40d
-            fixed_latency = rl;
4bc40d
+        if (min > min_latency)
4bc40d
+            min_latency = min;
4bc40d
+        if (max_latency == (pa_usec_t) -1 || max < max_latency)
4bc40d
+            max_latency = max;
4bc40d
+    }
4bc40d
+    if (max_latency == (pa_usec_t) -1) {
4bc40d
+        /* no outputs, use block size */
4bc40d
+        min_latency = u->default_min_latency;
4bc40d
+        max_latency = u->default_max_latency;
4bc40d
     }
4bc40d
+    else if (max_latency < min_latency)
4bc40d
+        max_latency = min_latency;
4bc40d
 
4bc40d
-    if (fixed_latency <= 0)
4bc40d
-        fixed_latency = u->block_usec;
4bc40d
+    /* never go below the min_latency or BLOCK_USEC */
4bc40d
+    max_latency = MIN (max_latency, MAX (min_latency, BLOCK_USEC));
4bc40d
 
4bc40d
-    pa_sink_set_fixed_latency_within_thread(u->sink, fixed_latency);
4bc40d
+    pa_log_debug("Sink update latency range %lu %lu", min_latency, max_latency);
4bc40d
+    pa_sink_set_latency_range_within_thread(u->sink, min_latency, max_latency);
4bc40d
 }
4bc40d
 
4bc40d
 /* Called from thread context of the io thread */
4bc40d
@@ -714,7 +757,6 @@ static void output_add_within_thread(struct output *o) {
4bc40d
 
4bc40d
 /* Called from thread context of the io thread */
4bc40d
 static void output_remove_within_thread(struct output *o) {
4bc40d
-
4bc40d
     pa_assert(o);
4bc40d
     pa_sink_assert_io_context(o->sink);
4bc40d
 
4bc40d
@@ -731,6 +773,28 @@ static void output_remove_within_thread(struct output *o) {
4bc40d
     }
4bc40d
 }
4bc40d
 
4bc40d
+/* Called from sink I/O thread context */
4bc40d
+static void sink_update_requested_latency(pa_sink *s) {
4bc40d
+    struct userdata *u;
4bc40d
+    struct output *o;
4bc40d
+
4bc40d
+    pa_sink_assert_ref(s);
4bc40d
+    pa_assert_se(u = s->userdata);
4bc40d
+
4bc40d
+    u->block_usec = pa_sink_get_requested_latency_within_thread(s);
4bc40d
+
4bc40d
+    if (u->block_usec == (pa_usec_t) -1)
4bc40d
+        u->block_usec = s->thread_info.max_latency;
4bc40d
+
4bc40d
+    pa_log_debug("Sink update requested latency %0.2f", (double) u->block_usec / PA_USEC_PER_MSEC);
4bc40d
+
4bc40d
+    /* Just hand this one over to all sink_inputs */
4bc40d
+    PA_LLIST_FOREACH(o, u->thread_info.active_outputs) {
4bc40d
+        pa_asyncmsgq_post(o->inq, PA_MSGOBJECT(o->sink_input), SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, u->block_usec, NULL, NULL);
4bc40d
+    }
4bc40d
+}
4bc40d
+
4bc40d
+
4bc40d
 /* Called from thread context of the io thread */
4bc40d
 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
4bc40d
     struct userdata *u = PA_SINK(o)->userdata;
4bc40d
@@ -769,13 +833,13 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
4bc40d
         case SINK_MESSAGE_ADD_OUTPUT:
4bc40d
             output_add_within_thread(data);
4bc40d
             update_max_request(u);
4bc40d
-            update_fixed_latency(u);
4bc40d
+            update_latency_range(u);
4bc40d
             return 0;
4bc40d
 
4bc40d
         case SINK_MESSAGE_REMOVE_OUTPUT:
4bc40d
             output_remove_within_thread(data);
4bc40d
             update_max_request(u);
4bc40d
-            update_fixed_latency(u);
4bc40d
+            update_latency_range(u);
4bc40d
             return 0;
4bc40d
 
4bc40d
         case SINK_MESSAGE_NEED:
4bc40d
@@ -801,9 +865,10 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
4bc40d
             update_max_request(u);
4bc40d
             break;
4bc40d
 
4bc40d
-        case SINK_MESSAGE_UPDATE_REQUESTED_LATENCY:
4bc40d
-            update_fixed_latency(u);
4bc40d
+        case SINK_MESSAGE_UPDATE_LATENCY_RANGE:
4bc40d
+            update_latency_range(u);
4bc40d
             break;
4bc40d
+
4bc40d
 }
4bc40d
 
4bc40d
     return pa_sink_process_msg(o, code, data, offset, chunk);
4bc40d
@@ -875,7 +940,7 @@ static int output_create_sink_input(struct output *o) {
4bc40d
     o->sink_input->process_rewind = sink_input_process_rewind_cb;
4bc40d
     o->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
4bc40d
     o->sink_input->update_max_request = sink_input_update_max_request_cb;
4bc40d
-    o->sink_input->update_sink_requested_latency = sink_input_update_sink_requested_latency_cb;
4bc40d
+    o->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
4bc40d
     o->sink_input->attach = sink_input_attach_cb;
4bc40d
     o->sink_input->detach = sink_input_detach_cb;
4bc40d
     o->sink_input->kill = sink_input_kill_cb;
4bc40d
@@ -966,7 +1031,6 @@ static void output_enable(struct output *o) {
4bc40d
             /* Enable the sink input. That means that the sink
4bc40d
              * is now asked for new data. */
4bc40d
             pa_sink_input_put(o->sink_input);
4bc40d
-
4bc40d
         }
4bc40d
     }
4bc40d
 
4bc40d
@@ -1129,6 +1193,7 @@ int pa__init(pa_module*m) {
4bc40d
     uint32_t idx;
4bc40d
     pa_sink_new_data data;
4bc40d
     uint32_t adjust_time_sec;
4bc40d
+    size_t nbytes;
4bc40d
 
4bc40d
     pa_assert(m);
4bc40d
 
4bc40d
@@ -1257,7 +1322,7 @@ int pa__init(pa_module*m) {
4bc40d
         pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Simultaneous Output");
4bc40d
     }
4bc40d
 
4bc40d
-    u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
4bc40d
+    u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY);
4bc40d
     pa_sink_new_data_done(&data);
4bc40d
 
4bc40d
     if (!u->sink) {
4bc40d
@@ -1267,13 +1332,20 @@ int pa__init(pa_module*m) {
4bc40d
 
4bc40d
     u->sink->parent.process_msg = sink_process_msg;
4bc40d
     u->sink->set_state = sink_set_state;
4bc40d
+    u->sink->update_requested_latency = sink_update_requested_latency;
4bc40d
     u->sink->userdata = u;
4bc40d
 
4bc40d
     pa_sink_set_rtpoll(u->sink, u->rtpoll);
4bc40d
     pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
4bc40d
 
4bc40d
     u->block_usec = BLOCK_USEC;
4bc40d
-    pa_sink_set_max_request(u->sink, pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec));
4bc40d
+    nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
4bc40d
+    pa_sink_set_max_request(u->sink, nbytes);
4bc40d
+    pa_sink_set_latency_range(u->sink, 0, u->block_usec);
4bc40d
+    /* pulse clamps the range, get the real values */
4bc40d
+    u->default_min_latency = u->sink->thread_info.min_latency;
4bc40d
+    u->default_max_latency = u->sink->thread_info.max_latency;
4bc40d
+
4bc40d
 
4bc40d
     if (!u->automatic) {
4bc40d
         const char*split_state;
4bc40d
-- 
4bc40d
1.9.3
4bc40d