diff options
Diffstat (limited to 'src/pulsecore')
-rw-r--r-- | src/pulsecore/cli-text.c | 12 | ||||
-rw-r--r-- | src/pulsecore/dbus-shared.c | 12 | ||||
-rw-r--r-- | src/pulsecore/dbus-util.c | 21 | ||||
-rw-r--r-- | src/pulsecore/log.h | 1 | ||||
-rw-r--r-- | src/pulsecore/memblockq.c | 52 | ||||
-rw-r--r-- | src/pulsecore/protocol-native.c | 14 | ||||
-rw-r--r-- | src/pulsecore/sink-input.c | 90 | ||||
-rw-r--r-- | src/pulsecore/sink-input.h | 12 | ||||
-rw-r--r-- | src/pulsecore/sink.c | 158 | ||||
-rw-r--r-- | src/pulsecore/sink.h | 8 | ||||
-rw-r--r-- | src/pulsecore/socket-server.c | 1 | ||||
-rw-r--r-- | src/pulsecore/source-output.c | 30 | ||||
-rw-r--r-- | src/pulsecore/source-output.h | 4 | ||||
-rw-r--r-- | src/pulsecore/source.c | 55 | ||||
-rw-r--r-- | src/pulsecore/source.h | 2 | ||||
-rw-r--r-- | src/pulsecore/time-smoother.c | 42 |
16 files changed, 370 insertions, 144 deletions
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 324f83c8..b0911ef1 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -288,7 +288,11 @@ char *pa_sink_list_to_string(pa_core *c) { (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC); - } + } else + pa_strbuf_printf( + s, + "\tfixed latency: %0.2f ms\n", + (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC); if (sink->card) pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name); @@ -382,7 +386,11 @@ char *pa_source_list_to_string(pa_core *c) { (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC); - } + } else + pa_strbuf_printf( + s, + "\tfixed latency: %0.2f ms\n", + (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC); if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index); diff --git a/src/pulsecore/dbus-shared.c b/src/pulsecore/dbus-shared.c index b52c14cb..9d9445b6 100644 --- a/src/pulsecore/dbus-shared.c +++ b/src/pulsecore/dbus-shared.c @@ -41,7 +41,7 @@ struct pa_dbus_connection { const char *property_name; }; -static pa_dbus_connection* pa_dbus_connection_new(pa_core *c, pa_dbus_wrap_connection *conn, const char *name) { +static pa_dbus_connection* dbus_connection_new(pa_core *c, pa_dbus_wrap_connection *conn, const char *name) { pa_dbus_connection *pconn; pconn = pa_xnew(pa_dbus_connection, 1); @@ -73,9 +73,7 @@ pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, DBusError *err if (!(conn = pa_dbus_wrap_connection_new(c->mainloop, type, error))) return NULL; - pconn = pa_dbus_connection_new(c, conn, prop_name[type]); - - return pconn; + return dbus_connection_new(c, conn, prop_name[type]); } DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c){ @@ -93,7 +91,8 @@ void pa_dbus_connection_unref(pa_dbus_connection *c) { if (PA_REFCNT_DEC(c) > 0) return; - /* already disconnected, just free */ + pa_dbus_wrap_connection_free(c->connection); + pa_shared_remove(c->core, c->property_name); pa_xfree(c); } @@ -106,6 +105,3 @@ pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c) { return c; } - - - diff --git a/src/pulsecore/dbus-util.c b/src/pulsecore/dbus-util.c index d712bff3..ece36def 100644 --- a/src/pulsecore/dbus-util.c +++ b/src/pulsecore/dbus-util.c @@ -28,6 +28,8 @@ #include <pulse/xmalloc.h> #include <pulse/timeval.h> + +#include <pulsecore/core-util.h> #include <pulsecore/log.h> #include "dbus-util.h" @@ -244,7 +246,8 @@ static void wakeup_main(void *userdata) { pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBusType type, DBusError *error) { DBusConnection *conn; - pa_dbus_wrap_connection *pconn = NULL; + pa_dbus_wrap_connection *pconn; + char *id; pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER); @@ -263,6 +266,13 @@ pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBus pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn); + pa_log_debug("Successfully connected to D-Bus %s bus %s as %s", + type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"), + pa_strnull((id = dbus_connection_get_server_id(conn))), + pa_strnull(dbus_bus_get_unique_name(conn))); + + dbus_free(id); + return pconn; } @@ -273,7 +283,8 @@ void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) { dbus_connection_close(c->connection); /* must process remaining messages, bit of a kludge to handle * both unload and shutdown */ - while (dbus_connection_read_write_dispatch(c->connection, -1)); + while (dbus_connection_read_write_dispatch(c->connection, -1)) + ; } c->mainloop->defer_free(c->dispatch_event); @@ -369,8 +380,10 @@ pa_dbus_pending *pa_dbus_pending_new( void pa_dbus_pending_free(pa_dbus_pending *p) { pa_assert(p); - if (p->pending) - dbus_pending_call_cancel(p->pending); /* p->pending is freed by cancel() */ + if (p->pending) { + dbus_pending_call_cancel(p->pending); + dbus_pending_call_unref(p->pending); + } if (p->message) dbus_message_unref(p->message); diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index 8628bf40..2f379f68 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -113,6 +113,7 @@ void pa_log_levelv( #define pa_log_notice(...) pa_log_level_meta(PA_LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__) #define pa_log_warn(...) pa_log_level_meta(PA_LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__) #define pa_log_error(...) pa_log_level_meta(PA_LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define pa_logl(level, ...) pa_log_level_meta(level, __FILE__, __LINE__, __func__, __VA_ARGS__) #else diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index d12d13a8..77f9efc9 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -90,8 +90,8 @@ pa_memblockq* pa_memblockq_new( pa_memblockq_set_maxlength(bq, maxlength); pa_memblockq_set_tlength(bq, tlength); - pa_memblockq_set_prebuf(bq, prebuf); pa_memblockq_set_minreq(bq, minreq); + pa_memblockq_set_prebuf(bq, prebuf); pa_memblockq_set_maxrewind(bq, maxrewind); pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu", @@ -784,16 +784,13 @@ void pa_memblockq_set_maxlength(pa_memblockq *bq, size_t maxlength) { if (bq->tlength > bq->maxlength) pa_memblockq_set_tlength(bq, bq->maxlength); - - if (bq->prebuf > bq->maxlength) - pa_memblockq_set_prebuf(bq, bq->maxlength); } void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) { size_t old_tlength; pa_assert(bq); - if (tlength <= 0) + if (tlength <= 0 || tlength == (size_t) -1) tlength = bq->maxlength; old_tlength = bq->tlength; @@ -802,49 +799,46 @@ void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) { if (bq->tlength > bq->maxlength) bq->tlength = bq->maxlength; - if (bq->prebuf > bq->tlength) - pa_memblockq_set_prebuf(bq, bq->tlength); - if (bq->minreq > bq->tlength) pa_memblockq_set_minreq(bq, bq->tlength); + if (bq->prebuf > bq->tlength+bq->base-bq->minreq) + pa_memblockq_set_prebuf(bq, bq->tlength+bq->base-bq->minreq); + bq->missing += (int64_t) bq->tlength - (int64_t) old_tlength; } +void pa_memblockq_set_minreq(pa_memblockq *bq, size_t minreq) { + pa_assert(bq); + + bq->minreq = (minreq/bq->base)*bq->base; + + if (bq->minreq > bq->tlength) + bq->minreq = bq->tlength; + + if (bq->minreq < bq->base) + bq->minreq = bq->base; + + if (bq->prebuf > bq->tlength+bq->base-bq->minreq) + pa_memblockq_set_prebuf(bq, bq->tlength+bq->base-bq->minreq); +} + void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) { pa_assert(bq); if (prebuf == (size_t) -1) - prebuf = bq->tlength; + prebuf = bq->tlength+bq->base-bq->minreq; bq->prebuf = ((prebuf+bq->base-1)/bq->base)*bq->base; if (prebuf > 0 && bq->prebuf < bq->base) bq->prebuf = bq->base; - if (bq->prebuf > bq->tlength) - bq->prebuf = bq->tlength; + if (bq->prebuf > bq->tlength+bq->base-bq->minreq) + bq->prebuf = bq->tlength+bq->base-bq->minreq; if (bq->prebuf <= 0 || pa_memblockq_get_length(bq) >= bq->prebuf) bq->in_prebuf = FALSE; - - if (bq->minreq > bq->prebuf) - pa_memblockq_set_minreq(bq, bq->prebuf); -} - -void pa_memblockq_set_minreq(pa_memblockq *bq, size_t minreq) { - pa_assert(bq); - - bq->minreq = (minreq/bq->base)*bq->base; - - if (bq->minreq > bq->tlength) - bq->minreq = bq->tlength; - - if (bq->minreq > bq->prebuf) - bq->minreq = bq->prebuf; - - if (bq->minreq < bq->base) - bq->minreq = bq->base; } void pa_memblockq_set_maxrewind(pa_memblockq *bq, size_t maxrewind) { diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 59e5d80e..7c2183d8 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -850,7 +850,7 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, /* Called from main context */ static void fix_playback_buffer_attr(playback_stream *s) { - size_t frame_size; + size_t frame_size, max_prebuf; pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec; pa_assert(s); @@ -976,8 +976,11 @@ static void fix_playback_buffer_attr(playback_stream *s) { if (s->buffer_attr.tlength <= s->buffer_attr.minreq) s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size; - if (s->buffer_attr.prebuf == (uint32_t) -1 || s->buffer_attr.prebuf > s->buffer_attr.tlength) - s->buffer_attr.prebuf = s->buffer_attr.tlength; + max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq; + + if (s->buffer_attr.prebuf == (uint32_t) -1 || + s->buffer_attr.prebuf > max_prebuf) + s->buffer_attr.prebuf = max_prebuf; } /* Called from main context */ @@ -1465,7 +1468,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk if (pa_memblockq_is_readable(s->memblockq)) s->is_underrun = FALSE; else { - pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq)); + if (!s->is_underrun) + pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq)); if (s->drain_request && pa_sink_input_safe_to_remove(i)) { s->drain_request = FALSE; @@ -4241,7 +4245,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o pa_native_connection_assert_ref(c); if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) { - pa_log("client sent block for invalid stream."); + pa_log_debug("Client sent block for invalid stream."); /* Ignoring */ return; } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 1fdb3fa6..b1b9fb56 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -117,6 +117,7 @@ static void reset_callbacks(pa_sink_input *i) { i->attach = NULL; i->detach = NULL; i->suspend = NULL; + i->suspend_within_thread = NULL; i->moving = NULL; i->kill = NULL; i->get_latency = NULL; @@ -287,6 +288,7 @@ int pa_sink_input_new( i->volume_factor = data->volume_factor; pa_cvolume_init(&i->soft_volume); + memset(i->relative_volume, 0, sizeof(i->relative_volume)); i->save_volume = data->save_volume; i->save_sink = data->save_sink; i->save_muted = data->save_muted; @@ -333,8 +335,8 @@ int pa_sink_input_new( 0, &i->sink->silence); - pa_assert_se(pa_idxset_put(core->sink_inputs, pa_sink_input_ref(i), &i->index) == 0); - pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0); + pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0); + pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0); if (i->client) pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0); @@ -529,7 +531,7 @@ void pa_sink_input_put(pa_sink_input *i) { pa_sink_update_flat_volume(i->sink, &new_volume); pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); } else - pa_sw_cvolume_multiply(&i->soft_volume, &i->virtual_volume, &i->volume_factor); + pa_sink_input_set_relative_volume(i, &i->virtual_volume); i->thread_info.soft_volume = i->soft_volume; i->thread_info.muted = i->muted; @@ -822,6 +824,9 @@ void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) { pa_sink_input_assert_ref(i); + if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY)) + usec = i->sink->fixed_latency; + if (usec != (pa_usec_t) -1) usec = PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); @@ -833,8 +838,6 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa /* Called from main context */ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) { - pa_usec_t min_latency, max_latency; - pa_sink_input_assert_ref(i); if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) { @@ -846,10 +849,14 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) * we have to touch the thread info data directly */ if (i->sink) { - pa_sink_get_latency_range(i->sink, &min_latency, &max_latency); + if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY)) + usec = i->sink->fixed_latency; - if (usec != (pa_usec_t) -1) + if (usec != (pa_usec_t) -1) { + pa_usec_t min_latency, max_latency; + pa_sink_get_latency_range(i->sink, &min_latency, &max_latency); usec = PA_CLAMP(usec, min_latency, max_latency); + } } i->thread_info.requested_sink_latency = usec; @@ -900,11 +907,12 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo /* OK, we are in normal volume mode. The volume only affects * ourselves */ - pa_sw_cvolume_multiply(&i->soft_volume, volume, &i->volume_factor); + pa_sink_input_set_relative_volume(i, volume); /* Hooks have the ability to play games with i->soft_volume */ pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i); + /* Copy the new soft_volume to the thread_info struct */ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0); } @@ -922,24 +930,50 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { /* Called from main context */ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) { + unsigned c; + pa_sink_input_assert_ref(i); pa_assert(v); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - *v = i->virtual_volume; - /* This always returns a relative volume, even in flat volume mode */ - if (i->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume sv; + v->channels = i->sample_spec.channels; + + for (c = 0; c < v->channels; c++) + v->values[c] = pa_sw_volume_from_linear(i->relative_volume[c]); + + return v; +} + +/* Called from main context */ +void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) { + unsigned c; + pa_cvolume _v; + + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec)); - sv = *pa_sink_get_volume(i->sink, FALSE); + if (!v) + v = pa_cvolume_reset(&_v, i->sample_spec.channels); - pa_sw_cvolume_divide(v, v, - pa_cvolume_remap(&sv, &i->sink->channel_map, &i->channel_map)); + /* This basically calculates: + * + * i->relative_volume := v + * i->soft_volume := i->relative_volume * i->volume_factor */ + + i->soft_volume.channels = i->sample_spec.channels; + + for (c = 0; c < i->sample_spec.channels; c++) { + i->relative_volume[c] = pa_sw_volume_to_linear(v->values[c]); + + i->soft_volume.values[c] = pa_sw_volume_from_linear( + i->relative_volume[c] * + pa_sw_volume_to_linear(i->volume_factor.values[c])); } - return v; + /* We don't copy the data to the thread_info data. That's left for someone else to do */ } /* Called from main context */ @@ -1109,9 +1143,11 @@ int pa_sink_input_start_move(pa_sink_input *i) { if (i->sink->flags & PA_SINK_FLAT_VOLUME) { pa_cvolume new_volume; - /* Make the absolute volume relative */ - i->virtual_volume = i->soft_volume; - i->soft_volume = i->volume_factor; + /* Make the virtual volume relative */ + pa_sink_input_get_relative_volume(i, &i->virtual_volume); + + /* And reset the the relative volume */ + pa_sink_input_set_relative_volume(i, NULL); /* We might need to update the sink's volume if we are in flat * volume mode. */ @@ -1124,6 +1160,8 @@ int pa_sink_input_start_move(pa_sink_input *i) { pa_sink_update_status(i->sink); i->sink = NULL; + pa_sink_input_unref(i); + return 0; } @@ -1171,7 +1209,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { i->sink = dest; i->save_sink = save; - pa_idxset_put(dest->inputs, i, NULL); + pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL); if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) i->sink->n_corked++; @@ -1236,11 +1274,19 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { if (!pa_sink_input_may_move_to(i, dest)) return -PA_ERR_NOTSUPPORTED; - if ((r = pa_sink_input_start_move(i)) < 0) + pa_sink_input_ref(i); + + if ((r = pa_sink_input_start_move(i)) < 0) { + pa_sink_input_unref(i); return r; + } - if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) + if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) { + pa_sink_input_unref(i); return r; + } + + pa_sink_input_unref(i); return 0; } diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 0dd5e9aa..96ad2baf 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -91,7 +91,10 @@ struct pa_sink_input { pa_sink_input *sync_prev, *sync_next; - pa_cvolume virtual_volume, soft_volume, volume_factor; + pa_cvolume virtual_volume; /* The volume clients are informed about */ + pa_cvolume volume_factor; /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */ + double relative_volume[PA_CHANNELS_MAX]; /* The calculated volume relative to the sink volume as linear factors. */ + pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through. Usually calculated as relative_volume * volume_factor */ pa_bool_t muted:1; /* if TRUE then the source we are connected to and/or the volume @@ -148,6 +151,10 @@ struct pa_sink_input { * to suspends or resumes. Called from main context */ void (*suspend) (pa_sink_input *i, pa_bool_t b); /* may be NULL */ + /* If non-NULL called whenever the sink this input is attached + * to suspends or resumes. Called from IO context */ + void (*suspend_within_thread) (pa_sink_input *i, pa_bool_t b); /* may be NULL */ + /* If non-NULL called whenever the sink input is moved to a new * sink. Called from main context after the sink input has been * detached from the old sink and before it has been attached to @@ -345,4 +352,7 @@ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i); pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret); +/* To be used by sink.c only */ +void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v); + #endif diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index a0f0ea7e..93800d14 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -50,6 +50,7 @@ #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE) #define ABSOLUTE_MIN_LATENCY (500) #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC) +#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC) static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject); @@ -208,6 +209,8 @@ pa_sink* pa_sink_new( s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; + s->fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; + reset_callbacks(s); s->userdata = NULL; @@ -363,8 +366,13 @@ void pa_sink_put(pa_sink* s) { if (s->flags & PA_SINK_LATENCY) s->monitor_source->flags |= PA_SOURCE_LATENCY; - if (s->flags & PA_SINK_DYNAMIC_LATENCY) + if (s->flags & PA_SINK_DYNAMIC_LATENCY) { s->monitor_source->flags |= PA_SOURCE_DYNAMIC_LATENCY; + s->fixed_latency = 0; + } else if (s->fixed_latency <= 0) + s->fixed_latency = DEFAULT_FIXED_LATENCY; + + s->monitor_source->fixed_latency = s->fixed_latency; pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0); @@ -515,8 +523,12 @@ pa_queue *pa_sink_move_all_start(pa_sink *s) { for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) { n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)); + pa_sink_input_ref(i); + if (pa_sink_input_start_move(i) >= 0) - pa_queue_push(q, pa_sink_input_ref(i)); + pa_queue_push(q, i); + else + pa_sink_input_unref(i); } return q; @@ -984,6 +996,46 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) { return usec; } +static void compute_new_soft_volume(pa_sink_input *i, const pa_cvolume *new_volume) { + unsigned c; + + pa_sink_input_assert_ref(i); + pa_assert(new_volume->channels == i->sample_spec.channels); + + /* + * This basically calculates: + * + * i->relative_volume := i->virtual_volume / new_volume + * i->soft_volume := i->relative_volume * i->volume_factor + */ + + /* The new sink volume passed in here must already be remapped to + * the sink input's channel map! */ + + i->soft_volume.channels = i->sample_spec.channels; + + for (c = 0; c < i->sample_spec.channels; c++) + + if (new_volume->values[c] <= PA_VOLUME_MUTED) + /* We leave i->relative_volume untouched */ + i->soft_volume.values[c] = PA_VOLUME_MUTED; + else { + i->relative_volume[c] = + pa_sw_volume_to_linear(i->virtual_volume.values[c]) / + pa_sw_volume_to_linear(new_volume->values[c]); + + i->soft_volume.values[c] = pa_sw_volume_from_linear( + i->relative_volume[c] * + pa_sw_volume_to_linear(i->volume_factor.values[c])); + } + + /* Hooks have the ability to play games with i->soft_volume */ + pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i); + + /* We don't copy the soft_volume to the thread_info data + * here. That must be done by the caller */ +} + /* Called from main thread */ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { pa_sink_input *i; @@ -998,7 +1050,7 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { * might need to fix up the sink volume accordingly. Please note * that we don't actually update the sinks volume here, we only * return how it needs to be updated. The caller should then call - * pa_sink_set_flat_volume().*/ + * pa_sink_set_volume().*/ if (pa_idxset_isempty(s->inputs)) { /* In the special case that we have no sink input we leave the @@ -1030,26 +1082,22 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { remapped_new_volume = *new_volume; pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map); - pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume); - pa_sw_cvolume_multiply(&i->soft_volume, &i->soft_volume, &i->volume_factor); - - /* Hooks have the ability to play games with i->soft_volume */ - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i); + compute_new_soft_volume(i, &remapped_new_volume); - /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because - * we want the update to have atomically with the sink - * volume update, hence we do it within the - * pa_sink_set_flat_volume() call below*/ + /* We don't copy soft_volume to the thread_info data here + * (i.e. issue PA_SINK_INPUT_MESSAGE_SET_VOLUME) because we + * want the update to be atomically with the sink volume + * update, hence we do it within the pa_sink_set_volume() call + * below */ } } /* Called from main thread */ -void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) { +void pa_sink_propagate_flat_volume(pa_sink *s) { pa_sink_input *i; uint32_t idx; pa_sink_assert_ref(s); - pa_assert(old_volume); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(s->flags & PA_SINK_FLAT_VOLUME); @@ -1058,39 +1106,43 @@ void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) { * sink input volumes accordingly */ for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) { - pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume; + pa_cvolume sink_volume, new_virtual_volume; unsigned c; - remapped_new_volume = s->virtual_volume; - pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map); + /* This basically calculates i->virtual_volume := i->relative_volume * s->virtual_volume */ - remapped_old_volume = *old_volume; - pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map); + sink_volume = s->virtual_volume; + pa_cvolume_remap(&sink_volume, &s->channel_map, &i->channel_map); for (c = 0; c < i->sample_spec.channels; c++) + new_virtual_volume.values[c] = pa_sw_volume_from_linear( + i->relative_volume[c] * + pa_sw_volume_to_linear(sink_volume.values[c])); - if (remapped_old_volume.values[c] == PA_VOLUME_MUTED) - fixed_volume.values[c] = PA_VOLUME_MUTED; - else - fixed_volume.values[c] = (pa_volume_t) - ((uint64_t) i->virtual_volume.values[c] * - (uint64_t) remapped_new_volume.values[c] / - (uint64_t) remapped_old_volume.values[c]); + new_virtual_volume.channels = i->sample_spec.channels; - fixed_volume.channels = i->virtual_volume.channels; + if (!pa_cvolume_equal(&new_virtual_volume, &i->virtual_volume)) { + i->virtual_volume = new_virtual_volume; - if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) { - i->virtual_volume = fixed_volume; + /* Hmm, the soft volume might no longer actually match + * what has been chosen as new virtual volume here, + * especially when the old volume was + * PA_VOLUME_MUTED. Hence let's recalculate the soft + * volumes here. */ + compute_new_soft_volume(i, &sink_volume); /* The virtual volume changed, let's tell people so */ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } } + + /* If the soft_volume of any of the sink inputs got changed, let's + * make sure the thread copies are synced up. */ + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SYNC_VOLUMES, NULL, 0, NULL) == 0); } /* Called from main thread */ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) { - pa_cvolume old_virtual_volume; pa_bool_t virtual_volume_changed; pa_sink_assert_ref(s); @@ -1099,14 +1151,13 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat pa_assert(pa_cvolume_valid(volume)); pa_assert(pa_cvolume_compatible(volume, &s->sample_spec)); - old_virtual_volume = s->virtual_volume; + virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume); s->virtual_volume = *volume; - virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume); /* Propagate this volume change back to the inputs */ if (virtual_volume_changed) if (propagate && (s->flags & PA_SINK_FLAT_VOLUME)) - pa_sink_propagate_flat_volume(s, &old_virtual_volume); + pa_sink_propagate_flat_volume(s); if (s->set_volume) { /* If we have a function set_volume(), then we do not apply a @@ -1157,7 +1208,7 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) { if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) { if (s->flags & PA_SINK_FLAT_VOLUME) - pa_sink_propagate_flat_volume(s, &old_virtual_volume); + pa_sink_propagate_flat_volume(s); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } @@ -1565,9 +1616,13 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse pa_sink_request_rewind(s, (size_t) -1); } - if (s->flags & PA_SINK_FLAT_VOLUME) - sync_input_volumes_within_thread(s); + if (!(s->flags & PA_SINK_FLAT_VOLUME)) + return 0; + + /* Fall through ... */ + case PA_SINK_MESSAGE_SYNC_VOLUMES: + sync_input_volumes_within_thread(s); return 0; case PA_SINK_MESSAGE_GET_VOLUME: @@ -1585,7 +1640,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse case PA_SINK_MESSAGE_GET_MUTE: return 0; - case PA_SINK_MESSAGE_SET_STATE: + case PA_SINK_MESSAGE_SET_STATE: { + + pa_bool_t suspend_change = + (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) || + (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED); s->thread_info.state = PA_PTR_TO_UINT(userdata); @@ -1594,7 +1653,17 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse s->thread_info.rewind_requested = FALSE; } + if (suspend_change) { + pa_sink_input *i; + void *state = NULL; + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + if (i->suspend_within_thread) + i->suspend_within_thread(i, s->thread_info.state == PA_SINK_SUSPENDED); + } + return 0; + } case PA_SINK_MESSAGE_DETACH: @@ -1763,6 +1832,9 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { pa_sink_assert_ref(s); + if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) + return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); + if (s->thread_info.requested_latency_valid) return s->thread_info.requested_latency; @@ -1778,13 +1850,8 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { (result == (pa_usec_t) -1 || result > monitor_latency)) result = monitor_latency; - if (result != (pa_usec_t) -1) { - if (result > s->thread_info.max_latency) - result = s->thread_info.max_latency; - - if (result < s->thread_info.min_latency) - result = s->thread_info.min_latency; - } + if (result != (pa_usec_t) -1) + result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency); s->thread_info.requested_latency = result; s->thread_info.requested_latency_valid = TRUE; @@ -1873,6 +1940,9 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) { pa_sink_assert_ref(s); + if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) + return; + s->thread_info.requested_latency_valid = FALSE; if (PA_SINK_IS_LINKED(s->thread_info.state)) { diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 634bf3ef..cb4697f9 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -74,7 +74,8 @@ struct pa_sink { pa_volume_t base_volume; /* shall be constant */ unsigned n_volume_steps; /* shall be constant */ - pa_cvolume virtual_volume, soft_volume; + pa_cvolume virtual_volume; /* The volume clients are informed about */ + pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through */ pa_bool_t muted:1; pa_bool_t refresh_volume:1; @@ -85,6 +86,8 @@ struct pa_sink { pa_memchunk silence; + pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */ + /* Called when the main loop requests a state change. Called from * main loop context. If returns -1 the state change will be * inhibited */ @@ -159,6 +162,7 @@ typedef enum pa_sink_message { PA_SINK_MESSAGE_REMOVE_INPUT, PA_SINK_MESSAGE_GET_VOLUME, PA_SINK_MESSAGE_SET_VOLUME, + PA_SINK_MESSAGE_SYNC_VOLUMES, PA_SINK_MESSAGE_GET_MUTE, PA_SINK_MESSAGE_SET_MUTE, PA_SINK_MESSAGE_GET_LATENCY, @@ -249,7 +253,7 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend); int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend); void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume); -void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume); +void pa_sink_propagate_flat_volume(pa_sink *s); void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg); const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh); diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 8147b27f..e660700c 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -536,6 +536,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { return NULL; pa_snprintf(c, l, "{%s}unix:%s", id, s->filename); + pa_xfree(id); return c; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 1c37be93..3ee26735 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -87,6 +87,7 @@ static void reset_callbacks(pa_source_output *o) { o->attach = NULL; o->detach = NULL; o->suspend = NULL; + o->suspend_within_thread = NULL; o->moving = NULL; o->kill = NULL; o->get_latency = NULL; @@ -519,6 +520,9 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* i pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); + if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY)) + usec = o->source->fixed_latency; + if (usec != (pa_usec_t) -1) usec = PA_CLAMP(usec, o->source->thread_info.min_latency, o->source->thread_info.max_latency); @@ -530,8 +534,6 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output /* Called from main context */ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) { - pa_usec_t min_latency, max_latency; - pa_source_output_assert_ref(o); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) { @@ -543,10 +545,14 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t * have to touch the thread info data directly */ if (o->source) { - pa_source_get_latency_range(o->source, &min_latency, &max_latency); + if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY)) + usec = o->source->fixed_latency; - if (usec != (pa_usec_t) -1) + if (usec != (pa_usec_t) -1) { + pa_usec_t min_latency, max_latency; + pa_source_get_latency_range(o->source, &min_latency, &max_latency); usec = PA_CLAMP(usec, min_latency, max_latency); + } } o->thread_info.requested_source_latency = usec; @@ -704,6 +710,8 @@ int pa_source_output_start_move(pa_source_output *o) { pa_source_update_status(o->source); o->source = NULL; + pa_source_output_unref(o); + return 0; } @@ -751,7 +759,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t o->source = dest; o->save_source = save; - pa_idxset_put(o->source->outputs, o, NULL); + pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL); if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) o->source->n_corked++; @@ -803,11 +811,19 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav if (!pa_source_output_may_move_to(o, dest)) return -PA_ERR_NOTSUPPORTED; - if ((r = pa_source_output_start_move(o)) < 0) + pa_source_output_ref(o); + + if ((r = pa_source_output_start_move(o)) < 0) { + pa_source_output_unref(o); return r; + } - if ((r = pa_source_output_finish_move(o, dest, save)) < 0) + if ((r = pa_source_output_finish_move(o, dest, save)) < 0) { + pa_source_output_unref(o); return r; + } + + pa_source_output_unref(o); return 0; } diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 9f5f7744..9824e160 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -120,6 +120,10 @@ struct pa_source_output { * to suspends or resumes. Called from main context */ void (*suspend) (pa_source_output *o, pa_bool_t b); /* may be NULL */ + /* If non-NULL called whenever the source this output is attached + * to suspends or resumes. Called from IO context */ + void (*suspend_within_thread) (pa_source_output *o, pa_bool_t b); /* may be NULL */ + /* If non-NULL called whenever the source output is moved to a new * source. Called from main context after the stream was detached * from the old source and before it is attached to the new diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 252e23ab..21902509 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -43,6 +43,7 @@ #define ABSOLUTE_MIN_LATENCY (500) #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC) +#define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC) static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject); @@ -199,6 +200,8 @@ pa_source* pa_source_new( s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; + s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; + reset_callbacks(s); s->userdata = NULL; @@ -303,8 +306,7 @@ void pa_source_put(pa_source *s) { /* The following fields must be initialized properly when calling _put() */ pa_assert(s->asyncmsgq); pa_assert(s->rtpoll); - pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency || - s->thread_info.min_latency <= s->thread_info.max_latency); + pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency); if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) { s->flags |= PA_SOURCE_DECIBEL_VOLUME; @@ -316,6 +318,11 @@ void pa_source_put(pa_source *s) { if (s->flags & PA_SOURCE_DECIBEL_VOLUME) s->n_volume_steps = PA_VOLUME_NORM+1; + if (s->flags & PA_SOURCE_DYNAMIC_LATENCY) + s->fixed_latency = 0; + else if (s->fixed_latency <= 0) + s->fixed_latency = DEFAULT_FIXED_LATENCY; + pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -466,8 +473,12 @@ pa_queue *pa_source_move_all_start(pa_source *s) { for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) { n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)); + pa_source_output_ref(o); + if (pa_source_output_start_move(o) >= 0) - pa_queue_push(q, pa_source_output_ref(o)); + pa_queue_push(q, o); + else + pa_source_output_unref(o); } return q; @@ -933,9 +944,26 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ case PA_SOURCE_MESSAGE_GET_MUTE: return 0; - case PA_SOURCE_MESSAGE_SET_STATE: + case PA_SOURCE_MESSAGE_SET_STATE: { + + pa_bool_t suspend_change = + (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) || + (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED); + s->thread_info.state = PA_PTR_TO_UINT(userdata); + + if (suspend_change) { + pa_source_output *o; + void *state = NULL; + + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + if (o->suspend_within_thread) + o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED); + } + + return 0; + } case PA_SOURCE_MESSAGE_DETACH: @@ -1075,6 +1103,9 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { pa_source_assert_ref(s); + if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) + return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); + if (s->thread_info.requested_latency_valid) return s->thread_info.requested_latency; @@ -1084,13 +1115,8 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency)) result = o->thread_info.requested_source_latency; - if (result != (pa_usec_t) -1) { - if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency) - result = s->thread_info.max_latency; - - if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency) - result = s->thread_info.min_latency; - } + if (result != (pa_usec_t) -1) + result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency); s->thread_info.requested_latency = result; s->thread_info.requested_latency_valid = TRUE; @@ -1100,7 +1126,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { /* Called from main thread */ pa_usec_t pa_source_get_requested_latency(pa_source *s) { - pa_usec_t usec; + pa_usec_t usec = 0; pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); @@ -1148,6 +1174,9 @@ void pa_source_invalidate_requested_latency(pa_source *s) { pa_source_assert_ref(s); + if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) + return; + s->thread_info.requested_latency_valid = FALSE; if (PA_SOURCE_IS_LINKED(s->thread_info.state)) { @@ -1217,7 +1246,7 @@ void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t } } -/* Called from IO thread, and from main thread before pa_sink_put() is called */ +/* Called from IO thread, and from main thread before pa_source_put() is called */ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) { void *state = NULL; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 652783ef..b502c228 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -87,6 +87,8 @@ struct pa_source { pa_memchunk silence; + pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */ + /* Called when the main loop requests a state change. Called from * main loop context. If returns -1 the state change will be * inhibited */ diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 55ac8687..9d5a0705 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -291,7 +291,8 @@ static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { pa_assert(s); pa_assert(y); - if (!s->smoothing || x >= s->px) { + if (x >= s->px) { + /* Linear interpolation right from px */ int64_t t; /* The requested point is right of the point where we wanted @@ -307,7 +308,22 @@ static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { if (deriv) *deriv = s->dp; + } else if (x <= s->ex) { + /* Linear interpolation left from ex */ + int64_t t; + + t = (int64_t) s->ey - (int64_t) llrint(s->de * (double) (s->ex - x)); + + if (t < 0) + t = 0; + + *y = (pa_usec_t) t; + + if (deriv) + *deriv = s->de; + } else { + /* Spline interpolation between ex and px */ double tx, ty; /* Ok, we're not yet on track, thus let's interpolate, and @@ -381,7 +397,9 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) { s->abc_valid = FALSE; -/* pa_log_debug("put(%llu | %llu) = %llu", (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y); */ +#ifdef DEBUG_DATA + pa_log_debug("%p, put(%llu | %llu) = %llu", s, (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y); +#endif } pa_usec_t pa_smoother_get(pa_smoother *s, pa_usec_t x) { @@ -412,7 +430,9 @@ pa_usec_t pa_smoother_get(pa_smoother *s, pa_usec_t x) { s->last_y = y; } -/* pa_log_debug("get(%llu | %llu) = %llu", (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y); */ +#ifdef DEBUG_DATA + pa_log_debug("%p, get(%llu | %llu) = %llu", s, (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y); +#endif return y; } @@ -422,7 +442,9 @@ void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t offset) { s->time_offset = offset; -/* pa_log_debug("offset(%llu)", (unsigned long long) offset); */ +#ifdef DEBUG_DATA + pa_log_debug("offset(%llu)", (unsigned long long) offset); +#endif } void pa_smoother_pause(pa_smoother *s, pa_usec_t x) { @@ -431,7 +453,9 @@ void pa_smoother_pause(pa_smoother *s, pa_usec_t x) { if (s->paused) return; -/* pa_log_debug("pause(%llu)", (unsigned long long) x); */ +#ifdef DEBUG_DATA + pa_log_debug("pause(%llu)", (unsigned long long) x); +#endif s->paused = TRUE; s->pause_time = x; @@ -446,7 +470,9 @@ void pa_smoother_resume(pa_smoother *s, pa_usec_t x, pa_bool_t fix_now) { if (x < s->pause_time) x = s->pause_time; -/* pa_log_debug("resume(%llu)", (unsigned long long) x); */ +#ifdef DEBUG_DATA + pa_log_debug("resume(%llu)", (unsigned long long) x); +#endif s->paused = FALSE; s->time_offset += x - s->pause_time; @@ -481,7 +507,9 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay) if (s->dp > nde) nde = s->dp; -/* pa_log_debug("translate(%llu) = %llu (%0.2f)", (unsigned long long) y_delay, (unsigned long long) ((double) y_delay / nde), nde); */ +#ifdef DEBUG_DATA + pa_log_debug("translate(%llu) = %llu (%0.2f)", (unsigned long long) y_delay, (unsigned long long) ((double) y_delay / nde), nde); +#endif return (pa_usec_t) llrint((double) y_delay / nde); } |