Promotion of av-userspace.lnx.1.0-00032.

CRs      Change ID                                   Subject
--------------------------------------------------------------------------------------------------------------
         Ib08ec8c6aef6d88bf4e4d413fb5d95e4167cce30   hal: close audio calibration fd
948361   I7fd8b7340e6c78ee6d00b41ccf679582338c011a   policy: Avoid unnecessary set_parameter calls
959131   If18e352971e92e82f4b67178924675a4a39c8460   hal: Fix closure of hardware dependent node
         Ifa0b214d16527973277a5c84b8a4f3fbd0760d07   policy_hal: fix for volume burst during FM device switch
948361   Id614d32df7f35ac93dd029a08b10e19f64ac631e   policy: Delay FM volume update to start of FM playback
959009   If66cc1e3d5467bf7d03137fdbbffd724a57ecaf6   hal: Validate active input before accessing source

CRs-Fixed: 948361, 959009, 959131

Conflicts:
	hal/msm8916/platform.c
	hal/msm8974/platform.c

Change-Id: I2334c946c86313f3886ee71ce15d3dacdf9464c9
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index c46f419..8c729ff 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -1000,7 +1000,8 @@
             out_snd_device = SND_DEVICE_NONE;
             if (in_snd_device == SND_DEVICE_NONE) {
                 audio_devices_t out_device = AUDIO_DEVICE_NONE;
-                if ((adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
+                if (adev->active_input &&
+                    (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
                     (adev->mode == AUDIO_MODE_IN_COMMUNICATION &&
                      adev->active_input->source == AUDIO_SOURCE_MIC)) &&
                      adev->primary_output && !adev->primary_output->standby) {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index a513048..f630270 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -247,6 +247,7 @@
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
     char ec_ref_mixer_path[64];
     char codec_version[CODEC_VERSION_MAX_LENGTH];
+    int hw_dep_fd;
 };
 
 static bool is_external_codec = false;
@@ -1386,14 +1387,15 @@
     return ret;
 }
 
-static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration,
+static void send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration,
                           struct platform_data *plat_data, int fd)
 {
-    int ret = 0, type;
+    int type;
 
     for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
         struct wcdcal_ioctl_buffer codec_buffer;
         struct param_data calib;
+        int ret;
 
         /* MAD calibration is handled by sound trigger HAL, skip here */
         if (type == WCD9XXX_MAD_CAL)
@@ -1410,14 +1412,14 @@
                                                                  &calib);
         if (ret < 0) {
             ALOGE("%s get_calibration failed\n", __func__);
-            return ret;
+            continue;
         }
         calib.get_size = 0;
         calib.buff = malloc(calib.buff_size);
         if(calib.buff == NULL) {
             ALOGE("%s mem allocation for %d bytes for %s failed\n"
                 , __func__, calib.buff_size, cal_name_info[type]);
-            return -1;
+            continue;
         }
         ret = acdb_loader_get_calibration(cal_name_info[type],
                               sizeof(struct param_data), &calib);
@@ -1425,7 +1427,7 @@
             ALOGE("%s get_calibration failed type=%s calib.size=%d\n"
                 , __func__, cal_name_info[type], codec_buffer.size);
             free(calib.buff);
-            return ret;
+            continue;
         }
         codec_buffer.buffer = calib.buff;
         codec_buffer.size = calib.data_size;
@@ -1437,14 +1439,14 @@
             , __func__, cal_name_info[type], codec_buffer.size);
         free(calib.buff);
     }
-    return ret;
 }
 
 static void audio_hwdep_send_cal(struct platform_data *plat_data)
 {
-    int fd;
+    int fd = plat_data->hw_dep_fd;
 
-    fd = hw_util_open(plat_data->adev->snd_card);
+    if (fd < 0)
+        fd = hw_util_open(plat_data->adev->snd_card);
     if (fd == -1) {
         ALOGE("%s error open\n", __func__);
         return;
@@ -1456,11 +1458,15 @@
     if (acdb_loader_get_calibration == NULL) {
         ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
            dlerror());
+        if (fd >= 0) {
+            close(fd);
+            plat_data->hw_dep_fd = -1;
+        }
         return;
     }
-    if (send_codec_cal(acdb_loader_get_calibration, plat_data, fd) < 0)
-        ALOGE("%s: Could not send anc cal", __FUNCTION__);
-    close(fd);
+
+    send_codec_cal(acdb_loader_get_calibration, plat_data, fd);
+    plat_data->hw_dep_fd = fd;
 }
 
 const char * get_snd_card_name_for_acdb_loader(const char *snd_card_name) {
@@ -1683,6 +1689,7 @@
     my_data->hd_voice = false;
     my_data->edid_info = NULL;
     my_data->is_wsa_speaker = false;
+    my_data->hw_dep_fd = -1;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1907,6 +1914,11 @@
         my_data->edid_info = NULL;
     }
 
+    if (my_data->hw_dep_fd >= 0) {
+        close(my_data->hw_dep_fd);
+        my_data->hw_dep_fd = -1;
+    }
+
     hw_info_deinit(my_data->hw_info);
     close_csd_client(my_data->csd);
 
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f243790..179593d 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -243,6 +243,7 @@
     char ec_ref_mixer_path[64];
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
     char codec_version[CODEC_VERSION_MAX_LENGTH];
+    int hw_dep_fd;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -1212,9 +1213,10 @@
 
 static void audio_hwdep_send_cal(struct platform_data *plat_data)
 {
-    int fd;
+    int fd = plat_data->hw_dep_fd;
 
-    fd = hw_util_open(plat_data->adev->snd_card);
+    if (fd < 0)
+        fd = hw_util_open(plat_data->adev->snd_card);
     if (fd == -1) {
         ALOGE("%s error open\n", __func__);
         return;
@@ -1226,11 +1228,15 @@
     if (acdb_loader_get_calibration == NULL) {
         ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
            dlerror());
+        if (fd >= 0) {
+            close(fd);
+            plat_data->hw_dep_fd = -1;
+        }
         return;
     }
 
     send_codec_cal(acdb_loader_get_calibration, plat_data, fd);
-    close(fd);
+    plat_data->hw_dep_fd = fd;
 }
 
 static int platform_acdb_init(void *platform)
@@ -1405,6 +1411,7 @@
     my_data->slowtalk = false;
     my_data->hd_voice = false;
     my_data->edid_info = NULL;
+    my_data->hw_dep_fd = -1;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1621,6 +1628,11 @@
         my_data->edid_info = NULL;
     }
 
+    if (my_data->hw_dep_fd >= 0) {
+        close(my_data->hw_dep_fd);
+        my_data->hw_dep_fd = -1;
+    }
+
     hw_info_deinit(my_data->hw_info);
     close_csd_client(my_data->csd);
 
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 8577620..1b1578e 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -279,15 +279,20 @@
 
 #ifdef FM_POWER_OPT
         // handle FM device connection state to trigger FM AFE loopback
-        if(device == AUDIO_DEVICE_OUT_FM && hasPrimaryOutput()) {
+        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;
+               mFMIsActive = true;
            } else {
+               mFMIsActive = false;
                mPrimaryOutput->changeRefCount(AUDIO_STREAM_MUSIC, -1);
            }
            AudioParameter param = AudioParameter();
+           float volumeDb = mPrimaryOutput->mCurVolume[AUDIO_STREAM_MUSIC];
+           mPrevFMVolumeDb = volumeDb;
+           param.addFloat(String8("fm_volume"), Volume::DbToAmpl(volumeDb));
            param.addInt(String8("handle_fm"), (int)newDevice);
            mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString());
         }
@@ -1270,10 +1275,16 @@
         }
 #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);
+               outputDesc == mPrimaryOutput && mFMIsActive) {
+        /* Avoid unnecessary set_parameter calls as it puts the primary
+           outputs FastMixer in HOT_IDLE leading to breaks in audio */
+        if (volumeDb != mPrevFMVolumeDb) {
+            mPrevFMVolumeDb = volumeDb;
+            AudioParameter param = AudioParameter();
+            param.addFloat(String8("fm_volume"), Volume::DbToAmpl(volumeDb));
+            //Double delayMs to avoid sound burst while device switch.
+            mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString(), delayMs*2);
+        }
 #endif /* FM_POWER_OPT end */
     }
 
@@ -2037,7 +2048,9 @@
     : AudioPolicyManager(clientInterface),
       mHdmiAudioDisabled(false),
       mHdmiAudioEvent(false),
-      mPrevPhoneState(0)
+      mPrevPhoneState(0),
+      mPrevFMVolumeDb(0.0f),
+      mFMIsActive(false)
 {
     char ssr_enabled[PROPERTY_VALUE_MAX] = {0};
     bool prop_ssr_enabled = false;
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
index 55d59ac..af8c2a8 100644
--- a/policy_hal/AudioPolicyManager.h
+++ b/policy_hal/AudioPolicyManager.h
@@ -154,6 +154,8 @@
         // Used for record + playback concurrency
         bool mIsInputRequestOnProgress;
 #endif
+        float mPrevFMVolumeDb;
+        bool mFMIsActive;
 };
 
 };