Merge "hal: end all calls when setmode(AUDIO_MODE_NORMAL) is called"
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index b661dd1..9ce8e19 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -98,7 +98,7 @@
     .format = PCM_FORMAT_S16_LE,
 };
 
-static const char * const use_case_table[AUDIO_USECASE_MAX] = {
+const char * const use_case_table[AUDIO_USECASE_MAX] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
     [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
@@ -2089,7 +2089,9 @@
     int val;
     int ret;
 
-    ALOGV("%s: enter: %s", __func__, kvpairs);
+    ALOGD("%s: enter: %s", __func__, kvpairs);
+
+    pthread_mutex_lock(&adev->lock);
     parms = str_parms_create_str(kvpairs);
 
     voice_set_parameters(adev, parms);
@@ -2131,7 +2133,6 @@
         default:
             ALOGE("%s: unexpected rotation of %d", __func__, val);
         }
-        pthread_mutex_lock(&adev->lock);
         if (adev->speaker_lr_swap != reverse_speakers) {
             adev->speaker_lr_swap = reverse_speakers;
             // only update the selected device if there is active pcm playback
@@ -2145,11 +2146,12 @@
                 }
             }
         }
-        pthread_mutex_unlock(&adev->lock);
     }
 
     audio_extn_set_parameters(adev, parms);
     str_parms_destroy(parms);
+
+    pthread_mutex_unlock(&adev->lock);
     ALOGV("%s: exit with code(%d)", __func__, ret);
     return ret;
 }
@@ -2162,12 +2164,15 @@
     struct str_parms *query = str_parms_create_str(keys);
     char *str;
 
+    pthread_mutex_lock(&adev->lock);
+
     audio_extn_get_parameters(adev, query, reply);
     platform_get_parameters(adev->platform, query, reply);
     str = str_parms_to_str(reply);
     str_parms_destroy(query);
     str_parms_destroy(reply);
 
+    pthread_mutex_unlock(&adev->lock);
     ALOGV("%s: exit: returns - %s", __func__, str);
     return str;
 }
@@ -2223,7 +2228,13 @@
 
 static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
 {
-    return voice_set_mic_mute((struct audio_device *)dev, state);
+    int ret;
+
+    pthread_mutex_lock(&adev->lock);
+    ret = voice_set_mic_mute((struct audio_device *)dev, state);
+    pthread_mutex_unlock(&adev->lock);
+
+    return ret;
 }
 
 static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index e9cb493..2aaaf4a 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1092,19 +1092,15 @@
     ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val);
     if (ret >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO);
-        pthread_mutex_lock(&my_data->adev->lock);
         my_data->btsco_sample_rate = val;
-        pthread_mutex_unlock(&my_data->adev->lock);
     }
 
     ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val);
     if (ret >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
-        pthread_mutex_lock(&my_data->adev->lock);
         ret = platform_set_slowtalk(my_data, val);
         if (ret)
             ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
-        pthread_mutex_unlock(&my_data->adev->lock);
     }
 
     ALOGV("%s: exit with code(%d)", __func__, ret);
@@ -1154,7 +1150,6 @@
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FLUENCE_TYPE,
                             value, sizeof(value));
     if (ret >= 0) {
-        pthread_mutex_lock(&my_data->adev->lock);
         if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
             strlcpy(value, "fluencepro", sizeof(value));
         } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
@@ -1162,7 +1157,6 @@
         } else {
             strlcpy(value, "none", sizeof(value));
         }
-        pthread_mutex_unlock(&my_data->adev->lock);
 
         str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FLUENCE_TYPE, value);
     }
diff --git a/hal/voice.c b/hal/voice.c
index 907ebc9..c85fcd4 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -41,20 +41,7 @@
     .format = PCM_FORMAT_S16_LE,
 };
 
-extern struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
-                                                   audio_usecase_t uc_id);
-extern int disable_snd_device(struct audio_device *adev,
-                              snd_device_t snd_device,
-                              bool update_mixer);
-extern int disable_audio_route(struct audio_device *adev,
-                               struct audio_usecase *usecase,
-                               bool update_mixer);
-
-extern int disable_snd_device(struct audio_device *adev,
-                              snd_device_t snd_device,
-                              bool update_mixer);
-extern int select_devices(struct audio_device *adev,
-                          audio_usecase_t uc_id);
+extern const char * const use_case_table[AUDIO_USECASE_MAX];
 
 static struct voice_session *voice_get_session_from_use_case(struct audio_device *adev,
                               audio_usecase_t usecase_id)
@@ -76,7 +63,7 @@
     struct audio_usecase *uc_info;
     struct voice_session *session = NULL;
 
-    ALOGD("%s: enter", __func__);
+    ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
 
     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
     session->state.current = CALL_INACTIVE;
@@ -124,10 +111,10 @@
     int pcm_dev_rx_id, pcm_dev_tx_id;
     struct voice_session *session = NULL;
     struct pcm_config voice_config = pcm_config_voice_call;
-    ALOGD("%s: enter", __func__);
+
+    ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
 
     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
-
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
     uc_info->id = usecase_id;
     uc_info->type = VOICE_CALL;
@@ -274,14 +261,11 @@
 {
     int err = 0;
 
-    pthread_mutex_lock(&adev->lock);
-
     err = platform_set_mic_mute(adev->platform, state);
     if (!err) {
         adev->voice.mic_mute = state;
     }
 
-    pthread_mutex_unlock(&adev->lock);
     return err;
 }
 
@@ -319,7 +303,7 @@
 {
     int ret = 0;
 
-    ret = voice_extn_update_calls(adev);
+    ret = voice_extn_start_call(adev);
     if (ret == -ENOSYS) {
         ret = start_call(adev, USECASE_VOICE_CALL);
     }
@@ -331,7 +315,7 @@
 {
     int ret = 0;
 
-    ret = voice_extn_update_calls(adev);
+    ret = voice_extn_stop_call(adev);
     if (ret == -ENOSYS) {
         ret = stop_call(adev, USECASE_VOICE_CALL);
     }
@@ -367,7 +351,6 @@
             goto done;
         }
 
-        pthread_mutex_lock(&adev->lock);
         if (tty_mode != adev->voice.tty_mode) {
             adev->voice.tty_mode = tty_mode;
             adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
@@ -375,7 +358,6 @@
                 //todo: what about voice2, volte and qchat usecases?
                 select_devices(adev, USECASE_VOICE_CALL);
         }
-        pthread_mutex_unlock(&adev->lock);
     }
 
 done:
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 903d2aa..87a97e2 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -63,7 +63,7 @@
 
 extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
 extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
-int voice_extn_update_calls(struct audio_device *adev);
+int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
 
 static bool is_valid_call_state(int call_state)
 {
@@ -130,104 +130,7 @@
     return session_id;
 }
 
-int voice_extn_get_active_session_id(struct audio_device *adev,
-                                     uint32_t *session_id)
-{
-    *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
-    return 0;
-}
-
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
-{
-    struct voice_session *session = NULL;
-    int i = 0;
-    *in_call = false;
-
-    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
-        session = &adev->voice.session[i];
-        if(session->state.current != CALL_INACTIVE){
-            *in_call = true;
-            break;
-        }
-    }
-
-    return 0;
-}
-
-static int voice_extn_update_call_states(struct audio_device *adev,
-                                    const uint32_t vsid, const int call_state)
-{
-    struct voice_session *session = NULL;
-    int i = 0;
-    bool is_in_call;
-
-    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
-        if (vsid == adev->voice.session[i].vsid) {
-            session = &adev->voice.session[i];
-            break;
-        }
-    }
-
-    if (session) {
-        session->state.new = call_state;
-        voice_extn_is_in_call(adev, &is_in_call);
-        ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode);
-        if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) {
-            /* Device routing is not triggered for voice calls on the subsequent
-             * subs, Hence update the call states if voice call is already
-             * active on other sub.
-             */
-            voice_extn_update_calls(adev);
-        }
-    } else {
-        return -EINVAL;
-    }
-
-    return 0;
-
-}
-
-void voice_extn_init(struct audio_device *adev)
-{
-    adev->voice.session[VOICE_SESS_IDX].vsid =  VOICE_VSID;
-    adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
-    adev->voice.session[VOLTE_SESS_IDX].vsid =  VOLTE_VSID;
-    adev->voice.session[QCHAT_SESS_IDX].vsid =  QCHAT_VSID;
-}
-
-int voice_extn_get_session_from_use_case(struct audio_device *adev,
-                                               const audio_usecase_t usecase_id,
-                                               struct voice_session **session)
-{
-
-    switch(usecase_id)
-    {
-    case USECASE_VOICE_CALL:
-        *session = &adev->voice.session[VOICE_SESS_IDX];
-        break;
-
-    case USECASE_VOICE2_CALL:
-        *session = &adev->voice.session[VOICE2_SESS_IDX];
-        break;
-
-    case USECASE_VOLTE_CALL:
-        *session = &adev->voice.session[VOLTE_SESS_IDX];
-        break;
-
-    case USECASE_QCHAT_CALL:
-        *session = &adev->voice.session[QCHAT_SESS_IDX];
-        break;
-
-    default:
-        ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
-        *session = NULL;
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-int voice_extn_update_calls(struct audio_device *adev)
+static int update_calls(struct audio_device *adev)
 {
     int i = 0;
     audio_usecase_t usecase_id = 0;
@@ -255,8 +158,9 @@
                 if(ret < 0) {
                     ALOGE("%s: voice_start_call() failed for usecase: %d\n",
                           __func__, usecase_id);
+                } else {
+                    session->state.current = session->state.new;
                 }
-                session->state.current = session->state.new;
                 break;
 
             case CALL_HOLD:
@@ -292,8 +196,9 @@
                 if(ret < 0) {
                     ALOGE("%s: voice_end_call() failed for usecase: %d\n",
                           __func__, usecase_id);
+                } else {
+                    session->state.current = session->state.new;
                 }
-                session->state.current = session->state.new;
                 break;
 
             default:
@@ -358,6 +263,136 @@
     return ret;
 }
 
+static int update_call_states(struct audio_device *adev,
+                                    const uint32_t vsid, const int call_state)
+{
+    struct voice_session *session = NULL;
+    int i = 0;
+    bool is_in_call;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        if (vsid == adev->voice.session[i].vsid) {
+            session = &adev->voice.session[i];
+            break;
+        }
+    }
+
+    if (session) {
+        session->state.new = call_state;
+        voice_extn_is_in_call(adev, &is_in_call);
+        ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode);
+        if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) {
+            /* Device routing is not triggered for voice calls on the subsequent
+             * subs, Hence update the call states if voice call is already
+             * active on other sub.
+             */
+            update_calls(adev);
+        }
+    } else {
+        return -EINVAL;
+    }
+
+    return 0;
+
+}
+
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id)
+{
+    *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
+    return 0;
+}
+
+int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+{
+    struct voice_session *session = NULL;
+    int i = 0;
+    *in_call = false;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        session = &adev->voice.session[i];
+        if(session->state.current != CALL_INACTIVE){
+            *in_call = true;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+void voice_extn_init(struct audio_device *adev)
+{
+    adev->voice.session[VOICE_SESS_IDX].vsid =  VOICE_VSID;
+    adev->voice.session[VOICE2_SESS_IDX].vsid = VOICE2_VSID;
+    adev->voice.session[VOLTE_SESS_IDX].vsid =  VOLTE_VSID;
+    adev->voice.session[QCHAT_SESS_IDX].vsid =  QCHAT_VSID;
+}
+
+int voice_extn_get_session_from_use_case(struct audio_device *adev,
+                                         const audio_usecase_t usecase_id,
+                                         struct voice_session **session)
+{
+
+    switch(usecase_id)
+    {
+    case USECASE_VOICE_CALL:
+        *session = &adev->voice.session[VOICE_SESS_IDX];
+        break;
+
+    case USECASE_VOICE2_CALL:
+        *session = &adev->voice.session[VOICE2_SESS_IDX];
+        break;
+
+    case USECASE_VOLTE_CALL:
+        *session = &adev->voice.session[VOLTE_SESS_IDX];
+        break;
+
+    case USECASE_QCHAT_CALL:
+        *session = &adev->voice.session[QCHAT_SESS_IDX];
+        break;
+
+    default:
+        ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
+        *session = NULL;
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int voice_extn_start_call(struct audio_device *adev)
+{
+    /* Start voice calls on sessions whose call state has been
+     * udpated.
+     */
+    ALOGV("%s: enter:", __func__);
+    return update_calls(adev);
+}
+
+int voice_extn_stop_call(struct audio_device *adev)
+{
+    int i;
+    int ret = 0;
+
+    ALOGV("%s: enter:", __func__);
+
+    /* If BT device is enabled and voice calls are ended, telephony will call
+     * set_mode(AUDIO_MODE_NORMAL) which will trigger audio policy manager to
+     * set routing with device BT A2DP profile. Hence end all voice calls when
+     * set_mode(AUDIO_MODE_NORMAL) before BT A2DP profile is selected.
+     */
+    if (adev->mode == AUDIO_MODE_NORMAL) {
+        ALOGD("%s: end all calls", __func__);
+        for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+            adev->voice.session[i].state.new = CALL_INACTIVE;
+        }
+
+        ret = update_calls(adev);
+    }
+
+    return ret;
+}
+
 int voice_extn_set_parameters(struct audio_device *adev,
                               struct str_parms *parms)
 {
@@ -375,7 +410,6 @@
         ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
         if (ret >= 0) {
             call_state = value;
-            //validate callstate
         } else {
             ALOGE("%s: call_state key not found", __func__);
             ret = -EINVAL;
@@ -383,11 +417,10 @@
         }
 
         if (is_valid_vsid(vsid) && is_valid_call_state(call_state)) {
-            pthread_mutex_lock(&adev->lock);
-            voice_extn_update_call_states(adev, vsid, call_state);
-            pthread_mutex_unlock(&adev->lock);
+            ret = update_call_states(adev, vsid, call_state);
         } else {
-            ALOGE("%s: invalid vsid or call_state", __func__);
+            ALOGE("%s: invalid vsid:%x or call_state:%d",
+                  __func__, vsid, call_state);
             ret = -EINVAL;
             goto done;
         }
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index dd2dfd8..c4e2131 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -21,18 +21,24 @@
 #define VOICE_EXTN_H
 
 #ifdef MULTI_VOICE_SESSION_ENABLED
-int voice_extn_update_calls(struct audio_device *adev);
+int voice_extn_start_call(struct audio_device *adev);
+int voice_extn_stop_call(struct audio_device *adev);
 int voice_extn_get_session_from_use_case(struct audio_device *adev,
                                          const audio_usecase_t usecase_id,
                                          struct voice_session **session);
-int voice_extn_init(struct audio_device *adev);
+void voice_extn_init(struct audio_device *adev);
 int voice_extn_set_parameters(struct audio_device *adev,
                               struct str_parms *parms);
 int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
 int voice_extn_get_active_session_id(struct audio_device *adev,
                                      uint32_t *session_id);
 #else
-static int voice_extn_update_calls(struct audio_device *adev)
+static int voice_extn_start_call(struct audio_device *adev)
+{
+    return -ENOSYS;
+}
+
+static int voice_extn_stop_call(struct audio_device *adev)
 {
     return -ENOSYS;
 }
@@ -44,9 +50,8 @@
     return -ENOSYS;
 }
 
-static int voice_extn_init(struct audio_device *adev)
+static void voice_extn_init(struct audio_device *adev)
 {
-    return -ENOSYS;
 }
 
 static int voice_extn_set_parameters(struct audio_device *adev,