X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/d802a76963e32bd821edfa89d6fe39764f1942f6..a998038ee26f86054d0e314fcfe589169ce97ea7:/src/pulsecore/sink-input.c diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index df42cae8..ae2c6f54 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -6,7 +6,7 @@ PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but @@ -79,6 +79,18 @@ void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cv data->volume = *volume; } +void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor) { + pa_assert(data); + pa_assert(volume_factor); + + if (data->volume_factor_is_set) + pa_sw_cvolume_multiply(&data->volume_factor, &data->volume_factor, volume_factor); + else { + data->volume_factor_is_set = TRUE; + data->volume_factor = *volume_factor; + } +} + void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) { pa_assert(data); @@ -110,6 +122,7 @@ static void reset_callbacks(pa_sink_input *i) { i->get_latency = NULL; i->state_change = NULL; i->may_move_to = NULL; + i->send_event = NULL; } /* Called from main context */ @@ -145,7 +158,6 @@ int pa_sink_input_new( pa_return_val_if_fail(data->sink, -PA_ERR_NOENTITY); pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE); pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID); - pa_return_val_if_fail(!(flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) || pa_sink_get_state(data->sink) != PA_SINK_SUSPENDED, -PA_ERR_BADSTATE); if (!data->sample_spec_is_set) data->sample_spec = data->sink->sample_spec; @@ -167,16 +179,24 @@ int pa_sink_input_new( if (data->sink->flags & PA_SINK_FLAT_VOLUME) { data->volume = *pa_sink_get_volume(data->sink, FALSE); pa_cvolume_remap(&data->volume, &data->sink->channel_map, &data->channel_map); - } else + data->volume_is_absolute = TRUE; + } else { pa_cvolume_reset(&data->volume, data->sample_spec.channels); + data->volume_is_absolute = FALSE; + } data->save_volume = FALSE; - } pa_return_val_if_fail(pa_cvolume_valid(&data->volume), -PA_ERR_INVALID); pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID); + if (!data->volume_factor_is_set) + pa_cvolume_reset(&data->volume_factor, data->sample_spec.channels); + + pa_return_val_if_fail(pa_cvolume_valid(&data->volume_factor), -PA_ERR_INVALID); + pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor, &data->sample_spec), -PA_ERR_INVALID); + if (!data->muted_is_set) data->muted = FALSE; @@ -207,6 +227,12 @@ int pa_sink_input_new( if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0) return r; + if ((flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) && + pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) { + pa_log_warn("Failed to create sink input: sink is suspended."); + return -PA_ERR_BADSTATE; + } + if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn("Failed to create sink input: too many inputs per sink."); return -PA_ERR_TOOLARGE; @@ -259,6 +285,7 @@ int pa_sink_input_new( } else i->virtual_volume = data->volume; + i->volume_factor = data->volume_factor; pa_cvolume_init(&i->soft_volume); i->save_volume = data->save_volume; i->save_sink = data->save_sink; @@ -441,6 +468,8 @@ void pa_sink_input_unlink(pa_sink_input *i) { i->sink = NULL; } + pa_core_maybe_vacuum(i->core); + pa_sink_input_unref(i); } @@ -500,7 +529,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 - i->soft_volume = i->virtual_volume; + pa_sw_cvolume_multiply(&i->soft_volume, &i->virtual_volume, &i->volume_factor); i->thread_info.soft_volume = i->soft_volume; i->thread_info.muted = i->muted; @@ -874,8 +903,7 @@ 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 */ - - i->soft_volume = *volume; + pa_sw_cvolume_multiply(&i->soft_volume, volume, &i->volume_factor); /* 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); @@ -895,6 +923,28 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { return &i->virtual_volume; } +/* Called from main context */ +pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) { + 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; + + sv = *pa_sink_get_volume(i->sink, FALSE); + + pa_sw_cvolume_divide(v, v, + pa_cvolume_remap(&sv, &i->sink->channel_map, &i->channel_map)); + } + + return v; +} + /* Called from main context */ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) { pa_assert(i); @@ -920,18 +970,16 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) { } /* Called from main thread */ -pa_bool_t pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) { - - pa_sink_input_assert_ref(i); - - pa_proplist_update(i->proplist, mode, p); +void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) { + pa_sink_input_assert_ref(i); - if (PA_SINK_IS_LINKED(i->state)) { - pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i); - pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } + if (p) + pa_proplist_update(i->proplist, mode, p); - return TRUE; + if (PA_SINK_IS_LINKED(i->state)) { + pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i); + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } } /* Called from main context */ @@ -1066,7 +1114,7 @@ int pa_sink_input_start_move(pa_sink_input *i) { /* Make the absolute volume relative */ i->virtual_volume = i->soft_volume; - pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels); + i->soft_volume = i->volume_factor; /* We might need to update the sink's volume if we are in flat * volume mode. */ @@ -1428,3 +1476,31 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) { return ret; } + +/* Called from main context */ +void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *data) { + pa_proplist *pl = NULL; + pa_sink_input_send_event_hook_data hook_data; + + pa_sink_input_assert_ref(i); + pa_assert(event); + + if (!i->send_event) + return; + + if (!data) + data = pl = pa_proplist_new(); + + hook_data.sink_input = i; + hook_data.data = data; + hook_data.event = event; + + if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], &hook_data) < 0) + goto finish; + + i->send_event(i, event, data); + +finish: + if (pl) + pa_proplist_free(pl); +}