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 1973178..ed554a7 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -260,6 +260,14 @@
LOCAL_SRC_FILES += audio_extn/listen.c
endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HDMI)),true)
+ LOCAL_CFLAGS += -DAUDIO_EXTERNAL_HDMI_ENABLED
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH)),true)
+ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-parsers
+ LOCAL_SHARED_LIBRARIES += libaudioparsers
+endif
+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 a0dd5ae..1571ea7 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -509,4 +509,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 audio_utils_set_hdmi_channel_status(out, buffer, bytes) (0)
+#else
+void audio_utils_set_hdmi_channel_status(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 b9e2a40..38dbb46 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -35,6 +35,12 @@
#include "audio_extn.h"
#include "voice.h"
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#ifdef HDMI_PASSTHROUGH_ENABLED
+#include "audio_parsers.h"
+#endif
+#endif
+
#define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
#define OUTPUTS_TAG "outputs"
@@ -52,6 +58,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;
@@ -765,3 +786,136 @@
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;
+}
+
+#ifdef HDMI_PASSTHROUGH_ENABLED
+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 *stream;
+ int ret = 0;
+ stream = (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(stream, audio_frame_size, codec_type) == -1)
+ {
+ ALOGE("init audio parser failed");
+ return -1;
+ }
+ ret = get_channel_status(channel_status, codec_type);
+ return ret;
+
+}
+
+#endif
+
+void get_lpcm_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 audio_utils_set_hdmi_channel_status(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;
+#ifdef HDMI_PASSTHROUGH_ENABLED
+ 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
+#endif
+ {
+ /*set channel status bit for LPCM*/
+ get_lpcm_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 1beb0f9..d37275d 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -603,6 +603,9 @@
audio_route_reset_and_update_path(adev->audio_route, device_name);
}
+ if (snd_device == SND_DEVICE_OUT_HDMI)
+ adev->is_channel_status_set = false;
+
audio_extn_dev_arbi_release(snd_device);
audio_extn_sound_trigger_update_device_status(snd_device,
ST_EVENT_SND_DEVICE_FREE);
@@ -2180,6 +2183,11 @@
adev->adm_register_output_stream(adev->adm_data, out->handle, out->flags);
}
+ if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+ audio_utils_set_hdmi_channel_status(out, buffer, bytes);
+ adev->is_channel_status_set = true;
+ }
+
if (is_offload_usecase(out->usecase)) {
ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
if (out->send_new_metadata) {
@@ -3758,6 +3766,7 @@
list_init(&adev->usecase_list);
adev->cur_wfd_channels = 2;
adev->offload_usecases_state = 0;
+ adev->is_channel_status_set = 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 070ebf6..0cb917b 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -325,6 +325,7 @@
int snd_card;
unsigned int cur_codec_backend_samplerate;
unsigned int cur_codec_backend_bit_width;
+ bool is_channel_status_set;
void *platform;
unsigned int offload_usecases_state;
void *visualizer_lib;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index aaca0b2..1bd7c49 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -4110,15 +4110,12 @@
}
edid_data[0] = count;
memcpy(&edid_data[1], block, count);
-
-#ifdef AUDIO_FEATURE_ENABLED_HDMI_EDID
if (!edid_get_sink_caps(info, edid_data)) {
ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
goto fail;
}
my_data->edid_valid = true;
return 0;
-#endif
fail:
if (my_data->edid_info) {
free(my_data->edid_info);