hal: Add a2dp state check for device routing

- During a2dp to sco transition multiple session
  open failures are seen due to a2dp start failure

- Check a2dp streaming state with BT lib before
  routing audio on a2dp device.
  If a2dp is not ready for streaming, force drop
  audio packets for a2dp path similar to BT HAL

Change-Id: If9fdd2184943c2e25a091067477cf0bcc5dce278
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 3dc00fb..40632bc 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -79,6 +79,7 @@
 typedef void (*clear_a2dpsuspend_flag_t)(void);
 typedef void * (*audio_get_codec_config_t)(uint8_t *multicast_status,uint8_t *num_dev,
                                audio_format_t *codec_type);
+typedef int (*audio_check_a2dp_ready_t)(void);
 
 enum A2DP_STATE {
     A2DP_STATE_CONNECTED,
@@ -102,6 +103,7 @@
     audio_handoff_triggered_t audio_handoff_triggered;
     clear_a2dpsuspend_flag_t clear_a2dpsuspend_flag;
     audio_get_codec_config_t audio_get_codec_config;
+    audio_check_a2dp_ready_t audio_check_a2dp_ready;
     enum A2DP_STATE bt_state;
     audio_format_t bt_encoder_format;
     uint32_t enc_sampling_rate;
@@ -244,6 +246,8 @@
                           dlsym(a2dp.bt_lib_handle, "audio_stop_stream");
             a2dp.audio_stream_close = (audio_stream_close_t)
                           dlsym(a2dp.bt_lib_handle, "audio_stream_close");
+            a2dp.audio_check_a2dp_ready = (audio_check_a2dp_ready_t)
+                        dlsym(a2dp.bt_lib_handle,"audio_check_a2dp_ready");
         }
     }
 
@@ -279,27 +283,17 @@
         ALOGE("a2dp handle is not identified, Ignoring close request");
         return -ENOSYS;
     }
-    if ((a2dp.bt_state == A2DP_STATE_CONNECTED) &&
-        (a2dp.bt_state == A2DP_STATE_STARTED) &&
-        (a2dp.bt_state == A2DP_STATE_STOPPED)) {
+    if (a2dp.bt_state != A2DP_STATE_DISCONNECTED) {
         ALOGD("calling BT stream close");
         if(a2dp.audio_stream_close() == false)
             ALOGE("failed close a2dp control path from BT library");
-        a2dp.a2dp_started = false;
-        a2dp.a2dp_total_active_session_request = 0;
-        a2dp.a2dp_suspended = false;
-        a2dp.bt_encoder_format = AUDIO_FORMAT_INVALID;
-        a2dp.enc_sampling_rate = 48000;
-        a2dp.bt_state = A2DP_STATE_DISCONNECTED;
-    } else {
-        ALOGD("close a2dp called in improper state");
-        a2dp.a2dp_started = false;
-        a2dp.a2dp_total_active_session_request = 0;
-        a2dp.a2dp_suspended = false;
-        a2dp.bt_encoder_format = AUDIO_FORMAT_INVALID;
-        a2dp.enc_sampling_rate = 48000;
-        a2dp.bt_state = A2DP_STATE_DISCONNECTED;
     }
+    a2dp.a2dp_started = false;
+    a2dp.a2dp_total_active_session_request = 0;
+    a2dp.a2dp_suspended = false;
+    a2dp.bt_encoder_format = AUDIO_FORMAT_INVALID;
+    a2dp.enc_sampling_rate = 48000;
+    a2dp.bt_state = A2DP_STATE_DISCONNECTED;
 
     return 0;
 }
@@ -631,7 +625,6 @@
         if (ret != 0 ) {
            ALOGE("BT controller start failed");
            a2dp.a2dp_started = false;
-           ret = -ETIMEDOUT;
         } else {
            if(configure_a2dp_encoder_format() == true) {
                 a2dp.a2dp_started = true;
@@ -692,7 +685,7 @@
         return -ENOSYS;
     }
 
-    if (a2dp.a2dp_started && (a2dp.a2dp_total_active_session_request > 0))
+    if (a2dp.a2dp_total_active_session_request > 0)
         a2dp.a2dp_total_active_session_request--;
 
     if ( a2dp.a2dp_started && !a2dp.a2dp_total_active_session_request) {
@@ -810,6 +803,17 @@
         *bit_width = 16;
     *sample_rate = a2dp.enc_sampling_rate;
 }
+
+bool audio_extn_a2dp_is_ready()
+{
+    bool ret = false;
+
+    if ((a2dp.is_a2dp_offload_supported) &&
+        (a2dp.audio_check_a2dp_ready))
+           ret = a2dp.audio_check_a2dp_ready();
+    return ret;
+}
+
 void audio_extn_a2dp_init (void *adev)
 {
   a2dp.adev = (struct audio_device*)adev;
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index c114d2d..93036af 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -206,7 +206,7 @@
 #define audio_extn_a2dp_set_handoff_mode(is_on)          (0)
 #define audio_extn_a2dp_get_apptype_params(sample_rate,bit_width)    (0)
 #define audio_extn_a2dp_get_encoder_latency()            (0)
-
+#define audio_extn_a2dp_is_ready()                       (0)
 #else
 void audio_extn_a2dp_init(void *adev);
 int audio_extn_a2dp_start_playback();
@@ -217,7 +217,7 @@
 void audio_extn_a2dp_get_apptype_params(uint32_t *sample_rate,
                                         uint32_t *bit_width);
 uint32_t audio_extn_a2dp_get_encoder_latency();
-
+bool audio_extn_a2dp_is_ready();
 #endif
 
 #ifndef SSR_ENABLED
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 262fec5..9da81e6 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2185,6 +2185,19 @@
         goto error_config;
     }
 
+    if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        if (!audio_extn_a2dp_is_ready()) {
+            if (out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+                //combo usecase just by pass a2dp
+                ALOGW("%s: A2DP profile is not ready, route it to speaker", __func__);
+                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+            } else {
+                ALOGE("%s: A2DP profile is not ready, return error", __func__);
+                ret = -EAGAIN;
+                goto error_config;
+            }
+        }
+    }
     out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
     if (out->pcm_device_id < 0) {
         ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
@@ -2647,17 +2660,27 @@
                 (val == AUDIO_DEVICE_NONE)) {
                 val = AUDIO_DEVICE_OUT_SPEAKER;
         }
-        /* To avoid a2dp to sco overlapping force route BT usecases
-         * to speaker based on Phone state
+        /* To avoid a2dp to sco overlapping / BT device improper state
+         * check with BT lib about a2dp streaming support before routing
          */
-        if ((((val & AUDIO_DEVICE_OUT_SPEAKER) &&
-                  (val & AUDIO_DEVICE_OUT_ALL_A2DP)) ||
-              ((adev->snd_dev_ref_cnt[SND_DEVICE_OUT_BT_A2DP] == 0) &&
-                  (val & AUDIO_DEVICE_OUT_ALL_A2DP))) &&
-            ((adev->mode == AUDIO_MODE_RINGTONE) ||
-            (adev->mode == AUDIO_MODE_IN_CALL))) {
-            ALOGD("Forcing a2dp routing to speaker for ring/call mode");
-            val = AUDIO_DEVICE_OUT_SPEAKER;
+        if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
+            if (!audio_extn_a2dp_is_ready()) {
+                if (val & AUDIO_DEVICE_OUT_SPEAKER) {
+                    //combo usecase just by pass a2dp
+                    ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
+                    val = AUDIO_DEVICE_OUT_SPEAKER;
+                } else {
+                    ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
+                    /* update device to a2dp and don't route as BT returned error
+                     * However it is still possible a2dp routing called because
+                     * of current active device disconnection (like wired headset)
+                     */
+                    out->devices = val;
+                    pthread_mutex_unlock(&out->lock);
+                    pthread_mutex_unlock(&adev->lock);
+                    goto error;
+                }
+            }
         }
         /*
          * select_devices() call below switches all the usecases on the same