From c32c6c833e328610729ec034801ea110f5178cc1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Apr 2009 03:49:16 +0200 Subject: introduce relative_volume field in sink_input and make use of it on sink flat volume change --- src/pulsecore/sink-input.c | 56 +++++++++++++++++++++++++++++++++---------- src/pulsecore/sink-input.h | 8 ++++++- src/pulsecore/sink.c | 59 +++++++++++++++++++++++----------------------- src/pulsecore/sink.h | 5 ++-- 4 files changed, 82 insertions(+), 46 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index ad6b9ca7..58559775 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -288,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; @@ -530,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; @@ -901,11 +902,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); } @@ -923,24 +925,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; - sv = *pa_sink_get_volume(i->sink, FALSE); + 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)); + + if (!v) + v = pa_cvolume_reset(&_v, i->sample_spec.channels); + + /* This basically calculates: + * + * i->relative_volume := v + * i->soft_volume := i->relative_volume * i->volume_factor */ - pa_sw_cvolume_divide(v, v, - pa_cvolume_remap(&sv, &i->sink->channel_map, &i->channel_map)); + 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 */ @@ -1110,9 +1138,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. */ diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 6ecb5d73..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 @@ -349,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 886402a6..4cf7b6c0 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -990,22 +990,32 @@ static void compute_new_soft_volume(pa_sink_input *i, const pa_cvolume *new_volu pa_sink_input_assert_ref(i); pa_assert(new_volume->channels == i->sample_spec.channels); - /* This basically calculates i->soft_volume := i->virtual_volume / new_volume * i->volume_factor */ + /* + * 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->soft_volume.values[c] = pa_sw_volume_from_linear( - pa_sw_volume_to_linear(i->virtual_volume.values[c]) * - pa_sw_volume_to_linear(i->volume_factor.values[c]) / - pa_sw_volume_to_linear(new_volume->values[c])); + 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.channels = i->sample_spec.channels; + 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); @@ -1071,12 +1081,11 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { } /* 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); @@ -1085,26 +1094,18 @@ 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, new_virtual_volume; + pa_cvolume sink_volume, new_virtual_volume; unsigned c; - /* This basically calculates i->virtual_volume := i->virtual_volume * s->virtual_volume / old_volume */ - - 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++) - - if (remapped_old_volume.values[c] <= PA_VOLUME_MUTED) - new_virtual_volume.values[c] = remapped_new_volume.values[c]; - else - new_virtual_volume.values[c] = pa_sw_volume_from_linear( - pa_sw_volume_to_linear(i->virtual_volume.values[c]) * - pa_sw_volume_to_linear(remapped_new_volume.values[c]) / - pa_sw_volume_to_linear(remapped_old_volume.values[c])); + new_virtual_volume.values[c] = pa_sw_volume_from_linear( + i->relative_volume[c] * + pa_sw_volume_to_linear(sink_volume.values[c])); new_virtual_volume.channels = i->sample_spec.channels; @@ -1116,7 +1117,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) { * especially when the old volume was * PA_VOLUME_MUTED. Hence let's recalculate the soft * volumes here. */ - compute_new_soft_volume(i, &remapped_new_volume); + 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); @@ -1130,7 +1131,6 @@ void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) { /* 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); @@ -1139,14 +1139,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 @@ -1197,7 +1196,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); } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index eb1c88fe..289054de 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; @@ -250,7 +251,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); -- cgit