diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 3a0af4e9..fc72590a 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -363,6 +363,157 @@ static void audio_extn_ext_disp_set_parameters(const struct audio_device *adev, } } +static int update_custom_mtmx_coefficients(struct audio_device *adev, + struct audio_custom_mtmx_params *params, + int pcm_device_id) +{ + struct mixer_ctl *ctl = NULL; + char *mixer_name_prefix = "AudStr"; + char *mixer_name_suffix = "ChMixer Weight Ch"; + char mixer_ctl_name[128] = {0}; + struct audio_custom_mtmx_params_info *pinfo = ¶ms->info; + int i = 0, err = 0; + + ALOGI("%s: ip_channels %d, op_channels %d, pcm_device_id %d", + __func__, pinfo->ip_channels, pinfo->op_channels, pcm_device_id); + + for (i = 0; i < (int)pinfo->op_channels; i++) { + snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %d %s %d", + mixer_name_prefix, pcm_device_id, mixer_name_suffix, i+1); + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + + err = mixer_ctl_set_array(ctl, + ¶ms->coeffs[pinfo->ip_channels * i], + pinfo->ip_channels); + if (err) { + ALOGE("%s: ERROR. Mixer ctl set failed", __func__); + return -EINVAL; + } + } + return 0; +} + +static void set_custom_mtmx_params(struct audio_device *adev, + struct audio_custom_mtmx_params_info *pinfo, + int pcm_device_id, bool enable) +{ + struct mixer_ctl *ctl = NULL; + char *mixer_name_prefix = "AudStr"; + char *mixer_name_suffix = "ChMixer Cfg"; + char mixer_ctl_name[128] = {0}; + int chmixer_cfg[5] = {0}, len = 0; + int be_id = -1, err = 0; + + be_id = platform_get_snd_device_backend_index(pinfo->snd_device); + + ALOGI("%s: ip_channels %d,op_channels %d,pcm_device_id %d,be_id %d", + __func__, pinfo->ip_channels, pinfo->op_channels, pcm_device_id, be_id); + + snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), + "%s %d %s", mixer_name_prefix, pcm_device_id, mixer_name_suffix); + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s", + __func__, mixer_ctl_name); + return; + } + chmixer_cfg[len++] = enable ? 1 : 0; + chmixer_cfg[len++] = 0; /* rule index */ + chmixer_cfg[len++] = pinfo->ip_channels; + chmixer_cfg[len++] = pinfo->op_channels; + chmixer_cfg[len++] = be_id + 1; + + err = mixer_ctl_set_array(ctl, chmixer_cfg, len); + if (err) + ALOGE("%s: ERROR. Mixer ctl set failed", __func__); +} + +void audio_extn_set_custom_mtmx_params(struct audio_device *adev, + struct audio_usecase *usecase, + bool enable) +{ + struct audio_custom_mtmx_params_info info = {0}; + struct audio_custom_mtmx_params *params = NULL; + int num_devices = 0, pcm_device_id = -1, i = 0, ret = 0; + snd_device_t new_snd_devices[SND_DEVICE_OUT_END] = {0}; + struct audio_backend_cfg backend_cfg = {0}; + uint32_t feature_id = 0; + + switch(usecase->type) { + case PCM_PLAYBACK: + if (usecase->stream.out) { + pcm_device_id = + platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK); + if (platform_split_snd_device(adev->platform, + usecase->out_snd_device, + &num_devices, new_snd_devices)) { + new_snd_devices[0] = usecase->out_snd_device; + num_devices = 1; + } + } else { + ALOGE("%s: invalid output stream for playback usecase id:%d", + __func__, usecase->id); + return; + } + break; + case PCM_CAPTURE: + if (usecase->stream.in) { + pcm_device_id = + platform_get_pcm_device_id(usecase->id, PCM_CAPTURE); + if (platform_split_snd_device(adev->platform, + usecase->in_snd_device, + &num_devices, new_snd_devices)) { + new_snd_devices[0] = usecase->in_snd_device; + num_devices = 1; + } + } else { + ALOGE("%s: invalid input stream for capture usecase id:%d", + __func__, usecase->id); + return; + } + break; + default: + ALOGV("%s: unsupported usecase id:%d", __func__, usecase->id); + return; + } + + /* + * check and update feature_id before this assignment, + * if features like dual_mono is enabled and overrides the default(i.e. 0). + */ + info.id = feature_id; + info.usecase_id = usecase->id; + for (i = 0, ret = 0; i < num_devices; i++) { + info.snd_device = new_snd_devices[i]; + platform_get_codec_backend_cfg(adev, info.snd_device, &backend_cfg); + if (usecase->type == PCM_PLAYBACK) { + info.ip_channels = audio_channel_count_from_out_mask( + usecase->stream.out->channel_mask); + info.op_channels = backend_cfg.channels; + } else { + info.ip_channels = backend_cfg.channels; + info.op_channels = audio_channel_count_from_in_mask( + usecase->stream.in->channel_mask); + } + + params = platform_get_custom_mtmx_params(adev->platform, &info); + if (params) { + if (enable) + ret = update_custom_mtmx_coefficients(adev, params, + pcm_device_id); + if (ret < 0) + ALOGE("%s: error updating mtmx coeffs err:%d", __func__, ret); + else + set_custom_mtmx_params(adev, &info, pcm_device_id, enable); + } + } +} + #ifndef DTS_EAGLE #define audio_extn_hpx_set_parameters(adev, parms) (0) #define audio_extn_hpx_get_parameters(query, reply) (0) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index a41463bb..8e1a0e8c 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -1205,4 +1205,7 @@ void audio_extn_send_dual_mono_mixing_coefficients(struct stream_out *out); void audio_extn_set_cpu_affinity(); bool audio_extn_is_record_play_concurrency_enabled(); bool audio_extn_is_concurrent_capture_enabled(); +void audio_extn_set_custom_mtmx_params(struct audio_device *adev, + struct audio_usecase *usecase, + bool enable); #endif /* AUDIO_EXTN_H */ diff --git a/hal/audio_hw.c b/hal/audio_hw.c index e33f248e..b0aff8eb 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1069,6 +1069,7 @@ int enable_audio_route(struct audio_device *adev, if (out && out->compr) audio_extn_utils_compress_set_clk_rec_mode(usecase); } + audio_extn_set_custom_mtmx_params(adev, usecase, true); strlcpy(mixer_path, use_case_table[usecase->id], MIXER_PATH_MAX_LENGTH); platform_add_backend_name(mixer_path, snd_device, usecase); @@ -1105,6 +1106,7 @@ int disable_audio_route(struct audio_device *adev, audio_route_reset_and_update_path(adev->audio_route, mixer_path); audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE); audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE); + audio_extn_set_custom_mtmx_params(adev, usecase, false); ALOGV("%s: exit", __func__); return 0; } diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c index 690f7719..d79f5a5f 100644 --- a/hal/msm8916/platform.c +++ b/hal/msm8916/platform.c @@ -309,6 +309,7 @@ struct platform_data { struct snd_device_to_mic_map mic_map[SND_DEVICE_MAX]; struct spkr_device_chmap *spkr_ch_map; bool use_sprk_default_sample_rate; + struct listnode custom_mtmx_params_list; }; struct spkr_device_chmap { @@ -2399,6 +2400,7 @@ void *platform_init(struct audio_device *adev) my_data->hifi_audio = true; list_init(&my_data->acdb_meta_key_list); + list_init(&my_data->custom_mtmx_params_list); set_platform_defaults(my_data); @@ -2769,6 +2771,75 @@ acdb_init_fail: return my_data; } +struct audio_custom_mtmx_params * + platform_get_custom_mtmx_params(void *platform, + struct audio_custom_mtmx_params_info *info) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct listnode *node = NULL; + struct audio_custom_mtmx_params *params = NULL; + + list_for_each(node, &my_data->custom_mtmx_params_list) { + params = node_to_item(node, struct audio_custom_mtmx_params, list); + if (params && + params->info.id == info->id && + params->info.ip_channels == info->ip_channels && + params->info.op_channels == info->op_channels && + params->info.usecase_id == info->usecase_id && + params->info.snd_device == info->snd_device) { + ALOGV("%s: found params with ip_ch %d op_ch %d uc_id %d snd_dev %d", + __func__, info->ip_channels, info->op_channels, + info->usecase_id, info->snd_device); + return params; + } + } + ALOGI("%s: no matching param with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d", + __func__, info->id, info->ip_channels, info->op_channels, + info->usecase_id, info->snd_device); + return NULL; +} + +int platform_add_custom_mtmx_params(void *platform, + struct audio_custom_mtmx_params_info *info) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_custom_mtmx_params *params = NULL; + uint32_t size = sizeof(*params); + + if (info->ip_channels > AUDIO_CHANNEL_COUNT_MAX || + info->op_channels > AUDIO_CHANNEL_COUNT_MAX) { + ALOGE("%s: unusupported channels in %d, out %d", + __func__, info->ip_channels, info->op_channels); + return -EINVAL; + } + + size += sizeof(params->coeffs[0]) * info->ip_channels * info->op_channels; + params = (struct audio_custom_mtmx_params *) calloc(1, size); + if (!params) { + ALOGE("%s: failed to add custom mtmx params", __func__); + return -ENOMEM; + } + + ALOGI("%s: adding mtmx params with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d", + __func__, info->id, info->ip_channels, info->op_channels, + info->usecase_id, info->snd_device); + + params->info = *info; + list_add_tail(&my_data->custom_mtmx_params_list, ¶ms->list); + return 0; +} + +static void platform_release_custom_mtmx_params(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct listnode *node = NULL, *tempnode = NULL; + + list_for_each_safe(node, tempnode, &my_data->custom_mtmx_params_list) { + list_remove(node); + free(node_to_item(node, struct audio_custom_mtmx_params, list)); + } +} + void platform_release_acdb_metainfo_key(void *platform) { struct platform_data *my_data = (struct platform_data *)platform; @@ -2854,6 +2925,7 @@ void platform_deinit(void *platform) /* free acdb_meta_key_list */ platform_release_acdb_metainfo_key(platform); + platform_release_custom_mtmx_params(platform); if (my_data->acdb_deallocate) my_data->acdb_deallocate(); diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 480ef135..f7a7ebfc 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2013 The Android Open Source Project @@ -353,6 +353,27 @@ void *platform_init(struct audio_device *adev) return my_data; } +struct audio_custom_mtmx_params * + platform_get_custom_mtmx_params + ( + void *platform __unused, + struct audio_custom_mtmx_params_info *info __unused + ) +{ + ALOGW("%s: not implemented!", __func__); + return NULL; +} + +int platform_add_custom_mtmx_params + ( + void *platform __unused, + struct audio_custom_mtmx_params_info *info __unused + ) +{ + ALOGW("%s: not implemented!", __func__); + return -ENOSYS; +} + void platform_deinit(void *platform) { struct platform_data *my_data = (struct platform_data *)platform; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index e0f4e2c6..92b8bfb4 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -336,6 +336,7 @@ struct platform_data { struct snd_device_to_mic_map mic_map[SND_DEVICE_MAX]; struct spkr_device_chmap *spkr_ch_map; bool use_sprk_default_sample_rate; + struct listnode custom_mtmx_params_list; }; struct spkr_device_chmap { @@ -2882,6 +2883,7 @@ void *platform_init(struct audio_device *adev) my_data->is_bcl_speaker = true; list_init(&my_data->acdb_meta_key_list); + list_init(&my_data->custom_mtmx_params_list); ret = audio_extn_is_hifi_audio_supported(); if (ret || !my_data->is_internal_codec) @@ -3381,6 +3383,74 @@ acdb_init_fail: return my_data; } +struct audio_custom_mtmx_params * + platform_get_custom_mtmx_params(void *platform, + struct audio_custom_mtmx_params_info *info) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct listnode *node = NULL; + struct audio_custom_mtmx_params *params = NULL; + + list_for_each(node, &my_data->custom_mtmx_params_list) { + params = node_to_item(node, struct audio_custom_mtmx_params, list); + if (params && + params->info.id == info->id && + params->info.ip_channels == info->ip_channels && + params->info.op_channels == info->op_channels && + params->info.usecase_id == info->usecase_id && + params->info.snd_device == info->snd_device) { + ALOGV("%s: found params with ip_ch %d op_ch %d uc_id %d snd_dev %d", + __func__, info->ip_channels, info->op_channels, + info->usecase_id, info->snd_device); + return params; + } + } + ALOGI("%s: no matching param with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d", + __func__, info->id, info->ip_channels, info->op_channels, + info->usecase_id, info->snd_device); + return NULL; +} + +int platform_add_custom_mtmx_params(void *platform, + struct audio_custom_mtmx_params_info *info) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct audio_custom_mtmx_params *params = NULL; + uint32_t size = sizeof(*params); + + if (info->ip_channels > AUDIO_CHANNEL_COUNT_MAX || + info->op_channels > AUDIO_CHANNEL_COUNT_MAX) { + ALOGE("%s: unusupported channels in %d, out %d", + __func__, info->ip_channels, info->op_channels); + return -EINVAL; + } + + size += sizeof(params->coeffs[0]) * info->ip_channels * info->op_channels; + params = (struct audio_custom_mtmx_params *) calloc(1, size); + if (!params) { + ALOGE("%s: failed to add custom mtmx params", __func__); + return -ENOMEM; + } + + ALOGI("%s: adding mtmx params with id %d ip_ch %d op_ch %d uc_id %d snd_dev %d", + __func__, info->id, info->ip_channels, info->op_channels, + info->usecase_id, info->snd_device); + + params->info = *info; + list_add_tail(&my_data->custom_mtmx_params_list, ¶ms->list); + return 0; +} + +static void platform_release_custom_mtmx_params(void *platform) +{ + struct platform_data *my_data = (struct platform_data *)platform; + struct listnode *node = NULL, *tempnode = NULL; + + list_for_each_safe(node, tempnode, &my_data->custom_mtmx_params_list) { + list_remove(node); + free(node_to_item(node, struct audio_custom_mtmx_params, list)); + } +} void platform_release_acdb_metainfo_key(void *platform) { @@ -3518,6 +3588,7 @@ void platform_deinit(void *platform) /* free acdb_meta_key_list */ platform_release_acdb_metainfo_key(platform); + platform_release_custom_mtmx_params(platform); if (my_data->acdb_deallocate) my_data->acdb_deallocate(); diff --git a/hal/platform_api.h b/hal/platform_api.h index cbc0a8b6..c53d4608 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -96,6 +96,21 @@ typedef struct acdb_audio_cal_cfg { uint32_t param_id; } acdb_audio_cal_cfg_t; + +struct audio_custom_mtmx_params_info { + uint32_t id; + uint32_t ip_channels; + uint32_t op_channels; + uint32_t usecase_id; + uint32_t snd_device; +}; + +struct audio_custom_mtmx_params { + struct listnode list; + struct audio_custom_mtmx_params_info info; + uint32_t coeffs[0]; +}; + enum card_status_t; void *platform_init(struct audio_device *adev); @@ -328,4 +343,9 @@ int platform_get_active_microphones(void *platform, unsigned int channels, int platform_get_license_by_product(void *platform, const char* product_name, int *product_id, char* product_license); int platform_get_haptics_pcm_device_id(); +struct audio_custom_mtmx_params * + platform_get_custom_mtmx_params(void *platform, + struct audio_custom_mtmx_params_info *info); +int platform_add_custom_mtmx_params(void *platform, + struct audio_custom_mtmx_params_info *info); #endif // AUDIO_PLATFORM_API_H diff --git a/hal/platform_info.c b/hal/platform_info.c index f8a78d8b..da0223e1 100644 --- a/hal/platform_info.c +++ b/hal/platform_info.c @@ -70,6 +70,8 @@ typedef enum { INPUT_SND_DEVICE_TO_MIC_MAPPING, SND_DEV, MIC_INFO, + CUSTOM_MTMX_PARAMS, + CUSTOM_MTMX_PARAM_COEFFS, } section_t; typedef void (* section_process_fn)(const XML_Char **attr); @@ -91,6 +93,8 @@ static void process_acdb_metainfo_key(const XML_Char **attr); static void process_microphone_characteristic(const XML_Char **attr); static void process_snd_dev(const XML_Char **attr); static void process_mic_info(const XML_Char **attr); +static void process_custom_mtmx_params(const XML_Char **attr); +static void process_custom_mtmx_param_coeffs(const XML_Char **attr); static section_process_fn section_table[] = { [ROOT] = process_root, @@ -109,6 +113,8 @@ static section_process_fn section_table[] = { [MICROPHONE_CHARACTERISTIC] = process_microphone_characteristic, [SND_DEV] = process_snd_dev, [MIC_INFO] = process_mic_info, + [CUSTOM_MTMX_PARAMS] = process_custom_mtmx_params, + [CUSTOM_MTMX_PARAM_COEFFS] = process_custom_mtmx_param_coeffs, }; static section_t section; @@ -213,6 +219,9 @@ static bool find_enum_by_string(const struct audio_string_to_enum * table, const } return false; } + +static struct audio_custom_mtmx_params_info mtmx_params_info; + /* * * @@ -959,6 +968,84 @@ done: return; } +static void process_custom_mtmx_param_coeffs(const XML_Char **attr) +{ + uint32_t attr_idx = 0, out_ch_idx = -1, ch_coeff_count = 0; + uint32_t ip_channels = 0, op_channels = 0; + char *context = NULL, *ch_coeff_value = NULL; + struct audio_custom_mtmx_params *mtmx_params = NULL; + + if (strcmp(attr[attr_idx++], "out_channel_index") != 0) { + ALOGE("%s: 'out_channel_index' not found", __func__); + return; + } + out_ch_idx = atoi((char *)attr[attr_idx++]); + + if (out_ch_idx < 0 || out_ch_idx >= mtmx_params_info.op_channels) { + ALOGE("%s: invalid out channel index(%d)", __func__, out_ch_idx); + return; + } + + if (strcmp(attr[attr_idx++], "values") != 0) { + ALOGE("%s: 'values' not found", __func__); + return; + } + mtmx_params = platform_get_custom_mtmx_params((void *)my_data.platform, + &mtmx_params_info); + if (mtmx_params == NULL) { + ALOGE("%s: mtmx params with given param info, not found", __func__); + return; + } + ch_coeff_value = strtok_r((char *)attr[attr_idx++], " ", &context); + ip_channels = mtmx_params->info.ip_channels; + op_channels = mtmx_params->info.op_channels; + while(ch_coeff_value && ch_coeff_count < op_channels) { + mtmx_params->coeffs[ip_channels * out_ch_idx + ch_coeff_count++] + = atoi(ch_coeff_value); + ch_coeff_value = strtok_r(NULL, " ", &context); + } + if (ch_coeff_count != mtmx_params->info.ip_channels || + ch_coeff_value != NULL) + ALOGE("%s: invalid/malformed coefficient values", __func__); +} + +static void process_custom_mtmx_params(const XML_Char **attr) +{ + int attr_idx = 0; + + if (strcmp(attr[attr_idx++], "param_id") != 0) { + ALOGE("%s: 'param_id' not found", __func__); + return; + } + mtmx_params_info.id = atoi((char *)attr[attr_idx++]); + + if (strcmp(attr[attr_idx++], "in_channel_count") != 0) { + ALOGE("%s: 'in_channel_count' not found", __func__); + return; + } + mtmx_params_info.ip_channels = atoi((char *)attr[attr_idx++]); + + if (strcmp(attr[attr_idx++], "out_channel_count") != 0) { + ALOGE("%s: 'out_channel_count' not found", __func__); + return; + } + mtmx_params_info.op_channels = atoi((char *)attr[attr_idx++]); + + if (strcmp(attr[attr_idx++], "usecase") != 0) { + ALOGE("%s: 'usecase' not found", __func__); + return; + } + mtmx_params_info.usecase_id = platform_get_usecase_index((char *)attr[attr_idx++]); + + if (strcmp(attr[attr_idx++], "snd_device") != 0) { + ALOGE("%s: 'snd_device' not found", __func__); + return; + } + mtmx_params_info.snd_device = platform_get_snd_device_index((char *)attr[attr_idx++]); + platform_add_custom_mtmx_params((void *)my_data.platform, &mtmx_params_info); + +} + static void start_tag(void *userdata __unused, const XML_Char *tag_name, const XML_Char **attr) { @@ -1101,7 +1188,23 @@ static void start_tag(void *userdata __unused, const XML_Char *tag_name, } section_process_fn fn = section_table[MIC_INFO]; fn(attr); - } + } else if (strcmp(tag_name, "custom_mtmx_params") == 0) { + if (section != ROOT) { + ALOGE("custom_mtmx_params tag supported only in ROOT section"); + return; + } + section = CUSTOM_MTMX_PARAMS; + section_process_fn fn = section_table[section]; + fn(attr); + } else if (strcmp(tag_name, "custom_mtmx_param_coeffs") == 0) { + if (section != CUSTOM_MTMX_PARAMS) { + ALOGE("custom_mtmx_param_coeffs tag supported only with CUSTOM_MTMX_PARAMS section"); + return; + } + section = CUSTOM_MTMX_PARAM_COEFFS; + section_process_fn fn = section_table[section]; + fn(attr); + } } else { if(strcmp(tag_name, "config_params") == 0) { section = CONFIG_PARAMS; @@ -1157,6 +1260,10 @@ static void end_tag(void *userdata __unused, const XML_Char *tag_name) section = SND_DEVICES; } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) { section = INPUT_SND_DEVICE; + } else if (strcmp(tag_name, "custom_mtmx_params") == 0) { + section = ROOT; + } else if (strcmp(tag_name, "custom_mtmx_param_coeffs") == 0) { + section = CUSTOM_MTMX_PARAMS; } }