[pulseaudio-commits] 8 commits - src/modules

Tanu Kaskinen tanuk at kemper.freedesktop.org
Wed Jul 13 22:14:26 UTC 2016


 src/modules/module-loopback.c |  169 ++++++++++++++++++------------------------
 1 file changed, 73 insertions(+), 96 deletions(-)

New commits:
commit dfa4f42480471a765578da116e8d7ab4c5c7545f
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:11 2016 +0200

    loopback: Stop tracking max_request and min_memblockq_length
    
    They are not needed any longer because the regulation is now based on the
    difference between current and configured latency.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 8a2b6c4..246d622 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -85,7 +85,6 @@ struct userdata {
     pa_usec_t latency;
 
     bool in_pop;
-    size_t min_memblockq_length;
 
     struct {
         int64_t send_counter;
@@ -96,9 +95,6 @@ struct userdata {
         size_t sink_input_buffer;
         pa_usec_t sink_latency;
         pa_usec_t sink_timestamp;
-
-        size_t min_memblockq_length;
-        size_t max_request;
     } latency_snapshot;
 };
 
@@ -122,8 +118,7 @@ static const char* const valid_modargs[] = {
 enum {
     SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
     SINK_INPUT_MESSAGE_REWIND,
-    SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT,
-    SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED
+    SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT
 };
 
 enum {
@@ -231,10 +226,6 @@ static void adjust_rates(struct userdata *u) {
 
     pa_log_debug("Loopback latency at base rate is %0.2f ms", (double)latency_at_optimum_rate / PA_USEC_PER_MSEC);
 
-    pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes",
-                u->latency_snapshot.max_request*2,
-                u->latency_snapshot.min_memblockq_length);
-
     /* Calculate new rate */
     new_rate = rate_controller(base_rate, u->adjust_time, latency_difference);
 
@@ -466,20 +457,6 @@ static void source_output_suspend_cb(pa_source_output *o, bool suspended) {
 }
 
 /* Called from output thread context */
-static void update_min_memblockq_length(struct userdata *u) {
-    size_t length;
-
-    pa_assert(u);
-    pa_sink_input_assert_io_context(u->sink_input);
-
-    length = pa_memblockq_get_length(u->memblockq);
-
-    if (u->min_memblockq_length == (size_t) -1 ||
-        length < u->min_memblockq_length)
-        u->min_memblockq_length = length;
-}
-
-/* Called from output thread context */
 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
     struct userdata *u;
 
@@ -501,8 +478,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
     chunk->length = PA_MIN(chunk->length, nbytes);
     pa_memblockq_drop(u->memblockq, chunk->length);
 
-    update_min_memblockq_length(u);
-
     return 0;
 }
 
@@ -544,8 +519,6 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
             else
                 pa_memblockq_flush_write(u->memblockq, true);
 
-            update_min_memblockq_length(u);
-
             /* Is this the end of an underrun? Then let's start things
              * right-away */
             if (!u->in_pop &&
@@ -573,15 +546,11 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
 
             u->recv_counter -= offset;
 
-            update_min_memblockq_length(u);
-
             return 0;
 
         case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
             size_t length;
 
-            update_min_memblockq_length(u);
-
             length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
 
             u->latency_snapshot.recv_counter = u->recv_counter;
@@ -591,23 +560,6 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
                                                pa_bytes_to_usec(length, &u->sink_input->sink->sample_spec);
             u->latency_snapshot.sink_timestamp = pa_rtclock_now();
 
-            u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
-
-            u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
-            u->min_memblockq_length = (size_t) -1;
-
-            return 0;
-        }
-
-        case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: {
-            /* This message is sent from the IO thread to the main
-             * thread! So don't be confused. All the user cases above
-             * are executed in thread context, but this one is not! */
-
-            pa_assert_ctl_context();
-
-            if (u->time_event)
-                adjust_rates(u);
             return 0;
         }
     }
@@ -630,8 +582,6 @@ static void sink_input_attach_cb(pa_sink_input *i) {
 
     pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
     pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
-
-    u->min_memblockq_length = (size_t) -1;
 }
 
 /* Called from output thread context */
@@ -669,7 +619,6 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
 
     pa_memblockq_set_prebuf(u->memblockq, nbytes*2);
     pa_log_info("Max request changed");
-    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL);
 }
 
 /* Called from main thread */

commit c03633766cc8b916565dce5ff2a7e4e263ca3b43
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:10 2016 +0200

    loopback: Adjust rate based on latency difference
    
    Replace the current latency controller with a modified P-controller. For
    better readability separate the controller function. For small latency
    differences, the controller forms a classical P-controller while it saturates
    at 1% deviation from the base rate for large latency differences.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 89a8909..8a2b6c4 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -168,11 +168,34 @@ static void teardown(struct userdata *u) {
     }
 }
 
+/* rate controller
+ * - maximum deviation from base rate is less than 1%
+ * - can create audible artifacts by changing the rate too quickly
+ * - exhibits hunting with USB or Bluetooth sources
+ */
+static uint32_t rate_controller(
+                uint32_t base_rate,
+                pa_usec_t adjust_time,
+                int32_t latency_difference_usec) {
+
+    uint32_t new_rate;
+    double min_cycles;
+
+    /* Calculate best rate to correct the current latency offset, limit at
+     * slightly below 1% difference from base_rate */
+    min_cycles = (double)abs(latency_difference_usec) / adjust_time / 0.01 + 1;
+    new_rate = base_rate * (1.0 + (double)latency_difference_usec / min_cycles / adjust_time);
+
+    return new_rate;
+}
+
 /* Called from main context */
 static void adjust_rates(struct userdata *u) {
-    size_t buffer, fs;
+    size_t buffer;
     uint32_t old_rate, base_rate, new_rate;
+    int32_t latency_difference;
     pa_usec_t current_buffer_latency, snapshot_delay, current_source_sink_latency, current_latency, latency_at_optimum_rate;
+    pa_usec_t final_latency;
 
     pa_assert(u);
     pa_assert_ctl_context();
@@ -197,6 +220,9 @@ static void adjust_rates(struct userdata *u) {
     /* Latency at base rate */
     latency_at_optimum_rate = current_source_sink_latency + current_buffer_latency * old_rate / base_rate;
 
+    final_latency = u->latency;
+    latency_difference = (int32_t)((int64_t)latency_at_optimum_rate - final_latency);
+
     pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
                 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
                 (double) current_buffer_latency / PA_USEC_PER_MSEC,
@@ -209,26 +235,10 @@ static void adjust_rates(struct userdata *u) {
                 u->latency_snapshot.max_request*2,
                 u->latency_snapshot.min_memblockq_length);
 
-    fs = pa_frame_size(&u->sink_input->sample_spec);
-
-    if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
-        new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
-    else
-        new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
-
-    if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) {
-        pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate);
-        new_rate = base_rate;
-    } else {
-        if (base_rate < new_rate + 20 && new_rate < base_rate + 20)
-          new_rate = base_rate;
-        /* Do the adjustment in small steps; 2‰ can be considered inaudible */
-        if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) {
-            pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate);
-            new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002));
-        }
-    }
+    /* Calculate new rate */
+    new_rate = rate_controller(base_rate, u->adjust_time, latency_difference);
 
+    /* Set rate */
     pa_sink_input_set_rate(u->sink_input, new_rate);
     pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);
 }

commit 4a11742652a99b00f86c8de2db7038c65fdf2225
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:09 2016 +0200

    loopback: Restart timer after 1/3 second
    
    After switching source or sink, call adjust_rates after a third of a second
    instead of waiting one full adjust time. This will ensure that latency regulation
    starts as soon as possible.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 2fd2be0..89a8909 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -251,13 +251,16 @@ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct tim
     adjust_rates(u);
 }
 
-/* Called from main context */
+/* Called from main context
+ * When source or sink changes, give it a third of a second to settle down, then call adjust_rates for the first time */
 static void enable_adjust_timer(struct userdata *u, bool enable) {
     if (enable) {
-        if (u->time_event || u->adjust_time <= 0)
+        if (!u->adjust_time)
             return;
+        if (u->time_event)
+            u->core->mainloop->time_free(u->time_event);
 
-        u->time_event = pa_core_rttime_new(u->module->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
+        u->time_event = pa_core_rttime_new(u->module->core, pa_rtclock_now() + 333 * PA_USEC_PER_MSEC, time_callback, u);
     } else {
         if (!u->time_event)
             return;

commit 919cc2f3f9ae0e2368b08086b9b566a53ec51481
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:08 2016 +0200

    loopback: Move timer restart and snapshots to timer callback
    
    Restaring the timer and obtaining the latency snapshots belong to the timer callback.
    To maintain an adjust time as near as possible to the configured value, the timer is
    now restarted immediately at the beginning of the timer callback.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 28b087a..2fd2be0 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -177,9 +177,6 @@ static void adjust_rates(struct userdata *u) {
     pa_assert(u);
     pa_assert_ctl_context();
 
-    pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
-    pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
-
     /* Rates and latencies*/
     old_rate = u->sink_input->sample_spec.rate;
     base_rate = u->source_output->sample_spec.rate;
@@ -234,8 +231,6 @@ static void adjust_rates(struct userdata *u) {
 
     pa_sink_input_set_rate(u->sink_input, new_rate);
     pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);
-
-    pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
 }
 
 /* Called from main context */
@@ -246,6 +241,13 @@ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct tim
     pa_assert(a);
     pa_assert(u->time_event == e);
 
+    /* Restart timer right away */
+    pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
+
+    /* Get sink and source latency snapshot */
+    pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
+    pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
+
     adjust_rates(u);
 }
 

commit b494bd62dd39201140d46339d727471d2d4db245
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:07 2016 +0200

    loopback: Change memblockq length
    
    The size of the memblockq must be increased to allow for long latencies
    at high sample rates.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 6539a95..28b087a 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -59,7 +59,7 @@ PA_MODULE_USAGE(
 
 #define DEFAULT_LATENCY_MSEC 200
 
-#define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
+#define MEMBLOCKQ_MAXLENGTH (1024*1024*32)
 
 #define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC)
 

commit 8c39a5c16c8ba1f84b286688ee42cd551fed4794
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:06 2016 +0200

    loopback: Improve latency estimation
    
    To improve the overall latency estimation, the delay between the two snapshots
    is taken into account. To minimize the snapshot delay, the order of the snapshots
    is reverted. Additionally the latency at the base rate is calculated. It will be
    used later as the input to the latency controller.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index aa559aa..6539a95 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -172,36 +172,47 @@ static void teardown(struct userdata *u) {
 static void adjust_rates(struct userdata *u) {
     size_t buffer, fs;
     uint32_t old_rate, base_rate, new_rate;
-    pa_usec_t buffer_latency;
+    pa_usec_t current_buffer_latency, snapshot_delay, current_source_sink_latency, current_latency, latency_at_optimum_rate;
 
     pa_assert(u);
     pa_assert_ctl_context();
 
-    pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
     pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
+    pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
 
-    buffer = u->latency_snapshot.sink_input_buffer;
+    /* Rates and latencies*/
+    old_rate = u->sink_input->sample_spec.rate;
+    base_rate = u->source_output->sample_spec.rate;
 
+    buffer = u->latency_snapshot.sink_input_buffer;
     if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
         buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
     else
         buffer = PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));
 
-    buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
+    current_buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
+    snapshot_delay = u->latency_snapshot.source_timestamp - u->latency_snapshot.sink_timestamp;
+    current_source_sink_latency = u->latency_snapshot.sink_latency + u->latency_snapshot.source_latency - snapshot_delay;
+
+    /* Current latency */
+    current_latency = current_source_sink_latency + current_buffer_latency;
+
+    /* Latency at base rate */
+    latency_at_optimum_rate = current_source_sink_latency + current_buffer_latency * old_rate / base_rate;
 
     pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
                 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
-                (double) buffer_latency / PA_USEC_PER_MSEC,
+                (double) current_buffer_latency / PA_USEC_PER_MSEC,
                 (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
-                ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);
+                (double) current_latency / PA_USEC_PER_MSEC);
+
+    pa_log_debug("Loopback latency at base rate is %0.2f ms", (double)latency_at_optimum_rate / PA_USEC_PER_MSEC);
 
     pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes",
                 u->latency_snapshot.max_request*2,
                 u->latency_snapshot.min_memblockq_length);
 
     fs = pa_frame_size(&u->sink_input->sample_spec);
-    old_rate = u->sink_input->sample_spec.rate;
-    base_rate = u->source_output->sample_spec.rate;
 
     if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
         new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;

commit 2d7a5cda430cd7c350ffe457f572006c32953fe5
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:05 2016 +0200

    loopback: Improve latency estimation in snapshots
    
    The delay and render memblockq are using the source and sink sample specs,
    so using pa_bytes_to_usec() will produce better estimates of the delays than
    using pa_resmpler_result(). Because the delays are considered to be part of
    the sink or source latency, they are added to them. source_output_buffer
    becomes obsolete.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 22615d3..aa559aa 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -89,7 +89,6 @@ struct userdata {
 
     struct {
         int64_t send_counter;
-        size_t source_output_buffer;
         pa_usec_t source_latency;
         pa_usec_t source_timestamp;
 
@@ -181,9 +180,7 @@ static void adjust_rates(struct userdata *u) {
     pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
     pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
 
-    buffer =
-        u->latency_snapshot.sink_input_buffer +
-        u->latency_snapshot.source_output_buffer;
+    buffer = u->latency_snapshot.sink_input_buffer;
 
     if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
         buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
@@ -316,8 +313,9 @@ static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data,
             length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
 
             u->latency_snapshot.send_counter = u->send_counter;
-            u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
-            u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
+            /* Add content of delay memblockq to the source latency */
+            u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source) +
+                                                 pa_bytes_to_usec(length, &u->source_output->source->sample_spec);
             u->latency_snapshot.source_timestamp = pa_rtclock_now();
 
             return 0;
@@ -561,10 +559,10 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
             length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
 
             u->latency_snapshot.recv_counter = u->recv_counter;
-            u->latency_snapshot.sink_input_buffer =
-                pa_memblockq_get_length(u->memblockq) +
-                (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
-            u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
+            u->latency_snapshot.sink_input_buffer = pa_memblockq_get_length(u->memblockq);
+            /* Add content of render memblockq to sink latency */
+            u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink) +
+                                               pa_bytes_to_usec(length, &u->sink_input->sink->sample_spec);
             u->latency_snapshot.sink_timestamp = pa_rtclock_now();
 
             u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);

commit 86e54c8c138b47701a79a8e524425c5e255b721b
Author: Georg Chini <georg at chini.tk>
Date:   Sun Jun 5 21:05:04 2016 +0200

    loopback: Save time stamps during latency snapshots
    
    Saving the time stamps is necessary to account for the delay between the two
    latency snapshots. Time stamps will be used in later patches.

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index f4d0761..22615d3 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -91,10 +91,12 @@ struct userdata {
         int64_t send_counter;
         size_t source_output_buffer;
         pa_usec_t source_latency;
+        pa_usec_t source_timestamp;
 
         int64_t recv_counter;
         size_t sink_input_buffer;
         pa_usec_t sink_latency;
+        pa_usec_t sink_timestamp;
 
         size_t min_memblockq_length;
         size_t max_request;
@@ -316,6 +318,7 @@ static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data,
             u->latency_snapshot.send_counter = u->send_counter;
             u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
             u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
+            u->latency_snapshot.source_timestamp = pa_rtclock_now();
 
             return 0;
         }
@@ -562,6 +565,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
                 pa_memblockq_get_length(u->memblockq) +
                 (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
             u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
+            u->latency_snapshot.sink_timestamp = pa_rtclock_now();
 
             u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
 



More information about the pulseaudio-commits mailing list