sink-input, source-output: Use new_data.volume only for absolute volume 47/26447/1
authorTanu Kaskinen <tanu.kaskinen@linux.intel.com>
Mon, 4 Aug 2014 18:42:45 +0000 (21:42 +0300)
committerTanu Kaskinen <tanu.kaskinen@linux.intel.com>
Fri, 22 Aug 2014 10:43:43 +0000 (13:43 +0300)
This simplifies life for modules that care about the initial volume of
streams. new_data.volume will always be the absolute volume (assuming
that flat volume is in effect) and new_data.reference_ratio will
always be the relative volume.

This will be especially useful when creating volume controls (absolute
and relative) for new streams in module-volume-api.

Change-Id: Ibca033c8441dde35a0b43d9276c41e383c675306

src/modules/module-match.c
src/modules/module-stream-restore.c
src/pulsecore/play-memblockq.c
src/pulsecore/protocol-native.c
src/pulsecore/sink-input.c
src/pulsecore/sink-input.h
src/pulsecore/sound-file-stream.c
src/pulsecore/source-output.c
src/pulsecore/source-output.h

index 8ce3f00..7d73086 100644 (file)
@@ -234,7 +234,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
                 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);
         }
index 4fc5645..1aa8a07 100644 (file)
@@ -1482,9 +1482,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
 
                 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;
             }
         }
@@ -1579,9 +1577,7 @@ static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source
 
                 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;
             }
         }
index ff0c52b..055fd2a 100644 (file)
@@ -203,7 +203,7 @@ pa_sink_input* pa_memblockq_sink_input_new(
     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;
 
index 21e02fe..b209737 100644 (file)
@@ -679,8 +679,7 @@ static record_stream* record_stream_new(
         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) {
@@ -1149,8 +1148,7 @@ static playback_stream* playback_stream_new(
         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) {
index d62be6f..796a567 100644 (file)
@@ -145,12 +145,44 @@ bool pa_sink_input_new_data_is_passthrough(pa_sink_input_new_data *data) {
     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) {
@@ -292,6 +324,7 @@ int pa_sink_input_new(
     int r;
     char *pt;
     char *memblockq_name;
+    pa_cvolume v;
 
     pa_assert(_i);
     pa_assert(core);
@@ -380,18 +413,17 @@ int pa_sink_input_new(
     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;
     }
 
@@ -432,6 +464,12 @@ int pa_sink_input_new(
     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.");
@@ -482,18 +520,7 @@ int pa_sink_input_new(
     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);
index c99ce1f..b2d4967 100644 (file)
@@ -311,6 +311,7 @@ typedef struct pa_sink_input_new_data {
     pa_idxset *nego_formats;
 
     pa_cvolume volume;
+    pa_cvolume reference_ratio;
     bool muted:1;
     pa_hashmap *volume_factor_items, *volume_factor_sink_items;
 
@@ -320,7 +321,7 @@ typedef struct pa_sink_input_new_data {
     bool volume_is_set:1;
     bool muted_is_set:1;
 
-    bool volume_is_absolute:1;
+    bool volume_is_relative:1;
 
     bool volume_writable:1;
 
@@ -331,7 +332,7 @@ pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data
 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);
index 33f7337..6886025 100644 (file)
@@ -302,7 +302,7 @@ int pa_play_file(
     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);
index ae5a92c..c929999 100644 (file)
@@ -86,12 +86,44 @@ bool pa_source_output_new_data_is_passthrough(pa_source_output_new_data *data) {
     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) {
@@ -226,6 +258,7 @@ int pa_source_output_new(
     pa_channel_map volume_map;
     int r;
     char *pt;
+    pa_cvolume v;
 
     pa_assert(_o);
     pa_assert(core);
@@ -316,18 +349,17 @@ int pa_source_output_new(
     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;
     }
 
@@ -378,6 +410,12 @@ int pa_source_output_new(
     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.");
@@ -427,18 +465,7 @@ int pa_source_output_new(
     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;
index 60bbda8..dc82af9 100644 (file)
@@ -257,6 +257,7 @@ typedef struct pa_source_output_new_data {
     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;
@@ -265,7 +266,7 @@ typedef struct pa_source_output_new_data {
     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;
 
@@ -276,7 +277,7 @@ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_d
 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);