Fix A2DP Offload lockup when RE-STARTING

The A2DP Offload vendor lib can cause a lockup in the corner case
when a START event is received while already in STARTING state
resulting in a mediaserver crash.
- Refactor state machine code.
- Move offload session configuration to a helper func.

Change-Id: I93dc2ebd3910c8302c3d0d5b1ee912cb7244b98b
Signed-off-by: Sridhar Vashist <svashist@motorola.com>
diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c
index 45d4295..0526196 100644
--- a/src/bt_vendor_brcm_a2dp.c
+++ b/src/bt_vendor_brcm_a2dp.c
@@ -84,18 +84,16 @@
 }
 tBRCM_VND_A2DP_SST_STATES;
 
+static uint8_t brcm_vnd_a2dp_offload_configure();
 static uint8_t brcm_vnd_a2dp_offload_cleanup();
 static uint8_t brcm_vnd_a2dp_offload_suspend();
-static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event);
-static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event);
-static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event);
 static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data);
 static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data);
 static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data);
 static void brcm_vnd_a2dp_hci_uipc_cback(void *pmem);
 
 typedef struct {
-    uint8_t        fcn;
+    uint8_t     fcn;
     uint32_t    pad_conf;
 }
 tBRCM_VND_PCM_CONF;
@@ -117,9 +115,9 @@
 /* state table */
 static tBRCM_VND_A2DP_SST_STATE brcm_vnd_a2dp_sst_tbl[] =
 {
-    {brcm_vnd_a2dp_sm_idle_enter,     brcm_vnd_a2dp_sm_idle_process_ev},
-    {brcm_vnd_a2dp_sm_starting_enter, brcm_vnd_a2dp_sm_starting_process_ev},
-    {brcm_vnd_a2dp_sm_stream_enter,   brcm_vnd_a2dp_sm_stream_process_ev},
+    {NULL, brcm_vnd_a2dp_sm_idle_process_ev},
+    {NULL, brcm_vnd_a2dp_sm_starting_process_ev},
+    {NULL, brcm_vnd_a2dp_sm_stream_process_ev},
 };
 
 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -307,10 +305,10 @@
     tBRCM_VND_A2DP_SST_STATE *state_table;
     tBRCM_VND_A2DP_SST_STATES next_state;
 
-    BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state);
-
     pthread_mutex_lock(&g_mutex);
 
+    BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state);
+
     if (brcm_vnd_a2dp_pdata.state != BRCM_VND_A2DP_INVALID_SST) {
         state_table = &brcm_vnd_a2dp_sst_tbl[brcm_vnd_a2dp_pdata.state];
         /* process event */
@@ -337,101 +335,6 @@
 
 /* state machine actions */
 
-static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event)
-{
-    UNUSED(event);
-    BTA2DPDBG("%s", __FUNCTION__);
-    brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID;
-    return brcm_vnd_a2dp_pdata.state;
-}
-
-static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event)
-{
-    UNUSED(event);
-    uint8_t *p, msg_req[HCI_CMD_MAX_LEN];
-    BTA2DPDBG("%s", __FUNCTION__);
-
-    p = msg_req;
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN);
-    UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT);
-    UINT8_TO_STREAM(p, UIPC_OPEN_REQ);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT);
-    UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size);
-    UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable));
-    UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start
-    UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end
-    UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard
-    UINT8_TO_STREAM(p, 1); //num_stream
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT);
-    UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ);
-    UINT8_TO_STREAM(p, 1); //num_stream
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid);
-    UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT);
-    UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ);
-    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC);
-    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF);
-    UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP);
-    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF);
-    UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA);
-    UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT);
-    UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ);
-    UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method);
-    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    p = msg_req;
-    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT);
-    UINT8_TO_STREAM(p, A2DP_START_REQ);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid);
-    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu);
-    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
-
-    return brcm_vnd_a2dp_pdata.state;
-}
-
-
-static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event)
-{
-    UNUSED(event);
-    ALOGV("%s", __FUNCTION__);
-
-    return brcm_vnd_a2dp_pdata.state;
-}
-
 static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data)
 {
     tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state;
@@ -442,9 +345,12 @@
             if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info,
                     (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) {
                 ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__);
+                bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START,
+                                                  brcm_vnd_a2dp_pdata.offload_params.bta_av_handle);
+            } else {
+                brcm_vnd_a2dp_offload_configure();
+                next_state = BRCM_VND_A2DP_STARTING_SST;
             }
-
-            next_state = BRCM_VND_A2DP_STARTING_SST;
             break;
 
         default:
@@ -458,6 +364,7 @@
 {
     tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state;
     uint8_t status, *p;
+
     switch (event) {
         case BRCM_VND_A2DP_OFFLOAD_START_REQ:
             brcm_vnd_a2dp_offload_cleanup();
@@ -465,12 +372,14 @@
             if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info(
                     &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) {
                 ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__);
+                bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START,
+                                                  brcm_vnd_a2dp_pdata.offload_params.bta_av_handle);
+                next_state = BRCM_VND_A2DP_IDLE_SST;
+            } else {
+                brcm_vnd_a2dp_offload_configure();
             }
-
-            next_state = BRCM_VND_A2DP_STARTING_SST;
             break;
 
-
         case BRCM_VND_A2DP_OFFLOAD_STOP_REQ:
             brcm_vnd_a2dp_offload_cleanup();
             next_state = BRCM_VND_A2DP_IDLE_SST;
@@ -571,8 +480,13 @@
             if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info(
                     &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) {
                 ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__);
+                bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START,
+                                                  brcm_vnd_a2dp_pdata.offload_params.bta_av_handle);
+                next_state = BRCM_VND_A2DP_IDLE_SST;
+            } else {
+                brcm_vnd_a2dp_offload_configure();
+                next_state = BRCM_VND_A2DP_STARTING_SST;
             }
-            next_state = BRCM_VND_A2DP_STARTING_SST;
             break;
 
         case BRCM_VND_A2DP_OFFLOAD_STOP_REQ:
@@ -590,6 +504,84 @@
     return next_state;
 }
 
+static uint8_t brcm_vnd_a2dp_offload_configure()
+{
+    uint8_t *p, msg_req[HCI_CMD_MAX_LEN];
+
+    BTA2DPDBG("%s", __FUNCTION__);
+
+    p = msg_req;
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN);
+    UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT);
+    UINT8_TO_STREAM(p, UIPC_OPEN_REQ);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT);
+    UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size);
+    UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable));
+    UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start
+    UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end
+    UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard
+    UINT8_TO_STREAM(p, 1); //num_stream
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT);
+    UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ);
+    UINT8_TO_STREAM(p, 1); //num_stream
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid);
+    UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT);
+    UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ);
+    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC);
+    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF);
+    UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP);
+    UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF);
+    UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA);
+    UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT);
+    UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ);
+    UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method);
+    UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    p = msg_req;
+    UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT);
+    UINT8_TO_STREAM(p, A2DP_START_REQ);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid);
+    UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu);
+    brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+
+    return 0;
+}
+
 static uint8_t brcm_vnd_a2dp_offload_cleanup()
 {
     uint8_t *p, msg_req[HCI_CMD_MAX_LEN];
@@ -621,6 +613,7 @@
         UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn);
         UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf);
         brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback);
+        brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID;
     }
 
     return 0;
@@ -736,7 +729,7 @@
     tBRCM_VND_A2DP_EVENT ssm_event = (opcode == BT_VND_OP_A2DP_OFFLOAD_START)?
         BRCM_VND_A2DP_OFFLOAD_START_REQ:BRCM_VND_A2DP_OFFLOAD_STOP_REQ;
 
-    ALOGD("%s opcode %d ", __FUNCTION__, opcode);
+    ALOGD("%s opcode %d , state %d", __FUNCTION__, opcode, brcm_vnd_a2dp_pdata.state);
 
     return brcm_vnd_a2dp_ssm_execute(ssm_event, ev_data);
 }