hal: Refactor HDMI backend configuration
-In current design HDMI backend configuration does not validate
incoming configuration against what is supported by the
connected sink ( using edid). This results in an incorrect
configuration of the HDMI backend, sometimes leading to no audio.
-Move HDMI backend configuration to
platform_check_and_set_codec_backend_cfg, this design ensures
that HDMI backend configuration happens with valid and only
supported parameters (sample rate, channels and bit width)
by the connected sink.
-Remove usleep from keep_alive and move to conditional timed wait,
this ensures to break from the keep_alive loop quickly, instead
of waiting for the complete usleep duration.
CRs-Fixed: 1039831
Change-Id: Id46ae76575f1b8169370cee817b505b97af8fe01
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index c8e3a3b..bf5b62b 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -192,8 +192,10 @@
typedef struct codec_backend_cfg {
uint32_t sample_rate;
uint32_t bit_width;
+ uint32_t channels;
char *bitwidth_mixer_ctl;
char *samplerate_mixer_ctl;
+ char *channels_mixer_ctl;
} codec_backend_cfg_t;
static native_audio_prop na_props = {0, 0, 0};
@@ -1927,6 +1929,8 @@
strdup("HDMI_RX Bit Format");
my_data->current_backend_cfg[HDMI_RX_BACKEND].samplerate_mixer_ctl =
strdup("HDMI_RX SampleRate");
+ my_data->current_backend_cfg[HDMI_RX_BACKEND].channels_mixer_ctl =
+ strdup("HDMI_RX Channels");
ret = audio_extn_utils_get_codec_version(snd_card_name,
my_data->adev->snd_card,
@@ -4046,16 +4050,21 @@
* configures afe with bit width and Sample Rate
*/
static int platform_set_codec_backend_cfg(struct audio_device* adev,
- snd_device_t snd_device, unsigned int bit_width,
- unsigned int sample_rate, audio_format_t format)
+ snd_device_t snd_device, struct audio_backend_cfg backend_cfg)
{
int ret = 0;
int backend_idx = DEFAULT_CODEC_BACKEND;
struct platform_data *my_data = (struct platform_data *)adev->platform;
+ unsigned int bit_width = backend_cfg.bit_width;
+ unsigned int sample_rate = backend_cfg.sample_rate;
+ unsigned int channels = backend_cfg.channels;
+ audio_format_t format = backend_cfg.format;
+ bool passthrough_enabled = backend_cfg.passthrough_enabled;
backend_idx = platform_get_backend_index(snd_device);
- ALOGI("%s:becf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
- __func__, bit_width, sample_rate, backend_idx,
+
+ ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d, backend_idx %d device (%s)",
+ __func__, bit_width, sample_rate, channels,backend_idx,
platform_get_snd_device_name(snd_device));
if (bit_width !=
@@ -4147,19 +4156,146 @@
mixer_ctl_set_enum_by_string(ctl, rate_str);
my_data->current_backend_cfg[backend_idx].sample_rate = sample_rate;
}
+ if ((backend_idx == HDMI_RX_BACKEND) &&
+ (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+ struct mixer_ctl *ctl;
+ char *channel_cnt_str = NULL;
+
+ switch (channels) {
+ case 8:
+ channel_cnt_str = "Eight"; break;
+ case 7:
+ channel_cnt_str = "Seven"; break;
+ case 6:
+ channel_cnt_str = "Six"; break;
+ case 5:
+ channel_cnt_str = "Five"; break;
+ case 4:
+ channel_cnt_str = "Four"; break;
+ case 3:
+ channel_cnt_str = "Three"; break;
+ default:
+ channel_cnt_str = "Two"; break;
+ }
+
+ ctl = mixer_get_ctl_by_name(adev->mixer,
+ my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+ if (!ctl) {
+ ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+ __func__,
+ my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+ return -EINVAL;
+ }
+ mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+ my_data->current_backend_cfg[backend_idx].channels = channels;
+ platform_set_edid_channels_configuration(adev->platform, channels);
+ ALOGD("%s:becf: afe: %s set to %s", __func__,
+ my_data->current_backend_cfg[backend_idx].channels_mixer_ctl, channel_cnt_str);
+ }
+
+ if (backend_idx == HDMI_RX_BACKEND) {
+ const char *hdmi_format_ctrl = "HDMI RX Format";
+ struct mixer_ctl *ctl;
+ ctl = mixer_get_ctl_by_name(adev->mixer,hdmi_format_ctrl);
+
+ if (!ctl) {
+ ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+ __func__, hdmi_format_ctrl);
+ return -EINVAL;
+ }
+
+ if (passthrough_enabled) {
+ ALOGD("%s:HDMI compress format", __func__);
+ mixer_ctl_set_enum_by_string(ctl, "Compr");
+ } else {
+ ALOGD("%s: HDMI PCM format", __func__);
+ mixer_ctl_set_enum_by_string(ctl, "LPCM");
+ }
+ }
return ret;
}
/*
+ *Validate the selected bit_width, sample_rate and channels using the edid
+ *of the connected sink device.
+ */
+static void platform_check_hdmi_backend_cfg(struct audio_device* adev,
+ struct audio_usecase* usecase,
+ struct audio_backend_cfg *hdmi_backend_cfg)
+{
+ unsigned int bit_width;
+ unsigned int sample_rate;
+ unsigned int channels, max_supported_channels = 0;
+ struct platform_data *my_data = (struct platform_data *)adev->platform;
+ edid_audio_info *edid_info = (edid_audio_info *)my_data->edid_info;
+ bool passthrough_enabled = false;
+
+ bit_width = hdmi_backend_cfg->bit_width;
+ sample_rate = hdmi_backend_cfg->sample_rate;
+ channels = hdmi_backend_cfg->channels;
+
+
+ ALOGI("%s:becf: HDMI: bitwidth %d, samplerate %d, channels %d"
+ ", usecase = %d", __func__, bit_width,
+ sample_rate, channels, usecase->id);
+
+ if (audio_extn_passthru_is_enabled() && audio_extn_passthru_is_active()
+ && (usecase->stream.out->compr_config.codec->compr_passthr != 0)) {
+ passthrough_enabled = true;
+ ALOGI("passthrough is enabled for this stream");
+ }
+
+ // For voice calls use default configuration i.e. 16b/48K, only applicable to
+ // default backend
+ if (!passthrough_enabled) {
+
+ max_supported_channels = platform_edid_get_max_channels(my_data);
+
+ //Check EDID info for supported samplerate
+ if (!edid_is_supported_sr(edid_info,sample_rate)) {
+ //reset to current sample rate
+ sample_rate = my_data->current_backend_cfg[HDMI_RX_BACKEND].sample_rate;
+ }
+
+ //Check EDID info for supported bit width
+ if (!edid_is_supported_bps(edid_info,bit_width)) {
+ //reset to current sample rate
+ bit_width = my_data->current_backend_cfg[HDMI_RX_BACKEND].bit_width;
+ }
+
+ if (channels > max_supported_channels)
+ channels = max_supported_channels;
+
+ } else {
+ /*During pass through set default bit width and channels*/
+ channels = DEFAULT_HDMI_OUT_CHANNELS;
+ if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
+ sample_rate = sample_rate * 4 ;
+
+ bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ /* We force route so that the BE format can be set to Compr */
+ }
+
+ ALOGI("%s:becf: afe: HDMI backend: passthrough %d updated bit width: %d and sample rate: %d"
+ "channels %d", __func__, passthrough_enabled , bit_width,
+ sample_rate, channels);
+
+ hdmi_backend_cfg->bit_width = bit_width;
+ hdmi_backend_cfg->sample_rate = sample_rate;
+ hdmi_backend_cfg->channels = channels;
+ hdmi_backend_cfg->passthrough_enabled = passthrough_enabled;
+}
+
+/*
* goes through all the current usecases and picks the highest
* bitwidth & samplerate
*/
static bool platform_check_codec_backend_cfg(struct audio_device* adev,
struct audio_usecase* usecase,
snd_device_t snd_device,
- unsigned int* new_bit_width,
- unsigned int* new_sample_rate)
+ struct audio_backend_cfg *backend_cfg)
{
bool backend_change = false;
struct listnode *node;
@@ -4167,18 +4303,21 @@
char value[PROPERTY_VALUE_MAX] = {0};
unsigned int bit_width;
unsigned int sample_rate;
+ unsigned int channels;
+ bool passthrough_enabled = false;
int backend_idx = DEFAULT_CODEC_BACKEND;
struct platform_data *my_data = (struct platform_data *)adev->platform;
int na_mode = platform_get_native_support();
- edid_audio_info *edid_info = (edid_audio_info *)my_data->edid_info;
+ bool channels_updated = false;
backend_idx = platform_get_backend_index(snd_device);
- bit_width = *new_bit_width;
- sample_rate = *new_sample_rate;
+ bit_width = backend_cfg->bit_width;
+ sample_rate = backend_cfg->sample_rate;
+ channels = backend_cfg->channels;
- ALOGI("%s:becf: afe: Codec selected backend: %d current bit width: %d and sample rate: %d",
- __func__, backend_idx, bit_width, sample_rate);
+ ALOGI("%s:becf: afe: Codec selected backend: %d current bit width: %d sample rate: %d channels: %d",
+ __func__, backend_idx, bit_width, sample_rate, channels);
// For voice calls use default configuration i.e. 16b/48K, only applicable to
// default backend
@@ -4204,12 +4343,13 @@
struct audio_usecase *uc;
uc = node_to_item(node, struct audio_usecase, list);
struct stream_out *out = (struct stream_out*) uc->stream.out;
+ unsigned int out_channels = audio_channel_count_from_out_mask(out->channel_mask);
if (uc->type == PCM_PLAYBACK && out && usecase != uc) {
ALOGD("%s:napb: (%d) - (%s)id (%d) sr %d bw "
- "(%d) device %s", __func__, i++, use_case_table[uc->id],
+ "(%d) ch (%d) device %s", __func__, i++, use_case_table[uc->id],
uc->id, out->sample_rate,
- out->bit_width,
+ out->bit_width, out_channels,
platform_get_snd_device_name(uc->out_snd_device));
if (platform_check_backends_match(snd_device, uc->out_snd_device)) {
@@ -4219,6 +4359,8 @@
sample_rate = out->sample_rate;
if (out->sample_rate < OUTPUT_SAMPLING_RATE_44100)
sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ if (channels < out_channels)
+ channels = out_channels;
}
}
}
@@ -4276,16 +4418,21 @@
}
if (backend_idx == HDMI_RX_BACKEND) {
- //Check EDID info for supported samplerate
- if (!edid_is_supported_sr(edid_info,sample_rate)) {
- //reset to current sample rate
- sample_rate = my_data->current_backend_cfg[backend_idx].sample_rate;
- }
- //Check EDID info for supported bit widhth
- if (!edid_is_supported_bps(edid_info,bit_width)) {
- //reset to current sample rate
- bit_width = my_data->current_backend_cfg[backend_idx].bit_width;
- }
+ struct audio_backend_cfg hdmi_backend_cfg;
+ hdmi_backend_cfg.bit_width = bit_width;
+ hdmi_backend_cfg.sample_rate = sample_rate;
+ hdmi_backend_cfg.channels = channels;
+ hdmi_backend_cfg.passthrough_enabled = false;
+
+ platform_check_hdmi_backend_cfg(adev, usecase, &hdmi_backend_cfg);
+
+ bit_width = hdmi_backend_cfg.bit_width;
+ sample_rate = hdmi_backend_cfg.sample_rate;
+ channels = hdmi_backend_cfg.channels;
+ passthrough_enabled = hdmi_backend_cfg.passthrough_enabled;
+
+ if (channels != my_data->current_backend_cfg[backend_idx].channels)
+ channels_updated = true;
}
//check if mulitchannel clip needs to be down sampled to 48k
@@ -4316,13 +4463,16 @@
// Force routing if the expected bitwdith or samplerate
// is not same as current backend comfiguration
if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
- (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate)) {
- *new_bit_width = bit_width;
- *new_sample_rate = sample_rate;
+ (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+ passthrough_enabled || channels_updated) {
+ backend_cfg->bit_width = bit_width;
+ backend_cfg->sample_rate = sample_rate;
+ backend_cfg->channels = channels;
+ backend_cfg->passthrough_enabled = passthrough_enabled;
backend_change = true;
- ALOGI("%s:becf: afe: Codec backend needs to be updated. new bit width: %d new sample rate: %d",
- __func__,
- *new_bit_width, *new_sample_rate);
+ ALOGI("%s:becf: afe: Codec backend needs to be updated. new bit width: %d"
+ " new sample rate: %d new channels %d",__func__,
+ backend_cfg->bit_width, backend_cfg->sample_rate, backend_cfg->channels);
}
return backend_change;
@@ -4331,23 +4481,24 @@
bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
struct audio_usecase *usecase, snd_device_t snd_device)
{
- unsigned int new_bit_width;
- unsigned int new_sample_rate;
int backend_idx = DEFAULT_CODEC_BACKEND;
int new_snd_devices[SND_DEVICE_OUT_END];
int i, num_devices = 1;
+ struct audio_backend_cfg backend_cfg;
bool ret = false;
- audio_format_t format;
backend_idx = platform_get_backend_index(snd_device);
- new_bit_width = usecase->stream.out->bit_width;
- new_sample_rate = usecase->stream.out->sample_rate;
- format = usecase->stream.out->format;
+ backend_cfg.bit_width = usecase->stream.out->bit_width;
+ backend_cfg.sample_rate = usecase->stream.out->sample_rate;
+ backend_cfg.format = usecase->stream.out->format;
+ backend_cfg.channels = audio_channel_count_from_out_mask(usecase->stream.out->channel_mask);
+ /*this is populated by check_codec_backend_cfg hence set default value to false*/
+ backend_cfg.passthrough_enabled = false;
- ALOGI("%s:becf: afe: bitwidth %d, samplerate %d"
- ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width,
- new_sample_rate, backend_idx, usecase->id,
+ ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
+ ", backend_idx %d usecase = %d device (%s)", __func__, backend_cfg.bit_width,
+ backend_cfg.sample_rate, backend_cfg.channels, backend_idx, usecase->id,
platform_get_snd_device_name(snd_device));
if (!platform_can_split_snd_device(adev->platform, snd_device,
@@ -4358,9 +4509,9 @@
ALOGI("%s: becf: new_snd_devices[%d] is %s", __func__, i,
platform_get_snd_device_name(new_snd_devices[i]));
if (platform_check_codec_backend_cfg(adev, usecase, new_snd_devices[i],
- &new_bit_width, &new_sample_rate)) {
+ &backend_cfg)) {
platform_set_codec_backend_cfg(adev, new_snd_devices[i],
- new_bit_width, new_sample_rate, format);
+ backend_cfg);
ret = true;
}
}
@@ -5030,6 +5181,7 @@
//reset HDMI_RX_BACKEND to default values
my_data->current_backend_cfg[HDMI_RX_BACKEND].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
my_data->current_backend_cfg[HDMI_RX_BACKEND].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ my_data->current_backend_cfg[HDMI_RX_BACKEND].channels = DEFAULT_HDMI_OUT_CHANNELS;
}
int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
@@ -5048,91 +5200,6 @@
return mixer_ctl_set_enum_by_string(ctl, mixer_val);
}
-static int set_mixer_control(struct mixer *mixer,
- const char * mixer_ctl_name,
- const char *mixer_val)
-{
- struct mixer_ctl *ctl;
- ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
- ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
- if (!ctl) {
- ALOGE("%s: could not get ctl for mixer cmd - %s",
- __func__, mixer_ctl_name);
- return -EINVAL;
- }
-
- return mixer_ctl_set_enum_by_string(ctl, mixer_val);
-}
-
-int platform_set_hdmi_config(void *platform, uint32_t channel_count,
- uint32_t sample_rate, bool enable_passthrough)
-{
- struct platform_data *my_data = (struct platform_data *)platform;
- struct audio_device *adev = my_data->adev;
- const char *hdmi_format_ctrl = "HDMI RX Format";
- const char *hdmi_rate_ctrl = "HDMI_RX SampleRate";
- const char *hdmi_chans_ctrl = "HDMI_RX Channels";
- const char *channel_cnt_str = NULL;
-
- ALOGI("%s ch[%d] sr[%d], pthru[%d]", __func__,
- channel_count, sample_rate, enable_passthrough);
-
- switch (channel_count) {
- case 8:
- channel_cnt_str = "Eight"; break;
- case 7:
- channel_cnt_str = "Seven"; break;
- case 6:
- channel_cnt_str = "Six"; break;
- case 5:
- channel_cnt_str = "Five"; break;
- case 4:
- channel_cnt_str = "Four"; break;
- case 3:
- channel_cnt_str = "Three"; break;
- default:
- channel_cnt_str = "Two"; break;
- }
- ALOGV("%s: HDMI channel count: %s", __func__, channel_cnt_str);
- set_mixer_control(adev->mixer, hdmi_chans_ctrl, channel_cnt_str);
-
- if (enable_passthrough) {
- ALOGD("%s:HDMI compress format", __func__);
- set_mixer_control(adev->mixer, hdmi_format_ctrl, "Compr");
- } else {
- ALOGD("%s: HDMI PCM format", __func__);
- set_mixer_control(adev->mixer, hdmi_format_ctrl, "LPCM");
- }
-
- switch (sample_rate) {
- case 32000:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_32");
- break;
- case 44100:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_44P1");
- break;
- case 96000:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_96");
- break;
- case 128000:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_128");
- break;
- case 176400:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_176_4");
- break;
- case 192000:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_192");
- break;
- default:
- case 48000:
- set_mixer_control(adev->mixer, hdmi_rate_ctrl, "KHZ_48");
- break;
- }
-
- return 0;
-}
-
-
int platform_set_device_params(struct stream_out *out, int param, int value)
{
struct audio_device *adev = out->dev;
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index cd5aeb7..dcd351a 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -372,4 +372,13 @@
char device_name[100];
char interface_name[100];
};
+
+struct audio_backend_cfg {
+ unsigned int sample_rate;
+ unsigned int channels;
+ unsigned int bit_width;
+ bool passthrough_enabled;
+ audio_format_t format;
+};
+
#endif // QCOM_AUDIO_PLATFORM_H