Loading hal/audio_extn/audio_extn.c +398 −12 Original line number Diff line number Diff line Loading @@ -366,7 +366,7 @@ static void audio_extn_ext_disp_set_parameters(const struct audio_device *adev, } } static int update_custom_mtmx_coefficients(struct audio_device *adev, static int update_custom_mtmx_coefficients_v2(struct audio_device *adev, struct audio_custom_mtmx_params *params, int pcm_device_id) { Loading Loading @@ -430,7 +430,7 @@ static int update_custom_mtmx_coefficients(struct audio_device *adev, return 0; } static void set_custom_mtmx_params(struct audio_device *adev, static void set_custom_mtmx_params_v2(struct audio_device *adev, struct audio_custom_mtmx_params_info *pinfo, int pcm_device_id, bool enable) { Loading Loading @@ -465,7 +465,7 @@ static void set_custom_mtmx_params(struct audio_device *adev, ALOGE("%s: ERROR. Mixer ctl set failed", __func__); } void audio_extn_set_custom_mtmx_params(struct audio_device *adev, void audio_extn_set_custom_mtmx_params_v2(struct audio_device *adev, struct audio_usecase *usecase, bool enable) { Loading Loading @@ -535,16 +535,402 @@ void audio_extn_set_custom_mtmx_params(struct audio_device *adev, params = platform_get_custom_mtmx_params(adev->platform, &info); if (params) { if (enable) ret = update_custom_mtmx_coefficients(adev, params, ret = update_custom_mtmx_coefficients_v2(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); set_custom_mtmx_params_v2(adev, &info, pcm_device_id, enable); } } } static int set_custom_mtmx_output_channel_map(struct audio_device *adev, char *mixer_name_prefix, uint32_t ch_count, bool enable) { struct mixer_ctl *ctl = NULL; char mixer_ctl_name[128] = {0}; int ret = 0; int channel_map[AUDIO_MAX_DSP_CHANNELS] = {0}; ALOGV("%s channel_count %d", __func__, ch_count); if (!enable) { ALOGV("%s: reset output channel map", __func__); goto exit; } switch (ch_count) { case 2: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; break; case 4: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_LS; channel_map[3] = PCM_CHANNEL_RS; break; case 6: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LS; channel_map[5] = PCM_CHANNEL_RS; break; case 8: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; break; case 10: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_LFE; channel_map[3] = PCM_CHANNEL_FC; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; break; case 12: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; channel_map[10] = PCM_CHANNEL_TSL; channel_map[11] = PCM_CHANNEL_TSR; break; case 14: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_LFE; channel_map[3] = PCM_CHANNEL_FC; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; channel_map[10] = PCM_CHANNEL_TSL; channel_map[11] = PCM_CHANNEL_TSR; channel_map[12] = PCM_CHANNEL_FLC; channel_map[13] = PCM_CHANNEL_FRC; break; case 16: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; channel_map[10] = PCM_CHANNEL_TSL; channel_map[11] = PCM_CHANNEL_TSR; channel_map[12] = PCM_CHANNEL_FLC; channel_map[13] = PCM_CHANNEL_FRC; channel_map[14] = PCM_CHANNEL_RLC; channel_map[15] = PCM_CHANNEL_RRC; break; default: ALOGE("%s: unsupported channels(%d) for setting channel map", __func__, ch_count); return -EINVAL; } exit: snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Output Channel Map"); 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; } ret = mixer_ctl_set_array(ctl, channel_map, ch_count); return ret; } static int update_custom_mtmx_coefficients_v1(struct audio_device *adev, struct audio_custom_mtmx_params *params, struct audio_custom_mtmx_in_params *in_params, int pcm_device_id, usecase_type_t type, bool enable) { struct mixer_ctl *ctl = NULL; char mixer_ctl_name[128] = {0}; struct audio_custom_mtmx_params_info *pinfo = ¶ms->info; char mixer_name_prefix[100]; int i = 0, err = 0, rule = 0; uint32_t mtrx_row_cnt = 0, mtrx_column_cnt = 0; int reset_coeffs[AUDIO_MAX_DSP_CHANNELS] = {0}; ALOGI("%s: ip_channels %d, op_channels %d, pcm_device_id %d, usecase type %d, enable %d", __func__, pinfo->ip_channels, pinfo->op_channels, pcm_device_id, type, enable); if (!strcmp(pinfo->fe_name, "")) { ALOGE("%s: Error. no front end defined", __func__); return -EINVAL; } strlcpy(mixer_name_prefix, pinfo->fe_name, sizeof(mixer_name_prefix)); /* * Enable/Disable channel mixer. * If enable, use params and in_params to configure mixer. * If disable, reset previously configured mixer. */ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Channel Mixer"); 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; } if (enable) err = mixer_ctl_set_enum_by_string(ctl, "Enable"); else err = mixer_ctl_set_enum_by_string(ctl, "Disable"); if (err) { ALOGE("%s: ERROR. %s channel mixer failed", __func__, enable ? "Enable" : "Disable"); return -EINVAL; } /* Configure output channels of channel mixer */ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Channels"); 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; } mtrx_row_cnt = pinfo->op_channels; mtrx_column_cnt = pinfo->ip_channels; if (enable) err = mixer_ctl_set_value(ctl, 0, mtrx_row_cnt); else err = mixer_ctl_set_value(ctl, 0, 0); if (err) { ALOGE("%s: ERROR. %s mixer output channels failed", __func__, enable ? "Set" : "Reset"); return -EINVAL; } /* To keep output channel map in sync with asm driver channel mapping */ err = set_custom_mtmx_output_channel_map(adev, mixer_name_prefix, mtrx_row_cnt, enable); if (err) { ALOGE("%s: ERROR. %s mtmx output channel map failed", __func__, enable ? "Set" : "Reset"); return -EINVAL; } /* Send channel mixer rule */ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Channel Rule"); 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; } mixer_ctl_set_value(ctl, 0, rule); /* Send channel coefficients for each output channel */ for (i = 0; i < mtrx_row_cnt; i++) { snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s%d", mixer_name_prefix, "Output Channel", 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; } if (enable) err = mixer_ctl_set_array(ctl, ¶ms->coeffs[mtrx_column_cnt * i], mtrx_column_cnt); else err = mixer_ctl_set_array(ctl, reset_coeffs, mtrx_column_cnt); if (err) { ALOGE("%s: ERROR. %s coefficients failed for output channel %d", __func__, enable ? "Set" : "Reset", i); return -EINVAL; } } /* Configure backend interfaces with information provided in xml */ i = 0; while (in_params->in_ch_info[i].ch_count != 0) { snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s%d", mixer_name_prefix, "Channel", 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; } if (enable) { ALOGD("%s: mixer %s, interface %s", __func__, mixer_ctl_name, in_params->in_ch_info[i].hw_interface); err = mixer_ctl_set_enum_by_string(ctl, in_params->in_ch_info[i].hw_interface); } else { err = mixer_ctl_set_enum_by_string(ctl, "ZERO"); } if (err) { ALOGE("%s: ERROR. %s channel backend interface failed", __func__, enable ? "Set" : "Reset"); return -EINVAL; } i++; } return 0; } void audio_extn_set_custom_mtmx_params_v1(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; struct audio_custom_mtmx_in_params_info in_info = {0}; struct audio_custom_mtmx_in_params *in_params = NULL; int pcm_device_id = -1, ret = 0; uint32_t feature_id = 0; switch(usecase->type) { case PCM_CAPTURE: if (usecase->stream.in) { pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_CAPTURE); info.snd_device = usecase->in_snd_device; } else { ALOGE("%s: invalid input stream for capture usecase id:%d", __func__, usecase->id); return; } break; case PCM_PLAYBACK: default: ALOGV("%s: unsupported usecase id:%d", __func__, usecase->id); return; } ALOGD("%s: snd device %d", __func__, info.snd_device); info.id = feature_id; info.usecase_id = usecase->id; info.op_channels = audio_channel_count_from_in_mask( usecase->stream.in->channel_mask); in_info.usecase_id = info.usecase_id; in_info.op_channels = info.op_channels; in_params = platform_get_custom_mtmx_in_params(adev->platform, &in_info); if (!in_params) { ALOGE("%s: Could not get in params for usecase %d, channels %d", __func__, in_info.usecase_id, in_info.op_channels); return; } info.ip_channels = in_params->ip_channels; ALOGD("%s: ip channels %d, op channels %d", __func__, info.ip_channels, info.op_channels); params = platform_get_custom_mtmx_params(adev->platform, &info); if (params) { ret = update_custom_mtmx_coefficients_v1(adev, params, in_params, pcm_device_id, usecase->type, enable); if (ret < 0) ALOGE("%s: error updating mtmx coeffs err:%d", __func__, ret); } } snd_device_t audio_extn_get_loopback_snd_device(struct audio_device *adev, struct audio_usecase *usecase, int channel_count) { snd_device_t snd_device = SND_DEVICE_NONE; struct audio_custom_mtmx_in_params_info in_info = {0}; struct audio_custom_mtmx_in_params *in_params = NULL; if (!adev || !usecase) { ALOGE("%s: Invalid params", __func__); return snd_device; } in_info.usecase_id = usecase->id; in_info.op_channels = channel_count; in_params = platform_get_custom_mtmx_in_params(adev->platform, &in_info); if (!in_params) { ALOGE("%s: Could not get in params for usecase %d, channels %d", __func__, in_info.usecase_id, in_info.op_channels); return snd_device; } switch(in_params->mic_ch) { case 2: snd_device = SND_DEVICE_IN_HANDSET_DMIC_AND_EC_REF_LOOPBACK; break; case 4: snd_device = SND_DEVICE_IN_HANDSET_QMIC_AND_EC_REF_LOOPBACK; break; case 6: snd_device = SND_DEVICE_IN_HANDSET_6MIC_AND_EC_REF_LOOPBACK; break; case 8: snd_device = SND_DEVICE_IN_HANDSET_8MIC_AND_EC_REF_LOOPBACK; break; default: ALOGE("%s: Unsupported mic channels %d", __func__, in_params->mic_ch); break; } ALOGD("%s: return snd device %d", __func__, snd_device); return snd_device; } #ifndef DTS_EAGLE #define audio_extn_hpx_set_parameters(adev, parms) (0) #define audio_extn_hpx_get_parameters(query, reply) (0) Loading Loading @@ -2893,10 +3279,10 @@ static int audio_extn_set_multichannel_mask(struct audio_device *adev, *channel_mask_updated = false; int max_mic_count = platform_get_max_mic_count(adev->platform); /* validate input params*/ /* validate input params. Avoid updated channel mask if loopback device */ if ((channel_count == 6) && (in->format == AUDIO_FORMAT_PCM_16_BIT)) { (in->format == AUDIO_FORMAT_PCM_16_BIT) && (!is_loopback_input_device(in->device))) { switch (max_mic_count) { case 4: config->channel_mask = AUDIO_CHANNEL_INDEX_MASK_4; Loading hal/audio_extn/audio_extn.h +7 −1 Original line number Diff line number Diff line Loading @@ -1269,7 +1269,13 @@ 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, void audio_extn_set_custom_mtmx_params_v2(struct audio_device *adev, struct audio_usecase *usecase, bool enable); void audio_extn_set_custom_mtmx_params_v1(struct audio_device *adev, struct audio_usecase *usecase, bool enable); snd_device_t audio_extn_get_loopback_snd_device(struct audio_device *adev, struct audio_usecase *usecase, int channel_count); #endif /* AUDIO_EXTN_H */ hal/audio_hw.c +34 −3 Original line number Diff line number Diff line Loading @@ -1081,6 +1081,7 @@ int enable_audio_route(struct audio_device *adev, snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; struct stream_out *out = NULL; struct stream_in *in = NULL; int ret = 0; if (usecase == NULL) Loading Loading @@ -1139,7 +1140,16 @@ 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); if (usecase->type == PCM_CAPTURE) { in = usecase->stream.in; if (in && is_loopback_input_device(in->device)) { ALOGD("%s: set custom mtmx params v1", __func__); audio_extn_set_custom_mtmx_params_v1(adev, usecase, true); } } else { audio_extn_set_custom_mtmx_params_v2(adev, usecase, true); } // we shouldn't truncate mixer_path ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path)) Loading @@ -1164,6 +1174,7 @@ int disable_audio_route(struct audio_device *adev, { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; struct stream_in *in = NULL; if (usecase == NULL || usecase->id == USECASE_INVALID) return -EINVAL; Loading @@ -1189,10 +1200,21 @@ int disable_audio_route(struct audio_device *adev, } 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); if (usecase->type == PCM_CAPTURE) { in = usecase->stream.in; if (in && is_loopback_input_device(in->device)) { ALOGD("%s: reset custom mtmx params v1", __func__); audio_extn_set_custom_mtmx_params_v1(adev, usecase, false); } } else { audio_extn_set_custom_mtmx_params_v2(adev, usecase, false); } if ((usecase->type == PCM_PLAYBACK) && (usecase->stream.out != NULL)) usecase->stream.out->pspd_coeff_sent = false; ALOGV("%s: exit", __func__); return 0; } Loading Loading @@ -2790,6 +2812,9 @@ static int stop_input_stream(struct stream_in *in) /* 2. Disable the tx device */ disable_snd_device(adev, uc_info->in_snd_device); if (is_loopback_input_device(in->device)) audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY); list_remove(&uc_info->list); free(uc_info); Loading Loading @@ -2977,6 +3002,9 @@ int start_input_stream(struct stream_in *in) audio_extn_audiozoom_set_microphone_direction(in, in->zoom); audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction); if (is_loopback_input_device(in->device)) audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY); done_open: audio_streaming_hint_end(); audio_extn_perf_lock_release(&adev->perf_lock_handle); Loading Loading @@ -3834,6 +3862,9 @@ static int check_input_parameters(uint32_t sample_rate, case 4: case 6: case 8: case 10: case 12: case 14: break; default: ret = -EINVAL; Loading Loading @@ -5397,7 +5428,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, */ usecase = get_usecase_from_list(adev, out->usecase); if (usecase != NULL) { audio_extn_set_custom_mtmx_params(adev, usecase, true); audio_extn_set_custom_mtmx_params_v2(adev, usecase, true); out->pspd_coeff_sent = true; } } Loading hal/audio_hw.h +8 −0 Original line number Diff line number Diff line Loading @@ -729,6 +729,14 @@ size_t get_output_period_size(uint32_t sample_rate, __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ " ASSERT_FATAL(" #condition ") failed.") static inline bool is_loopback_input_device(audio_devices_t device) { if (!audio_is_output_device(device) && ((device & AUDIO_DEVICE_IN_LOOPBACK) == AUDIO_DEVICE_IN_LOOPBACK)) return true; else return false; } /* * NOTE: when multiple mutexes have to be acquired, always take the * stream_in or stream_out mutex first, followed by the audio_device mutex. Loading hal/msm8916/platform.c +14 −0 Original line number Diff line number Diff line Loading @@ -2845,6 +2845,20 @@ static void platform_release_custom_mtmx_params(void *platform) } } struct audio_custom_mtmx_in_params *platform_get_custom_mtmx_in_params(void *platform, struct audio_custom_mtmx_in_params_info *info) { ALOGW("%s: not implemented!", __func__); return -ENOSYS; } int platform_add_custom_mtmx_in_params(void *platform, struct audio_custom_mtmx_in_params_info *info) { ALOGW("%s: not implemented!", __func__); return -ENOSYS; } void platform_release_acdb_metainfo_key(void *platform) { struct platform_data *my_data = (struct platform_data *)platform; Loading Loading
hal/audio_extn/audio_extn.c +398 −12 Original line number Diff line number Diff line Loading @@ -366,7 +366,7 @@ static void audio_extn_ext_disp_set_parameters(const struct audio_device *adev, } } static int update_custom_mtmx_coefficients(struct audio_device *adev, static int update_custom_mtmx_coefficients_v2(struct audio_device *adev, struct audio_custom_mtmx_params *params, int pcm_device_id) { Loading Loading @@ -430,7 +430,7 @@ static int update_custom_mtmx_coefficients(struct audio_device *adev, return 0; } static void set_custom_mtmx_params(struct audio_device *adev, static void set_custom_mtmx_params_v2(struct audio_device *adev, struct audio_custom_mtmx_params_info *pinfo, int pcm_device_id, bool enable) { Loading Loading @@ -465,7 +465,7 @@ static void set_custom_mtmx_params(struct audio_device *adev, ALOGE("%s: ERROR. Mixer ctl set failed", __func__); } void audio_extn_set_custom_mtmx_params(struct audio_device *adev, void audio_extn_set_custom_mtmx_params_v2(struct audio_device *adev, struct audio_usecase *usecase, bool enable) { Loading Loading @@ -535,16 +535,402 @@ void audio_extn_set_custom_mtmx_params(struct audio_device *adev, params = platform_get_custom_mtmx_params(adev->platform, &info); if (params) { if (enable) ret = update_custom_mtmx_coefficients(adev, params, ret = update_custom_mtmx_coefficients_v2(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); set_custom_mtmx_params_v2(adev, &info, pcm_device_id, enable); } } } static int set_custom_mtmx_output_channel_map(struct audio_device *adev, char *mixer_name_prefix, uint32_t ch_count, bool enable) { struct mixer_ctl *ctl = NULL; char mixer_ctl_name[128] = {0}; int ret = 0; int channel_map[AUDIO_MAX_DSP_CHANNELS] = {0}; ALOGV("%s channel_count %d", __func__, ch_count); if (!enable) { ALOGV("%s: reset output channel map", __func__); goto exit; } switch (ch_count) { case 2: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; break; case 4: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_LS; channel_map[3] = PCM_CHANNEL_RS; break; case 6: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LS; channel_map[5] = PCM_CHANNEL_RS; break; case 8: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; break; case 10: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_LFE; channel_map[3] = PCM_CHANNEL_FC; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; break; case 12: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; channel_map[10] = PCM_CHANNEL_TSL; channel_map[11] = PCM_CHANNEL_TSR; break; case 14: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_LFE; channel_map[3] = PCM_CHANNEL_FC; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; channel_map[10] = PCM_CHANNEL_TSL; channel_map[11] = PCM_CHANNEL_TSR; channel_map[12] = PCM_CHANNEL_FLC; channel_map[13] = PCM_CHANNEL_FRC; break; case 16: channel_map[0] = PCM_CHANNEL_FL; channel_map[1] = PCM_CHANNEL_FR; channel_map[2] = PCM_CHANNEL_FC; channel_map[3] = PCM_CHANNEL_LFE; channel_map[4] = PCM_CHANNEL_LB; channel_map[5] = PCM_CHANNEL_RB; channel_map[6] = PCM_CHANNEL_LS; channel_map[7] = PCM_CHANNEL_RS; channel_map[8] = PCM_CHANNEL_TFL; channel_map[9] = PCM_CHANNEL_TFR; channel_map[10] = PCM_CHANNEL_TSL; channel_map[11] = PCM_CHANNEL_TSR; channel_map[12] = PCM_CHANNEL_FLC; channel_map[13] = PCM_CHANNEL_FRC; channel_map[14] = PCM_CHANNEL_RLC; channel_map[15] = PCM_CHANNEL_RRC; break; default: ALOGE("%s: unsupported channels(%d) for setting channel map", __func__, ch_count); return -EINVAL; } exit: snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Output Channel Map"); 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; } ret = mixer_ctl_set_array(ctl, channel_map, ch_count); return ret; } static int update_custom_mtmx_coefficients_v1(struct audio_device *adev, struct audio_custom_mtmx_params *params, struct audio_custom_mtmx_in_params *in_params, int pcm_device_id, usecase_type_t type, bool enable) { struct mixer_ctl *ctl = NULL; char mixer_ctl_name[128] = {0}; struct audio_custom_mtmx_params_info *pinfo = ¶ms->info; char mixer_name_prefix[100]; int i = 0, err = 0, rule = 0; uint32_t mtrx_row_cnt = 0, mtrx_column_cnt = 0; int reset_coeffs[AUDIO_MAX_DSP_CHANNELS] = {0}; ALOGI("%s: ip_channels %d, op_channels %d, pcm_device_id %d, usecase type %d, enable %d", __func__, pinfo->ip_channels, pinfo->op_channels, pcm_device_id, type, enable); if (!strcmp(pinfo->fe_name, "")) { ALOGE("%s: Error. no front end defined", __func__); return -EINVAL; } strlcpy(mixer_name_prefix, pinfo->fe_name, sizeof(mixer_name_prefix)); /* * Enable/Disable channel mixer. * If enable, use params and in_params to configure mixer. * If disable, reset previously configured mixer. */ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Channel Mixer"); 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; } if (enable) err = mixer_ctl_set_enum_by_string(ctl, "Enable"); else err = mixer_ctl_set_enum_by_string(ctl, "Disable"); if (err) { ALOGE("%s: ERROR. %s channel mixer failed", __func__, enable ? "Enable" : "Disable"); return -EINVAL; } /* Configure output channels of channel mixer */ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Channels"); 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; } mtrx_row_cnt = pinfo->op_channels; mtrx_column_cnt = pinfo->ip_channels; if (enable) err = mixer_ctl_set_value(ctl, 0, mtrx_row_cnt); else err = mixer_ctl_set_value(ctl, 0, 0); if (err) { ALOGE("%s: ERROR. %s mixer output channels failed", __func__, enable ? "Set" : "Reset"); return -EINVAL; } /* To keep output channel map in sync with asm driver channel mapping */ err = set_custom_mtmx_output_channel_map(adev, mixer_name_prefix, mtrx_row_cnt, enable); if (err) { ALOGE("%s: ERROR. %s mtmx output channel map failed", __func__, enable ? "Set" : "Reset"); return -EINVAL; } /* Send channel mixer rule */ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s", mixer_name_prefix, "Channel Rule"); 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; } mixer_ctl_set_value(ctl, 0, rule); /* Send channel coefficients for each output channel */ for (i = 0; i < mtrx_row_cnt; i++) { snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s%d", mixer_name_prefix, "Output Channel", 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; } if (enable) err = mixer_ctl_set_array(ctl, ¶ms->coeffs[mtrx_column_cnt * i], mtrx_column_cnt); else err = mixer_ctl_set_array(ctl, reset_coeffs, mtrx_column_cnt); if (err) { ALOGE("%s: ERROR. %s coefficients failed for output channel %d", __func__, enable ? "Set" : "Reset", i); return -EINVAL; } } /* Configure backend interfaces with information provided in xml */ i = 0; while (in_params->in_ch_info[i].ch_count != 0) { snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "%s %s%d", mixer_name_prefix, "Channel", 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; } if (enable) { ALOGD("%s: mixer %s, interface %s", __func__, mixer_ctl_name, in_params->in_ch_info[i].hw_interface); err = mixer_ctl_set_enum_by_string(ctl, in_params->in_ch_info[i].hw_interface); } else { err = mixer_ctl_set_enum_by_string(ctl, "ZERO"); } if (err) { ALOGE("%s: ERROR. %s channel backend interface failed", __func__, enable ? "Set" : "Reset"); return -EINVAL; } i++; } return 0; } void audio_extn_set_custom_mtmx_params_v1(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; struct audio_custom_mtmx_in_params_info in_info = {0}; struct audio_custom_mtmx_in_params *in_params = NULL; int pcm_device_id = -1, ret = 0; uint32_t feature_id = 0; switch(usecase->type) { case PCM_CAPTURE: if (usecase->stream.in) { pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_CAPTURE); info.snd_device = usecase->in_snd_device; } else { ALOGE("%s: invalid input stream for capture usecase id:%d", __func__, usecase->id); return; } break; case PCM_PLAYBACK: default: ALOGV("%s: unsupported usecase id:%d", __func__, usecase->id); return; } ALOGD("%s: snd device %d", __func__, info.snd_device); info.id = feature_id; info.usecase_id = usecase->id; info.op_channels = audio_channel_count_from_in_mask( usecase->stream.in->channel_mask); in_info.usecase_id = info.usecase_id; in_info.op_channels = info.op_channels; in_params = platform_get_custom_mtmx_in_params(adev->platform, &in_info); if (!in_params) { ALOGE("%s: Could not get in params for usecase %d, channels %d", __func__, in_info.usecase_id, in_info.op_channels); return; } info.ip_channels = in_params->ip_channels; ALOGD("%s: ip channels %d, op channels %d", __func__, info.ip_channels, info.op_channels); params = platform_get_custom_mtmx_params(adev->platform, &info); if (params) { ret = update_custom_mtmx_coefficients_v1(adev, params, in_params, pcm_device_id, usecase->type, enable); if (ret < 0) ALOGE("%s: error updating mtmx coeffs err:%d", __func__, ret); } } snd_device_t audio_extn_get_loopback_snd_device(struct audio_device *adev, struct audio_usecase *usecase, int channel_count) { snd_device_t snd_device = SND_DEVICE_NONE; struct audio_custom_mtmx_in_params_info in_info = {0}; struct audio_custom_mtmx_in_params *in_params = NULL; if (!adev || !usecase) { ALOGE("%s: Invalid params", __func__); return snd_device; } in_info.usecase_id = usecase->id; in_info.op_channels = channel_count; in_params = platform_get_custom_mtmx_in_params(adev->platform, &in_info); if (!in_params) { ALOGE("%s: Could not get in params for usecase %d, channels %d", __func__, in_info.usecase_id, in_info.op_channels); return snd_device; } switch(in_params->mic_ch) { case 2: snd_device = SND_DEVICE_IN_HANDSET_DMIC_AND_EC_REF_LOOPBACK; break; case 4: snd_device = SND_DEVICE_IN_HANDSET_QMIC_AND_EC_REF_LOOPBACK; break; case 6: snd_device = SND_DEVICE_IN_HANDSET_6MIC_AND_EC_REF_LOOPBACK; break; case 8: snd_device = SND_DEVICE_IN_HANDSET_8MIC_AND_EC_REF_LOOPBACK; break; default: ALOGE("%s: Unsupported mic channels %d", __func__, in_params->mic_ch); break; } ALOGD("%s: return snd device %d", __func__, snd_device); return snd_device; } #ifndef DTS_EAGLE #define audio_extn_hpx_set_parameters(adev, parms) (0) #define audio_extn_hpx_get_parameters(query, reply) (0) Loading Loading @@ -2893,10 +3279,10 @@ static int audio_extn_set_multichannel_mask(struct audio_device *adev, *channel_mask_updated = false; int max_mic_count = platform_get_max_mic_count(adev->platform); /* validate input params*/ /* validate input params. Avoid updated channel mask if loopback device */ if ((channel_count == 6) && (in->format == AUDIO_FORMAT_PCM_16_BIT)) { (in->format == AUDIO_FORMAT_PCM_16_BIT) && (!is_loopback_input_device(in->device))) { switch (max_mic_count) { case 4: config->channel_mask = AUDIO_CHANNEL_INDEX_MASK_4; Loading
hal/audio_extn/audio_extn.h +7 −1 Original line number Diff line number Diff line Loading @@ -1269,7 +1269,13 @@ 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, void audio_extn_set_custom_mtmx_params_v2(struct audio_device *adev, struct audio_usecase *usecase, bool enable); void audio_extn_set_custom_mtmx_params_v1(struct audio_device *adev, struct audio_usecase *usecase, bool enable); snd_device_t audio_extn_get_loopback_snd_device(struct audio_device *adev, struct audio_usecase *usecase, int channel_count); #endif /* AUDIO_EXTN_H */
hal/audio_hw.c +34 −3 Original line number Diff line number Diff line Loading @@ -1081,6 +1081,7 @@ int enable_audio_route(struct audio_device *adev, snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; struct stream_out *out = NULL; struct stream_in *in = NULL; int ret = 0; if (usecase == NULL) Loading Loading @@ -1139,7 +1140,16 @@ 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); if (usecase->type == PCM_CAPTURE) { in = usecase->stream.in; if (in && is_loopback_input_device(in->device)) { ALOGD("%s: set custom mtmx params v1", __func__); audio_extn_set_custom_mtmx_params_v1(adev, usecase, true); } } else { audio_extn_set_custom_mtmx_params_v2(adev, usecase, true); } // we shouldn't truncate mixer_path ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path)) Loading @@ -1164,6 +1174,7 @@ int disable_audio_route(struct audio_device *adev, { snd_device_t snd_device; char mixer_path[MIXER_PATH_MAX_LENGTH]; struct stream_in *in = NULL; if (usecase == NULL || usecase->id == USECASE_INVALID) return -EINVAL; Loading @@ -1189,10 +1200,21 @@ int disable_audio_route(struct audio_device *adev, } 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); if (usecase->type == PCM_CAPTURE) { in = usecase->stream.in; if (in && is_loopback_input_device(in->device)) { ALOGD("%s: reset custom mtmx params v1", __func__); audio_extn_set_custom_mtmx_params_v1(adev, usecase, false); } } else { audio_extn_set_custom_mtmx_params_v2(adev, usecase, false); } if ((usecase->type == PCM_PLAYBACK) && (usecase->stream.out != NULL)) usecase->stream.out->pspd_coeff_sent = false; ALOGV("%s: exit", __func__); return 0; } Loading Loading @@ -2790,6 +2812,9 @@ static int stop_input_stream(struct stream_in *in) /* 2. Disable the tx device */ disable_snd_device(adev, uc_info->in_snd_device); if (is_loopback_input_device(in->device)) audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY); list_remove(&uc_info->list); free(uc_info); Loading Loading @@ -2977,6 +3002,9 @@ int start_input_stream(struct stream_in *in) audio_extn_audiozoom_set_microphone_direction(in, in->zoom); audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction); if (is_loopback_input_device(in->device)) audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY); done_open: audio_streaming_hint_end(); audio_extn_perf_lock_release(&adev->perf_lock_handle); Loading Loading @@ -3834,6 +3862,9 @@ static int check_input_parameters(uint32_t sample_rate, case 4: case 6: case 8: case 10: case 12: case 14: break; default: ret = -EINVAL; Loading Loading @@ -5397,7 +5428,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, */ usecase = get_usecase_from_list(adev, out->usecase); if (usecase != NULL) { audio_extn_set_custom_mtmx_params(adev, usecase, true); audio_extn_set_custom_mtmx_params_v2(adev, usecase, true); out->pspd_coeff_sent = true; } } Loading
hal/audio_hw.h +8 −0 Original line number Diff line number Diff line Loading @@ -729,6 +729,14 @@ size_t get_output_period_size(uint32_t sample_rate, __FILE__ ":" LITERAL_TO_STRING(__LINE__)\ " ASSERT_FATAL(" #condition ") failed.") static inline bool is_loopback_input_device(audio_devices_t device) { if (!audio_is_output_device(device) && ((device & AUDIO_DEVICE_IN_LOOPBACK) == AUDIO_DEVICE_IN_LOOPBACK)) return true; else return false; } /* * NOTE: when multiple mutexes have to be acquired, always take the * stream_in or stream_out mutex first, followed by the audio_device mutex. Loading
hal/msm8916/platform.c +14 −0 Original line number Diff line number Diff line Loading @@ -2845,6 +2845,20 @@ static void platform_release_custom_mtmx_params(void *platform) } } struct audio_custom_mtmx_in_params *platform_get_custom_mtmx_in_params(void *platform, struct audio_custom_mtmx_in_params_info *info) { ALOGW("%s: not implemented!", __func__); return -ENOSYS; } int platform_add_custom_mtmx_in_params(void *platform, struct audio_custom_mtmx_in_params_info *info) { ALOGW("%s: not implemented!", __func__); return -ENOSYS; } void platform_release_acdb_metainfo_key(void *platform) { struct platform_data *my_data = (struct platform_data *)platform; Loading