/* * Copyright (c) Hisilicon Technologies Co., Ltd. Technologies Co., Ltd. 2020-2020. All rights reserved. * Description: audio hal settings manage source file. * Author: yinyingcai * Create: 2020-05-11 * Notes: NA * History: 2020-05-11 yinyingcai for CodingStyle */ #define LOG_TAG "audio_hal_setting" #define LOG_NDEBUG 0 #include "audio_setting.h" #include #include #include "uapi_version.h" #include "uapi_sound.h" #include "audio_hw.h" #include "securec.h" #define HDMI_MODE_NONE 0 // refere to setting menu order #define HDMI_MODE_AUTO 1 #define HDMI_MODE_LPCM 2 #define HDMI_MODE_RAW 3 #define SPDIF_MODE_NONE 0 #define SPDIF_MODE_LPCM 1 #define SPDIF_MODE_RAW 2 #define HBR_MODE_AUTO 0 #define HBR_MODE_RAW_5_1 1 #define HBR_MODE_RAW_7_1 2 #define OUTPUT_FMT_AC3 0 #define OUTPUT_FMT_TRUEHD 1 #define String_ENABLE_TRUEHD "1" #define String_DISABLE_TRUEHD "0" #define PROPERTY_ENABLE_TRUEHD "persist.vendor.audiohal.hp.truehd" #define AUDIO_1POINT_CAPABILITY \ "AUDIO_CHANNEL_OUT_MONO" #define AUDIO_2POINT_CAPABILITY \ "AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO" #define AUDIO_5POINT1_CAPABILITY \ "AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_5POINT1" #define AUDIO_7POINT1_CAPABILITY \ "AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1" static void set_default_audio_cap(struct audio_setting *setting) { setting->edidAudioNum = 1; // default only support 1 audio format setting->edidAudio[0].enAudFmtCode = (int)AUDIO_FORMAT_PCM_SUB_16_BIT; setting->edidAudio[0].u8AudChannel = AUDIO_STEREO_CHANNELS; setting->edidAudio[0].u32SupportSampleRateNum = 1; // default only support 1 audio samplerate setting->edidAudio[0].enSupportSampleRate[0] = SAMPLE_RATE_48000; } static int updateHbr2LbrPolicy(const struct audio_setting *setting) { #if (UAPI_VERSION_CODE == UAPI_VERSION(1, 0)) (void) setting; return 0; #endif } int initAndOpenHDMI(struct audio_setting *setting) { #if (UAPI_VERSION_CODE == UAPI_VERSION(1, 0)) set_default_audio_cap(setting); return 0; #endif } void deinit_and_close_hdmi(void) { ALOGD("deinit_and_close_hdmi over"); } static int freshHdmiAbility(struct audio_setting *setting, uint32_t HdmiMode) { int ret = 0; setting->hdmiMode = HdmiMode; if (HdmiMode == HDMI_MODE_RAW || HdmiMode == HDMI_MODE_AUTO) { ret = updateHbr2LbrPolicy(setting); if (ret != 0) { ALOGE("updateHbr2LbrPolicy ret(0x%x)", ret); } } return ret; } #if (UAPI_VERSION_CODE == UAPI_VERSION(1, 0)) int setSpdifMode(struct audio_setting *setting, uint32_t SpdifMode) { int ret; uapi_snd snd = UAPI_SND_0; uapi_snd_out_port port = UAPI_SND_OUT_PORT_SPDIF0; uapi_snd_output_mode mode = UAPI_SND_OUTPUT_MODE_LPCM; if (SpdifMode == SPDIF_MODE_NONE) { setting->spdifMode = SPDIF_MODE_NONE; ret = uapi_snd_set_soft_mute(snd, port, TRUE); ALOGD("SPDIF setting NONE mute port ret(0x%x)", ret); return ret; } if (SpdifMode == SPDIF_MODE_LPCM) { mode = UAPI_SND_OUTPUT_MODE_LPCM; } else if (SpdifMode == SPDIF_MODE_RAW) { mode = UAPI_SND_OUTPUT_MODE_RAW; } else { ALOGD("unsupport SPDIF mode"); } ret = uapi_snd_set_output_mode(snd, port, mode); ALOGD("Set spdif port mode=%d ret(0x%x)", mode, ret); if (setting->spdifMode == SPDIF_MODE_NONE) { ret = uapi_snd_set_soft_mute(snd, port, FALSE); ALOGD("SPDIF setting from NONE to other unmute port ret(0x%x)", ret); } setting->spdifMode = SpdifMode; return ret; } #endif #if (UAPI_VERSION_CODE == UAPI_VERSION(1, 0)) int setHdmiMode(struct audio_setting *setting, uint32_t HdmiMode) { int ret; uapi_snd snd = UAPI_SND_0; uapi_snd_out_port port = UAPI_SND_OUT_PORT_HDMITX0; uapi_snd_output_mode mode = UAPI_SND_OUTPUT_MODE_LPCM; if (HdmiMode == HDMI_MODE_NONE) { ALOGD("HDMI setting NONE mute port"); ret = uapi_snd_set_soft_mute(snd, port, TRUE); setting->hdmiMode = HdmiMode; return ret; } if (HdmiMode == HDMI_MODE_LPCM) { mode = UAPI_SND_OUTPUT_MODE_LPCM; } else if (HdmiMode == HDMI_MODE_RAW) { mode = UAPI_SND_OUTPUT_MODE_RAW; } else if (HdmiMode == HDMI_MODE_AUTO) { mode = UAPI_SND_OUTPUT_MODE_AUTO; } else { ALOGD("unsupport HDMI mode"); } ret = uapi_snd_set_output_mode(snd, port, mode); ALOGD("Set hdmi port mode=%d ret(0x%x)", mode, ret); if (setting->hdmiMode == HDMI_MODE_NONE) { ret = uapi_snd_set_soft_mute(snd, port, FALSE); ALOGD("HDMI setting from NONE to other unmute port ret(0x%x)", ret); } return freshHdmiAbility(setting, HdmiMode); } #endif int setHbr2LbrMode(struct audio_setting *setting, uint32_t Hbr2LbrMode) { setting->Hbr2LbrMode = Hbr2LbrMode; return updateHbr2LbrPolicy(setting); } static void getHDMIAudioCap(struct audio_setting *setting) { #if (UAPI_VERSION_CODE == UAPI_VERSION(1, 0)) set_default_audio_cap(setting); #endif } static char *get_channels_string(uint32_t channels) { switch (channels) { case AUDIO_MONO_CHANNELS: return AUDIO_1POINT_CAPABILITY; case AUDIO_STEREO_CHANNELS: return AUDIO_2POINT_CAPABILITY; case AUDIO_5POINT1_CHANNELS: return AUDIO_5POINT1_CAPABILITY; case AUDIO_7POINT1_CHANNELS: return AUDIO_7POINT1_CAPABILITY; default: return NULL; } } static void auto_mode_get_support_formats(struct audio_setting *setting, char* value, uint32_t length) { int ret = -EINVAL; getHDMIAudioCap(setting); for (unsigned int i = 0; i < setting->edidAudioNum; i++) { switch (setting->edidAudio[i].enAudFmtCode) { case AUDIO_FORMAT_PCM_16_BIT: ret = strcat_s(value, length, "AUDIO_FORMAT_PCM_16_BIT|"); if (ret != 0) { ALOGE("strcat_s AUDIO_FORMAT_PCM_16_BIT INFO failed"); return; } break; case AUDIO_FORMAT_AC3: ret = strcat_s(value, length, "AUDIO_FORMAT_AC3|"); if (ret != 0) { ALOGE("strcat_s AUDIO_FORMAT_AC3 INFO failed"); return; } break; case AUDIO_FORMAT_E_AC3: ret = strcat_s(value, length, "AUDIO_FORMAT_E_AC3|"); if (ret != 0) { ALOGE("strcat_s AUDIO_FORMAT_E_AC3 INFO failed"); return; } break; case AUDIO_FORMAT_AAC: ret = strcat_s(value, length, "AUDIO_FORMAT_AAC|"); if (ret != 0) { ALOGE("strcat_s AUDIO_FORMAT_AAC INFO failed"); return; } break; case AUDIO_FORMAT_DTS: ret = strcat_s(value, length, "AUDIO_FORMAT_DTS|"); if (ret != 0) { ALOGE("strcat_s AUDIO_FORMAT_DTS INFO failed"); return; } break; default: ALOGD("%s: unrepported format", __func__); break; } } } static int check_valid_format(const struct audio_setting* setting, int targetFormat) { if (targetFormat == (int)AUDIO_FORMAT_INVALID) { return -EINVAL; } // when hdmimode was HDMI_MODE_LPCM or HDMI_MODE_NONE only report the support channels of pcm if ((setting->hdmiMode == HDMI_MODE_LPCM || setting->hdmiMode == HDMI_MODE_NONE) && targetFormat != AUDIO_FORMAT_PCM_16_BIT && setting->spdifMode != SPDIF_MODE_RAW) { return -EINVAL; } return 0; } void get_support_channels(const struct audio_setting* setting, char* value, int targetFormat, uint32_t length) { int ret; value[0] = '\0'; if (check_valid_format(setting, targetFormat) != 0) { return; } if (setting->hdmiMode == HDMI_MODE_RAW || setting->spdifMode == SPDIF_MODE_RAW) { ret = strcat_s(value, length, AUDIO_7POINT1_CAPABILITY); if (ret != EOK) { ALOGE("strcat_s AUDIO_7POINT1_CAPABILITY ret(0x%x)", ret); return; } return; } if (setting->hdmiMode == HDMI_MODE_LPCM || setting->hdmiMode == HDMI_MODE_NONE) { ret = strcat_s(value, length, AUDIO_2POINT_CAPABILITY); if (ret != EOK) { ALOGE("strcat AUDIO_2POINT_CAPABILITY faild ret(0x%x)", ret); return; } return; } if (setting->hdmiMode != HDMI_MODE_AUTO) { ALOGD("%s: unsupported hdmiMode(%d)", __func__, setting->hdmiMode); return; } for (unsigned int i = 0; i < setting->edidAudioNum; i++) { if (setting->edidAudio[i].enAudFmtCode != targetFormat) { continue; } char *channels = get_channels_string (setting->edidAudio[i].u8AudChannel); if (channels == NULL) { ALOGE("%s: unrepported channel %d", __func__, setting->edidAudio[i].u8AudChannel); return; } ret = strcat_s(value, length, channels); if (ret != EOK) { ALOGE("strcat_s channel(%d) faild ret(0x%x)", setting->edidAudio[i].u8AudChannel, ret); return; } } return; } void get_support_formats(struct audio_setting *setting, char* value, uint32_t length) { int ret; value[0] = '\0'; if (setting->hdmiMode == HDMI_MODE_RAW || setting->spdifMode == SPDIF_MODE_RAW) { ret = strcat_s(value, length, "AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AC3|AUDIO_FORMAT_E_AC3"); if (ret != EOK) { ALOGE("strcat_s4 faild ret(0x%x)", ret); return; } } else if (setting->hdmiMode == HDMI_MODE_AUTO) { auto_mode_get_support_formats(setting, value, length); } else if (setting->hdmiMode == HDMI_MODE_LPCM || setting->hdmiMode == HDMI_MODE_NONE) { ret = strcat_s(value, length, "AUDIO_FORMAT_PCM_16_BIT"); if (ret != EOK) { ALOGE("strcat_s6 faild ret(0x%x)", ret); return; } } else { ALOGD("%s: unsupported hdmiMode(%d)", __func__, setting->hdmiMode); } } static int get_rates_string(int samplerate, char *value, uint32_t length) { switch (samplerate) { case SAMPLE_RATE_8000: return strcat_s(value, length, "8000|"); case SAMPLE_RATE_11025: return strcat_s(value, length, "11025|"); case SAMPLE_RATE_12000: return strcat_s(value, length, "12000|"); case SAMPLE_RATE_16000: return strcat_s(value, length, "16000|"); case SAMPLE_RATE_22050: return strcat_s(value, length, "22050|"); case SAMPLE_RATE_24000: return strcat_s(value, length, "24000|"); case SAMPLE_RATE_32000: return strcat_s(value, length, "32000|"); case SAMPLE_RATE_44100: return strcat_s(value, length, "44100|"); case SAMPLE_RATE_48000: return strcat_s(value, length, "48000|"); default: ALOGD("%s: unrepported sample rate", __func__); return 0; } } void get_support_rates(const struct audio_setting* setting, char* value, int targetFormat, uint32_t length) { int ret; value[0] = '\0'; if (check_valid_format(setting, targetFormat) != 0) { return; } if (setting->hdmiMode != HDMI_MODE_AUTO) { // 22050,16000,11025,8000 samplerate check by VTS ret = strcat_s(value, length, "48000|44100|32000|22050|24000|16000|11025|8000"); if (ret != EOK) { ALOGE("strcat_s rate all faild ret(0x%x)", ret); return; } return; } for (unsigned int i = 0; i < setting->edidAudioNum; i++) { if (setting->edidAudio[i].enAudFmtCode != targetFormat) { continue; } for (unsigned int j = 0; j < setting->edidAudio[i].u32SupportSampleRateNum; j++) { ret = get_rates_string((int)(setting->edidAudio[i].enSupportSampleRate[j]), value, length); if (ret != 0) { ALOGE("strcat_s rate %d failed(0x%x)", setting->edidAudio[i].enSupportSampleRate[j], ret); } } } return; }