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_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index b316473..569b4b2 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -763,6 +763,7 @@
    audio_extn_pm_set_parameters(parms);
    audio_extn_source_track_set_parameters(adev, parms);
    audio_extn_fbsp_set_parameters(parms);
+   audio_extn_keep_alive_set_parameters(adev, parms);
    check_and_set_hdmi_connection_status(parms);
    if (adev->offload_effects_set_parameters != NULL)
        adev->offload_effects_set_parameters(parms);
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index 1a4f135..60e7eef 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -38,7 +38,7 @@
 
 #define SILENCE_MIXER_PATH "silence-playback hdmi"
 #define SILENCE_DEV_ID 32           /* index into machine driver */
-#define SILENCE_INTERVAL_US 2000000
+#define SILENCE_INTERVAL 2 /*In secs*/
 
 typedef enum {
     STATE_DEINIT = -1,
@@ -52,7 +52,9 @@
 
 typedef struct {
     pthread_mutex_t lock;
+    pthread_mutex_t sleep_lock;
     pthread_cond_t  cond;
+    pthread_cond_t  wake_up_cond;
     pthread_t thread;
     state_t state;
     struct listnode cmd_list;
@@ -88,6 +90,8 @@
     ka.pcm = NULL;
     pthread_mutex_init(&ka.lock, (const pthread_mutexattr_t *) NULL);
     pthread_cond_init(&ka.cond, (const pthread_condattr_t *) NULL);
+    pthread_cond_init(&ka.wake_up_cond, (const pthread_condattr_t *) NULL);
+    pthread_mutex_init(&ka.sleep_lock, (const pthread_mutexattr_t *) NULL);
     list_init(&ka.cmd_list);
     if (pthread_create(&ka.thread,  (const pthread_attr_t *) NULL,
                        keep_alive_loop, NULL) < 0) {
@@ -143,6 +147,27 @@
     return 0;
 }
 
+
+static int set_mixer_control(struct mixer *mixer,
+                             const char * mixer_ctl_name,
+                             const char *mixer_val)
+{
+    struct mixer_ctl *ctl;
+    if ((mixer == NULL) || (mixer_ctl_name == NULL) || (mixer_val == NULL)) {
+       ALOGE("%s: Invalid input", __func__);
+       return -EINVAL;
+    }
+    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);
+}
+
 /* must be called with adev lock held */
 void audio_extn_keep_alive_start()
 {
@@ -151,18 +176,20 @@
     int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
     struct mixer_ctl *ctl;
     int acdb_dev_id, snd_device;
+    struct listnode *node;
+    struct audio_usecase *usecase;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
 
     pthread_mutex_lock(&ka.lock);
 
     if (ka.state == STATE_DEINIT) {
         ALOGE(" %s : Invalid state ",__func__);
-        return;
+        goto exit;
     }
 
     if (audio_extn_passthru_is_active()) {
         ALOGE(" %s : Pass through is already active", __func__);
-        return;
+        goto exit;
     }
 
     if (ka.state == STATE_ACTIVE) {
@@ -170,6 +197,14 @@
         goto exit;
     }
 
+    /* Dont start keep_alive if any other PCM session is routed to HDMI*/
+    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)
+             goto exit;
+    }
+
     ka.done = false;
 
     /*configure app type */
@@ -202,9 +237,15 @@
           platform_get_default_app_type(adev->platform),
           acdb_dev_id, sample_rate);
     mixer_ctl_set_array(ctl, app_type_cfg, len);
+    /*Configure HDMI Backend with default values, this as well
+     *helps reconfigure HDMI backend after passthrough
+     */
+    set_mixer_control(adev->mixer, "HDMI RX Format", "LPCM");
+    set_mixer_control(adev->mixer, "HDMI_RX SampleRate", "KHZ_48");
+    set_mixer_control(adev->mixer, "HDMI_RX Channels", "Two");
 
     /*send calibration*/
-    struct audio_usecase *usecase = calloc(1, sizeof(struct audio_usecase));
+    usecase = calloc(1, sizeof(struct audio_usecase));
     usecase->type = PCM_PLAYBACK;
     usecase->out_snd_device = SND_DEVICE_OUT_HDMI;
 
@@ -232,13 +273,13 @@
 
     pthread_mutex_lock(&ka.lock);
 
-    if (ka.state == STATE_DEINIT)
-        return;
-
-    if (ka.state == STATE_IDLE)
+    if ((ka.state == STATE_DEINIT) || (ka.state == STATE_IDLE))
         goto exit;
 
+    pthread_mutex_lock(&ka.sleep_lock);
     ka.done = true;
+    pthread_cond_signal(&ka.wake_up_cond);
+    pthread_mutex_unlock(&ka.sleep_lock);
     while (ka.state != STATE_IDLE) {
         pthread_cond_wait(&ka.cond, &ka.lock);
     }
@@ -290,6 +331,7 @@
     struct listnode *item;
     uint8_t * silence = NULL;
     int32_t bytes = 0;
+    struct timespec ts;
 
     while (true) {
         pthread_mutex_lock(&ka.lock);
@@ -328,9 +370,17 @@
              * Just something to keep the connection alive is sufficient.
              * Hence a short burst of silence periodically.
              */
-            usleep(SILENCE_INTERVAL_US);
-        }
+            pthread_mutex_lock(&ka.sleep_lock);
+            clock_gettime(CLOCK_REALTIME, &ts);
+            ts.tv_sec += SILENCE_INTERVAL;
+            ts.tv_nsec = 0;
 
+            if (!ka.done)
+              pthread_cond_timedwait(&ka.wake_up_cond,
+                            &ka.sleep_lock, &ts);
+
+            pthread_mutex_unlock(&ka.sleep_lock);
+        }
         pthread_mutex_lock(&ka.lock);
         ka.state = STATE_IDLE;
         pthread_cond_signal(&ka.cond);
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index e6ac4dd..eaa8c0a 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -82,8 +82,14 @@
  */
 bool audio_extn_passthru_should_drop_data(struct stream_out * out)
 {
-
-    if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+    /*Drop data only
+     *stream is routed to HDMI and
+     *stream has PCM format or
+     *if a compress offload (DSP decode) session
+     */
+    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+        (((out->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) ||
+        ((out->compr_config.codec != NULL) && (out->compr_config.codec->compr_passthr == LEGACY_PCM)))) {
         if (android_atomic_acquire_load(&compress_passthru_active) > 0) {
             ALOGI("drop data as pass thru is active");
             return true;
@@ -112,9 +118,6 @@
     ALOGV("inc pass thru count to notify other streams");
     android_atomic_inc(&compress_passthru_active);
 
-    ALOGV("keep_alive_stop");
-    audio_extn_keep_alive_stop();
-
     while (true) {
         /* find max period time among active playback use cases */
         list_for_each(node, &adev->usecase_list) {