Merge "hal: update playback channel mapping for USB headset"
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index d3dbea4..70e8c55 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1017,6 +1017,44 @@
     return ret;
 }
 
+int platform_set_device_mute(void *platform, bool state, char *dir)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = NULL;
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              0};
+    if(dir == NULL) {
+        ALOGE("%s: Invalid direction:%s", __func__, dir);
+        return -EINVAL;
+    }
+
+    if (!strncmp("rx", dir, sizeof("rx"))) {
+        mixer_ctl_name = "Voice Rx Device Mute";
+    } else if (!strncmp("tx", dir, sizeof("tx"))) {
+        mixer_ctl_name = "Voice Tx Device Mute";
+    } else {
+        return -EINVAL;
+    }
+
+    set_values[0] = state;
+    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("%s: Setting device mute state: %d, mixer ctrl:%s",
+          __func__,state, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    return ret;
+}
+
 snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index c1ba595..ed1a781 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -561,6 +561,12 @@
     return ret;
 }
 
+int platform_set_device_mute(void *platform, bool state, char *dir)
+{
+    LOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
 snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 87f58a0..79736a8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1092,6 +1092,44 @@
     return ret;
 }
 
+int platform_set_device_mute(void *platform, bool state, char *dir)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = NULL;
+    int ret = 0;
+    uint32_t set_values[ ] = {0,
+                              ALL_SESSION_VSID,
+                              0};
+    if(dir == NULL) {
+        ALOGE("%s: Invalid direction:%s", __func__, dir);
+        return -EINVAL;
+    }
+
+    if (!strncmp("rx", dir, sizeof("rx"))) {
+        mixer_ctl_name = "Voice Rx Device Mute";
+    } else if (!strncmp("tx", dir, sizeof("tx"))) {
+        mixer_ctl_name = "Voice Tx Device Mute";
+    } else {
+        return -EINVAL;
+    }
+
+    set_values[0] = state;
+    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("%s: Setting device mute state: %d, mixer ctrl:%s",
+          __func__,state, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+    return ret;
+}
+
 snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -1396,8 +1434,10 @@
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
                 channel_count == 1 ) {
             if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                    my_data->fluence_in_audio_rec)
+                    my_data->fluence_in_audio_rec) {
                 snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+                set_echo_reference(adev->mixer, EC_REF_RX);
+            }
         }
     } else if (source == AUDIO_SOURCE_FM_RX ||
                source == AUDIO_SOURCE_FM_RX_A2DP) {
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 0f72a54..a6c32c9 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -197,7 +197,7 @@
 #define VOWLAN_CALL_PCM_DEVICE 30
 #elif PLATFORM_APQ8084
 #define VOICE_CALL_PCM_DEVICE 20
-#define VOICE2_CALL_PCM_DEVICE 13
+#define VOICE2_CALL_PCM_DEVICE 28
 #define VOLTE_CALL_PCM_DEVICE 21
 #define QCHAT_CALL_PCM_DEVICE 06
 #define VOWLAN_CALL_PCM_DEVICE -1
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 2ec6b50..03890e9 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -45,6 +45,7 @@
 int platform_set_voice_volume(void *platform, int volume);
 int platform_set_mic_mute(void *platform, bool state);
 int platform_get_sample_rate(void *platform, uint32_t *rate);
+int platform_set_device_mute(void *platform, bool state, char *dir);
 snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
 snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
 int platform_set_hdmi_channels(void *platform, int channel_count);
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index f2dc6bc..f6083f3 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -38,6 +38,8 @@
 #define AUDIO_PARAMETER_KEY_CALL_STATE          "call_state"
 #define AUDIO_PARAMETER_KEY_AUDIO_MODE          "audio_mode"
 #define AUDIO_PARAMETER_KEY_ALL_CALL_STATES     "all_call_states"
+#define AUDIO_PARAMETER_KEY_DEVICE_MUTE         "device_mute"
+#define AUDIO_PARAMETER_KEY_DIRECTION           "direction"
 
 #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
 
@@ -440,6 +442,7 @@
     int value;
     int ret = 0, err;
     char *kv_pairs = str_parms_to_str(parms);
+    char str_value[256] = {0};
 
     ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
 
@@ -465,8 +468,34 @@
             ret = -EINVAL;
             goto done;
         }
-    } else {
-        ALOGV("%s: Not handled here", __func__);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE, str_value,
+                            sizeof(str_value));
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_DEVICE_MUTE);
+        bool mute = false;
+
+        if (!strncmp("true", str_value, sizeof("true"))) {
+            mute = true;
+        }
+
+        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DIRECTION, str_value,
+                                sizeof(str_value));
+        if (err >= 0) {
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_DIRECTION);
+        } else {
+            ALOGE("%s: direction key not found", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+
+        ret = platform_set_device_mute(adev->platform, mute, str_value);
+        if (ret != 0) {
+            ALOGE("%s: Failed to set mute err:%d", __func__, ret);
+            ret = -EINVAL;
+            goto done;
+        }
     }
 
 done:
diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk
index c68ab6e..4f3a737 100644
--- a/policy_hal/Android.mk
+++ b/policy_hal/Android.mk
@@ -29,6 +29,9 @@
 ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true)
 LOCAL_CFLAGS += -DAUDIO_EXTN_INCALL_MUSIC_ENABLED
 endif
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_HDMI_SPK)),true)
+LOCAL_CFLAGS += -DAUDIO_EXTN_HDMI_SPK_ENABLED
+endif
 
 
 ifeq ($(strip $(TARGET_BOARD_PLATFORM)),msm8916)
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index a774c9e..8947456 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -44,6 +44,7 @@
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
+const char* AudioPolicyManager::HDMI_SPKR_STR = "hdmi_spkr";
 
 status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
                                                       AudioSystem::device_connection_state state,
@@ -85,6 +86,15 @@
         // handle output device connection
         case AudioSystem::DEVICE_STATE_AVAILABLE:
             if (mAvailableOutputDevices & device) {
+#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED
+                if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+                   if (!strncmp(device_address, HDMI_SPKR_STR, MAX_DEVICE_ADDRESS_LEN)) {
+                        mHdmiAudioDisabled = false;
+                    } else {
+                        mHdmiAudioEvent = true;
+                    }
+                }
+#endif
                 ALOGW("setDeviceConnectionState() device already connected: %x", device);
                 return INVALID_OPERATION;
             }
@@ -98,6 +108,18 @@
             // register new device as available
             mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
 
+#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED
+            if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+                if (!strncmp(device_address, HDMI_SPKR_STR, MAX_DEVICE_ADDRESS_LEN)) {
+                    mHdmiAudioDisabled = false;
+                } else {
+                    mHdmiAudioEvent = true;
+                }
+                if (mHdmiAudioDisabled || !mHdmiAudioEvent) {
+                    mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+                }
+            }
+#endif
             if (!outputs.isEmpty()) {
                 String8 paramStr;
                 if (mHasA2dp && audio_is_a2dp_device(device)) {
@@ -127,6 +149,15 @@
         // handle output device disconnection
         case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
             if (!(mAvailableOutputDevices & device)) {
+#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED
+                if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+                    if (!strncmp(device_address, HDMI_SPKR_STR, MAX_DEVICE_ADDRESS_LEN)) {
+                        mHdmiAudioDisabled = true;
+                    } else {
+                        mHdmiAudioEvent = false;
+                    }
+                }
+#endif
                 ALOGW("setDeviceConnectionState() device not connected: %x", device);
                 return INVALID_OPERATION;
             }
@@ -135,6 +166,15 @@
             // remove device from available output devices
             mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
 
+#ifdef AUDIO_EXTN_HDMI_SPK_ENABLED
+            if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+                if (!strncmp(device_address, HDMI_SPKR_STR, MAX_DEVICE_ADDRESS_LEN)) {
+                    mHdmiAudioDisabled = true;
+                } else {
+                    mHdmiAudioEvent = false;
+                }
+            }
+#endif
             checkOutputsForDevice(device, state, outputs);
             if (mHasA2dp && audio_is_a2dp_device(device)) {
                 // handle A2DP device disconnection
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
index 34ca701..188488a 100644
--- a/policy_hal/AudioPolicyManager.h
+++ b/policy_hal/AudioPolicyManager.h
@@ -35,7 +35,9 @@
 
 public:
                 AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
-                : AudioPolicyManagerBase(clientInterface) {}
+                : AudioPolicyManagerBase(clientInterface) {
+                    mHdmiAudioDisabled = false;
+                    mHdmiAudioEvent = false; }
 
         virtual ~AudioPolicyManager() {}
 
@@ -89,5 +91,13 @@
         // returns the category the device belongs to with regard to volume curve management
         static device_category getDeviceCategory(audio_devices_t device);
 
+        static const char* HDMI_SPKR_STR;
+
+        //parameter indicates of HDMI speakers disabled from the Qualcomm settings
+        bool mHdmiAudioDisabled;
+
+        //parameter indicates if HDMI plug in/out detected
+        bool mHdmiAudioEvent;
+
 };
 };