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);
}