merge in klp-release history after reset to klp-dev
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index c5e44aa..08d9c32 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -783,6 +783,83 @@
     return 0;
 }
 
+static bool allow_hdmi_channel_config(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    bool ret = true;
+
+    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) {
+                ALOGD("%s: voice call is active, no change in HDMI channels",
+                      __func__);
+                ret = false;
+                break;
+            } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+                ALOGD("%s: multi channel playback is active, "
+                      "no change in HDMI channels", __func__);
+                ret = false;
+                break;
+            }
+        }
+    }
+    return ret;
+}
+
+static int check_and_set_hdmi_channels(struct audio_device *adev,
+                                       unsigned int channels)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    /* Check if change in HDMI channel config is allowed */
+    if (!allow_hdmi_channel_config(adev))
+        return 0;
+
+    if (channels == adev->cur_hdmi_channels) {
+        ALOGD("%s: Requested channels are same as current", __func__);
+        return 0;
+    }
+
+    platform_set_hdmi_channels(adev->platform, channels);
+    adev->cur_hdmi_channels = channels;
+
+    /*
+     * 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, true);
+        }
+    }
+
+    /*
+     * 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, true);
+        }
+    }
+
+    return 0;
+}
+
 static int stop_output_stream(struct stream_out *out)
 {
     int i, ret = 0;
@@ -811,6 +888,10 @@
     list_remove(&uc_info->list);
     free(uc_info);
 
+    /* Must be called after removing the usecase from list */
+    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+        check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
+
     ALOGV("%s: exit: status(%d)", __func__, ret);
     return ret;
 }
@@ -839,6 +920,10 @@
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
+    /* This must be called before adding this usecase to the list */
+    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+        check_and_set_hdmi_channels(adev, out->config.channels);
+
     list_add_tail(&adev->usecase_list, &uc_info->list);
 
     select_devices(adev, out->usecase);
@@ -1776,12 +1861,8 @@
         pthread_mutex_lock(&adev->lock);
         ret = read_hdmi_channel_masks(out);
         pthread_mutex_unlock(&adev->lock);
-        if (ret != 0) {
-            /* If HDMI does not support multi channel playback, set the default */
-            out->config.channels = popcount(out->channel_mask);
-            platform_set_hdmi_channels(adev->platform, out->config.channels);
+        if (ret != 0)
             goto error_open;
-        }
 
         if (config->sample_rate == 0)
             config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
@@ -1795,7 +1876,6 @@
         out->config.rate = config->sample_rate;
         out->config.channels = popcount(out->channel_mask);
         out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
-        platform_set_hdmi_channels(adev->platform, out->config.channels);
     } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
         out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
         out->config = pcm_config_deep_buffer;
@@ -2277,6 +2357,7 @@
     adev->bluetooth_nrec = true;
     adev->in_call = false;
     adev->acdb_settings = TTY_MODE_OFF;
+    /* adev->cur_hdmi_channels = 0;  by calloc() */
     adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
     list_init(&adev->usecase_list);
     pthread_mutex_unlock(&adev->lock);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 717c0a6..0da4324 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -39,6 +39,7 @@
 #define ACDB_DEV_TYPE_IN 2
 
 #define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define DEFAULT_HDMI_OUT_CHANNELS   2
 
 typedef int snd_device_t;
 
@@ -188,6 +189,7 @@
     struct audio_route *audio_route;
     int acdb_settings;
     bool speaker_lr_swap;
+    unsigned int cur_hdmi_channels;
 
     void *platform;