hal-interface, stream-manager: Add support for setting volume ratio to HAL 20/203720/4
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 17 Apr 2019 04:39:27 +0000 (13:39 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 18 Apr 2019 03:45:31 +0000 (12:45 +0900)
It is an extension of the previous patches regarding the
individual volume feature.

The 'ratio' parameter of the new HAL API is calculated
considering master volume ratio, group volume ratio and
individual volume ratio. The two former factors are
affected only when the volume type of the target stream
is not the HAL volume type defined in stream-map.json.

[Version] 11.1.41
[Issue type] New feature

Change-Id: I912a0f6eb1edc3fe33e058ef6290f4aba1267ed0
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/hal-interface.c
src/hal-interface.h
src/stream-manager-volume.c
src/stream-manager.c

index 5a975f2..5a58c7f 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          11.1.40
+Version:          11.1.41
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 1692a80..bbd2d33 100644 (file)
@@ -64,6 +64,7 @@ pa_hal_interface* pa_hal_interface_get(pa_core *core) {
         h->intf.get_volume_value = dlsym(h->dl_handle, "audio_get_volume_value");
         h->intf.get_volume_mute = dlsym(h->dl_handle, "audio_get_volume_mute");
         h->intf.set_volume_mute = dlsym(h->dl_handle, "audio_set_volume_mute");
+        h->intf.set_volume_ratio = dlsym(h->dl_handle, "audio_set_volume_ratio");
         h->intf.update_route = dlsym(h->dl_handle, "audio_update_route");
         h->intf.update_route_option = dlsym(h->dl_handle, "audio_update_route_option");
         h->intf.notify_stream_connection_changed = dlsym(h->dl_handle, "audio_notify_stream_connection_changed");
@@ -246,6 +247,30 @@ int32_t pa_hal_interface_set_volume_mute(pa_hal_interface *h, const char *volume
     return ret;
 }
 
+int32_t pa_hal_interface_set_volume_ratio(pa_hal_interface *h, const char *stream_role, io_direction_t direction, uint32_t idx, double ratio) {
+    int32_t ret = 0;
+    audio_return_t hal_ret = AUDIO_RET_OK;
+    audio_stream_info_t info = {NULL, 0, 0};
+
+    pa_assert(h);
+    pa_assert(stream_role);
+
+    if (h->intf.set_volume_ratio == NULL) {
+        pa_log_warn("there is no set_volume_ratio symbol in this audio hal, skip it");
+        return -1;
+    }
+
+    info.role = stream_role;
+    info.direction = direction;
+    info.idx = idx;
+
+    if (AUDIO_RET_OK != (hal_ret = h->intf.set_volume_ratio(h->ah_handle, &info, ratio))) {
+        pa_log_error("set_volume_ratio returns error:0x%x", hal_ret);
+        ret = -1;
+    }
+    return ret;
+}
+
 int32_t pa_hal_interface_update_route(pa_hal_interface *h, hal_route_info *info) {
     int32_t ret = 0;
     audio_return_t hal_ret = AUDIO_RET_OK;
index 20c14f8..b654845 100644 (file)
@@ -90,6 +90,7 @@ int32_t pa_hal_interface_set_volume_level(pa_hal_interface *h, const char *volum
 int32_t pa_hal_interface_get_volume_value(pa_hal_interface *h, const char *volume_type, const char *gain_type, io_direction_t direction, uint32_t level, double *value);
 int32_t pa_hal_interface_get_volume_mute(pa_hal_interface *h, const char *volume_type, io_direction_t direction, uint32_t *mute);
 int32_t pa_hal_interface_set_volume_mute(pa_hal_interface *h, const char *volume_type, io_direction_t direction, uint32_t mute);
+int32_t pa_hal_interface_set_volume_ratio(pa_hal_interface *h, const char *stream_role, io_direction_t direction, uint32_t idx, double ratio);
 int32_t pa_hal_interface_update_route(pa_hal_interface *h, hal_route_info *info);
 int32_t pa_hal_interface_update_route_option(pa_hal_interface *h, hal_route_option *option);
 int32_t pa_hal_interface_notify_stream_connection_changed(pa_hal_interface *h, hal_stream_connection_info *info);
index c5b475e..295533a 100644 (file)
@@ -265,25 +265,32 @@ int32_t update_mute_vconf(const char *type, unsigned int mute)
 }
 
 void apply_individual_ratio(pa_stream_manager *m, pa_object *stream, double volume_linear, pa_cvolume *result) {
-        double individual_ratio;
+        bool is_sink_input = false;
         double result_linear;
+        double individual_ratio;
+        double master_ratio;
+        double group_ratio;
+        double result_ratio;
         pa_volume_t volume;
         uint32_t index;
         unsigned channels;
+        io_direction_t io_direction;
+        const char *role;
+        const char *volume_type;
+        pa_hashmap *volumes = NULL;
+        volume_info *v = NULL;
+        stream_type_t stream_type;
+        stream_direction_t stream_direction;
 
         pa_assert(m);
         pa_assert(stream);
-        pa_assert(volume_linear);
+        pa_assert(result);
 
-        if (pa_sink_input_isinstance(stream)) {
-            individual_ratio = ((pa_sink_input*)stream)->individual_volume_ratio;
-            index = ((pa_sink_input*)stream)->index;
-            channels = ((pa_sink_input*)stream)->sample_spec.channels;
-        } else {
-            individual_ratio = ((pa_source_output*)stream)->individual_volume_ratio;
-            index = ((pa_source_output*)stream)->index;
-            channels = ((pa_sink_input*)stream)->sample_spec.channels;
-        }
+        is_sink_input = pa_sink_input_isinstance(stream);
+        individual_ratio = is_sink_input ? ((pa_sink_input*)stream)->individual_volume_ratio :
+                                            ((pa_source_output*)stream)->individual_volume_ratio;
+        channels = is_sink_input ? ((pa_sink_input*)stream)->sample_spec.channels :
+                                    ((pa_source_output*)stream)->sample_spec.channels;
 
         volume = pa_sw_volume_from_linear(volume_linear) * individual_ratio;
         result = pa_cvolume_set(result, channels, volume);
@@ -291,6 +298,34 @@ void apply_individual_ratio(pa_stream_manager *m, pa_object *stream, double volu
 
         pa_log_info("apply the individual ratio[%f] to stream[idx:%u], result volume linear[%f]",
                         individual_ratio, index, result_linear);
+
+        /* Here's calculation before calling HAL API */
+        stream_type = is_sink_input ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT;
+        if (!(volume_type = pa_proplist_gets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
+            pa_log_error("no volume type");
+            return;
+        }
+        role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROLE);
+        stream_direction = is_sink_input ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN;
+        volumes = m->volume_infos;
+        if (!(v = pa_hashmap_get(volumes, MASTER_VOLUME_TYPE))) {
+            pa_log_error("could not get volume_info, volume_type[%s]", MASTER_VOLUME_TYPE);
+            return;
+        }
+        master_ratio = v->is_hal_volume_type ? 1.0 : (double)v->values[stream_direction].current_level / MASTER_VOLUME_LEVEL_MAX;
+        if (!(v = pa_hashmap_get(volumes, volume_type))) {
+            pa_log_error("could not get volume_info, volume_type[%s]", volume_type);
+            return;
+        }
+        group_ratio = v->is_hal_volume_type ? 1.0 : (double)v->values[stream_direction].current_level / (pa_idxset_size(v->values[stream_direction].idx_volume_values) - 1);
+        result_ratio = master_ratio * group_ratio * individual_ratio;
+        pa_log_debug("role(%s), volume_type(%s) : master_ratio(%f), group_ratio(%f), individual_ratio(%f) => result_ratio(%f)",
+                    role, volume_type, master_ratio, group_ratio, individual_ratio, result_ratio);
+
+        index = GET_STREAM_INDEX(stream, stream_type);
+        io_direction = is_sink_input ? DIRECTION_OUT : DIRECTION_IN;
+
+        pa_hal_interface_set_volume_ratio(m->hal, role, io_direction, index, result_ratio);
 }
 
 int32_t set_volume_level_by_type(pa_stream_manager *m, stream_type_t stream_type, const char *volume_type, uint32_t volume_level) {
@@ -526,6 +561,7 @@ int32_t set_volume_level_with_new_data(pa_stream_manager *m, void *stream, strea
     bool is_hal_volume = false;
     pa_cvolume cv;
     double volume_linear = 1.0;
+    double *modifier_gain_value = NULL;
     const char *volume_type_str = NULL;
     const char *modifier_gain = NULL;
 
@@ -547,24 +583,25 @@ int32_t set_volume_level_with_new_data(pa_stream_manager *m, void *stream, strea
         if (pa_hal_interface_set_volume_level(m->hal, volume_type_str, CONVERT_TO_HAL_DIRECTION(stream_type), volume_level))
             return -1;
 
+    if (get_volume_value(m, stream_type, is_hal_volume, volume_type_str, volume_level, &volume_linear))
+        return -1;
+
     /* Get modifier for gain */
     modifier_gain = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE);
-
-    if (!get_volume_value(m, stream_type, is_hal_volume, volume_type_str, volume_level, &volume_linear)) {
-        if (modifier_gain) {
-            double *modifier_gain_value = NULL;
-            if ((modifier_gain_value = pa_hashmap_get(m->volume_modifiers, modifier_gain))) {
-                volume_linear *= (*modifier_gain_value);
-                pa_log_info("apply the modifier for the gain value[%s=>%f], result volume_linear[%f]",
-                            modifier_gain, *modifier_gain_value, volume_linear);
-            }
+    if (modifier_gain && m->volume_modifiers) {
+        if ((modifier_gain_value = pa_hashmap_get(m->volume_modifiers, modifier_gain))) {
+            volume_linear *= (*modifier_gain_value);
+            pa_log_info("apply the modifier for the gain value[%s=>%f], result volume_linear[%f]",
+                        modifier_gain, *modifier_gain_value, volume_linear);
         }
-        pa_cvolume_set(&cv, GET_STREAM_NEW_SAMPLE_SPEC(stream, stream_type).channels, pa_sw_volume_from_linear(volume_linear));
-        if (stream_type == STREAM_SINK_INPUT)
-            pa_sink_input_new_data_set_volume((pa_sink_input_new_data*)stream, &cv);
-        else if (stream_type == STREAM_SOURCE_OUTPUT)
-            pa_source_output_new_data_set_volume((pa_source_output_new_data*)stream, &cv);
     }
+
+    pa_cvolume_set(&cv, GET_STREAM_NEW_SAMPLE_SPEC(stream, stream_type).channels, pa_sw_volume_from_linear(volume_linear));
+    if (stream_type == STREAM_SINK_INPUT)
+        pa_sink_input_new_data_set_volume((pa_sink_input_new_data*)stream, &cv);
+    else if (stream_type == STREAM_SOURCE_OUTPUT)
+        pa_source_output_new_data_set_volume((pa_source_output_new_data*)stream, &cv);
+
     pa_log_debug("stream_type[%d], volume_type[%s], level[%u], value[%f]",
                  stream_type, volume_type_str, volume_level, volume_linear);
 
@@ -615,7 +652,7 @@ int32_t set_volume_rate_by_idx(pa_stream_manager *m, stream_type_t stream_type,
 
     /* Get modifier for gain */
     modifier_gain = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE);
-    if (modifier_gain) {
+    if (modifier_gain && m->volume_modifiers) {
         if ((modifier_gain_value = pa_hashmap_get(m->volume_modifiers, modifier_gain))) {
             volume_linear *= (*modifier_gain_value);
             pa_log_info("apply the modifier for the gain value[%s=>%f], result volume_linear[%f]",
index d2f931f..370b770 100644 (file)
@@ -2000,18 +2000,31 @@ process_stream_result_t process_stream(pa_stream_manager *m, void *stream, strea
             pa_log_warn("role is null, skip it");
         }
 
-    } else if (command == PROCESS_COMMAND_UPDATE_VOLUME && is_new_data) {
-        if ((si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
-            v = pa_hashmap_get(m->volume_infos, si_volume_type_str);
-            if (v && v->values[type].idx_volume_values) {
+    } else if (command == PROCESS_COMMAND_UPDATE_VOLUME) {
+        if (is_new_data)
+            si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
+        else
+            si_volume_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
+
+        if (!si_volume_type_str)
+            goto finish;
+
+        v = pa_hashmap_get(m->volume_infos, si_volume_type_str);
+        if (v && v->values[type].idx_volume_values) {
+            if (is_new_data) {
                 /* Update volume-level */
                 if ((volume_ret = set_volume_level_with_new_data(m, stream, type, v->values[type].current_level)))
-                    pa_log_error("failed to set_volume_level_by_idx(), stream_type(%d), level(%u), ret(0x%x)",
-                                 type, v->values[type].current_level, volume_ret);
+                    pa_log_error("failed to set_volume_level_with_new_data(), stream_type(%d), level(%u), ret(0x%x)",
+                                    type, v->values[type].current_level, volume_ret);
                 /* Update volume-mute */
                 if ((volume_ret = set_volume_mute_with_new_data(m, stream, type, v->values[type].is_muted)))
-                    pa_log_error("failed to set_volume_mute_by_idx(), stream_type(%d), mute(%d), ret(0x%x)",
-                                 type, v->values[type].is_muted, volume_ret);
+                    pa_log_error("failed to set_volume_mute_with_new_data(), stream_type(%d), mute(%d), ret(0x%x)",
+                                    type, v->values[type].is_muted, volume_ret);
+            } else {
+                /* Update volume-level by stream index*/
+                if ((volume_ret = set_volume_level_by_idx(m, type, GET_STREAM_INDEX(stream, type), v->values[type].current_level)))
+                    pa_log_error("failed to set_volume_level_by_idx(), stream_type(%d), index(%u), level(%u), ret(0x%x)",
+                                    type, GET_STREAM_INDEX(stream, type), v->values[type].current_level, volume_ret);
             }
         }
 
@@ -2110,6 +2123,7 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_st
 
     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_APPLY_FILTER, false);
+    process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, false);
     if (stream_is_call_family(PA_OBJECT(i))) {
         change_active_route_for_call(m, PA_OBJECT(i), true);
         m->on_call = true;
@@ -2230,6 +2244,7 @@ static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o,
 
     update_mirroring_streams(m, o, true);
     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
+    process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, false);
     if (stream_is_call_family(PA_OBJECT(o))) {
         change_active_route_for_call(m, PA_OBJECT(o), true);
         m->on_call = true;