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");
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;
}
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);
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) {
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;
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);
/* 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]",
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);
}
}
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;
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;