Merge "hal: Support for multi-channel      for AFE_PROXY"
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 176df8c..3f457d2 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -143,6 +143,77 @@
 #define audio_extn_set_afe_proxy_parameters(parms)        (0)
 #define audio_extn_get_afe_proxy_parameters(query, reply) (0)
 #else
+/* Front left channel. */
+#define PCM_CHANNEL_FL    1
+
+/* Front right channel. */
+#define PCM_CHANNEL_FR    2
+
+/* Front center channel. */
+#define PCM_CHANNEL_FC    3
+
+/* Left surround channel.*/
+#define PCM_CHANNEL_LS   4
+
+/* Right surround channel.*/
+#define PCM_CHANNEL_RS   5
+
+/* Low frequency effect channel. */
+#define PCM_CHANNEL_LFE  6
+
+/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_LB   8
+
+/* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_RB   9
+
+static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev,
+                                                     int channel_count)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Playback Channel Map";
+    int set_values[8] = {0};
+    int ret;
+    ALOGV("%s channel_count:%d",__func__, channel_count);
+
+    switch (channel_count) {
+    case 6:
+        set_values[0] = PCM_CHANNEL_FL;
+        set_values[1] = PCM_CHANNEL_FR;
+        set_values[2] = PCM_CHANNEL_FC;
+        set_values[3] = PCM_CHANNEL_LFE;
+        set_values[4] = PCM_CHANNEL_LS;
+        set_values[5] = PCM_CHANNEL_RS;
+        break;
+    case 8:
+        set_values[0] = PCM_CHANNEL_FL;
+        set_values[1] = PCM_CHANNEL_FR;
+        set_values[2] = PCM_CHANNEL_FC;
+        set_values[3] = PCM_CHANNEL_LFE;
+        set_values[4] = PCM_CHANNEL_LS;
+        set_values[5] = PCM_CHANNEL_RS;
+        set_values[6] = PCM_CHANNEL_LB;
+        set_values[7] = PCM_CHANNEL_RB;
+        break;
+    default:
+        ALOGE("unsupported channels(%d) for setting channel map",
+                                                    channel_count);
+        return -EINVAL;
+    }
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    ALOGV("AFE: set mapping(%d %d %d %d %d %d %d %d) for channel:%d",
+        set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
+        set_values[5], set_values[6], set_values[7], channel_count);
+    ret = mixer_ctl_set_array(ctl, set_values, channel_count);
+    return ret;
+}
+
 int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev)
 {
     int32_t ret = 0;
@@ -150,7 +221,6 @@
     struct mixer_ctl *ctl = NULL;
     const char *mixer_ctl_name = "PROXY_RX Channels";
 
-
     ALOGD("%s: entry", __func__);
     /* use the existing channel count set by hardware params to
     configure the back end for stereo as usb/a2dp would be
@@ -177,6 +247,11 @@
     }
     mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
 
+    if (aextnmod.proxy_channel_num == 6 ||
+          aextnmod.proxy_channel_num == 8)
+        ret = afe_proxy_set_channel_mapping(adev,
+                             aextnmod.proxy_channel_num);
+
     ALOGD("%s: exit", __func__);
     return ret;
 }
@@ -215,6 +290,34 @@
 
     return 0;
 }
+
+/* must be called with hw device mutex locked */
+int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out)
+{
+    int ret = 0;
+    int channels = aextnmod.proxy_channel_num;
+
+    switch (channels) {
+        /*
+         * Do not handle stereo output in Multi-channel cases
+         * Stereo case is handled in normal playback path
+         */
+    case 6:
+        ALOGV("%s: AFE PROXY supports 5.1", __func__);
+        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        break;
+    case 8:
+        ALOGV("%s: AFE PROXY supports 5.1 and 7.1 channels", __func__);
+        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
+        break;
+    default:
+        ALOGE("AFE PROXY does not support multi channel playback");
+        ret = -ENOSYS;
+        break;
+    }
+    return ret;
+}
 #endif /* AFE_PROXY_ENABLED */
 
 void audio_extn_set_parameters(struct audio_device *adev,
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index e6db5c1..c6d06df 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -41,8 +41,10 @@
 
 #ifndef AFE_PROXY_ENABLED
 #define audio_extn_set_afe_proxy_channel_mixer(adev)     (0)
+#define audio_extn_read_afe_proxy_channel_masks(out)     (0)
 #else
 int32_t audio_extn_set_afe_proxy_channel_mixer(struct audio_device *adev);
+int32_t audio_extn_read_afe_proxy_channel_masks(struct stream_out *out);
 #endif
 
 #ifndef USB_HEADSET_ENABLED
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 937c79b..b8195b4 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2008,10 +2008,16 @@
     out->handle = handle;
 
     /* Init use case and pcm_config */
-    if (out->flags == AUDIO_OUTPUT_FLAG_DIRECT &&
-        out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
+        (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+        out->devices & AUDIO_DEVICE_OUT_PROXY)) {
+
         pthread_mutex_lock(&adev->lock);
-        ret = read_hdmi_channel_masks(out);
+        if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+            ret = read_hdmi_channel_masks(out);
+
+        if (out->devices & AUDIO_DEVICE_OUT_PROXY)
+            ret = audio_extn_read_afe_proxy_channel_masks(out);
         pthread_mutex_unlock(&adev->lock);
         if (ret != 0)
             goto error_open;