summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2009-11-09 13:45:38 +0100
committerWim Taymans <wim.taymans@collabora.co.uk>2009-11-09 13:45:38 +0100
commit7282cdca0d22e8eb8454d9471fa82947488ac047 (patch)
tree66b669d9e63b7a992a2c52b91d511819aff9867c
parent7938442f77fafbc6c14d5072d14b773b289dc809 (diff)
interpol: timing improvement experimenttest
Try to improve the client timing values by exposing the server side time vs audio clock estimations.
-rw-r--r--src/modules/alsa/alsa-sink.c25
-rw-r--r--src/modules/dbus/iface-device.c12
-rw-r--r--src/modules/module-combine.c10
-rw-r--r--src/modules/module-equalizer-sink.c7
-rw-r--r--src/modules/module-esound-sink.c7
-rw-r--r--src/modules/module-ladspa-sink.c8
-rw-r--r--src/modules/module-loopback.c4
-rw-r--r--src/modules/module-null-sink.c6
-rw-r--r--src/modules/module-pipe-sink.c3
-rw-r--r--src/modules/module-remap-sink.c7
-rw-r--r--src/modules/module-tunnel.c9
-rw-r--r--src/modules/rtp/module-rtp-recv.c4
-rw-r--r--src/pulse/def.h5
-rw-r--r--src/pulse/stream.c14
-rw-r--r--src/pulsecore/cli-text.c4
-rw-r--r--src/pulsecore/memblockq.c8
-rw-r--r--src/pulsecore/protocol-native.c21
-rw-r--r--src/pulsecore/sink-input.c5
-rw-r--r--src/pulsecore/sink.c49
-rw-r--r--src/pulsecore/sink.h4
-rw-r--r--src/pulsecore/source-output.c4
-rw-r--r--src/pulsecore/time-smoother.c2
22 files changed, 138 insertions, 80 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 37419d98c..8e76c8d5b 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -826,8 +826,8 @@ static void update_smoother(struct userdata *u) {
u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL);
}
-static pa_usec_t sink_get_latency(struct userdata *u) {
- pa_usec_t r;
+static void sink_get_latency(struct userdata *u, pa_usec_t *r) {
+ pa_usec_t latency = 0;
int64_t delay;
pa_usec_t now1, now2;
@@ -836,14 +836,18 @@ static pa_usec_t sink_get_latency(struct userdata *u) {
now1 = pa_rtclock_now();
now2 = pa_smoother_get(u->smoother, now1);
- delay = (int64_t) pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - (int64_t) now2;
+ if (u->pcm_handle) {
+ delay = (int64_t) pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - (int64_t) now2;
- r = delay >= 0 ? (pa_usec_t) delay : 0;
+ latency = delay >= 0 ? (pa_usec_t) delay : 0;
- if (u->memchunk.memblock)
- r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
+ if (u->memchunk.memblock)
+ latency += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
+ }
- return r;
+ r[0] = latency;
+ r[1] = now1;
+ r[2] = now2;
}
static int build_pollfd(struct userdata *u) {
@@ -1021,12 +1025,9 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
switch (code) {
case PA_SINK_MESSAGE_GET_LATENCY: {
- pa_usec_t r = 0;
-
- if (u->pcm_handle)
- r = sink_get_latency(u);
+ pa_usec_t *r = (pa_usec_t*) data;
- *((pa_usec_t*) data) = r;
+ sink_get_latency(u, r);
return 0;
}
diff --git a/src/modules/dbus/iface-device.c b/src/modules/dbus/iface-device.c
index 3a747a447..175973a87 100644
--- a/src/modules/dbus/iface-device.c
+++ b/src/modules/dbus/iface-device.c
@@ -599,6 +599,7 @@ static void handle_get_has_dynamic_latency(DBusConnection *conn, DBusMessage *ms
static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
pa_dbusiface_device *d = userdata;
dbus_uint64_t latency = 0;
+ pa_usec_t r, now1, now2;
pa_assert(conn);
pa_assert(msg);
@@ -612,7 +613,12 @@ static void handle_get_latency(DBusConnection *conn, DBusMessage *msg, void *use
"Source %s doesn't support latency querying.", d->source->name);
return;
- latency = (d->type == DEVICE_TYPE_SINK) ? pa_sink_get_latency(d->sink) : pa_source_get_latency(d->source);
+ if (d->type == DEVICE_TYPE_SINK)
+ pa_sink_get_latency(d->sink, &r, &now1, &now2);
+ else
+ r = pa_source_get_latency(d->source);
+
+ latency = r;
pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &latency);
}
@@ -814,6 +820,7 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
unsigned n_ports = 0;
const char *active_port = NULL;
unsigned i = 0;
+ pa_usec_t r, now1, now2;
pa_assert(conn);
pa_assert(msg);
@@ -836,7 +843,8 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
has_hardware_mute = d->sink->flags & PA_SINK_HW_MUTE_CTRL;
configured_latency = pa_sink_get_requested_latency(d->sink);
has_dynamic_latency = d->sink->flags & PA_SINK_DYNAMIC_LATENCY;
- latency = pa_sink_get_latency(d->sink);
+ pa_sink_get_latency(d->sink, &r, &now1, &now2);
+ latency = r;
is_hardware_device = d->sink->flags & PA_SINK_HARDWARE;
is_network_device = d->sink->flags & PA_SINK_NETWORK;
state = pa_sink_get_state(d->sink);
diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index a186c899b..f58f9f7f9 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -734,17 +734,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
break;
case PA_SINK_MESSAGE_GET_LATENCY: {
- pa_usec_t x, y, c, *delay = data;
+ pa_usec_t x, y, c, *r = data;
- x = pa_rtclock_now();
- y = pa_smoother_get(u->thread_info.smoother, x);
+ r[1] = pa_rtclock_now();
+ r[2] = pa_smoother_get(u->thread_info.smoother, x);
c = pa_bytes_to_usec(u->thread_info.counter, &u->sink->sample_spec);
if (y < c)
- *delay = c - y;
+ r[0] = c - y;
else
- *delay = 0;
+ r[0] = 0;
return 0;
}
diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c
index 7c0ccd3a4..9e67e0818 100644
--- a/src/modules/module-equalizer-sink.c
+++ b/src/modules/module-equalizer-sink.c
@@ -230,6 +230,7 @@ static void alloc_input_buffers(struct userdata *u, size_t min_buffer_length){
/* Called from I/O thread context */
static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK(o)->userdata;
+ pa_usec_t latency, now1, now2;
switch (code) {
@@ -245,10 +246,10 @@ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t of
return 0;
}
- *((pa_usec_t*) data) =
- /* Get the latency of the master sink */
- pa_sink_get_latency_within_thread(u->sink_input->sink) +
+ /* Get the latency of the master sink */
+ pa_sink_get_latency_within_thread(u->sink_input->sink, &latency, &now1, &now2);
+ *((pa_usec_t*) data) = latency +
/* Add the latency internal to our sink input on top */
pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
// pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec);
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index d7c678ca9..888f0839d 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -166,12 +166,13 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
break;
case PA_SINK_MESSAGE_GET_LATENCY: {
- pa_usec_t w, r;
+ pa_usec_t *r = (pa_usec_t *)data, w;
- r = pa_smoother_get(u->smoother, pa_rtclock_now());
+ r[1] = pa_rtclock_now();
+ r[2] = pa_smoother_get(u->smoother, r[1]);
w = pa_bytes_to_usec((uint64_t) u->offset + u->memchunk.length, &u->sink->sample_spec);
- *((pa_usec_t*) data) = w > r ? w - r : 0;
+ r[0] = w > r[2] ? w - r[2] : 0;
return 0;
}
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index 994c778fe..6b5ecf87f 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -103,6 +103,7 @@ static const char* const valid_modargs[] = {
/* Called from I/O thread context */
static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK(o)->userdata;
+ pa_usec_t latency, now1, now2;
switch (code) {
@@ -117,11 +118,10 @@ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t of
return 0;
}
- *((pa_usec_t*) data) =
-
- /* Get the latency of the master sink */
- pa_sink_get_latency_within_thread(u->sink_input->sink) +
+ /* Get the latency of the master sink */
+ pa_sink_get_latency_within_thread(u->sink_input->sink, &latency, &now1, &now2);
+ *((pa_usec_t*) data) = latency +
/* Add the latency internal to our sink input on top */
pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index bb0182b00..e337d0838 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -467,6 +467,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
size_t length;
+ pa_usec_t latency, now1, now2;
update_min_memblockq_length(u);
@@ -476,7 +477,8 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
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);
+ pa_sink_get_latency_within_thread(u->sink_input->sink, &latency, &now1, &now2);
+ u->latency_snapshot.sink_latency = latency;
u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index 74a2ebb1f..0bcae2bae 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -108,10 +108,10 @@ static int sink_process_msg(
break;
case PA_SINK_MESSAGE_GET_LATENCY: {
- pa_usec_t now;
+ pa_usec_t *r = data;
- now = pa_rtclock_now();
- *((pa_usec_t*) data) = u->timestamp > now ? u->timestamp - now : 0ULL;
+ r[1] = r[2] = pa_rtclock_now();
+ r[0] = u->timestamp > r[1] ? u->timestamp - r[1] : 0ULL;
return 0;
}
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index 10cc34150..c888ea727 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -102,6 +102,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
case PA_SINK_MESSAGE_GET_LATENCY: {
size_t n = 0;
int l;
+ pa_usec_t *r = data;
#ifdef FIONREAD
if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0)
@@ -110,7 +111,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
n += u->memchunk.length;
- *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
+ r[0] = pa_bytes_to_usec(n, &u->sink->sample_spec);
return 0;
}
}
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index 43748bd0f..b4b0913fe 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -78,6 +78,7 @@ static const char* const valid_modargs[] = {
/* Called from I/O thread context */
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK(o)->userdata;
+ pa_usec_t latency, now1, now2;
switch (code) {
@@ -91,10 +92,10 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
return 0;
}
- *((pa_usec_t*) data) =
- /* Get the latency of the master sink */
- pa_sink_get_latency_within_thread(u->sink_input->sink) +
+ /* Get the latency of the master sink */
+ pa_sink_get_latency_within_thread(u->sink_input->sink, &latency, &now1, &now2);
+ *((pa_usec_t*) data) = latency +
/* Add the latency internal to our sink input on top */
pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index c97de3a11..419d3e9fd 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -500,12 +500,15 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
}
case PA_SINK_MESSAGE_GET_LATENCY: {
- pa_usec_t yl, yr, *usec = data;
+ pa_usec_t yl, *r = data;
+
+ r[1] = pa_rtclock_now();
+ r[2] = pa_smoother_get(u->smoother, r[1]);
yl = pa_bytes_to_usec((uint64_t) u->counter, &u->sink->sample_spec);
- yr = pa_smoother_get(u->smoother, pa_rtclock_now());
- *usec = yl > yr ? yl - yr : 0;
+ r[0] = yl > r[2] ? yl - r[2] : 0;
+
return 0;
}
diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c
index 7dbb1efa6..1c88ba6c2 100644
--- a/src/modules/rtp/module-rtp-recv.c
+++ b/src/modules/rtp/module-rtp-recv.c
@@ -286,7 +286,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
pa_atomic_store(&s->timestamp, (int) now.tv_sec);
if (s->last_rate_update + RATE_UPDATE_INTERVAL < pa_timeval_load(&now)) {
- pa_usec_t wi, ri, render_delay, sink_delay = 0, latency, fix;
+ pa_usec_t wi, ri, render_delay, sink_delay = 0, latency, fix, now1, now2;
unsigned fix_samples;
pa_log_debug("Updating sample rate");
@@ -296,7 +296,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
pa_log_debug("wi=%lu ri=%lu", (unsigned long) wi, (unsigned long) ri);
- sink_delay = pa_sink_get_latency_within_thread(s->sink_input->sink);
+ pa_sink_get_latency_within_thread(s->sink_input->sink, &sink_delay, &now1, &now2);
render_delay = pa_bytes_to_usec(pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq), &s->sink_input->sink->sample_spec);
if (ri > render_delay+sink_delay)
diff --git a/src/pulse/def.h b/src/pulse/def.h
index 30a076d55..3e177eff4 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -651,6 +651,11 @@ typedef struct pa_timing_info {
* underrun. playing will tell you which case it is. \since
* 0.9.11 */
+ pa_usec_t now1;
+ /**< The time of the sink. \since 0.9.11 */
+ pa_usec_t now2;
+ /**< The time of the audio card. \since 0.9.11 */
+
} pa_timing_info;
/** A structure for the spawn api. This may be used to integrate auto
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 299796256..fbad2fb3a 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1542,6 +1542,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command,
pa_timing_info *i;
pa_bool_t playing = FALSE;
uint64_t underrun_for = 0, playing_for = 0;
+ pa_usec_t now1 = 0, now2 = 0;
pa_assert(pd);
pa_assert(o);
@@ -1583,6 +1584,15 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command,
goto finish;
}
+ if (o->context->version >= 17 &&
+ o->stream->direction == PA_STREAM_PLAYBACK)
+ if (pa_tagstruct_get_usec(t, &now1) < 0 ||
+ pa_tagstruct_get_usec(t, &now2) < 0) {
+
+ pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ goto finish;
+ }
+
if (!pa_tagstruct_eof(t)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
@@ -1592,6 +1602,9 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command,
i->write_index_corrupt = FALSE;
i->read_index_corrupt = FALSE;
+ i->now1 = now1;
+ i->now2 = now2;
+
i->playing = (int) playing;
i->since_underrun = (int64_t) (playing ? playing_for : underrun_for);
@@ -1701,6 +1714,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command,
if ((o->stream->direction == PA_STREAM_PLAYBACK && !i->read_index_corrupt) ||
(o->stream->direction == PA_STREAM_RECORD && !i->write_index_corrupt))
pa_smoother_put(o->stream->smoother, u, calc_time(o->stream, TRUE));
+ //pa_smoother_put(o->stream->smoother, u, i->now2);
if (i->playing)
pa_smoother_resume(o->stream->smoother, x, TRUE);
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 23a57d370..7d7870604 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -220,9 +220,11 @@ char *pa_sink_list_to_string(pa_core *c) {
vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
const char *cmn;
+ pa_usec_t latency, now1, now2;
cmn = pa_channel_map_to_pretty_name(&sink->channel_map);
+ pa_sink_get_latency(sink, &latency, &now1, &now2);
pa_strbuf_printf(
s,
@@ -273,7 +275,7 @@ char *pa_sink_list_to_string(pa_core *c) {
sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "",
sink->n_volume_steps,
pa_yes_no(pa_sink_get_mute(sink, FALSE)),
- (double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC,
+ (double) latency / (double) PA_USEC_PER_MSEC,
(unsigned long) pa_sink_get_max_request(sink) / 1024,
(unsigned long) pa_sink_get_max_rewind(sink) / 1024,
sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index 32758be32..bd4f8f1ae 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -562,10 +562,18 @@ void pa_memblockq_rewind(pa_memblockq *bq, size_t length) {
pa_assert(bq);
pa_assert(length % bq->base == 0);
+ pa_log ("%p, before rewind: %lld, %lld, %lld", bq, bq->read_index, bq->missing, length);
+
+#if 0
/* This is kind of the inverse of pa_memblockq_drop() */
+ if (bq->read_index < length)
+ length = bq->read_index;
+#endif
bq->read_index -= (int64_t) length;
bq->missing -= (int64_t) length;
+
+ pa_log ("%p, after rewind: %lld, %lld, %lld", bq, bq->read_index, bq->missing, length);
}
pa_bool_t pa_memblockq_is_readable(pa_memblockq *bq) {
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index bb29a196d..13cfb9763 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -134,6 +134,7 @@ typedef struct playback_stream {
size_t render_memblockq_length;
pa_usec_t current_sink_latency;
uint64_t playing_for, underrun_for;
+ pa_usec_t now1, now2;
} playback_stream;
#define PLAYBACK_STREAM(o) (playback_stream_cast(o))
@@ -1431,16 +1432,17 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
return 0;
}
- case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
+ case SINK_INPUT_MESSAGE_UPDATE_LATENCY: {
/* Atomically get a snapshot of all timing parameters... */
s->read_index = pa_memblockq_get_read_index(s->memblockq);
s->write_index = pa_memblockq_get_write_index(s->memblockq);
s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
- s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
+ pa_sink_get_latency_within_thread(s->sink_input->sink, &s->current_sink_latency, &s->now1, &s->now2);
s->underrun_for = s->sink_input->thread_info.underrun_for;
s->playing_for = s->sink_input->thread_info.playing_for;
return 0;
+ }
case PA_SINK_INPUT_MESSAGE_SET_STATE: {
int64_t windex;
@@ -1668,6 +1670,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_source_output *o = PA_SOURCE_OUTPUT(_o);
record_stream *s;
+ pa_usec_t now1, now2;
pa_source_output_assert_ref(o);
s = RECORD_STREAM(o->userdata);
@@ -1676,7 +1679,10 @@ static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata,
switch (code) {
case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
/* Atomically get a snapshot of all timing parameters... */
- s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
+ if (o->source->monitor_of)
+ pa_sink_get_latency_within_thread(o->source->monitor_of, &s->current_monitor_latency, &now1, &now2);
+ else
+ s->current_monitor_latency = 0;
s->current_source_latency = pa_source_get_latency_within_thread(o->source);
s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
return 0;
@@ -2599,6 +2605,10 @@ static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uin
pa_tagstruct_putu64(reply, s->underrun_for);
pa_tagstruct_putu64(reply, s->playing_for);
}
+ if (c->version >= 17) {
+ pa_tagstruct_put_usec (reply, s->now1);
+ pa_tagstruct_put_usec (reply, s->now2);
+ }
pa_pstream_send_tagstruct(c->pstream, reply);
}
@@ -2846,12 +2856,15 @@ static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, co
static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
pa_sample_spec fixed_ss;
+ pa_usec_t latency, now1, now2;
pa_assert(t);
pa_sink_assert_ref(sink);
fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
+ pa_sink_get_latency(sink, &latency, &now1, &now2);
+
pa_tagstruct_put(
t,
PA_TAG_U32, sink->index,
@@ -2864,7 +2877,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
- PA_TAG_USEC, pa_sink_get_latency(sink),
+ PA_TAG_USEC, sink,
PA_TAG_STRING, sink->driver,
PA_TAG_U32, sink->flags,
PA_TAG_INVALID);
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 1af2823f9..5ba20795a 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1455,10 +1455,11 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
return 0;
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
- pa_usec_t *r = userdata;
+ pa_usec_t *r = userdata, latency, now1, now2;
r[0] += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);
- r[1] += pa_sink_get_latency_within_thread(i->sink);
+ pa_sink_get_latency_within_thread(i->sink, &latency, &now1, &now2);
+ r[1] += latency;
return 0;
}
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 971436d30..442bba501 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1115,8 +1115,8 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
}
/* Called from main thread */
-pa_usec_t pa_sink_get_latency(pa_sink *s) {
- pa_usec_t usec = 0;
+void pa_sink_get_latency(pa_sink *s, pa_usec_t *latency, pa_usec_t *now1, pa_usec_t *now2) {
+ pa_usec_t r[3] = { 0, 0, 0 };
pa_sink_assert_ref(s);
pa_assert_ctl_context();
@@ -1124,21 +1124,18 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) {
/* The returned value is supposed to be in the time domain of the sound card! */
- if (s->state == PA_SINK_SUSPENDED)
- return 0;
-
- if (!(s->flags & PA_SINK_LATENCY))
- return 0;
-
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
+ if (s->state != PA_SINK_SUSPENDED && (s->flags & PA_SINK_LATENCY))
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
- return usec;
+ *latency = r[0];
+ *now1 = r[1];
+ *now2 = r[2];
}
/* Called from IO thread */
-pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
- pa_usec_t usec = 0;
+void pa_sink_get_latency_within_thread(pa_sink *s, pa_usec_t *latency, pa_usec_t *now1, pa_usec_t *now2) {
pa_msgobject *o;
+ pa_usec_t r[3] = { 0, 0, 0 };
pa_sink_assert_ref(s);
pa_sink_assert_io_context(s);
@@ -1146,20 +1143,18 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
/* The returned value is supposed to be in the time domain of the sound card! */
- if (s->thread_info.state == PA_SINK_SUSPENDED)
- return 0;
-
- if (!(s->flags & PA_SINK_LATENCY))
- return 0;
+ if (s->thread_info.state != PA_SINK_SUSPENDED && (s->flags & PA_SINK_LATENCY)) {
+ o = PA_MSGOBJECT(s);
- o = PA_MSGOBJECT(s);
+ /* FIXME: We probably should make this a proper vtable callback instead of going through process_msg() */
- /* FIXME: We probably should make this a proper vtable callback instead of going through process_msg() */
-
- if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
- return -1;
+ if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0)
+ r[0] = -1;
+ }
- return usec;
+ *latency = r[0];
+ *now1 = r[1];
+ *now2 = r[2];
}
/* Called from main context */
@@ -1851,11 +1846,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_assert(!i->thread_info.sync_prev);
if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
- pa_usec_t usec = 0;
+ pa_usec_t usec = 0, now1, now2;
size_t sink_nbytes, total_nbytes;
/* Get the latency of the sink */
- usec = pa_sink_get_latency_within_thread(s);
+ pa_sink_get_latency_within_thread(s, &usec, &now1, &now2);
sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
@@ -1910,11 +1905,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
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;
+ pa_usec_t usec = 0, now1, now2;
size_t nbytes;
/* Get the latency of the sink */
- usec = pa_sink_get_latency_within_thread(s);
+ pa_sink_get_latency_within_thread(s, &usec, &now1, &now2);
nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
if (nbytes > 0)
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index ba547fc32..a2fe9eddb 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -295,7 +295,7 @@ unsigned pa_device_init_priority(pa_proplist *p);
/**** May be called by everyone, from main context */
/* The returned value is supposed to be in the time domain of the sound card! */
-pa_usec_t pa_sink_get_latency(pa_sink *s);
+void pa_sink_get_latency(pa_sink *s, pa_usec_t *latency, pa_usec_t *now1, pa_usec_t *now2);
pa_usec_t pa_sink_get_requested_latency(pa_sink *s);
void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency);
pa_usec_t pa_sink_get_fixed_latency(pa_sink *s);
@@ -355,7 +355,7 @@ void pa_sink_request_rewind(pa_sink*s, size_t nbytes);
void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic);
-pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s);
+void pa_sink_get_latency_within_thread(pa_sink *s, pa_usec_t *latency, pa_usec_t *now1, pa_usec_t *now2);
pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
void pa_device_port_free(pa_device_port *p);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 57ccc067e..3713a6c0c 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -453,7 +453,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
limit = o->process_rewind ? 0 : o->source->thread_info.max_rewind;
if (limit > 0 && o->source->monitor_of) {
- pa_usec_t latency;
+ pa_usec_t latency, now1, now2;
size_t n;
/* Hmm, check the latency for knowing how much of the buffered
@@ -463,7 +463,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
* of the queued data is actually still changeable. Hence
* FIXME! */
- latency = pa_sink_get_latency_within_thread(o->source->monitor_of);
+ pa_sink_get_latency_within_thread(o->source->monitor_of, &latency, &now1, &now2);
n = pa_usec_to_bytes(latency, &o->source->sample_spec);
diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c
index 1371ad562..a4e1fefa6 100644
--- a/src/pulsecore/time-smoother.c
+++ b/src/pulsecore/time-smoother.c
@@ -32,6 +32,8 @@
#include "time-smoother.h"
+#undef DEBUG_DATA
+
#define HISTORY_MAX 64
/*