diff options
Diffstat (limited to 'src/pulsecore/source-output.c')
-rw-r--r-- | src/pulsecore/source-output.c | 199 |
1 files changed, 140 insertions, 59 deletions
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index c92c5ab7..1e1ac4e1 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -29,6 +29,7 @@ #include <pulse/utf8.h> #include <pulse/xmalloc.h> +#include <pulse/util.h> #include <pulsecore/sample-util.h> #include <pulsecore/core-subscribe.h> @@ -111,8 +112,10 @@ pa_source_output* pa_source_output_new( pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); - if (!data->source) - data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, TRUE); + if (!data->source) { + data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE); + data->save_source = FALSE; + } pa_return_null_if_fail(data->source); pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED); @@ -153,6 +156,9 @@ pa_source_output* pa_source_output_new( pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); + if (data->client) + pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data) < 0) return NULL; @@ -177,8 +183,6 @@ pa_source_output* pa_source_output_new( pa_log_warn("Unsupported resampling operation."); return NULL; } - - data->resample_method = pa_resampler_get_method(resampler); } o = pa_msgobject_new(pa_source_output); @@ -189,17 +193,20 @@ pa_source_output* pa_source_output_new( o->state = PA_SOURCE_OUTPUT_INIT; o->flags = flags; o->proplist = pa_proplist_copy(data->proplist); - o->driver = pa_xstrdup(data->driver); + o->driver = pa_xstrdup(pa_path_get_filename(data->driver)); o->module = data->module; o->source = data->source; o->client = data->client; - o->resample_method = data->resample_method; + o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID; + o->requested_resample_method = data->resample_method; o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; o->direct_on_input = data->direct_on_input; + o->save_source = data->save_source; + reset_callbacks(o); o->userdata = NULL; @@ -223,6 +230,9 @@ pa_source_output* pa_source_output_new( pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); + if (o->client) + pa_assert_se(pa_idxset_put(o->client->source_outputs, o, NULL) >= 0); + if (o->direct_on_input) pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0); @@ -242,11 +252,13 @@ pa_source_output* pa_source_output_new( static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); + if (!o->source) + return; + if (o->state == PA_SOURCE_OUTPUT_CORKED && state != PA_SOURCE_OUTPUT_CORKED) pa_assert_se(o->source->n_corked -- >= 1); else if (o->state != PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_CORKED) o->source->n_corked++; - } /* Called from main context */ @@ -262,7 +274,7 @@ static int source_output_set_state(pa_source_output *o, pa_source_output_state_t o->state = state; if (state != PA_SOURCE_OUTPUT_UNLINKED) - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o); + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o); pa_source_update_status(o->source); @@ -282,31 +294,39 @@ void pa_source_output_unlink(pa_source_output*o) { linked = PA_SOURCE_OUTPUT_IS_LINKED(o->state); if (linked) - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); if (o->direct_on_input) pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - if (pa_idxset_remove_by_data(o->source->outputs, o, NULL)) - pa_source_output_unref(o); + + pa_idxset_remove_by_data(o->core->source_outputs, o, NULL); + + if (o->source) + if (pa_idxset_remove_by_data(o->source->outputs, o, NULL)) + pa_source_output_unref(o); + + if (o->client) + pa_idxset_remove_by_data(o->client->source_outputs, o, NULL); update_n_corked(o, PA_SOURCE_OUTPUT_UNLINKED); o->state = PA_SOURCE_OUTPUT_UNLINKED; - if (linked) + if (linked && o->source) if (o->source->asyncmsgq) pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0); reset_callbacks(o); if (linked) { - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o); + pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o); } - pa_source_update_status(o->source); + if (o->source) { + pa_source_update_status(o->source); + o->source = NULL; + } - o->source = NULL; pa_source_output_unref(o); } @@ -355,8 +375,8 @@ void pa_source_output_put(pa_source_output *o) { pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o); + pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o); pa_source_update_status(o->source); } @@ -564,7 +584,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); return 0; } @@ -587,18 +607,48 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { pa_proplist_unset(o->proplist, PA_PROP_MEDIA_NAME); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) { - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o); + pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); } } +/* Called from main thread */ +pa_bool_t pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) { + + pa_source_output_assert_ref(o); + + pa_proplist_update(o->proplist, mode, p); + + if (PA_SINK_IS_LINKED(o->state)) { + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o); + pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + } + + return TRUE; +} + /* Called from main context */ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { pa_source_output_assert_ref(o); - return o->resample_method; + return o->actual_resample_method; +} + +/* Called from main context */ +pa_bool_t pa_source_output_may_move(pa_source_output *o) { + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); + + if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) + return FALSE; + + if (o->direct_on_input) + return FALSE; + + return TRUE; } +/* Called from main context */ pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) { pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); @@ -607,10 +657,7 @@ pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) { if (dest == o->source) return TRUE; - if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) - return FALSE; - - if (o->direct_on_input) + if (!pa_source_output_may_move(o)) return FALSE; if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { @@ -626,26 +673,56 @@ pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) { } /* Called from main context */ -int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { +int pa_source_output_start_move(pa_source_output *o) { pa_source *origin; - pa_resampler *new_resampler; - pa_source_output_move_hook_data hook_data; pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); - pa_source_assert_ref(dest); + pa_assert(o->source); + + if (!pa_source_output_may_move(o)) + return -1; + + if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], o) < 0) + return -1; origin = o->source; - if (dest == origin) - return 0; + pa_idxset_remove_by_data(o->source->outputs, o, NULL); + + if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) + pa_assert_se(origin->n_corked-- >= 1); + + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0); + + pa_source_update_status(o->source); + o->source = NULL; + + return 0; +} + +/* Called from main context */ +int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save) { + pa_resampler *new_resampler; + + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); + pa_assert(!o->source); + pa_source_assert_ref(dest); if (!pa_source_output_may_move_to(o, dest)) return -1; + o->source = dest; + o->save_source = save; + pa_idxset_put(o->source->outputs, o, NULL); + + if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) + o->source->n_corked++; + if (o->thread_info.resampler && - pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && - pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) + pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) && + pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map)) /* Try to reuse the old resampler if possible */ new_resampler = o->thread_info.resampler; @@ -657,10 +734,10 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { /* Okey, we need a new resampler for the new source */ if (!(new_resampler = pa_resampler_new( - dest->core->mempool, + o->core->mempool, &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, - o->resample_method, + o->requested_resample_method, ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { @@ -670,22 +747,6 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { } else new_resampler = NULL; - hook_data.source_output = o; - hook_data.destination = dest; - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data); - - /* Okey, let's move it */ - pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0); - - pa_idxset_remove_by_data(origin->outputs, o, NULL); - pa_idxset_put(dest->outputs, o, NULL); - o->source = dest; - - if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) { - pa_assert_se(origin->n_corked-- >= 1); - dest->n_corked++; - } - /* Replace resampler */ if (new_resampler != o->thread_info.resampler) { if (o->thread_info.resampler) @@ -705,20 +766,40 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &o->source->silence); } - pa_source_update_status(origin); pa_source_update_status(dest); - pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0); + pa_log_debug("Successfully moved source output %i to %s.", o->index, dest->name); + + /* Notify everyone */ if (o->moved) o->moved(o); - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o); + pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], o); + pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); - pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name); + return 0; +} - /* Notify everyone */ - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); +/* Called from main context */ +int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save) { + + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); + pa_assert(o->source); + pa_source_assert_ref(dest); + + if (dest == o->source) + return 0; + + if (!pa_source_output_may_move_to(o, dest)) + return -1; + + if (pa_source_output_start_move(o) < 0) + return -1; + + if (pa_source_output_finish_move(o, dest, save) < 0) + return -1; return 0; } |