pa_cvolume cv;
pa_log_debug("changing volume of sink input '%s' to 0x%03x", n, r->volume);
pa_cvolume_set(&cv, si->sample_spec.channels, r->volume);
- pa_sink_input_new_data_set_volume(si, &cv);
+ pa_sink_input_new_data_set_volume(si, &cv, true);
} else
pa_log_debug("the volume of sink input '%s' is not writable, can't change it", n);
}
v = e->volume;
pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
- pa_sink_input_new_data_set_volume(new_data, &v);
-
- new_data->volume_is_absolute = false;
+ pa_sink_input_new_data_set_volume(new_data, &v, true);
new_data->save_volume = true;
}
}
v = e->volume;
pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
- pa_source_output_new_data_set_volume(new_data, &v);
-
- new_data->volume_is_absolute = false;
+ pa_source_output_new_data_set_volume(new_data, &v, true);
new_data->save_volume = true;
}
}
data.driver = __FILE__;
pa_sink_input_new_data_set_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map);
- pa_sink_input_new_data_set_volume(&data, volume);
+ pa_sink_input_new_data_set_volume(&data, volume, false);
pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
data.flags |= flags;
pa_source_output_new_data_set_formats(&data, formats);
data.direct_on_input = direct_on_input;
if (volume) {
- pa_source_output_new_data_set_volume(&data, volume);
- data.volume_is_absolute = !relative_volume;
+ pa_source_output_new_data_set_volume(&data, volume, relative_volume);
data.save_volume = false;
}
if (muted_set) {
formats = NULL;
}
if (volume) {
- pa_sink_input_new_data_set_volume(&data, volume);
- data.volume_is_absolute = !relative_volume;
+ pa_sink_input_new_data_set_volume(&data, volume, relative_volume);
data.save_volume = false;
}
if (muted_set) {
return false;
}
-void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
+void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume, bool relative) {
+ pa_cvolume remapped_sink_volume;
+
pa_assert(data);
pa_assert(data->volume_writable);
if ((data->volume_is_set = !!volume))
data->volume = *volume;
+ else
+ return;
+
+ data->volume_is_relative = relative;
+
+ if (data->sink) {
+ remapped_sink_volume = data->sink->reference_volume;
+ pa_cvolume_remap(&remapped_sink_volume, &data->sink->channel_map, &data->channel_map);
+ }
+
+ if (relative) {
+ data->reference_ratio = data->volume;
+
+ if (data->sink && pa_sink_flat_volume_enabled(data->sink)) {
+ /* Let's keep data->volume as absolute, so that modules won't ever
+ * have to specially handle the relative case. Modules inspecting
+ * the volume should do so in the FIXATE hook, and at that point
+ * data->sink is always set. data->volume is relative only during
+ * the time before routing, and only if the sink input owner
+ * requested relative volume. */
+ pa_sw_cvolume_multiply(&data->volume, &data->volume, &remapped_sink_volume);
+ data->volume_is_relative = false;
+ }
+ } else {
+ if (data->sink)
+ pa_sw_cvolume_divide(&data->reference_ratio, &data->volume, &remapped_sink_volume);
+
+ /* If data->sink is not set, we can't compute the reference ratio.
+ * We'll compute it after routing. */
+ }
}
void pa_sink_input_new_data_add_volume_factor(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor) {
int r;
char *pt;
char *memblockq_name;
+ pa_cvolume v;
pa_assert(_i);
pa_assert(core);
if (r != PA_OK)
return r;
+ /* Now that the routing is done, we can finalize the volume if it has been
+ * set. If the set volume is relative, we convert it to absolute, and if
+ * it's absolute, we compute the reference ratio. */
+ if (data->volume_is_set)
+ pa_sink_input_new_data_set_volume(data, &data->volume, data->volume_is_relative);
+
/* Don't restore (or save) stream volume for passthrough streams and
* prevent attenuation/gain */
if (pa_sink_input_new_data_is_passthrough(data)) {
- data->volume_is_set = true;
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- data->volume_is_absolute = true;
- data->save_volume = false;
- }
-
- if (!data->volume_is_set) {
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- data->volume_is_absolute = false;
+ pa_cvolume_reset(&v, data->sample_spec.channels);
+ pa_sink_input_new_data_set_volume(data, &v, false);
data->save_volume = false;
}
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
return r;
+ if (!data->volume_is_set) {
+ pa_cvolume_reset(&v, data->sample_spec.channels);
+ pa_sink_input_new_data_set_volume(data, &v, true);
+ data->save_volume = false;
+ }
+
if ((data->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) &&
pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
pa_log_warn("Failed to create sink input: sink is suspended.");
i->sample_spec = data->sample_spec;
i->channel_map = data->channel_map;
i->format = pa_format_info_copy(data->format);
-
- if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
- pa_cvolume remapped;
-
- /* When the 'absolute' bool is not set then we'll treat the volume
- * as relative to the sink volume even in flat volume mode */
- remapped = data->sink->reference_volume;
- pa_cvolume_remap(&remapped, &data->sink->channel_map, &data->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &data->volume, &remapped);
- } else
- i->volume = data->volume;
-
+ i->volume = data->volume;
i->volume_factor_items = data->volume_factor_items;
data->volume_factor_items = NULL;
volume_factor_from_hashmap(&i->volume_factor, i->volume_factor_items, i->sample_spec.channels);
pa_idxset *nego_formats;
pa_cvolume volume;
+ pa_cvolume reference_ratio;
bool muted:1;
pa_hashmap *volume_factor_items, *volume_factor_sink_items;
bool volume_is_set:1;
bool muted_is_set:1;
- bool volume_is_absolute:1;
+ bool volume_is_relative:1;
bool volume_writable:1;
void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec);
void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map);
bool pa_sink_input_new_data_is_passthrough(pa_sink_input_new_data *data);
-void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
+void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume, bool relative);
void pa_sink_input_new_data_add_volume_factor(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor);
void pa_sink_input_new_data_add_volume_factor_sink(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor);
void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, bool mute);
data.driver = __FILE__;
pa_sink_input_new_data_set_sample_spec(&data, &ss);
pa_sink_input_new_data_set_channel_map(&data, &cm);
- pa_sink_input_new_data_set_volume(&data, volume);
+ pa_sink_input_new_data_set_volume(&data, volume, false);
pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
pa_sndfile_init_proplist(u->sndfile, data.proplist);
return false;
}
-void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume) {
+void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume, bool relative) {
+ pa_cvolume remapped_source_volume;
+
pa_assert(data);
pa_assert(data->volume_writable);
if ((data->volume_is_set = !!volume))
data->volume = *volume;
+ else
+ return;
+
+ data->volume_is_relative = relative;
+
+ if (data->source) {
+ remapped_source_volume = data->source->reference_volume;
+ pa_cvolume_remap(&remapped_source_volume, &data->source->channel_map, &data->channel_map);
+ }
+
+ if (relative) {
+ data->reference_ratio = data->volume;
+
+ if (data->source && pa_source_flat_volume_enabled(data->source)) {
+ /* Let's keep data->volume as absolute, so that modules won't ever
+ * have to specially handle the relative case. Modules inspecting
+ * the volume should do so in the FIXATE hook, and at that point
+ * data->source is always set. data->volume is relative only during
+ * the time before routing, and only if the source output owner
+ * requested relative volume. */
+ pa_sw_cvolume_multiply(&data->volume, &data->volume, &remapped_source_volume);
+ data->volume_is_relative = false;
+ }
+ } else {
+ if (data->source)
+ pa_sw_cvolume_divide(&data->reference_ratio, &data->volume, &remapped_source_volume);
+
+ /* If data->source is not set, we can't compute the reference ratio.
+ * We'll compute it after routing. */
+ }
}
void pa_source_output_new_data_apply_volume_factor(pa_source_output_new_data *data, const pa_cvolume *volume_factor) {
pa_channel_map volume_map;
int r;
char *pt;
+ pa_cvolume v;
pa_assert(_o);
pa_assert(core);
if (r < 0)
return r;
+ /* Now that the routing is done, we can finalize the volume if it has been
+ * set. If the set volume is relative, we convert it to absolute, and if
+ * it's absolute, we compute the reference ratio. */
+ if (data->volume_is_set)
+ pa_source_output_new_data_set_volume(data, &data->volume, data->volume_is_relative);
+
/* Don't restore (or save) stream volume for passthrough streams and
* prevent attenuation/gain */
if (pa_source_output_new_data_is_passthrough(data)) {
- data->volume_is_set = true;
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- data->volume_is_absolute = true;
- data->save_volume = false;
- }
-
- if (!data->volume_is_set) {
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- data->volume_is_absolute = false;
+ pa_cvolume_reset(&v, data->sample_spec.channels);
+ pa_source_output_new_data_set_volume(data, &v, false);
data->save_volume = false;
}
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
return r;
+ if (!data->volume_is_set) {
+ pa_cvolume_reset(&v, data->sample_spec.channels);
+ pa_source_output_new_data_set_volume(data, &v, true);
+ data->save_volume = false;
+ }
+
if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
pa_log("Failed to create source output: source is suspended.");
o->sample_spec = data->sample_spec;
o->channel_map = data->channel_map;
o->format = pa_format_info_copy(data->format);
-
- if (!data->volume_is_absolute && pa_source_flat_volume_enabled(o->source)) {
- pa_cvolume remapped;
-
- /* When the 'absolute' bool is not set then we'll treat the volume
- * as relative to the source volume even in flat volume mode */
- remapped = data->source->reference_volume;
- pa_cvolume_remap(&remapped, &data->source->channel_map, &data->channel_map);
- pa_sw_cvolume_multiply(&o->volume, &data->volume, &remapped);
- } else
- o->volume = data->volume;
-
+ o->volume = data->volume;
o->volume_factor = data->volume_factor;
o->volume_factor_source = data->volume_factor_source;
o->real_ratio = o->reference_ratio = data->volume;
pa_idxset *nego_formats;
pa_cvolume volume, volume_factor, volume_factor_source;
+ pa_cvolume reference_ratio;
bool muted:1;
bool sample_spec_is_set:1;
bool volume_is_set:1, volume_factor_is_set:1, volume_factor_source_is_set:1;
bool muted_is_set:1;
- bool volume_is_absolute:1;
+ bool volume_is_relative:1;
bool volume_writable:1;
void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec);
void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map);
bool pa_source_output_new_data_is_passthrough(pa_source_output_new_data *data);
-void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume);
+void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume, bool relative);
void pa_source_output_new_data_apply_volume_factor(pa_source_output_new_data *data, const pa_cvolume *volume_factor);
void pa_source_output_new_data_apply_volume_factor_source(pa_source_output_new_data *data, const pa_cvolume *volume_factor);
void pa_source_output_new_data_set_muted(pa_source_output_new_data *data, bool mute);