hal: add support to set custom channel configs

Add generic implementation to set custom channel configs
as per usecase config present in platform info xml.
Each usecase identified by usecase id, input channels,
output channels, snd_device and feature id can have
a separate channel config.

Change-Id: I957b5b06adbcd17f65ed49b839327bf8e9e8b318
This commit is contained in:
Dhananjay Kumar 2018-12-10 22:26:53 +05:30 committed by Dhanalakshmi Siddani
parent 3119505971
commit 429eb45770
8 changed files with 449 additions and 2 deletions

View File

@ -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 = &params->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,
&params->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)

View File

@ -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 */

View File

@ -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;
}

View File

@ -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, &params->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();

View File

@ -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;

View File

@ -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, &params->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();

View File

@ -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

View File

@ -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;
/*
* <audio_platform_info>
* <acdb_ids>
@ -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;
}
}