X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/fe6e41d7d27790338eb57073e42bfa8776112dd0..2f6364dfe454d3fe21cf98854ac8942870e52436:/src/pulsecore/sink.c diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 08143e9b..fbb14d27 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -235,6 +235,12 @@ pa_sink* pa_sink_new( pa_device_init_icon(data->proplist, true); pa_device_init_intended_roles(data->proplist); + if (!data->active_port) { + pa_device_port *p = pa_device_port_find_best(data->ports); + if (p) + pa_sink_new_data_set_port(data, p->name); + } + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) { pa_xfree(s); pa_namereg_unregister(core, name); @@ -300,23 +306,10 @@ pa_sink* pa_sink_new( if ((s->active_port = pa_hashmap_get(s->ports, data->active_port))) s->save_port = data->save_port; - if (!s->active_port) { - void *state; - pa_device_port *p; - - PA_HASHMAP_FOREACH(p, s->ports, state) { - if (p->available == PA_AVAILABLE_NO) - continue; - - if (!s->active_port || p->priority > s->active_port->priority) - s->active_port = p; - } - if (!s->active_port) { - PA_HASHMAP_FOREACH(p, s->ports, state) - if (!s->active_port || p->priority > s->active_port->priority) - s->active_port = p; - } - } + /* Hopefully the active port has already been assigned in the previous call + to pa_device_port_find_best, but better safe than sorry */ + if (!s->active_port) + s->active_port = pa_device_port_find_best(s->ports); if (s->active_port) s->latency_offset = s->active_port->latency_offset; @@ -515,7 +508,7 @@ void pa_sink_set_write_volume_callback(pa_sink *s, pa_sink_cb_t cb) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } -void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_cb_t cb) { +void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_get_mute_cb_t cb) { pa_assert(s); s->get_mute = cb; @@ -1842,20 +1835,13 @@ static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_chan PA_IDXSET_FOREACH(i, s->inputs, idx) { if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) { if (pa_sink_flat_volume_enabled(s)) { - pa_cvolume old_volume = i->volume; + pa_cvolume new_input_volume; /* Follow the root sink's real volume. */ - i->volume = *new_volume; - pa_cvolume_remap(&i->volume, channel_map, &i->channel_map); + new_input_volume = *new_volume; + pa_cvolume_remap(&new_input_volume, channel_map, &i->channel_map); + pa_sink_input_set_volume_direct(i, &new_input_volume); compute_reference_ratio(i); - - /* The volume changed, let's tell people so */ - if (!pa_cvolume_equal(&old_volume, &i->volume)) { - if (i->volume_changed) - i->volume_changed(i); - - pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } } update_real_volume(i->origin_sink, new_volume, channel_map); @@ -1910,7 +1896,7 @@ static void propagate_reference_volume(pa_sink *s) { * sink input volumes accordingly */ PA_IDXSET_FOREACH(i, s->inputs, idx) { - pa_cvolume old_volume; + pa_cvolume new_volume; if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) { propagate_reference_volume(i->origin_sink); @@ -1921,24 +1907,14 @@ static void propagate_reference_volume(pa_sink *s) { continue; } - old_volume = i->volume; - /* This basically calculates: * * i->volume := s->reference_volume * i->reference_ratio */ - i->volume = s->reference_volume; - pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map); - pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio); - - /* The volume changed, let's tell people so */ - if (!pa_cvolume_equal(&old_volume, &i->volume)) { - - if (i->volume_changed) - i->volume_changed(i); - - pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } + new_volume = s->reference_volume; + pa_cvolume_remap(&new_volume, &s->channel_map, &i->channel_map); + pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio); + pa_sink_input_set_volume_direct(i, &new_volume); } } @@ -1961,13 +1937,11 @@ static bool update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_ch pa_cvolume_remap(&volume, channel_map, &s->channel_map); reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume); - s->reference_volume = volume; + pa_sink_set_reference_volume_direct(s, &volume); s->save_volume = (!reference_volume_changed && s->save_volume) || save; - if (reference_volume_changed) - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - else if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) + if (!reference_volume_changed && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) /* If the root sink's volume doesn't change, then there can't be any * changes in the other sinks in the sink tree either. * @@ -2135,7 +2109,7 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) if (pa_sink_flat_volume_enabled(s)) { PA_IDXSET_FOREACH(i, s->inputs, idx) { - pa_cvolume old_volume = i->volume; + pa_cvolume new_volume; /* 2. Since the sink's reference and real volumes are equal * now our ratios should be too. */ @@ -2149,18 +2123,10 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) * i->volume = s->reference_volume * i->reference_ratio * * This is identical to propagate_reference_volume() */ - i->volume = s->reference_volume; - pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map); - pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio); - - /* Notify if something changed */ - if (!pa_cvolume_equal(&old_volume, &i->volume)) { - - if (i->volume_changed) - i->volume_changed(i); - - pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } + new_volume = s->reference_volume; + pa_cvolume_remap(&new_volume, &s->channel_map, &i->channel_map); + pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio); + pa_sink_input_set_volume_direct(i, &new_volume); if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) propagate_real_volume(i->origin_sink, old_real_volume); @@ -2230,19 +2196,30 @@ void pa_sink_set_mute(pa_sink *s, bool mute, bool save) { pa_sink_assert_ref(s); pa_assert_ctl_context(); - pa_assert(PA_SINK_IS_LINKED(s->state)); old_muted = s->muted; + + if (mute == old_muted) { + s->save_muted |= save; + return; + } + s->muted = mute; - s->save_muted = (old_muted == s->muted && s->save_muted) || save; + s->save_muted = save; - if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute) + if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute) { + s->set_mute_in_progress = true; s->set_mute(s); + s->set_mute_in_progress = false; + } - pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0); + if (!PA_SINK_IS_LINKED(s->state)) + return; - if (old_muted != s->muted) - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + pa_log_debug("The mute of sink %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute)); + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED], s); } /* Called from main thread */ @@ -2252,21 +2229,15 @@ bool pa_sink_get_mute(pa_sink *s, bool force_refresh) { pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); - if (s->refresh_muted || force_refresh) { - bool old_muted = s->muted; - - if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_mute) - s->get_mute(s); + if ((s->refresh_muted || force_refresh) && s->get_mute) { + bool mute; - pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0); - - if (old_muted != s->muted) { - s->save_muted = true; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - - /* Make sure the soft mute status stays in sync */ - pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0); + if (s->flags & PA_SINK_DEFERRED_VOLUME) { + if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &mute, 0, NULL) >= 0) + pa_sink_mute_changed(s, mute); + } else { + if (s->get_mute(s, &mute) >= 0) + pa_sink_mute_changed(s, mute); } } @@ -2279,15 +2250,17 @@ void pa_sink_mute_changed(pa_sink *s, bool new_muted) { pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); - /* The sink implementor may call this if the volume changed to make sure everyone is notified */ - - if (s->muted == new_muted) + if (s->set_mute_in_progress) return; - s->muted = new_muted; - s->save_muted = true; + /* pa_sink_set_mute() does this same check, so this may appear redundant, + * but we must have this here also, because the save parameter of + * pa_sink_set_mute() would otherwise have unintended side effects (saving + * the mute state when it shouldn't be saved). */ + if (new_muted == s->muted) + return; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + pa_sink_set_mute(s, new_muted, true); } /* Called from main thread */ @@ -2554,9 +2527,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse i->thread_info.sync_next = NULL; } - if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index))) - pa_sink_input_unref(i); - + pa_hashmap_remove_and_free(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)); pa_sink_invalidate_requested_latency(s, true); pa_sink_request_rewind(s, (size_t) -1); @@ -2637,8 +2608,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse i->thread_info.attached = false; /* Let's remove the sink input ...*/ - if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index))) - pa_sink_input_unref(i); + pa_hashmap_remove_and_free(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)); pa_sink_invalidate_requested_latency(s, true); @@ -2775,7 +2745,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse case PA_SINK_MESSAGE_GET_MUTE: if (s->flags & PA_SINK_DEFERRED_VOLUME && s->get_mute) - s->get_mute(s); + return s->get_mute(s, userdata); return 0; @@ -3808,3 +3778,28 @@ done: return out_formats; } + +/* Called from the main thread. */ +void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) { + pa_cvolume old_volume; + char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; + char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; + + pa_assert(s); + pa_assert(volume); + + old_volume = s->reference_volume; + + if (pa_cvolume_equal(volume, &old_volume)) + return; + + s->reference_volume = *volume; + pa_log_debug("The reference volume of sink %s changed from %s to %s.", s->name, + pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &s->channel_map, + s->flags & PA_SINK_DECIBEL_VOLUME), + pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &s->channel_map, + s->flags & PA_SINK_DECIBEL_VOLUME)); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s); +}