mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
introduce relative_volume field in sink_input and make use of it on sink flat volume change
This commit is contained in:
parent
14e89d4ecd
commit
c32c6c833e
4 changed files with 83 additions and 47 deletions
|
|
@ -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,26 +925,52 @@ 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;
|
||||
|
||||
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));
|
||||
}
|
||||
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;
|
||||
|
||||
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 */
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
/* We don't copy the data to the thread_info data. That's left for someone else to do */
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
/* This basically calculates i->virtual_volume := i->relative_volume * s->virtual_volume */
|
||||
|
||||
remapped_new_volume = s->virtual_volume;
|
||||
pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue