/****************************************************************************** * * Copyright 2004-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * This is the stream state machine for the BTA advanced audio/video. * ******************************************************************************/ #include "bt_target.h" // Must be first to define build configuration #include "bta/av/bta_av_int.h" #include "osi/include/log.h" /***************************************************************************** * Constants and types ****************************************************************************/ /* state machine states */ enum { BTA_AV_INIT_SST, BTA_AV_INCOMING_SST, BTA_AV_OPENING_SST, BTA_AV_OPEN_SST, BTA_AV_RCFG_SST, BTA_AV_CLOSING_SST }; static void bta_av_better_stream_state_machine(tBTA_AV_SCB* p_scb, uint16_t event, tBTA_AV_DATA* p_data) { uint8_t previous_state = p_scb->state; tBTA_AV_ACT event_handler1 = nullptr; tBTA_AV_ACT event_handler2 = nullptr; switch (p_scb->state) { case BTA_AV_INIT_SST: switch (event) { case BTA_AV_API_OPEN_EVT: p_scb->state = BTA_AV_OPENING_SST; event_handler1 = &bta_av_do_disc_a2dp; break; case BTA_AV_API_CLOSE_EVT: event_handler1 = &bta_av_cleanup; break; case BTA_AV_SDP_DISC_OK_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_SDP_DISC_FAIL_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_STR_CONFIG_IND_EVT: p_scb->state = BTA_AV_INCOMING_SST; event_handler1 = &bta_av_config_ind; break; case BTA_AV_ACP_CONNECT_EVT: p_scb->state = BTA_AV_INCOMING_SST; break; case BTA_AV_API_OFFLOAD_START_EVT: event_handler1 = &bta_av_offload_req; break; case BTA_AV_API_OFFLOAD_START_RSP_EVT: event_handler1 = &bta_av_offload_rsp; break; } break; case BTA_AV_INCOMING_SST: switch (event) { case BTA_AV_API_OPEN_EVT: event_handler1 = &bta_av_open_at_inc; break; case BTA_AV_API_CLOSE_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_cco_close; event_handler2 = &bta_av_disconnect_req; break; case BTA_AV_API_PROTECT_REQ_EVT: event_handler1 = &bta_av_security_req; break; case BTA_AV_API_PROTECT_RSP_EVT: event_handler1 = &bta_av_security_rsp; break; case BTA_AV_CI_SETCONFIG_OK_EVT: event_handler1 = &bta_av_setconfig_rsp; event_handler2 = &bta_av_st_rc_timer; break; case BTA_AV_CI_SETCONFIG_FAIL_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_setconfig_rej; event_handler2 = &bta_av_cleanup; break; case BTA_AV_SDP_DISC_OK_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_SDP_DISC_FAIL_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_STR_DISC_OK_EVT: event_handler1 = &bta_av_disc_res_as_acp; break; case BTA_AV_STR_GETCAP_OK_EVT: event_handler1 = &bta_av_save_caps; break; case BTA_AV_STR_OPEN_OK_EVT: p_scb->state = BTA_AV_OPEN_SST; event_handler1 = &bta_av_str_opened; break; case BTA_AV_STR_CLOSE_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_cco_close; event_handler2 = &bta_av_cleanup; break; case BTA_AV_STR_CONFIG_IND_EVT: event_handler1 = &bta_av_config_ind; break; case BTA_AV_STR_SECURITY_IND_EVT: event_handler1 = &bta_av_security_ind; break; case BTA_AV_STR_SECURITY_CFM_EVT: event_handler1 = &bta_av_security_cfm; break; case BTA_AV_AVDT_DISCONNECT_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_cco_close; event_handler2 = &bta_av_disconnect_req; break; case BTA_AV_AVDT_DELAY_RPT_EVT: event_handler1 = &bta_av_delay_co; break; case BTA_AV_API_OFFLOAD_START_EVT: event_handler1 = &bta_av_offload_req; break; case BTA_AV_API_OFFLOAD_START_RSP_EVT: event_handler1 = &bta_av_offload_rsp; break; } break; case BTA_AV_OPENING_SST: switch (event) { case BTA_AV_API_CLOSE_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_do_close; break; case BTA_AV_API_PROTECT_REQ_EVT: event_handler1 = &bta_av_security_req; break; case BTA_AV_API_PROTECT_RSP_EVT: event_handler1 = &bta_av_security_rsp; break; case BTA_AV_SDP_DISC_OK_EVT: event_handler1 = &bta_av_connect_req; break; case BTA_AV_SDP_DISC_FAIL_EVT: event_handler1 = &bta_av_connect_req; break; case BTA_AV_STR_DISC_OK_EVT: event_handler1 = &bta_av_disc_results; break; case BTA_AV_STR_DISC_FAIL_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_open_failed; break; case BTA_AV_STR_GETCAP_OK_EVT: event_handler1 = &bta_av_getcap_results; break; case BTA_AV_STR_GETCAP_FAIL_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_open_failed; break; case BTA_AV_STR_OPEN_OK_EVT: p_scb->state = BTA_AV_OPEN_SST; event_handler1 = &bta_av_st_rc_timer; event_handler2 = &bta_av_str_opened; break; case BTA_AV_STR_OPEN_FAIL_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_open_failed; break; case BTA_AV_STR_CONFIG_IND_EVT: p_scb->state = BTA_AV_INCOMING_SST; event_handler1 = &bta_av_config_ind; break; case BTA_AV_STR_SECURITY_IND_EVT: event_handler1 = &bta_av_security_ind; break; case BTA_AV_STR_SECURITY_CFM_EVT: event_handler1 = &bta_av_security_cfm; break; case BTA_AV_AVRC_TIMER_EVT: event_handler1 = &bta_av_switch_role; break; case BTA_AV_AVDT_CONNECT_EVT: event_handler1 = &bta_av_discover_req; break; case BTA_AV_AVDT_DISCONNECT_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_conn_failed; break; case BTA_AV_ROLE_CHANGE_EVT: event_handler1 = &bta_av_role_res; break; case BTA_AV_AVDT_DELAY_RPT_EVT: event_handler1 = &bta_av_delay_co; break; case BTA_AV_API_OFFLOAD_START_EVT: event_handler1 = &bta_av_offload_req; break; case BTA_AV_API_OFFLOAD_START_RSP_EVT: event_handler1 = &bta_av_offload_rsp; break; } break; case BTA_AV_OPEN_SST: switch (event) { case BTA_AV_API_CLOSE_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_do_close; break; case BTA_AV_AP_START_EVT: event_handler1 = &bta_av_do_start; break; case BTA_AV_AP_STOP_EVT: event_handler1 = &bta_av_str_stopped; break; case BTA_AV_API_RECONFIG_EVT: p_scb->state = BTA_AV_RCFG_SST; event_handler1 = &bta_av_reconfig; break; case BTA_AV_API_PROTECT_REQ_EVT: event_handler1 = &bta_av_security_req; break; case BTA_AV_API_PROTECT_RSP_EVT: event_handler1 = &bta_av_security_rsp; break; case BTA_AV_API_RC_OPEN_EVT: event_handler1 = &bta_av_set_use_rc; break; case BTA_AV_SRC_DATA_READY_EVT: event_handler1 = &bta_av_data_path; break; case BTA_AV_SDP_DISC_OK_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_SDP_DISC_FAIL_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_STR_GETCAP_OK_EVT: event_handler1 = &bta_av_save_caps; break; case BTA_AV_STR_START_OK_EVT: event_handler1 = &bta_av_start_ok; break; case BTA_AV_STR_START_FAIL_EVT: event_handler1 = &bta_av_start_failed; break; case BTA_AV_STR_CLOSE_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_str_closed; break; case BTA_AV_STR_CONFIG_IND_EVT: event_handler1 = &bta_av_setconfig_rej; break; case BTA_AV_STR_SECURITY_IND_EVT: event_handler1 = &bta_av_security_ind; break; case BTA_AV_STR_SECURITY_CFM_EVT: event_handler1 = &bta_av_security_cfm; break; case BTA_AV_STR_WRITE_CFM_EVT: event_handler1 = &bta_av_clr_cong; event_handler2 = &bta_av_data_path; break; case BTA_AV_STR_SUSPEND_CFM_EVT: event_handler1 = &bta_av_suspend_cfm; break; case BTA_AV_AVRC_TIMER_EVT: event_handler1 = &bta_av_open_rc; break; case BTA_AV_AVDT_DISCONNECT_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_str_closed; break; case BTA_AV_ROLE_CHANGE_EVT: event_handler1 = &bta_av_role_res; break; case BTA_AV_AVDT_DELAY_RPT_EVT: event_handler1 = &bta_av_delay_co; break; case BTA_AV_API_OFFLOAD_START_EVT: event_handler1 = &bta_av_offload_req; break; case BTA_AV_API_OFFLOAD_START_RSP_EVT: event_handler1 = &bta_av_offload_rsp; break; } break; case BTA_AV_RCFG_SST: switch (event) { case BTA_AV_API_CLOSE_EVT: p_scb->state = BTA_AV_CLOSING_SST; event_handler1 = &bta_av_disconnect_req; break; case BTA_AV_API_RECONFIG_EVT: event_handler1 = &bta_av_reconfig; break; case BTA_AV_SDP_DISC_OK_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_SDP_DISC_FAIL_EVT: event_handler1 = &bta_av_free_sdb; break; case BTA_AV_STR_DISC_OK_EVT: event_handler1 = &bta_av_disc_results; break; case BTA_AV_STR_DISC_FAIL_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_str_closed; break; case BTA_AV_STR_GETCAP_OK_EVT: event_handler1 = &bta_av_getcap_results; break; case BTA_AV_STR_GETCAP_FAIL_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_str_closed; break; case BTA_AV_STR_OPEN_OK_EVT: p_scb->state = BTA_AV_OPEN_SST; event_handler1 = &bta_av_rcfg_str_ok; break; case BTA_AV_STR_OPEN_FAIL_EVT: event_handler1 = &bta_av_rcfg_failed; break; case BTA_AV_STR_CLOSE_EVT: event_handler1 = &bta_av_rcfg_connect; break; case BTA_AV_STR_CONFIG_IND_EVT: event_handler1 = &bta_av_setconfig_rej; break; case BTA_AV_STR_SUSPEND_CFM_EVT: event_handler1 = &bta_av_suspend_cfm; event_handler2 = &bta_av_suspend_cont; break; case BTA_AV_STR_RECONFIG_CFM_EVT: event_handler1 = &bta_av_rcfg_cfm; break; case BTA_AV_AVDT_CONNECT_EVT: event_handler1 = &bta_av_rcfg_open; break; case BTA_AV_AVDT_DISCONNECT_EVT: event_handler1 = &bta_av_rcfg_discntd; break; case BTA_AV_AVDT_DELAY_RPT_EVT: event_handler1 = &bta_av_delay_co; break; case BTA_AV_API_OFFLOAD_START_EVT: event_handler1 = &bta_av_offload_req; break; case BTA_AV_API_OFFLOAD_START_RSP_EVT: event_handler1 = &bta_av_offload_rsp; break; } break; case BTA_AV_CLOSING_SST: switch (event) { case BTA_AV_API_CLOSE_EVT: event_handler1 = &bta_av_disconnect_req; break; case BTA_AV_SDP_DISC_OK_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_sdp_failed; break; case BTA_AV_SDP_DISC_FAIL_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_sdp_failed; break; case BTA_AV_STR_OPEN_OK_EVT: event_handler1 = &bta_av_do_close; break; case BTA_AV_STR_OPEN_FAIL_EVT: event_handler1 = &bta_av_disconnect_req; break; case BTA_AV_STR_CLOSE_EVT: event_handler1 = &bta_av_disconnect_req; break; case BTA_AV_STR_CONFIG_IND_EVT: event_handler1 = &bta_av_setconfig_rej; break; case BTA_AV_STR_SECURITY_IND_EVT: event_handler1 = &bta_av_security_rej; break; case BTA_AV_AVDT_DISCONNECT_EVT: p_scb->state = BTA_AV_INIT_SST; event_handler1 = &bta_av_str_closed; break; case BTA_AV_API_OFFLOAD_START_EVT: event_handler1 = &bta_av_offload_req; break; case BTA_AV_API_OFFLOAD_START_RSP_EVT: event_handler1 = &bta_av_offload_rsp; break; } break; } if (previous_state != p_scb->state) { LOG_INFO("peer %s p_scb=%#x(%p) AV event=0x%x(%s) state=%d(%s) -> %d(%s)", p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, p_scb, event, bta_av_evt_code(event), previous_state, bta_av_sst_code(previous_state), p_scb->state, bta_av_sst_code(p_scb->state)); } else { LOG_DEBUG("peer %s p_scb=%#x(%p) AV event=0x%x(%s) state=%d(%s)", p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, p_scb, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state)); } if (event_handler1 != nullptr) { event_handler1(p_scb, p_data); } if (event_handler2 != nullptr) { event_handler2(p_scb, p_data); } } /******************************************************************************* * * Function bta_av_ssm_execute * * Description Stream state machine event handling function for AV * * * Returns void * ******************************************************************************/ void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event, tBTA_AV_DATA* p_data) { if (p_scb == NULL) { /* this stream is not registered */ APPL_TRACE_EVENT("%s: AV channel not registered", __func__); return; } bta_av_better_stream_state_machine(p_scb, event, p_data); } /******************************************************************************* * * Function bta_av_is_scb_opening * * Description Returns true is scb is in opening state. * * * Returns true if scb is in opening state. * ******************************************************************************/ bool bta_av_is_scb_opening(tBTA_AV_SCB* p_scb) { bool is_opening = false; if (p_scb) { if (p_scb->state == BTA_AV_OPENING_SST) is_opening = true; } return is_opening; } /******************************************************************************* * * Function bta_av_is_scb_incoming * * Description Returns true is scb is in incoming state. * * * Returns true if scb is in incoming state. * ******************************************************************************/ bool bta_av_is_scb_incoming(tBTA_AV_SCB* p_scb) { bool is_incoming = false; if (p_scb) { if (p_scb->state == BTA_AV_INCOMING_SST) is_incoming = true; } return is_incoming; } /******************************************************************************* * * Function bta_av_set_scb_sst_init * * Description Set SST state to INIT. * Use this function to change SST outside of state machine. * * Returns None * ******************************************************************************/ void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb) { if (p_scb == nullptr) { return; } uint8_t next_state = BTA_AV_INIT_SST; APPL_TRACE_VERBOSE( "%s: peer %s AV (hndl=0x%x) state=%d(%s) next state=%d(%s) p_scb=%p", __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, p_scb->state, bta_av_sst_code(p_scb->state), next_state, bta_av_sst_code(next_state), p_scb); p_scb->state = next_state; } /******************************************************************************* * * Function bta_av_is_scb_init * * Description Returns true is scb is in init state. * * * Returns true if scb is in incoming state. * ******************************************************************************/ bool bta_av_is_scb_init(tBTA_AV_SCB* p_scb) { bool is_init = false; if (p_scb) { if (p_scb->state == BTA_AV_INIT_SST) is_init = true; } return is_init; } /******************************************************************************* * * Function bta_av_set_scb_sst_incoming * * Description Set SST state to incoming. * Use this function to change SST outside of state machine. * * Returns None * ******************************************************************************/ void bta_av_set_scb_sst_incoming(tBTA_AV_SCB* p_scb) { if (p_scb) { p_scb->state = BTA_AV_INCOMING_SST; } } /***************************************************************************** * Debug Functions ****************************************************************************/ /******************************************************************************* * * Function bta_av_sst_code * * Description * * Returns char * * ******************************************************************************/ const char* bta_av_sst_code(uint8_t state) { switch (state) { case BTA_AV_INIT_SST: return "INIT"; case BTA_AV_INCOMING_SST: return "INCOMING"; case BTA_AV_OPENING_SST: return "OPENING"; case BTA_AV_OPEN_SST: return "OPEN"; case BTA_AV_RCFG_SST: return "RCFG"; case BTA_AV_CLOSING_SST: return "CLOSING"; default: return "unknown"; } }