You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

381 lines
13 KiB

/*
* 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 <log/log.h>
#include <cutils/properties.h>
#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;
}