diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c index 15fdaaaa2..cba3a4ebc 100644 --- a/src/modules/module-device-manager.c +++ b/src/modules/module-device-manager.c @@ -656,14 +656,14 @@ static void route_sink_input(struct userdata *u, pa_sink_input *si) { pa_assert(u); pa_assert(u->do_routing); - /* Don't override user or application routing requests. */ - if (si->save_sink || si->sink_requested_by_application) - return; - /* Skip this if it is already in the process of being moved anyway */ if (!si->sink) return; + /* Don't override user or application routing requests. */ + if (pa_safe_streq(si->sink->name, si->preferred_sink) || si->sink_requested_by_application) + return; + auto_filtered_prop = pa_proplist_gets(si->proplist, "module-device-manager.auto_filtered"); if (auto_filtered_prop) auto_filtered = (pa_parse_boolean(auto_filtered_prop) == 1); diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c index adee51c20..4ddc03431 100644 --- a/src/modules/module-intended-roles.c +++ b/src/modules/module-intended-roles.c @@ -175,14 +175,14 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; - if (si->save_sink) - continue; - /* Skip this if it is already in the process of being moved * anyway */ if (!si->sink) continue; + if (pa_safe_streq(si->sink->name, si->preferred_sink)) + continue; + /* It might happen that a stream and a sink are set up at the same time, in which case we want to make sure we don't interfere with that */ diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index cbef4782d..1676d8968 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1311,15 +1311,17 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted); } - if (sink_input->save_sink) { + if (sink_input->preferred_sink != NULL) { + pa_sink *s; pa_xfree(entry->device); - entry->device = pa_xstrdup(sink_input->sink->name); + entry->device = pa_xstrdup(sink_input->preferred_sink); entry->device_valid = true; device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device)); - if (sink_input->sink->card) { + s = pa_namereg_get(c, entry->device, PA_NAMEREG_SINK); + if (s && s->card) { pa_xfree(entry->card); - entry->card = pa_xstrdup(sink_input->sink->card->name); + entry->card = pa_xstrdup(s->card->name); entry->card_valid = true; } } @@ -1650,14 +1652,14 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->sink == sink) continue; - if (si->save_sink) - continue; - /* Skip this if it is already in the process of being moved * anyway */ if (!si->sink) continue; + if (pa_safe_streq(si->sink->name, si->preferred_sink)) + continue; + /* Skip this sink input if it is connecting a filter sink to * the master */ if (si->origin_sink) @@ -1951,12 +1953,13 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) { if (u->restore_device) { if (!e->device_valid) { - if (si->save_sink) { + if (si->preferred_sink != NULL) { pa_log_info("Ensuring device is not saved for stream %s.", name); /* If the device is not valid we should make sure the - save flag is cleared as the user may have specifically + preferred_sink is cleared as the user may have specifically removed the sink element from the rule. */ - si->save_sink = false; + pa_xfree(si->preferred_sink); + si->preferred_sink = NULL; /* This is cheating a bit. The sink input itself has not changed but the rules governing its routing have, so we fire this event such that other routing modules (e.g. module-device-manager) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index 4205a7865..bde91e42d 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -124,7 +124,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* } PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) { - if (i->save_sink || !PA_SINK_INPUT_IS_LINKED(i->state)) + if (pa_safe_streq(i->sink->name, i->preferred_sink) || !PA_SINK_INPUT_IS_LINKED(i->state)) continue; if (pa_sink_input_move_to(i, sink, false) < 0) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index d3ead2cb5..cc798cf82 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -190,7 +190,10 @@ bool pa_sink_input_new_data_set_sink(pa_sink_input_new_data *data, pa_sink *s, b if (!data->req_formats) { /* We're not working with the extended API */ data->sink = s; - data->save_sink = save; + if (save) { + pa_xfree(data->preferred_sink); + data->preferred_sink = pa_xstrdup(s->name); + } data->sink_requested_by_application = requested_by_application; } else { /* Extended API: let's see if this sink supports the formats the client can provide */ @@ -199,7 +202,10 @@ bool pa_sink_input_new_data_set_sink(pa_sink_input_new_data *data, pa_sink *s, b if (formats && !pa_idxset_isempty(formats)) { /* Sink supports at least one of the requested formats */ data->sink = s; - data->save_sink = save; + if (save) { + pa_xfree(data->preferred_sink); + data->preferred_sink = pa_xstrdup(s->name); + } data->sink_requested_by_application = requested_by_application; if (data->nego_formats) pa_idxset_free(data->nego_formats, (pa_free_cb_t) pa_format_info_free); @@ -226,7 +232,7 @@ bool pa_sink_input_new_data_set_formats(pa_sink_input_new_data *data, pa_idxset if (data->sink) { /* Trigger format negotiation */ - return pa_sink_input_new_data_set_sink(data, data->sink, data->save_sink, data->sink_requested_by_application); + return pa_sink_input_new_data_set_sink(data, data->sink, (data->preferred_sink != NULL), data->sink_requested_by_application); } return true; @@ -250,6 +256,9 @@ void pa_sink_input_new_data_done(pa_sink_input_new_data *data) { if (data->volume_factor_sink_items) pa_hashmap_free(data->volume_factor_sink_items); + if (data->preferred_sink) + pa_xfree(data->preferred_sink); + pa_proplist_free(data->proplist); } @@ -518,7 +527,7 @@ int pa_sink_input_new( pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels); i->volume_writable = data->volume_writable; i->save_volume = data->save_volume; - i->save_sink = data->save_sink; + i->preferred_sink = pa_xstrdup(data->preferred_sink); i->save_muted = data->save_muted; i->muted = data->muted; @@ -776,6 +785,9 @@ static void sink_input_free(pa_object *o) { if (i->volume_factor_sink_items) pa_hashmap_free(i->volume_factor_sink_items); + if (i->preferred_sink) + pa_xfree(i->preferred_sink); + pa_xfree(i->driver); pa_xfree(i); } @@ -1914,7 +1926,12 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) { i->moving(i, dest); i->sink = dest; - i->save_sink = save; + /* save == true, means user is calling the move_to() and want to + save the preferred_sink */ + if (save) { + pa_xfree(i->preferred_sink); + i->preferred_sink = pa_xstrdup(dest->name); + } pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL); PA_HASHMAP_FOREACH(v, i->volume_factor_sink_items, state) diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index f7f923744..16b6bf8eb 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -119,11 +119,16 @@ struct pa_sink_input { bool muted:1; - /* if true then the sink we are connected to and/or the volume - * set is worth remembering, i.e. was explicitly chosen by the - * user and not automatically. module-stream-restore looks for + /* if true then the volume and the mute state of this sink-input + * are worth remembering, module-stream-restore looks for * this.*/ - bool save_sink:1, save_volume:1, save_muted:1; + bool save_volume:1, save_muted:1; + + /* if users move the sink-input to a sink, and the sink is not default_sink, + * the sink->name will be saved in preferred_sink. And later if sink-input + * is moved to other sinks for some reason, it still can be restored to the + * preferred_sink at an appropriate time */ + char *preferred_sink; pa_resample_method_t requested_resample_method, actual_resample_method; @@ -315,7 +320,9 @@ typedef struct pa_sink_input_new_data { bool volume_writable:1; - bool save_sink:1, save_volume:1, save_muted:1; + bool save_volume:1, save_muted:1; + + char *preferred_sink; } pa_sink_input_new_data; pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data);