diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-11-09 13:45:38 +0100 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-11-09 13:45:38 +0100 |
commit | 7282cdca0d22e8eb8454d9471fa82947488ac047 (patch) | |
tree | 66b669d9e63b7a992a2c52b91d511819aff9867c | |
parent | 7938442f77fafbc6c14d5072d14b773b289dc809 (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.c | 25 | ||||
-rw-r--r-- | src/modules/dbus/iface-device.c | 12 | ||||
-rw-r--r-- | src/modules/module-combine.c | 10 | ||||
-rw-r--r-- | src/modules/module-equalizer-sink.c | 7 | ||||
-rw-r--r-- | src/modules/module-esound-sink.c | 7 | ||||
-rw-r--r-- | src/modules/module-ladspa-sink.c | 8 | ||||
-rw-r--r-- | src/modules/module-loopback.c | 4 | ||||
-rw-r--r-- | src/modules/module-null-sink.c | 6 | ||||
-rw-r--r-- | src/modules/module-pipe-sink.c | 3 | ||||
-rw-r--r-- | src/modules/module-remap-sink.c | 7 | ||||
-rw-r--r-- | src/modules/module-tunnel.c | 9 | ||||
-rw-r--r-- | src/modules/rtp/module-rtp-recv.c | 4 | ||||
-rw-r--r-- | src/pulse/def.h | 5 | ||||
-rw-r--r-- | src/pulse/stream.c | 14 | ||||
-rw-r--r-- | src/pulsecore/cli-text.c | 4 | ||||
-rw-r--r-- | src/pulsecore/memblockq.c | 8 | ||||
-rw-r--r-- | src/pulsecore/protocol-native.c | 21 | ||||
-rw-r--r-- | src/pulsecore/sink-input.c | 5 | ||||
-rw-r--r-- | src/pulsecore/sink.c | 49 | ||||
-rw-r--r-- | src/pulsecore/sink.h | 4 | ||||
-rw-r--r-- | src/pulsecore/source-output.c | 4 | ||||
-rw-r--r-- | src/pulsecore/time-smoother.c | 2 |
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 /* |