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/audio_hw.c b/hal/audio_hw.c
index 65c285f..69d5cce 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -892,8 +892,9 @@
if (usecase->type != PCM_CAPTURE &&
usecase != uc_info &&
(usecase->out_snd_device != snd_device || force_routing) &&
- (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND ||
- force_restart_session) &&
+ ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+ (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+ (force_restart_session)) &&
platform_check_backends_match(snd_device, usecase->out_snd_device)) {
ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
@@ -1802,193 +1803,6 @@
return 0;
}
-static bool allow_hdmi_channel_config(struct audio_device *adev,
- bool enable_passthru)
-{
- struct listnode *node;
- struct audio_usecase *usecase;
- bool ret = true;
-
- if (enable_passthru && !audio_extn_passthru_is_enabled()) {
- ret = false;
- goto exit;
- }
-
- if (audio_extn_passthru_is_active()) {
- ALOGI("%s: Compress audio passthrough is active,"
- "no HDMI config change allowed", __func__);
- ret = false;
- goto exit;
- }
-
- list_for_each(node, &adev->usecase_list) {
- usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- /*
- * If voice call is already existing, do not proceed further to avoid
- * disabling/enabling both RX and TX devices, CSD calls, etc.
- * Once the voice call done, the HDMI channels can be configured to
- * max channels of remaining use cases.
- */
- if (usecase->id == USECASE_VOICE_CALL) {
- ALOGV("%s: voice call is active, no change in HDMI channels",
- __func__);
- ret = false;
- break;
- } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
- if (!enable_passthru) {
- ALOGV("%s: multi channel playback is active, "
- "no change in HDMI channels", __func__);
- ret = false;
- break;
- }
- } else if (is_offload_usecase(usecase->id) &&
- audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) {
- if (!enable_passthru) {
- ALOGD("%s:multi-channel(%x) compress offload playback is active"
- ", no change in HDMI channels", __func__,
- usecase->stream.out->channel_mask);
- ret = false;
- break;
- }
- }
- }
- }
- ALOGV("allow hdmi config %d", ret);
-exit:
- return ret;
-}
-
-static int check_and_set_hdmi_config(struct audio_device *adev,
- uint32_t channels,
- uint32_t sample_rate,
- audio_format_t format,
- bool enable_passthru)
-{
- struct listnode *node;
- struct audio_usecase *usecase;
- int32_t factor = 1;
- bool config = false;
-
- ALOGV("%s channels %d sample_rate %d format:%x enable_passthru:%d",
- __func__, channels, sample_rate, format, enable_passthru);
-
- if (channels != adev->cur_hdmi_channels) {
- ALOGV("channel does not match current hdmi channels");
- config = true;
- }
-
- if (sample_rate != adev->cur_hdmi_sample_rate) {
- ALOGV("sample rate does not match current hdmi sample rate");
- config = true;
- }
-
- if (format != adev->cur_hdmi_format) {
- ALOGV("format does not match current hdmi format");
- config = true;
- }
-
- /* TBD - add check for bit width */
- if (!config) {
- ALOGV("No need to config hdmi");
- return 0;
- }
-
- if (enable_passthru &&
- (format == AUDIO_FORMAT_E_AC3)) {
- ALOGV("factor 4 for E_AC3 passthru");
- factor = 4;
- }
-
- platform_set_hdmi_config(adev->platform, channels, factor * sample_rate,
- enable_passthru);
- adev->cur_hdmi_channels = channels;
- adev->cur_hdmi_format = format;
- adev->cur_hdmi_sample_rate = sample_rate;
-
- /*
- * Deroute all the playback streams routed to HDMI so that
- * the back end is deactivated. Note that backend will not
- * be deactivated if any one stream is connected to it.
- */
- list_for_each(node, &adev->usecase_list) {
- usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->type == PCM_PLAYBACK &&
- usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- disable_audio_route(adev, usecase);
- }
- }
-
- bool was_active = audio_extn_keep_alive_is_active();
- if (was_active)
- audio_extn_keep_alive_stop();
-
- /*
- * Enable all the streams disabled above. Now the HDMI backend
- * will be activated with new channel configuration
- */
- list_for_each(node, &adev->usecase_list) {
- usecase = node_to_item(node, struct audio_usecase, list);
- if (usecase->type == PCM_PLAYBACK &&
- usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- enable_audio_route(adev, usecase);
- }
- }
-
- if (was_active)
- audio_extn_keep_alive_start();
-
- return 0;
-}
-
-/* called with out lock taken */
-static int check_and_set_hdmi_backend(struct stream_out *out)
-{
- struct audio_device *adev = out->dev;
- int ret;
- bool enable_passthru = false;
-
- if (!(out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL))
- return -1;
-
- ALOGV("%s usecase %s out->format:%x out->bit_width:%d", __func__, use_case_table[out->usecase],out->format,out->bit_width);
-
- if (is_offload_usecase(out->usecase) &&
- audio_extn_passthru_is_passthrough_stream(out)) {
- enable_passthru = true;
- ALOGV("%s : enable_passthru is set to true", __func__);
- }
-
- /* Check if change in HDMI channel config is allowed */
- if (!allow_hdmi_channel_config(adev, enable_passthru)) {
- return -EPERM;
- }
-
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- uint32_t channels;
- ALOGV("Offload usecase, enable passthru %d", enable_passthru);
-
- if (enable_passthru) {
- audio_extn_passthru_on_start(out);
- audio_extn_passthru_update_stream_configuration(adev, out);
- }
-
- /* For pass through case, the backend should be configured as stereo */
- channels = enable_passthru ? DEFAULT_HDMI_OUT_CHANNELS :
- out->compr_config.codec->ch_in;
-
- ret = check_and_set_hdmi_config(adev, channels,
- out->sample_rate, out->format,
- enable_passthru);
- } else
- ret = check_and_set_hdmi_config(adev, out->config.channels,
- out->config.rate,
- out->format,
- false);
- return ret;
-}
-
-
static int stop_output_stream(struct stream_out *out)
{
int ret = 0;
@@ -2029,17 +1843,14 @@
ALOGV("Disable passthrough , reset mixer to pcm");
/* NO_PASSTHROUGH */
out->compr_config.codec->compr_passthr = 0;
-
audio_extn_passthru_on_stop(out);
audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
}
/* Must be called after removing the usecase from list */
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
- check_and_set_hdmi_config(adev, DEFAULT_HDMI_OUT_CHANNELS,
- DEFAULT_HDMI_OUT_SAMPLE_RATE,
- DEFAULT_HDMI_OUT_FORMAT,
- false);
+ audio_extn_keep_alive_start();
+
ALOGV("%s: exit: status(%d)", __func__, ret);
return ret;
}
@@ -2081,12 +1892,6 @@
goto error_config;
}
- /* This must be called before adding this usecase to the list */
- if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- /* This call can fail if compress pass thru is already active */
- check_and_set_hdmi_backend(out);
- }
-
uc_info->id = out->usecase;
uc_info->type = PCM_PLAYBACK;
uc_info->stream.out = out;
@@ -2098,6 +1903,16 @@
audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
adev->perf_lock_opts,
adev->perf_lock_opts_size);
+
+ if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ audio_extn_keep_alive_stop();
+ if (audio_extn_passthru_is_enabled() &&
+ audio_extn_passthru_is_passthrough_stream(out)) {
+ audio_extn_passthru_on_start(out);
+ audio_extn_passthru_update_stream_configuration(adev, out);
+ }
+ }
+
select_devices(adev, out->usecase);
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
@@ -2791,9 +2606,10 @@
}
if (audio_extn_passthru_should_drop_data(out)) {
- ALOGD(" %s : Drop data as compress passthrough session is going on", __func__);
- usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
- out_get_sample_rate(&out->stream.common));
+ ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
+ if (audio_bytes_per_sample(out->format) != 0)
+ out->written += bytes / (out->config.channels * audio_bytes_per_sample(out->format));
+ ret = -EIO;
goto exit;
}
@@ -3168,7 +2984,6 @@
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
pthread_mutex_lock(&out->dev->lock);
ALOGV("offload resume, check and set hdmi backend again");
- check_and_set_hdmi_backend(out);
pthread_mutex_unlock(&out->dev->lock);
}
status = compress_resume(out->compr);