audio: Enable External HDMI support
-For HDMI compliance, channel status bits
should be configured for the external HDMI chip.
-Hence HAL based on the output format i.e compressed
or LPCM populates the channel_status information
and passes it to the dai-driver which in turn
configures the external HDMI chip.
Change-Id: Ibf192492d259a722070a08f4764fde9498dd268d
diff --git a/hal/Android.mk b/hal/Android.mk
index 74de942..713f2c1 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -54,6 +54,7 @@
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
LOCAL_SRC_FILES += edid.c
+ LOCAL_CFLAGS := -DHDMI_EDID_ENABLED
endif
ifeq ($(strip $(AUDIO_USE_LL_AS_PRIMARY_OUTPUT)),true)
@@ -251,6 +252,12 @@
LOCAL_SRC_FILES += audio_extn/listen.c
endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HDMI)),true)
+ LOCAL_CFLAGS += -DAUDIO_EXTERNAL_HDMI_ENABLED
+ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-parsers
+ LOCAL_SHARED_LIBRARIES += libaudioparsers
+endif
+
ifeq ($(strip $(BOARD_SUPPORTS_SOUND_TRIGGER)),true)
LOCAL_CFLAGS += -DSOUND_TRIGGER_ENABLED
LOCAL_CFLAGS += -DSOUND_TRIGGER_PLATFORM_NAME=$(TARGET_BOARD_PLATFORM)
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 8bcc885..c47f5ed 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -486,4 +486,10 @@
void audio_extn_perf_lock_acquire(void);
void audio_extn_perf_lock_release(void);
#endif /* KPI_OPTIMIZE_ENABLED */
+
+#ifndef AUDIO_EXTERNAL_HDMI_ENABLED
+#define setChannelStatus(out, buffer, bytes) (0)
+#else
+void setChannelStatus(struct stream_out *out, char * buffer, size_t bytes);
+#endif
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index a2b644e..c2b2f64 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -35,6 +35,10 @@
#include "audio_extn.h"
#include "voice.h"
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#include "audio_parsers.h"
+#endif
+
#define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
#define OUTPUTS_TAG "outputs"
@@ -52,6 +56,21 @@
#define BASE_TABLE_SIZE 64
#define MAX_BASEINDEX_LEN 256
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#define PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
+#define NON_LPCM (1<<1) /* 0 = audio, 1 = non-audio */
+#define SR_44100 (0<<0) /* 44.1kHz */
+#define SR_NOTID (1<<0) /* non indicated */
+#define SR_48000 (2<<0) /* 48kHz */
+#define SR_32000 (3<<0) /* 32kHz */
+#define SR_22050 (4<<0) /* 22.05kHz */
+#define SR_24000 (6<<0) /* 24kHz */
+#define SR_88200 (8<<0) /* 88.2kHz */
+#define SR_96000 (10<<0) /* 96kHz */
+#define SR_176400 (12<<0) /* 176.4kHz */
+#define SR_192000 (14<<0) /* 192kHz */
+
+#endif
struct string_to_enum {
const char *name;
uint32_t value;
@@ -747,3 +766,130 @@
outp[k] = '\0';
return k;
}
+
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+
+void get_default_compressed_channel_status(
+ unsigned char *channel_status)
+{
+ int32_t status = 0;
+ unsigned char bit_index;
+ memset(channel_status,0,24);
+
+ /* block start bit in preamble bit 3 */
+ channel_status[0] |= PROFESSIONAL;
+ //compre out
+ channel_status[0] |= NON_LPCM;
+ // sample rate; fixed 48K for default/transcode
+ channel_status[3] |= SR_48000;
+}
+
+int32_t get_compressed_channel_status(void *audio_stream_data,
+ uint32_t audio_frame_size,
+ unsigned char *channel_status,
+ enum audio_parser_code_type codec_type)
+ // codec_type - AUDIO_PARSER_CODEC_AC3
+ // - AUDIO_PARSER_CODEC_DTS
+{
+ unsigned char *streamPtr;
+ int ret = 0;
+ streamPtr = (unsigned char *)audio_stream_data;
+
+ if (audio_stream_data == NULL || audio_frame_size == 0) {
+ ALOGW("no buffer to get channel status, return default for compress");
+ get_default_compressed_channel_status(channel_status);
+ return ret;
+ }
+
+ memset(channel_status,0,24);
+ if(init_audio_parser(streamPtr, audio_frame_size, codec_type) == -1)
+ {
+ ALOGE("init audio parser failed");
+ return -1;
+ }
+ ret = get_channel_status(channel_status, codec_type);
+ return ret;
+
+}
+
+void get_linearpcm_channel_status(uint32_t sampleRate,
+ unsigned char *channel_status)
+{
+ int32_t status = 0;
+ unsigned char bit_index;
+ memset(channel_status,0,24);
+ /* block start bit in preamble bit 3 */
+ channel_status[0] |= PROFESSIONAL;
+ //LPCM OUT
+ channel_status[0] &= ~NON_LPCM;
+
+ switch (sampleRate) {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ channel_status[3] |= SR_NOTID;
+ case 24000:
+ channel_status[3] |= SR_24000;
+ break;
+ case 32000:
+ channel_status[3] |= SR_32000;
+ break;
+ case 44100:
+ channel_status[3] |= SR_44100;
+ break;
+ case 48000:
+ channel_status[3] |= SR_48000;
+ break;
+ case 88200:
+ channel_status[3] |= SR_88200;
+ break;
+ case 96000:
+ channel_status[3] |= SR_96000;
+ break;
+ case 176400:
+ channel_status[3] |= SR_176400;
+ break;
+ case 192000:
+ channel_status[3] |= SR_192000;
+ break;
+ default:
+ ALOGV("Invalid sample_rate %u\n", sampleRate);
+ status = -1;
+ break;
+ }
+}
+
+void setChannelStatus(struct stream_out *out, char * buffer, size_t bytes)
+{
+ unsigned char channel_status[24]={0};
+ struct snd_aes_iec958 iec958;
+ const char *mixer_ctl_name = "IEC958 Playback PCM Stream";
+ struct mixer_ctl *ctl;
+ int i=0;
+ if (audio_extn_is_dolby_format(out->format) &&
+ /*TODO:Extend code to support DTS passthrough*/
+ /*set compressed channel status bits*/
+ audio_extn_dolby_is_passthrough_stream(out->flags)){
+ get_compressed_channel_status(buffer, bytes, channel_status, AUDIO_PARSER_CODEC_AC3);
+ } else {
+ /*set channel status bit for LPCM*/
+ get_linearpcm_channel_status(out->sample_rate, channel_status);
+ }
+
+ memcpy(iec958.status, channel_status,sizeof(iec958.status));
+ ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return;
+ }
+ if (mixer_ctl_set_array(ctl, &iec958, sizeof(iec958)) < 0) {
+ ALOGE("%s: Could not set channel status for ext HDMI ",
+ __func__);
+ return;
+ }
+
+}
+#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 3286e6b..ece0a04 100755
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -564,6 +564,9 @@
audio_route_reset_and_update_path(adev->audio_route, device_name);
}
+ if (snd_device == SND_DEVICE_OUT_HDMI)
+ adev->mChannelStatusSet = false;
+
audio_extn_dev_arbi_release(snd_device);
audio_extn_sound_trigger_update_device_status(snd_device,
ST_EVENT_SND_DEVICE_FREE);
@@ -2127,6 +2130,11 @@
}
}
+ if (adev->mChannelStatusSet == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+ setChannelStatus(out, buffer, bytes);
+ adev->mChannelStatusSet = true;
+ }
+
if (is_offload_usecase(out->usecase)) {
ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
if (out->send_new_metadata) {
@@ -2783,7 +2791,6 @@
out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
out->non_blocking = 0;
out->use_small_bufs = false;
-
/* Init use case and pcm_config */
if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT) &&
!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
@@ -3665,6 +3672,7 @@
list_init(&adev->usecase_list);
adev->cur_wfd_channels = 2;
adev->offload_usecases_state = 0;
+ adev->mChannelStatusSet = false;
pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL);
adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 67f5279..45e90b7 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -311,6 +311,7 @@
int snd_card;
unsigned int cur_codec_backend_samplerate;
unsigned int cur_codec_backend_bit_width;
+ bool mChannelStatusSet;
void *platform;
unsigned int offload_usecases_state;
void *visualizer_lib;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 72f4685..a2310e4 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -4024,14 +4024,15 @@
edid_data[0] = count;
memcpy(&edid_data[1], block, count);
-#ifdef AUDIO_FEATURE_ENABLED_HDMI_EDID
+#ifdef HDMI_EDID_ENABLED
if (!edid_get_sink_caps(info, edid_data)) {
ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
goto fail;
}
+#endif
+
my_data->edid_valid = true;
return 0;
-#endif
fail:
if (my_data->edid_info) {
free(my_data->edid_info);