/* * Copyright (C) 2021-2022 Huawei Device Co., Ltd. * 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. */ #include "a2dp_state_machine.h" #include "a2dp_codec_thread.h" #include "a2dp_service.h" #include "a2dp_sink.h" #include "compat.h" #include "log.h" #include "power_manager.h" #include "securec.h" namespace OHOS { namespace bluetooth { std::recursive_mutex g_stateMutex {}; void A2dpStateIdle::Entry() { A2dpCodecThread *codecThread = A2dpCodecThread::GetInstance(); if (codecThread->GetInitStatus()) { codecThread->StopA2dpCodecThread(); delete codecThread; } } bool A2dpStateIdle::Dispatch(const utility::Message &msg) { if (msg.arg2_ == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s input error parameter\n", __func__); return false; } uint8_t label = 0; A2dpAvdtMsgData msgData = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->a2dpMsg; uint8_t role = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->role; A2dpAvdtp avdtp(role); switch (msg.what_) { case EVT_CONNECT_REQ: avdtp.ConnectReq(msgData.connectInfo.addr); break; case EVT_DISCOVER_REQ: ProcessDiscoverReq(msgData.connectInfo.addr, role, msgData.connectInfo.errCode); break; case EVT_GET_ALLCAP_REQ: avdtp.GetAllCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_GET_CAP_REQ: avdtp.GetCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_SETCONFIG_REQ: ProcessSetConfigReq(msgData, role); break; case EVT_DISCONNECT_REQ: ProcessDisconnectReq(msgData.connectInfo.addr, role); break; case EVT_SDP_CFM: ProcessSDPFailure(msgData.stream.addr, role); break; case EVT_SETCONFIG_IND: ProcessSetConfigInd(msgData, role); break; case EVT_DISCONNECT_IND: ProcessDisconnectInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_DISCONNECT_CFM: ProcessDisconnectCfm(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_TIME_OUT: ProcessTimeout(msgData.stream.addr, role); break; default: break; } return true; } void A2dpStateIdle::ProcessDisconnectCfm(BtAddr addr, uint16_t handle, uint8_t role) const { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_INT, true, handle}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateIdle::SetStateName(std::string state) { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); Transition(state); } void A2dpStateIdle::ProcessDisconnectReq(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); A2dpProfile *profile = GetProfileInstance(role); CallbackParameter param = {role, true, 0}; profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateIdle::ProcessTimeout(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); } void A2dpStateIdle::ProcessDisconnectInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_ACP, false, handle}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateIdle::ProcessSetConfigReq(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); A2dpAvdtp avdtp(role); uint8_t label = 0; SetStateName(A2DP_PROFILE_CONFIG); avdtp.SetConfigureReq(msgData.configStream.addr, msgData.configStream.intSeid, msgData.configStream.acpSeid, msgData.configStream.cfg, label); } void A2dpStateIdle::ProcessSetConfigInd(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); CallbackParameter param = {A2DP_ROLE_ACP, false, 0}; A2dpAvdtp avdtp(role); A2dpProfilePeer *profilePeer = nullptr; uint8_t resultConfig[A2DP_CODEC_SIZE]; (void)memset_s(resultConfig, A2DP_CODEC_SIZE, 0, A2DP_CODEC_SIZE); uint8_t *pResultConfig = &resultConfig[0]; A2dpCodecCapability userConfig = {}; bool reconfig = false; bool ret = false; if (profile == nullptr) { return; } profilePeer = profile->FindPeerByAddress(msgData.configRsp.addr); if (profilePeer == nullptr) { return; } A2dpCodecFactory *codecFactory = profilePeer->GetCodecConfigure(); if (codecFactory == nullptr) { return; } uint8_t *pCodecInfo = msgData.configRsp.codecInfo; SetStateName(A2DP_PROFILE_CONFIG); avdtp.SetConfigureRsp(msgData.configRsp.handle, msgData.configRsp.label, msgData.configRsp.category); profile->ConnectStateChangedNotify(msgData.configRsp.addr, STREAM_CONNECTING, static_cast<void *>(¶m)); if (role == A2DP_ROLE_SOURCE) { ret = codecFactory->SetCodecConfig(pCodecInfo, pResultConfig); LOG_INFO("[A2dpStateIdle]%{public}s SetConfig result(%{public}d)\n", __func__, ret); } else { if (codecFactory->FindSourceCodec(pCodecInfo) == nullptr || codecFactory->GetIndexedSinkCodecs().front() == nullptr) { return; } if (codecFactory->GetIndexedSinkCodecs().front()->GetCodecIndex() == (codecFactory->FindSourceCodec(pCodecInfo)->GetCodecIndex() + A2DP_SINK_CODEC_INDEX_MIN - A2DP_SOURCE_CODEC_INDEX_SBC)) { ret = codecFactory->SetSinkCodecConfig(pCodecInfo, pResultConfig); LOG_INFO("[A2dpStateIdle]%{public}s SetSinkCodecConfig result(%{public}d)\n", __func__, ret); } else { userConfig.codecIndex_ = codecFactory->FindSourceCodec(pCodecInfo)->GetCodecIndex(); userConfig.codecPriority_ = A2DP_CODEC_PRIORITY_HIGHEST; ret = codecFactory->SetCodecUserConfig(userConfig, pCodecInfo, pResultConfig, &reconfig); LOG_INFO("[A2dpStateIdle]%{public}s SetuserConfig result(%{public}d)\n", __func__, ret); } } } void A2dpStateIdle::ProcessDiscoverReq(BtAddr addr, uint8_t role, uint8_t errCode) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); CallbackParameter param = {A2DP_ROLE_INT, true, 0}; A2dpAvdtp avdtp(role); uint8_t label = 0; if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } A2dpProfilePeer *peer = profile->FindPeerByAddress(addr); if (peer == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profilePeer instance\n", __func__); return; } if (errCode != AVDT_SUCCESS) { profile->ConnectStateChangedNotify(addr, STREAM_CONNECT_FAILED, (void *)¶m); } else if (peer->GetDisconnectIndication()) { ProcessDisconnectReq(addr, role); peer->SetDisconnectIndication(false); } else { avdtp.DiscoverReq(addr, AVDT_NUM_SEPS, label); } } void A2dpStateIdle::ProcessSDPFailure(BtAddr addr, uint8_t role) const { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); CallbackParameter param = {A2DP_ROLE_INT, true, 0}; if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } profile->DeletePeer(addr); profile->ConnectStateChangedNotify(addr, STREAM_CONNECT_FAILED, (void *)¶m); } bool A2dpStateConfigure::Dispatch(const utility::Message &msg) { LOG_INFO("[A2dpStateConfigure]%{public}s\n", __func__); if (msg.arg2_ == nullptr) { LOG_ERROR("[A2dpStateConfigure]%{public}s input error parameter\n", __func__); return false; } uint8_t label = 0; A2dpAvdtMsgData msgData = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->a2dpMsg; uint8_t role = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->role; A2dpAvdtp avdtp(role); switch (msg.what_) { case EVT_GET_ALLCAP_REQ: avdtp.GetAllCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_GET_CAP_REQ: avdtp.GetCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_OPEN_REQ: ProcessOpenReq(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_DISCONNECT_REQ: ProcessDisconnectReq(msgData.connectInfo.addr, role); break; case EVT_SETCONFIG_IND: ProcessSetConfigInd(msgData, role); break; case EVT_OPEN_IND: ProcessOpenInd(msgData, role); break; case EVT_DISCONNECT_IND: ProcessDisconnectInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_TIME_OUT: avdtp.DisconnectReq(msgData.stream.addr); SetStateName(A2DP_PROFILE_CLOSING); break; case EVT_DELAY_IND: ProcessDelayReportInd(msgData, role); break; default: break; } return true; } void A2dpStateConfigure::SetStateName(std::string state) { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); Transition(state); } void A2dpStateConfigure::ProcessOpenReq(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateConfigure]%{public}s\n", __func__); A2dpAvdtp avdtp(role); uint8_t label = 0; SetStateName(A2DP_PROFILE_OPENING); avdtp.OpenReq(handle, label); } void A2dpStateConfigure::ProcessDisconnectReq(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateConfigure]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); } void A2dpStateConfigure::ProcessDisconnectInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateIdle]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_ACP, false, handle}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateConfigure::ProcessOpenInd(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateConfigure]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_ACP, false, 0}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } SetStateName(A2DP_PROFILE_OPEN); param.handle = msgData.stream.handle; profile->CodecChangedNotify(msgData.stream.addr, nullptr); LOG_INFO("[A2dpStateOpen]%{public}s open handle[%u]\n", __func__, param.handle); profile->ConnectStateChangedNotify(msgData.stream.addr, STREAM_CONNECT, static_cast<void *>(¶m)); if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_ON, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(msgData.stream.addr.addr)); } } void A2dpStateConfigure::ProcessSetConfigInd(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateConfigure]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); A2dpAvdtp avdtp(role); A2dpProfilePeer *profilePeer = nullptr; uint8_t resultConfig[A2DP_CODEC_SIZE]; uint8_t *pResultConfig = &resultConfig[0]; A2dpCodecCapability userConfig = {}; bool reconfig = false; (void)memset_s(resultConfig, A2DP_CODEC_SIZE, 0, A2DP_CODEC_SIZE); if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } profilePeer = profile->FindPeerByAddress(msgData.configRsp.addr); if (profilePeer == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profilePeer instance\n", __func__); return; } A2dpCodecFactory *codecFactory = profilePeer->GetCodecConfigure(); uint8_t *pCodecInfo = msgData.configRsp.codecInfo; if (role == A2DP_ROLE_SOURCE) { codecFactory->SetCodecConfig(pCodecInfo, pResultConfig); } else { if (codecFactory->GetIndexedSinkCodecs().front() == nullptr || codecFactory->FindSourceCodec(pCodecInfo) == nullptr) { return; } if (codecFactory->GetIndexedSinkCodecs().front()->GetCodecIndex() == (codecFactory->FindSourceCodec(pCodecInfo)->GetCodecIndex() + A2DP_SINK_CODEC_INDEX_MIN - A2DP_SOURCE_CODEC_INDEX_SBC)) { codecFactory->SetSinkCodecConfig(pCodecInfo, pResultConfig); } else { userConfig.codecIndex_ = codecFactory->FindSourceCodec(pCodecInfo)->GetCodecIndex(); userConfig.codecPriority_ = A2DP_CODEC_PRIORITY_HIGHEST; codecFactory->SetCodecUserConfig(userConfig, pCodecInfo, pResultConfig, &reconfig); } } avdtp.SetConfigureRsp(msgData.configRsp.handle, msgData.configRsp.label, msgData.configRsp.category); } void A2dpStateConfigure::ProcessDelayReportInd(A2dpAvdtMsgData msgData, uint8_t role) const { LOG_INFO("[A2dpStateConfigure]%{public}s\n", __func__); if (role == A2DP_ROLE_SINK) { LOG_INFO("[A2dpStateConfigure]%{public}s sink role does not handle delay report ind return.", __func__); return; } A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateConfigure]%{public}s Failed to get profile instance\n", __func__); return; } BtAddr addr = msgData.delayReportInfo.addr; uint16_t value = msgData.delayReportInfo.delayValue; profile->DelayReportNotify(addr, value); } bool A2dpStateOpening::Dispatch(const utility::Message &msg) { LOG_INFO("[A2dpStateOpening]%{public}s\n", __func__); if (msg.arg2_ == nullptr) { LOG_ERROR("[A2dpStateOpening]%{public}s input error parameter\n", __func__); return false; } A2dpAvdtMsgData msgData = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->a2dpMsg; uint8_t role = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->role; A2dpAvdtp avdtp(role); uint8_t label = 0; switch (msg.what_) { case EVT_GET_ALLCAP_REQ: avdtp.GetAllCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_GET_CAP_REQ: avdtp.GetCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_DISCONNECT_REQ: ProcessDisconnectReq(msgData.connectInfo.addr, role); break; case EVT_DISCONNECT_IND: ProcessDisconnectInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_OPEN_CFM: ProcessOpenCfm(msgData, role); break; case EVT_TIME_OUT: avdtp.DisconnectReq(msgData.stream.addr); SetStateName(A2DP_PROFILE_CLOSING); break; case EVT_DELAY_IND: ProcessDelayReportInd(msgData, role); break; default: break; } return true; } void A2dpStateOpening::SetStateName(std::string state) { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); Transition(state); } void A2dpStateOpening::ProcessOpenCfm(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateOpening]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_INT, true, msgData.stream.handle}; A2dpAvdtp avdtp(role); A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpening]%{public}s Failed to get profile instance\n", __func__); return; } if (msgData.stream.errCode != AVDT_SUCCESS) { LOG_ERROR("[A2dpStateOpening]%{public}s [errcode: %u]", __func__, msgData.stream.errCode); profile->ConnectStateChangedNotify(msgData.stream.addr, STREAM_CONNECT_FAILED, static_cast<void *>(¶m)); } else { SetStateName(A2DP_PROFILE_OPEN); profile->CodecChangedNotify(msgData.stream.addr, nullptr); LOG_INFO("[A2dpStateOpen]%{public}s open handle[%u]\n", __func__, param.handle); if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_ON, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(msgData.stream.addr.addr)); } profile->ConnectStateChangedNotify(msgData.stream.addr, STREAM_CONNECT, static_cast<void *>(¶m)); } } void A2dpStateOpening::ProcessDisconnectReq(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateOpening]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); } void A2dpStateOpening::ProcessDisconnectInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateOpening]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_ACP, false, handle}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpening]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateOpening::ProcessDelayReportInd(A2dpAvdtMsgData msgData, uint8_t role) const { LOG_INFO("[A2dpStateOpening]%{public}s\n", __func__); if (role == A2DP_ROLE_SINK) { LOG_INFO("[A2dpStateOpening]%{public}s sink role does not handle delay report ind return.", __func__); return; } A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpening]%{public}s Failed to get profile instance\n", __func__); return; } BtAddr addr = msgData.delayReportInfo.addr; uint16_t value = msgData.delayReportInfo.delayValue; profile->DelayReportNotify(addr, value); } bool A2dpStateOpen::Dispatch(const utility::Message &msg) { if (msg.arg2_ == nullptr) { return false; } A2dpAvdtMsgData msgData = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->a2dpMsg; uint8_t role = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->role; A2dpAvdtp avdtp(role); switch (msg.what_) { case EVT_START_IND: ProcessStartInd(msgData, role); break; case EVT_CLOSE_IND: ProcessCloseInd(msgData, role); break; case EVT_DISCONNECT_IND: ProcessDisconnectInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_RECONFIG_IND: avdtp.ReconfigureRsp(msgData.configRsp.handle, msgData.configRsp.label, msgData.configRsp.category); break; case EVT_CLOSE_REQ: avdtp.CloseReq(msgData.stream.handle); break; case EVT_DISCONNECT_REQ: ProcessDisconnectReq(msgData.connectInfo.addr, role); break; case EVT_START_REQ: avdtp.StartReq(msgData.stream.handle, label_); break; case EVT_RECONFIG_REQ: avdtp.ReconfigureReq(msgData.configStream.intSeid, msgData.configStream.cfg, label_); break; case EVT_RECONFIG_CFM: ProcessReconfigCfm(msgData.stream.addr, role, msgData.stream.handle); break; case EVT_CLOSE_CFM: ProcessCloseCfm(msgData.stream.addr, role); break; case EVT_START_CFM: ProcessStartCfm(msgData.stream.addr, role); break; case EVT_DELAY_IND: ProcessDelayReportInd(msgData, role); break; default: ProcessSubOpenState(msgData, role, msg.what_); break; } return true; } void A2dpStateOpen::SetStateName(std::string state) { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); Transition(state); } void A2dpStateOpen::ProcessSubOpenState(A2dpAvdtMsgData msgData, uint8_t role, int cmd) { LOG_INFO("[A2dpStateOpen]%{public}s cmd(%{public}d)\n", __func__, cmd); A2dpAvdtp avdtp(role); uint8_t label = 0; switch (cmd) { case EVT_GET_ALLCAP_REQ: avdtp.GetAllCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_GET_CAP_REQ: avdtp.GetCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_TIME_OUT: ProcessTimeout(msgData.stream.addr, role); break; default: break; } } void A2dpStateOpen::ProcessCloseInd(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.CloseRsp(msgData.stream.handle, msgData.stream.label, 0); } void A2dpStateOpen::ProcessStartInd(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); uint8_t gavdpRole = A2DP_ROLE_ACP; A2dpAvdtp avdtp(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateIdle]%{public}s Failed to get profile instance\n", __func__); return; } SetStateName(A2DP_PROFILE_STREAMING); if (avdtp.StartRsp(msgData.stream.handle, msgData.stream.label, 0, 0) == AVDT_SUCCESS) { profile->AudioStateChangedNotify(msgData.stream.addr, A2DP_IS_PLAYING, (void *)&gavdpRole); if (role == A2DP_ROLE_SOURCE) { profile->NotifyEncoder(msgData.stream.addr); } else { profile->NotifyDecoder(msgData.stream.addr); } } else { SetStateName(A2DP_PROFILE_OPEN); } } void A2dpStateOpen::ProcessDisconnectInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_ACP, false, handle}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpen]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateOpen::ProcessDisconnectReq(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); } void A2dpStateOpen::ProcessReconfigCfm(BtAddr addr, uint8_t role, uint16_t handle) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); A2dpAvdtp avdtp(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpen]%{public}s Failed to get profile instance\n", __func__); return; } profile->FindPeerByAddress(addr)->SetRestart(false); if (Compat::CompatCheck(CompatType::COMPAT_REJECT_AVDTP_RECONFIGURE, bluetooth::RawAddress::ConvertToString(addr.addr).GetAddress())) { LOG_ERROR("[A2dpStateOpen]%{public}s The remote device is disable to reconfigure\n", __func__); avdtp.CloseReq(handle); return; } profile->CodecChangedNotify(addr, nullptr); if (profile->IsActiveDevice(addr)) { uint8_t label = 0; avdtp.StartReq(handle, label); } } void A2dpStateOpen::ProcessCloseCfm(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpen]%{public}s Failed to get profile instance\n", __func__); return; } SetStateName(A2DP_PROFILE_IDLE); if (profile->FindPeerByAddress(addr)->GetRestart()) { profile->FindPeerByAddress(addr)->UpdateConfigure(); } if (!profile->HasOpen() && profile->GetDisalbeTag()) { profile->Disable(); } } void A2dpStateOpen::ProcessStartCfm(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); uint8_t gavdpRole = A2DP_ROLE_INT; if (profile == nullptr) { LOG_ERROR("[A2dpStateOpen]%{public}s Failed to get profile instance\n", __func__); return; } SetStateName(A2DP_PROFILE_STREAMING); profile->AudioStateChangedNotify(addr, A2DP_IS_PLAYING, (void *)&gavdpRole); if (role == A2DP_ROLE_SOURCE) { profile->NotifyEncoder(addr); } else { profile->NotifyDecoder(addr); } } void A2dpStateOpen::ProcessDelayReportInd(A2dpAvdtMsgData msgData, uint8_t role) const { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); if (role == A2DP_ROLE_SINK) { LOG_INFO("[A2dpStateOpen]%{public}s sink role does not handle delay report ind return.", __func__); return; } A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpen]%{public}s Failed to get profile instance\n", __func__); return; } BtAddr addr = msgData.delayReportInfo.addr; uint16_t value = msgData.delayReportInfo.delayValue; profile->DelayReportNotify(addr, value); } void A2dpStateOpen::ProcessTimeout(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateOpen]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); } void A2dpStateStreaming::Entry() { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpCodecThread *codecThread = A2dpCodecThread::GetInstance(); if (codecThread == nullptr) { return; } if (codecThread->GetInitStatus()) { codecThread->StartTimer(); } else { if (codecThread != nullptr) { codecThread->StartA2dpCodecThread(); } } } void A2dpStateStreaming::Exit() { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpCodecThread *codecThread = A2dpCodecThread::GetInstance(); if (codecThread->GetInitStatus()) { codecThread->StopTimer(); } } bool A2dpStateStreaming::Dispatch(const utility::Message &msg) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); if (msg.arg2_ == nullptr) { LOG_ERROR("[A2dpStateStreaming]%{public}s input error parameter\n", __func__); return false; } A2dpAvdtMsgData msgData = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->a2dpMsg; uint8_t role = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->role; A2dpAvdtp avdtp(role); uint8_t label = 0; switch (msg.what_) { case EVT_GET_ALLCAP_REQ: avdtp.GetAllCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_GET_CAP_REQ: avdtp.GetCapabilityReq(msgData.stream.addr, msgData.stream.acpSeid, label); break; case EVT_SUSPEND_IND: ProcessSuspendInd(msgData, role); break; case EVT_CLOSE_IND: SetStateName(A2DP_PROFILE_IDLE); avdtp.CloseRsp(msgData.stream.handle, msgData.stream.label, 0); break; case EVT_DISCONNECT_IND: ProcessDisconnectInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_DISCONNECT_REQ: ProcessDisconnectReq(msgData.connectInfo.addr, role); break; case EVT_CLOSE_REQ: avdtp.CloseReq(msgData.stream.handle); break; case EVT_SUSPEND_REQ: ProcessSuspendReq(msgData.stream.handle, role); break; case EVT_CLOSE_CFM: ProcessCloseCfm(msgData.stream.addr, role); break; case EVT_SUSPEND_CFM: ProcessSuspendCfm(msgData, role); break; case EVT_WRITE_CFM: ProcessWriteCfm(msgData, role); break; case EVT_DELAY_IND: ProcessDelayReportInd(msgData, role); break; default: break; } return true; } void A2dpStateStreaming::SetStateName(std::string state) { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); Transition(state); } void A2dpStateStreaming::ProcessSuspendInd(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); uint8_t gavdpRole = A2DP_ROLE_ACP; A2dpAvdtp avdtp(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateStreaming]%{public}s Failed to get profile instance\n", __func__); return; } /// check the stream status if (avdtp.SuspendRsp(msgData.stream.handle, msgData.stream.label, 0, 0) == AVDT_SUCCESS) { SetStateName(A2DP_PROFILE_OPEN); profile->AudioStateChangedNotify(msgData.stream.addr, A2DP_NOT_PLAYING, (void *)&gavdpRole); } } void A2dpStateStreaming::ProcessSuspendCfm(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); uint8_t gavdpRole = A2DP_ROLE_INT; A2dpAvdtp avdtp(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateStreaming]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_ON, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(msgData.stream.addr.addr)); } SetStateName(A2DP_PROFILE_OPEN); profile->AudioStateChangedNotify(msgData.stream.addr, A2DP_NOT_PLAYING, (void *)&gavdpRole); A2dpService *service = GetServiceInstance(role); if (service != nullptr) { std::string addr = service->GetActiveSinkDevice().GetAddress(); if (strcmp(addr.c_str(), RawAddress::ConvertToString(msgData.stream.addr.addr).GetAddress().c_str()) != 0) { service->ActiveDevice(); } } if (profile->GetDisalbeTag()) { profile->CloseAll(); } if (profile->FindPeerByAddress(msgData.stream.addr)->GetRestart()) { avdtp.ReconfigureReq( msgData.stream.handle, profile->FindPeerByAddress(msgData.stream.addr)->GetReconfig(), label_); } } void A2dpStateStreaming::ProcessWriteCfm(A2dpAvdtMsgData msgData, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(A2DP_ROLE_SOURCE); profile->DequeuePacket(); } void A2dpStateStreaming::ProcessDisconnectReq(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpAvdtp avdtp(role); SetStateName(A2DP_PROFILE_CLOSING); avdtp.DisconnectReq(addr); if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::IDLE, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } } void A2dpStateStreaming::ProcessSuspendReq(uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s role(%u)\n", __func__, role); A2dpAvdtp avdtp(role); avdtp.SuspendReq(handle, label_); } void A2dpStateStreaming::ProcessDisconnectInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_ACP, false, handle}; A2dpProfile *profile = GetProfileInstance(role); uint8_t gavdpRole = A2DP_ROLE_ACP; if (profile == nullptr) { LOG_ERROR("[A2dpStateStreaming]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); profile->AudioStateChangedNotify(addr, A2DP_NOT_PLAYING, (void *)&gavdpRole); profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateStreaming::ProcessCloseCfm(BtAddr addr, uint8_t role) { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateOpen]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::IDLE, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); if (profile->FindPeerByAddress(addr)->GetRestart()) { profile->FindPeerByAddress(addr)->UpdateConfigure(); } } void A2dpStateStreaming::ProcessDelayReportInd(A2dpAvdtMsgData msgData, uint8_t role) const { LOG_INFO("[A2dpStateStreaming]%{public}s\n", __func__); if (role == A2DP_ROLE_SINK) { LOG_INFO("[A2dpStateStreaming]%{public}s sink role does not handle delay report ind return.", __func__); return; } A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateStreaming]%{public}s Failed to get profile instance\n", __func__); return; } BtAddr addr = msgData.delayReportInfo.addr; uint16_t value = msgData.delayReportInfo.delayValue; profile->DelayReportNotify(addr, value); } bool A2dpStateClosing::Dispatch(const utility::Message &msg) { LOG_INFO("[A2dpStateClosing]%{public}s\n", __func__); if (msg.arg2_ == nullptr) { LOG_ERROR("[A2dpStateClosing]%{public}s input error parameter\n", __func__); return false; } A2dpAvdtMsgData msgData = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->a2dpMsg; uint8_t role = (static_cast<A2dpAvdtMsg*>(msg.arg2_))->role; switch (msg.what_) { case EVT_DISCONNECT_IND: ProcessDisconnectInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_CLOSE_TRANS_IND: ProcessCloseStreamInd(msgData.stream.addr, msgData.stream.handle, role); break; case EVT_DISCONNECT_CFM: ProcessDisconnectCfm(msgData.stream.addr, msgData.stream.handle, role); break; default: break; } return true; } void A2dpStateClosing::SetStateName(std::string state) { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); Transition(state); } void A2dpStateClosing::ProcessCloseStreamInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateClosing]%{public}s\n", __func__); A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateClosing]%{public}s Failed to get profile instance\n", __func__); return; } SetStateName(A2DP_PROFILE_IDLE); A2dpProfilePeer *peer = profile->FindOrCreatePeer(addr, role); if (peer == nullptr) { LOG_ERROR("[A2dpStateClosing]%{public}s Failed to get profile Peer\n", __func__); return; } peer->SetCurrentCmd(EVT_DISCONNECT_IND); peer->SetSignalingTimer(A2DP_ACCEPT_SIGNALLING_TIMEOUT_MS, false); } void A2dpStateClosing::ProcessDisconnectInd(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateClosing]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_INT, false, handle}; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateClosing]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } void A2dpStateClosing::ProcessDisconnectCfm(BtAddr addr, uint16_t handle, uint8_t role) { LOG_INFO("[A2dpStateClosing]%{public}s\n", __func__); CallbackParameter param = {A2DP_ROLE_INT, true, handle}; uint8_t gavdpRole = A2DP_ROLE_INT; A2dpProfile *profile = GetProfileInstance(role); if (profile == nullptr) { LOG_ERROR("[A2dpStateClosing]%{public}s Failed to get profile instance\n", __func__); return; } if (role == A2DP_ROLE_SOURCE) { IPowerManager::GetInstance().StatusUpdate( RequestStatus::CONNECT_OFF, PROFILE_NAME_A2DP_SRC, bluetooth::RawAddress::ConvertToString(addr.addr)); } SetStateName(A2DP_PROFILE_IDLE); profile->AudioStateChangedNotify(addr, A2DP_NOT_PLAYING, (void *)&gavdpRole); profile->ConnectStateChangedNotify(addr, STREAM_DISCONNECT, (void *)¶m); } const std::string A2dpStateMachine::GetStateName(void) const { std::lock_guard<std::recursive_mutex> lock(g_stateMutex); return GetState()->Name(); } } // namespace bluetooth } // namespace OHOS