Merge "hal: Add performance lock during device switch"
diff --git a/hal/Android.mk b/hal/Android.mk
index e457b83..0e0f8b3 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -85,8 +85,8 @@
     LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
 endif
 
-ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM)),true)
-    LOCAL_CFLAGS += -DFM_ENABLED
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM_POWER_OPT)),true)
+    LOCAL_CFLAGS += -DFM_POWER_OPT
     LOCAL_SRC_FILES += audio_extn/fm.c
 endif
 
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index ce8f965..fe959be 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -82,7 +82,7 @@
 #define AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE "offload_num_active"
 #define AUDIO_PARAMETER_HPX            "HPX"
 
-#ifndef FM_ENABLED
+#ifndef FM_POWER_OPT
 #define audio_extn_fm_set_parameters(adev, parms) (0)
 #else
 void audio_extn_fm_set_parameters(struct audio_device *adev,
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index b4848a4..ccdff09 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -59,13 +59,8 @@
 #define AUDIO_OUTPUT_FLAG_INCALL_MUSIC 0x8000
 #endif
 
-#ifndef FM_ENABLED
-#define AUDIO_DEVICE_OUT_FM 0x80000
-#define AUDIO_DEVICE_OUT_FM_TX 0x100000
-#define AUDIO_SOURCE_FM_RX 9
-#define AUDIO_SOURCE_FM_RX_A2DP 10
-#define AUDIO_DEVICE_IN_FM_RX (AUDIO_DEVICE_BIT_IN | 0x8000)
-#define AUDIO_DEVICE_IN_FM_RX_A2DP (AUDIO_DEVICE_BIT_IN | 0x10000)
+#ifndef AUDIO_DEVICE_OUT_FM_TX
+#define AUDIO_DEVICE_OUT_FM_TX 0x8000000
 #endif
 
 #ifndef FLAC_OFFLOAD_ENABLED
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index ed3776c..6381e68 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -31,10 +31,11 @@
 #include <stdlib.h>
 #include <cutils/str_parms.h>
 
-#ifdef FM_ENABLED
+#ifdef FM_POWER_OPT
 #define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
 #define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume"
 #define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
+#define FM_LOOPBACK_DRAIN_TIME_MS 2
 
 static struct pcm_config pcm_config_fm = {
     .channels = 2,
@@ -65,7 +66,7 @@
   .scard_state = SND_CARD_STATE_ONLINE,
 };
 
-static int32_t fm_set_volume(struct audio_device *adev, float value)
+static int32_t fm_set_volume(struct audio_device *adev, float value, bool persist)
 {
     int32_t vol, ret = 0;
     struct mixer_ctl *ctl;
@@ -82,7 +83,8 @@
         value = 1.0;
     }
     vol  = lrint((value * 0x2000) + 0.5);
-    fmmod.fm_volume = value;
+    if (persist)
+        fmmod.fm_volume = value;
 
     if (!fmmod.is_fm_running) {
         ALOGV("%s: FM not active, ignoring set_fm_volume call", __func__);
@@ -202,7 +204,7 @@
     pcm_start(fmmod.fm_pcm_tx);
 
     fmmod.is_fm_running = true;
-    fm_set_volume(adev, fmmod.fm_volume);
+    fm_set_volume(adev, fmmod.fm_volume, false);
 
     ALOGD("%s: exit: status(%d)", __func__, ret);
     return 0;
@@ -263,8 +265,11 @@
                 adev->primary_output->devices = val & ~AUDIO_DEVICE_OUT_FM;
                 fm_start(adev);
             } else if (!(val & AUDIO_DEVICE_OUT_FM)
-                     && fmmod.is_fm_running == true)
+                     && fmmod.is_fm_running == true) {
+                fm_set_volume(adev, 0, false);
+                usleep(FM_LOOPBACK_DRAIN_TIME_MS*1000);
                 fm_stop(adev);
+            }
        }
     }
 
@@ -278,7 +283,7 @@
             goto exit;
         }
         ALOGD("%s: set_fm_volume usecase", __func__);
-        fm_set_volume(adev, vol);
+        fm_set_volume(adev, vol, true);
     }
 
 #ifdef RECORD_PLAY_CONCURRENCY
@@ -293,10 +298,10 @@
             ALOGD("Record play concurrency OFF Forcing FM device reroute");
 
         select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
-        fm_set_volume(adev,fmmod.fm_volume);
+        fm_set_volume(adev, fmmod.fm_volume, false);
     }
 #endif
 exit:
     ALOGV("%s: exit", __func__);
 }
-#endif /* FM_ENABLED end */
+#endif /* FM_POWER_OPT end */
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index 69c9341..6990f23 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -240,6 +240,18 @@
         hw_info->snd_devices = NULL;
         hw_info->num_snd_devices = 0;
         strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8952-sku1-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8952", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8952-sku2-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8952", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
     } else {
         ALOGW("%s: Not an  8x16/8939/8909/8952 device", __func__);
     }
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index a478f93..44ee73a 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -51,6 +51,8 @@
 #define MIXER_XML_PATH_SKUE "/system/etc/mixer_paths_skue.xml"
 #define MIXER_XML_PATH_SKUL "/system/etc/mixer_paths_skul.xml"
 #define MIXER_XML_PATH_SKUM "/system/etc/mixer_paths_qrd_skum.xml"
+#define MIXER_XML_PATH_SKU1 "/system/etc/mixer_paths_qrd_sku1.xml"
+#define MIXER_XML_PATH_SKU2 "/system/etc/mixer_paths_qrd_sku2.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
 #define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
@@ -902,6 +904,20 @@
         msm_device_to_be_id = msm_device_to_be_id_external_codec;
         msm_be_id_array_len  =
             sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+    }  else if (!strncmp(snd_card_name, "msm8952-sku1-snd-card",
+                 sizeof("msm8952-sku1-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKU1,
+                sizeof(MIXER_XML_PATH_SKU1));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+    }  else if (!strncmp(snd_card_name, "msm8952-sku2-snd-card",
+                 sizeof("msm8952-sku2-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKU2,
+                sizeof(MIXER_XML_PATH_SKU2));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
     } else if (!strncmp(snd_card_name, "msm8952-skum-snd-card",
                  sizeof("msm8952-skum-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUM,
@@ -2792,9 +2808,7 @@
                 }
             }
         }
-    } else if (source == AUDIO_SOURCE_FM_RX ||
-               source == AUDIO_SOURCE_FM_RX_A2DP ||
-               source == AUDIO_SOURCE_FM_TUNER) {
+    } else if (source == AUDIO_SOURCE_FM_TUNER) {
         snd_device = SND_DEVICE_IN_CAPTURE_FM;
     } else if (source == AUDIO_SOURCE_DEFAULT) {
         goto exit;
@@ -2837,8 +2851,7 @@
         } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
                    in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
             snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_FM_RX ||
-                   in_device & AUDIO_DEVICE_IN_FM_TUNER) {
+        } else if (in_device & AUDIO_DEVICE_IN_FM_TUNER) {
             snd_device = SND_DEVICE_IN_CAPTURE_FM;
         } else {
             ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
@@ -3522,8 +3535,7 @@
 int platform_update_usecase_from_source(int source, int usecase)
 {
     ALOGV("%s: input source :%d", __func__, source);
-    if (source == AUDIO_SOURCE_FM_RX_A2DP ||
-        source == AUDIO_SOURCE_FM_TUNER)
+    if (source == AUDIO_SOURCE_FM_TUNER)
         usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
     return usecase;
 }
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index cc48b9e..0af5a08 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2657,9 +2657,7 @@
                 }
             }
         }
-    } else if (source == AUDIO_SOURCE_FM_RX ||
-               source == AUDIO_SOURCE_FM_RX_A2DP||
-               source == AUDIO_SOURCE_FM_TUNER) {
+    } else if (source == AUDIO_SOURCE_FM_TUNER) {
         snd_device = SND_DEVICE_IN_CAPTURE_FM;
     } else if (source == AUDIO_SOURCE_DEFAULT) {
         goto exit;
@@ -2702,8 +2700,7 @@
         } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
                    in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
             snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_FM_RX ||
-                   in_device & AUDIO_DEVICE_IN_FM_TUNER) {
+        } else if (in_device & AUDIO_DEVICE_IN_FM_TUNER) {
             snd_device = SND_DEVICE_IN_CAPTURE_FM;
         } else {
             ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
@@ -3452,8 +3449,7 @@
 int platform_update_usecase_from_source(int source, int usecase)
 {
     ALOGV("%s: input source :%d", __func__, source);
-    if (source == AUDIO_SOURCE_FM_RX_A2DP ||
-        source == AUDIO_SOURCE_FM_TUNER)
+    if (source == AUDIO_SOURCE_FM_TUNER)
         usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
     return usecase;
 }
diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk
index 52ed11d..70814d8 100644
--- a/policy_hal/Android.mk
+++ b/policy_hal/Android.mk
@@ -59,6 +59,10 @@
     LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FM_POWER_OPT)),true)
+LOCAL_CFLAGS += -DFM_POWER_OPT
+endif
+
 LOCAL_MODULE := libaudiopolicymanager
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 46c58c5..7876e5b 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -26,7 +26,6 @@
 #else
 #define ALOGVV(a...) do { } while(0)
 #endif
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
 
 // A device mask for all audio output devices that are considered "remote" when evaluating
 // active output devices in isStreamActiveRemotely()
@@ -35,9 +34,6 @@
 // type alone is not enough: the address must match too
 #define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
                                             AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
-// Following delay should be used if the calculated routing delay from all active
-// input streams is higher than this value
-#define MAX_VOICE_CALL_START_DELAY_MS 100
 
 #include <inttypes.h>
 #include <math.h>
@@ -254,6 +250,23 @@
             audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
             updateCallRouting(newDevice);
         }
+
+#ifdef FM_POWER_OPT
+        // handle FM device connection state to trigger FM AFE loopback
+        if(device == AUDIO_DEVICE_OUT_FM && hasPrimaryOutput()) {
+           audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
+           if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+               mPrimaryOutput->changeRefCount(AUDIO_STREAM_MUSIC, 1);
+               newDevice = newDevice | AUDIO_DEVICE_OUT_FM;
+           } else {
+               mPrimaryOutput->changeRefCount(AUDIO_STREAM_MUSIC, -1);
+           }
+           AudioParameter param = AudioParameter();
+           param.addInt(String8("handle_fm"), (int)newDevice);
+           mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString());
+        }
+#endif /* FM_POWER_OPT end */
+
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
@@ -397,6 +410,13 @@
         return false;
     }
 
+    // Check if offload has been disabled
+    bool offloadDisabled = property_get_bool("audio.offload.disable", false);
+    if (offloadDisabled) {
+        ALOGI("offload disabled by audio.offload.disable=%d", offloadDisabled);
+        return false;
+    }
+
     char propValue[PROPERTY_VALUE_MAX];
     bool pcmOffload = false;
 #ifdef PCM_OFFLOAD_ENABLED
@@ -426,13 +446,13 @@
     }
 #endif
     if (!pcmOffload) {
-        // Check if offload has been disabled
-        if (property_get("audio.offload.disable", propValue, "0")) {
-            if (atoi(propValue) != 0) {
-                ALOGV("offload disabled by audio.offload.disable=%s", propValue );
-                return false;
-            }
+
+        bool compressedOffloadDisabled = property_get_bool("audio.offload.compress.disable", false);
+        if (compressedOffloadDisabled) {
+            ALOGI("compressed offload disabled by audio.offload.compress.disable=%d", compressedOffloadDisabled);
+            return false;
         }
+
         //check if it's multi-channel AAC (includes sub formats) and FLAC format
         if ((popcount(offloadInfo.channel_mask) > 2) &&
            (((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) ||
@@ -853,9 +873,6 @@
             setStrategyMute(STRATEGY_SONIFICATION, false, desc, MUTE_TIME_MS,
                 getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
         }
-        ALOGV("Setting the delay from %dms to %dms", delayMs,
-                MIN(delayMs, MAX_VOICE_CALL_START_DELAY_MS));
-         delayMs = MIN(delayMs, MAX_VOICE_CALL_START_DELAY_MS);
     }
 
     if (hasPrimaryOutput()) {
@@ -1235,6 +1252,13 @@
             mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
             mLastVoiceVolume = voiceVolume;
         }
+#ifdef FM_POWER_OPT
+    } else if (stream == AUDIO_STREAM_MUSIC && hasPrimaryOutput() &&
+               outputDesc == mPrimaryOutput) {
+        AudioParameter param = AudioParameter();
+        param.addFloat(String8("fm_volume"), Volume::DbToAmpl(volumeDb));
+        mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString(), delayMs);
+#endif /* FM_POWER_OPT end */
     }
 
     return NO_ERROR;
@@ -1264,7 +1288,17 @@
 {
     audio_offload_info_t tOffloadInfo = AUDIO_INFO_INITIALIZER;
 
-    bool pcmOffloadEnabled = property_get_bool("audio.offload.track.enable", false);
+    bool offloadDisabled = property_get_bool("audio.offload.disable", false);
+    bool pcmOffloadEnabled = false;
+
+    if (offloadDisabled) {
+        ALOGI("offload disabled by audio.offload.disable=%d", offloadDisabled);
+    }
+
+    //read track offload property only if the global offload switch is off.
+    if (!offloadDisabled) {
+         pcmOffloadEnabled = property_get_bool("audio.offload.track.enable", false);
+    }
 
     if (offloadInfo == NULL && pcmOffloadEnabled) {
         tOffloadInfo.sample_rate  = samplingRate;
@@ -1276,7 +1310,7 @@
             ALOGV("found attribute .. setting usage %d ", attr->usage);
             tOffloadInfo.usage = attr->usage;
         } else {
-            ALOGD("%s:: attribute is NULL .. no usage set", __func__);
+            ALOGI("%s:: attribute is NULL .. no usage set", __func__);
         }
         offloadInfo = &tOffloadInfo;
     }