| /****************************************************************************** |
| * |
| * Copyright 2021 The Android Open Source Project |
| * |
| * 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. |
| * |
| ******************************************************************************/ |
| |
| |
| #pragma once |
| |
| #include <string> |
| #include "state_machine.h" |
| #include <list> |
| #include "bta_bap_uclient_api.h" |
| #include "bta_pacs_client_api.h" |
| #include "bta_ascs_client_api.h" |
| #include "bt_trace.h" |
| #include "uclient_alarm.h" |
| #include "btif_util.h" |
| |
| namespace bluetooth { |
| namespace bap { |
| namespace ucast { |
| |
| using bluetooth::bap::pacs::ConnectionState; |
| using bluetooth::bap::pacs::PacsClient; |
| using bluetooth::bap::ascs::GattState; |
| using bluetooth::bap::ascs::AscsClient; |
| using bluetooth::bap::ascs::AseParams; |
| using bluetooth::bap::ascs::AseCodecConfigParams; |
| using bluetooth::bap::ascs::AseCodecConfigOp; |
| using bluetooth::bap::cis::CisInterface; |
| |
| using bluetooth::bap::cis::CigState; |
| using bluetooth::bap::cis::CisState; |
| |
| using bluetooth::bap::alarm::BapAlarm; |
| using bluetooth::bap::alarm::BapAlarmCallbacks; |
| |
| class UstreamManager; |
| class UstreamManagers; |
| struct UcastAudioStream; |
| class UcastAudioStreams; |
| class StreamContexts; |
| struct StreamContext; |
| class StreamTracker; |
| |
| enum class StreamAttachedState { |
| IDLE = 0x1 << 0, |
| IDLE_TO_PHY = 0x1 << 1, |
| VIRTUAL = 0x1 << 2, |
| VIR_TO_PHY = 0x1 << 3, |
| PHYSICAL = 0x1 << 4 |
| }; |
| |
| enum class StreamControlType { |
| None = 0x00, |
| Connect = 0X01, |
| Disconnect = 0x02, |
| Start = 0x04, |
| Stop = 0x08, |
| Reconfig = 0x10, |
| UpdateStream = 0x20 |
| }; |
| |
| enum class DeviceType { |
| NONE = 0x00, |
| EARBUD = 0X01, // group member |
| HEADSET_STEREO = 0x02, // headset with 1 CIS |
| HEADSET_SPLIT_STEREO = 0x03 // headset with 2 CIS |
| }; |
| |
| enum class IntConnectState { |
| IDLE = 0x00, |
| PACS_CONNECTING = 0x01, |
| PACS_DISCOVERING = 0X02, |
| ASCS_CONNECTING = 0x03, |
| ASCS_DISCOVERING = 0x04, |
| ASCS_DISCOVERED = 0x05, |
| }; |
| |
| enum class AscsPendingCmd { |
| NONE = 0x00, |
| CODEC_CONFIG_ISSUED = 0x01, |
| QOS_CONFIG_ISSUED = 0x02, |
| ENABLE_ISSUED = 0x03, |
| START_READY_ISSUED = 0x04, |
| DISABLE_ISSUED = 0x05, |
| STOP_READY_ISSUED = 0x06, |
| RELEASE_ISSUED = 0x07, |
| UPDATE_METADATA_ISSUED = 0x08 |
| }; |
| |
| enum class CisPendingCmd { |
| NONE = 0x00, |
| CIG_CREATE_ISSUED = 0x08, |
| CIS_CREATE_ISSUED = 0x09, |
| CIS_SETUP_DATAPATH_ISSUED = 0x10, |
| CIS_RMV_DATAPATH_ISSUED = 0x11, |
| CIS_DESTROY_ISSUED = 0x12, |
| CIG_REMOVE_ISSUED = 0x13 |
| }; |
| |
| enum class GattPendingCmd { |
| NONE = 0x00, |
| GATT_CONN_PENDING = 0x01, |
| GATT_DISC_PENDING = 0x02 |
| }; |
| |
| typedef enum { |
| BAP_CONNECT_REQ_EVT = 0X00, |
| BAP_DISCONNECT_REQ_EVT, |
| BAP_START_REQ_EVT, |
| BAP_STOP_REQ_EVT, |
| BAP_RECONFIG_REQ_EVT, |
| BAP_STREAM_UPDATE_REQ_EVT, |
| PACS_CONNECTION_STATE_EVT, |
| PACS_DISCOVERY_RES_EVT, |
| PACS_AUDIO_CONTEXT_RES_EVT, |
| ASCS_CONNECTION_STATE_EVT, |
| ASCS_DISCOVERY_RES_EVT, |
| ASCS_ASE_STATE_EVT, |
| ASCS_ASE_OP_FAILED_EVT, |
| CIS_GROUP_STATE_EVT, |
| CIS_STATE_EVT, |
| BAP_TIME_OUT_EVT, |
| } BapEvent; |
| |
| struct BapConnect { |
| std::vector<RawAddress> bd_addr; |
| bool is_direct; |
| std::vector<StreamConnect> streams; |
| }; |
| |
| struct BapDisconnect { |
| RawAddress bd_addr; |
| std::vector<StreamType> streams; |
| }; |
| |
| struct BapStart { |
| RawAddress bd_addr; |
| std::vector<StreamType> streams; |
| }; |
| |
| struct BapStop { |
| RawAddress bd_addr; |
| std::vector<StreamType> streams; |
| }; |
| |
| struct BapReconfig { |
| RawAddress bd_addr; |
| std::vector<StreamReconfig> streams; |
| }; |
| |
| struct BapStreamUpdate { |
| RawAddress bd_addr; |
| std::vector<StreamUpdate> update_streams; |
| }; |
| |
| struct PacsConnectionState { |
| RawAddress bd_addr; |
| ConnectionState state; |
| }; |
| |
| struct AscsConnectionState { |
| RawAddress bd_addr; |
| GattState state; |
| }; |
| |
| struct AscsDiscovery { |
| int status; |
| RawAddress bd_addr; |
| std::vector<AseParams> sink_ases_list; |
| std::vector<AseParams> src_ases_list; |
| }; |
| |
| struct AscsState { |
| RawAddress bd_addr; |
| AseParams ase_params; |
| }; |
| |
| struct AscsOpFailed { |
| RawAddress bd_addr; |
| ascs::AseOpId ase_op_id; |
| std::vector<ascs::AseOpStatus> ase_list; |
| }; |
| |
| struct CisGroupState { |
| uint8_t cig_id; |
| CigState state; |
| }; |
| |
| struct CisStreamState { |
| uint8_t cig_id; |
| uint8_t cis_id; |
| uint8_t direction; |
| CisState state; |
| }; |
| |
| struct PacsDiscovery { |
| int status; |
| RawAddress bd_addr; |
| std::vector<CodecConfig> sink_pac_records; |
| std::vector<CodecConfig> src_pac_records; |
| uint32_t sink_locations; |
| uint32_t src_locations; |
| uint32_t available_contexts; |
| uint32_t supported_contexts; |
| }; |
| |
| struct PacsAvailableContexts { |
| RawAddress bd_addr; |
| uint32_t available_contexts; |
| }; |
| |
| struct IntStrmTracker { |
| IntStrmTracker(StreamType strm_type, uint8_t ase_id, uint8_t cig_id, |
| uint8_t cis_id, CodecConfig &codec_config, |
| QosConfig &qos_config) |
| : strm_type(strm_type), ase_id(ase_id) , cig_id(cig_id) , |
| cis_id(cis_id), codec_config(codec_config), |
| qos_config(qos_config) { |
| attached_state = StreamAttachedState::IDLE; |
| } |
| StreamType strm_type; |
| uint8_t ase_id; |
| uint8_t cig_id; |
| uint8_t cis_id; |
| CodecConfig codec_config; |
| QosConfig qos_config; |
| StreamAttachedState attached_state; |
| }; |
| |
| class IntStrmTrackers { |
| public: |
| std::vector<IntStrmTracker *> FindByCigId(uint8_t cig_id) { |
| std::vector<IntStrmTracker *> trackers; |
| for (auto i = int_strm_trackers.begin(); |
| i != int_strm_trackers.end();i++) { |
| if((*i)->cig_id == cig_id) { |
| LOG(WARNING) << __func__ << " tracker found"; |
| trackers.push_back(*i); |
| } |
| } |
| return trackers; |
| } |
| |
| std::vector<IntStrmTracker *> FindByCigIdAndDir(uint8_t cig_id, |
| uint8_t direction) { |
| std::vector<IntStrmTracker *> trackers; |
| for (auto i = int_strm_trackers.begin(); |
| i != int_strm_trackers.end();i++) { |
| if((*i)->cig_id == cig_id && |
| (*i)->strm_type.direction == direction) { |
| trackers.push_back(*i); |
| } |
| } |
| return trackers; |
| } |
| |
| std::vector<IntStrmTracker *> FindByCisId(uint8_t cig_id, uint8_t cis_id) { |
| std::vector<IntStrmTracker *> trackers; |
| for (auto i = int_strm_trackers.begin(); |
| i != int_strm_trackers.end();i++) { |
| if((*i)->cig_id == cig_id && (*i)->cis_id == cis_id) { |
| trackers.push_back(*i); |
| } |
| } |
| return trackers; |
| } |
| |
| IntStrmTracker *FindByIndex(uint8_t i) { |
| IntStrmTracker *tracker = int_strm_trackers.at(i); |
| return tracker; |
| } |
| |
| IntStrmTracker *FindByAseId(uint8_t ase_id) { |
| auto iter = std::find_if(int_strm_trackers.begin(), int_strm_trackers.end(), |
| [&ase_id](IntStrmTracker *tracker) { |
| return tracker->ase_id == ase_id; |
| }); |
| |
| return (iter == int_strm_trackers.end()) ? nullptr : (*iter); |
| } |
| |
| IntStrmTracker *FindOrAddBytrackerType(StreamType strm_type, |
| uint8_t ase_id, uint8_t cig_id, uint8_t cis_id, |
| CodecConfig &codec_config, QosConfig &qos_config) { |
| |
| auto iter = std::find_if(int_strm_trackers.begin(), int_strm_trackers.end(), |
| [&strm_type, &cig_id, &cis_id](IntStrmTracker *tracker) { |
| return ((tracker->strm_type.type == strm_type.type) && |
| (tracker->strm_type.direction == |
| strm_type.direction) && |
| (tracker->cig_id == cig_id) && |
| (tracker->cis_id == cis_id)); |
| }); |
| |
| if (iter == int_strm_trackers.end()) { |
| IntStrmTracker *tracker = new IntStrmTracker(strm_type, |
| ase_id, cig_id, cis_id, codec_config, qos_config); |
| int_strm_trackers.push_back(tracker); |
| return tracker; |
| } else { |
| return (*iter); |
| } |
| } |
| |
| void Remove(StreamType strm_type, uint8_t cig_id, uint8_t cis_id) { |
| for (auto it = int_strm_trackers.begin(); it != int_strm_trackers.end();) { |
| if (((*it)->strm_type.type = strm_type.type) && |
| ((*it)->strm_type.direction = strm_type.direction) && |
| ((*it)->cig_id = cig_id) && ((*it)->cis_id = cis_id)) { |
| delete(*it); |
| it = int_strm_trackers.erase(it); |
| } else { |
| it++; |
| } |
| } |
| } |
| |
| void RemoveVirtualAttachedTrackers() { |
| LOG(WARNING) << __func__; |
| for (auto it = int_strm_trackers.begin(); it != int_strm_trackers.end();) { |
| if ((*it)->attached_state == StreamAttachedState::VIRTUAL) { |
| delete(*it); |
| it = int_strm_trackers.erase(it); |
| LOG(WARNING) << __func__ |
| << ": Removed virtual attached tracker"; |
| } else { |
| it++; |
| } |
| } |
| } |
| |
| size_t size() { return (int_strm_trackers.size()); } |
| |
| std::vector<IntStrmTracker *> *GetTrackerList() { |
| return &int_strm_trackers; |
| } |
| |
| std::vector<IntStrmTracker *> GetTrackerListByDir(uint8_t direction) { |
| std::vector<IntStrmTracker *> trackers; |
| for (auto i = int_strm_trackers.begin(); |
| i != int_strm_trackers.end();i++) { |
| if((*i)->strm_type.direction == direction) { |
| trackers.push_back(*i); |
| } |
| } |
| return trackers; |
| } |
| |
| private: |
| std::vector<IntStrmTracker *> int_strm_trackers; |
| }; |
| |
| union BapEventData { |
| BapConnect connect_req; |
| BapDisconnect disc_req; |
| BapStart start_req; |
| BapStop stop_req; |
| BapReconfig reconfig_req; |
| PacsConnectionState connection_state_rsp; |
| PacsDiscovery pacs_discovery_rsp; |
| PacsAvailableContexts pacs_audio_context_rsp; |
| }; |
| |
| enum class TimeoutVal { //in milli seconds(1sec = 1000ms) |
| ConnectingTimeout = 10000, |
| StartingTimeout = 2000, |
| StoppingTimeout = 2000, |
| DisconnectingTimeout = 1000, |
| ReconfiguringTimeout = 2000, |
| UpdatingTimeout = 1000 |
| }; |
| |
| enum class MaxTimeoutVal { //in milli seconds(1sec = 1000ms) |
| ConnectingTimeout = 10000, |
| StartingTimeout = 4000, |
| StoppingTimeout = 4000, |
| DisconnectingTimeout = 4000, |
| ReconfiguringTimeout = 8000, |
| UpdatingTimeout = 4000 |
| }; |
| |
| enum class TimeoutReason { |
| STATE_TRANSITION = 1, |
| }; |
| |
| struct BapTimeout { |
| RawAddress bd_addr; |
| StreamTracker* tracker; |
| TimeoutReason reason; |
| int transition_state; |
| }; |
| |
| class StreamTracker : public bluetooth::common::StateMachine { |
| public: |
| enum { |
| kStateIdle, // |
| kStateConnecting, // |
| kStateConnected, // |
| kStateStarting, // |
| kStateStreaming, // |
| kStateStopping, // |
| kStateDisconnecting, // |
| kStateReconfiguring, // |
| kStateUpdating |
| }; |
| |
| class StateIdle : public State { |
| public: |
| StateIdle(StreamTracker& sm) |
| : State(sm, kStateIdle), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()) {} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Idle"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| }; |
| |
| class StateConnecting : public State { |
| public: |
| StateConnecting(StreamTracker& sm) |
| : State(sm, kStateConnecting), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()) {} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Connecting"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| void DeriveDeviceType(PacsDiscovery *pacs_discovery); |
| bool AttachStreamsToContext(std::vector<IntStrmTracker *> *all_trackers, |
| std::vector<UcastAudioStream *> *streams, |
| uint8_t cis_count, |
| std::vector<AseCodecConfigOp> *ase_ops); |
| alarm_t* state_transition_timer; |
| BapTimeout timeout; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| PacsDiscovery pacs_discovery_; |
| AscsDiscovery ascs_discovery_; |
| IntStrmTrackers int_strm_trackers_; |
| }; |
| |
| class StateConnected : public State { |
| public: |
| StateConnected(StreamTracker& sm) |
| : State(sm, kStateConnected), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()){} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Connected"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| }; |
| |
| class StateStarting : public State { |
| public: |
| StateStarting(StreamTracker& sm) |
| : State(sm, kStateStarting), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()){} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Starting"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| bool CheckAndUpdateStreamingState(); |
| alarm_t* state_transition_timer; |
| PacsAvailableContexts pacs_contexts; |
| BapTimeout timeout; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| IntStrmTrackers int_strm_trackers_; |
| }; |
| |
| class StateStreaming : public State { |
| public: |
| StateStreaming(StreamTracker& sm) |
| : State(sm, kStateStreaming), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()){} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Streaming"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| }; |
| |
| class StateStopping : public State { |
| public: |
| StateStopping(StreamTracker& sm) |
| : State(sm, kStateStopping), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()) {} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Stopping"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| bool TerminateCisAndCig(UcastAudioStream *stream); |
| bool CheckAndUpdateStoppedState(); |
| alarm_t* state_transition_timer; |
| BapTimeout timeout; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| IntStrmTrackers int_strm_trackers_; |
| }; |
| |
| class StateDisconnecting : public State { |
| public: |
| StateDisconnecting(StreamTracker& sm) |
| : State(sm, kStateDisconnecting), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()) {} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Disconnecting"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| bool TerminateGattConnection(); |
| void ContinueDisconnection(UcastAudioStream *stream); |
| bool CheckAndUpdateDisconnectedState(); |
| alarm_t* state_transition_timer; |
| BapTimeout timeout; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| IntStrmTrackers int_strm_trackers_; |
| }; |
| |
| class StateReconfiguring: public State { |
| public: |
| StateReconfiguring(StreamTracker& sm) |
| : State(sm, kStateReconfiguring), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()) {} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Reconfiguring"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| alarm_t* state_transition_timer; |
| BapTimeout timeout; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| IntStrmTrackers int_strm_trackers_; |
| }; |
| |
| class StateUpdating: public State { |
| public: |
| StateUpdating(StreamTracker& sm) |
| : State(sm, kStateUpdating), tracker_(sm), |
| strm_mgr_(sm.GetStreamManager()) {} |
| void OnEnter() override; |
| void OnExit() override; |
| const char* GetState() { return "Updating"; } |
| bool ProcessEvent(uint32_t event, void* p_data) override; |
| alarm_t* state_transition_timer; |
| BapTimeout timeout; |
| |
| private: |
| StreamTracker &tracker_; |
| UstreamManager *strm_mgr_; |
| IntStrmTrackers int_strm_trackers_; |
| }; |
| |
| StreamTracker(int init_state_id, UstreamManager *strm_mgr, |
| std::vector<StreamConnect> *connect_streams, |
| std::vector<StreamReconfig> *reconfig_streams, |
| std::vector<StreamType> *streams, |
| StreamControlType ops_type): |
| init_state_id_(init_state_id), |
| strm_mgr_(strm_mgr) { |
| |
| state_idle_ = new StateIdle(*this); |
| state_connecting_ = new StateConnecting(*this); |
| state_connected_ = new StateConnected(*this); |
| state_starting_ = new StateStarting(*this); |
| state_streaming_ = new StateStreaming(*this); |
| state_stopping_ = new StateStopping(*this); |
| state_disconnecting_ = new StateDisconnecting(*this); |
| state_reconfiguring_ = new StateReconfiguring(*this); |
| state_updating_ = new StateUpdating(*this); |
| pacs_disc_succeded_ = false; |
| |
| AddState(state_idle_); |
| AddState(state_connecting_); |
| AddState(state_connected_); |
| AddState(state_starting_); |
| AddState(state_streaming_); |
| AddState(state_stopping_); |
| AddState(state_disconnecting_); |
| AddState(state_reconfiguring_); |
| AddState(state_updating_); |
| |
| switch(init_state_id) { |
| case kStateIdle: |
| SetInitialState(state_idle_); |
| break; |
| case kStateConnected: |
| SetInitialState(state_connected_); |
| break; |
| case kStateStreaming: |
| SetInitialState(state_streaming_); |
| break; |
| case kStateDisconnecting: |
| SetInitialState(state_disconnecting_); |
| break; |
| default: |
| SetInitialState(state_idle_); |
| } |
| |
| str_ops_type = ops_type; |
| |
| if(ops_type == StreamControlType::Connect) { |
| conn_streams = *connect_streams; |
| } else if(ops_type == StreamControlType::Reconfig) { |
| reconf_streams = *reconfig_streams; |
| } else if(ops_type != StreamControlType::UpdateStream) { |
| other_streams = *streams; |
| } |
| } |
| |
| void PauseRemoteDevInteraction(bool pause); |
| bool decoupleStream(StreamType *stream_info); |
| |
| uint8_t ChooseBestCodec(StreamType stream_type, |
| std::vector<CodecQosConfig> *codec_qos_configs, |
| PacsDiscovery *pacs_discovery); |
| |
| bool ChooseBestQos(QosConfig *src_config, |
| ascs::AseCodecConfigParams *rem_qos_prefs, |
| QosConfig *dst_config, |
| int stream_state, uint8_t stream_direction); |
| |
| bool HandlePacsConnectionEvent(void *p_data); |
| |
| bool HandlePacsAudioContextEvent(PacsAvailableContexts *pacs_contexts); |
| |
| bool HandleCisEventsInStreaming(void* p_data); |
| |
| bool HandleStreamUpdate (int cur_state); |
| |
| bool CheckAndUpdateStreamingState(IntStrmTrackers *int_strm_trackers); |
| |
| bool HandleAscsConnectionEvent(void *p_data); |
| |
| void HandleCigStateEvent(uint32_t event, void *p_data, |
| IntStrmTrackers *int_strm_trackers); |
| |
| void HandleAseStateEvent(void *p_data, StreamControlType control_type, |
| IntStrmTrackers *int_strm_trackers); |
| |
| void HandleAseOpFailedEvent(void *p_data); |
| |
| bool ValidateAseUpdate(void* p_data, IntStrmTrackers *int_strm_trackers, |
| int exp_strm_state); |
| |
| bool HandleDisconnect(void* p_data, int cur_state); |
| |
| bool HandleRemoteDisconnect(uint32_t event, void* p_data, int cur_state); |
| |
| bool StreamCanbeDisconnected(StreamContext *cur_context, uint8_t ase_id); |
| |
| bool HandleInternalDisconnect(bool release); |
| |
| bool HandleStop(void* p_data, int cur_state); |
| |
| bool HandleRemoteStop(uint32_t event, void* p_data, int cur_state); |
| |
| bool HandleRemoteReconfig(uint32_t event, void* p_data, int cur_state); |
| |
| bool PrepareCodecConfigPayload(std::vector<AseCodecConfigOp> *ase_ops, |
| UcastAudioStream *stream); |
| |
| void CheckAndSendQosConfig(IntStrmTrackers *int_strm_trackers); |
| |
| void CheckAndSendEnable(IntStrmTrackers *int_strm_trackers); |
| |
| bool HandleAbruptStop(uint32_t event, void* p_data); |
| |
| alarm_t* SetTimer(const char* alarmname, BapTimeout* timeout, |
| TimeoutReason reason, uint64_t ms); |
| |
| void ClearTimer(alarm_t* timer, const char* alarmname); |
| |
| void OnTimeout(void* data); |
| |
| StreamControlType GetControlType() { |
| return str_ops_type; |
| } |
| |
| UstreamManager *GetStreamManager() { |
| return strm_mgr_; |
| } |
| |
| bool UpdatePacsDiscovery(PacsDiscovery disc_res) { |
| pacs_disc_succeded_ = true; |
| pacs_discovery_ = disc_res; |
| return true; |
| } |
| |
| PacsDiscovery *GetPacsDiscovery() { |
| if(pacs_disc_succeded_) { |
| return &pacs_discovery_; |
| } else { |
| return nullptr; |
| } |
| } |
| |
| bool UpdateControlType(StreamControlType ops_type) { |
| str_ops_type = ops_type; |
| return true; |
| } |
| |
| bool UpdateStreams(std::vector<StreamType> *streams) { |
| other_streams = *streams; |
| return true; |
| } |
| |
| bool UpdateConnStreams( |
| std::vector<StreamConnect> *connect_streams) { |
| conn_streams = *connect_streams; |
| return true; |
| } |
| |
| bool UpdateReconfStreams( |
| std::vector<StreamReconfig> *reconfig_streams) { |
| reconf_streams = *reconfig_streams; |
| return true; |
| } |
| |
| bool UpdateMetaUpdateStreams( |
| std::vector<StreamUpdate> *meta_streams) { |
| meta_update_streams = *meta_streams; |
| return true; |
| } |
| |
| std::vector<StreamType> *GetStreams() { |
| return &other_streams; |
| } |
| std::vector<StreamConnect> *GetConnStreams() { |
| return &conn_streams; |
| } |
| std::vector<StreamReconfig> *GetReconfStreams() { |
| return &reconf_streams; |
| } |
| |
| std::vector<StreamUpdate> *GetMetaUpdateStreams() { |
| return &meta_update_streams; |
| } |
| |
| const char* GetEventName(uint32_t event) { |
| switch (event) { |
| CASE_RETURN_STR(BAP_CONNECT_REQ_EVT) |
| CASE_RETURN_STR(BAP_DISCONNECT_REQ_EVT) |
| CASE_RETURN_STR(BAP_START_REQ_EVT) |
| CASE_RETURN_STR(BAP_STOP_REQ_EVT) |
| CASE_RETURN_STR(BAP_RECONFIG_REQ_EVT) |
| CASE_RETURN_STR(BAP_STREAM_UPDATE_REQ_EVT) |
| CASE_RETURN_STR(PACS_CONNECTION_STATE_EVT) |
| CASE_RETURN_STR(PACS_DISCOVERY_RES_EVT) |
| CASE_RETURN_STR(PACS_AUDIO_CONTEXT_RES_EVT) |
| CASE_RETURN_STR(ASCS_CONNECTION_STATE_EVT) |
| CASE_RETURN_STR(ASCS_DISCOVERY_RES_EVT) |
| CASE_RETURN_STR(ASCS_ASE_STATE_EVT) |
| CASE_RETURN_STR(ASCS_ASE_OP_FAILED_EVT) |
| CASE_RETURN_STR(CIS_GROUP_STATE_EVT) |
| CASE_RETURN_STR(CIS_STATE_EVT) |
| CASE_RETURN_STR(BAP_TIME_OUT_EVT) |
| default: |
| return "Unknown Event"; |
| } |
| } |
| |
| private: |
| int init_state_id_; |
| UstreamManager *strm_mgr_; |
| std::vector<StreamConnect> conn_streams; |
| std::vector<StreamType> other_streams; |
| std::vector<StreamReconfig> reconf_streams; |
| std::vector<StreamUpdate> meta_update_streams; |
| StreamControlType str_ops_type; |
| bool pacs_disc_succeded_; |
| PacsDiscovery pacs_discovery_; |
| StateIdle *state_idle_; |
| StateConnecting *state_connecting_; |
| StateConnected *state_connected_; |
| StateStarting *state_starting_; |
| StateStreaming *state_streaming_; |
| StateStopping *state_stopping_; |
| StateDisconnecting *state_disconnecting_; |
| StateReconfiguring *state_reconfiguring_; |
| StateUpdating *state_updating_; |
| }; |
| |
| struct StreamOpConnect { |
| StreamType stream_type; |
| //std::vector<CodecConfig> codec_configs; |
| //std::vector<QosConfig> qos_configs; |
| }; |
| |
| struct StreamOpReconfig { |
| StreamType stream_type; |
| //std::vector<CodecConfig> codec_configs; |
| //std::vector<QosConfig> qos_configs; |
| }; |
| |
| union StreamOpData { |
| StreamOpConnect connect_op; |
| StreamType stream_type; |
| StreamOpReconfig reconfig_op; |
| }; |
| |
| struct StreamOpNode { |
| bool busy; |
| bool is_client_originated; |
| StreamControlType ops_type; |
| StreamOpData ops_data; |
| }; |
| |
| struct StreamIdType { |
| uint8_t ase_id; |
| uint8_t ase_direction; |
| bool virtual_attach; |
| uint8_t cig_id; |
| uint8_t cis_id; |
| }; |
| |
| struct StreamContext { |
| StreamContext(StreamType strm_type) |
| : stream_type(strm_type) { |
| stream_state = StreamState::DISCONNECTED; |
| attached_state = StreamAttachedState::IDLE; |
| } |
| StreamType stream_type; |
| StreamAttachedState attached_state; |
| std::vector<StreamIdType> stream_ids; |
| StreamState stream_state; |
| IntConnectState connection_state; |
| CodecConfig codec_config; |
| QosConfig qos_config; |
| QosConfig req_qos_config; |
| }; |
| |
| class StreamContexts { |
| public: |
| |
| StreamContext *FindByType(StreamType stream_type); |
| |
| StreamContext *FindOrAddByType(StreamType stream_type); |
| |
| void Remove(StreamType stream_type); |
| |
| bool IsAseAttached(StreamType stream_type); |
| |
| std::vector<StreamContext *> FindByAseAttachedState(uint16_t ase_id, |
| StreamAttachedState state); |
| |
| |
| StreamContext* FindByAseId(uint16_t ase_id); |
| |
| std::vector<StreamContext *> *GetAllContexts() { |
| return &strm_contexts; |
| } |
| |
| size_t size() { return (strm_contexts.size()); } |
| |
| private: |
| std::vector<StreamContext *> strm_contexts; |
| }; |
| |
| |
| class StreamOpsQueue { |
| public: |
| bool Add(StreamOpNode op_node); |
| |
| bool AddFirst(StreamOpNode op_node); |
| |
| StreamOpNode *GetNextNode(); |
| |
| bool Remove(StreamType stream_type); |
| |
| StreamOpNode* FindByContext(StreamType stream_type); |
| |
| bool ChangeOpType(StreamType stream_type, StreamControlType new_ops_type); |
| |
| size_t size() { return (queue.size()); } |
| |
| std::vector<StreamOpNode> queue; |
| }; |
| |
| class StreamTrackers { |
| public: |
| StreamTracker *FindOrAddByType(int init_state_id, UstreamManager *strm_mgr, |
| std::vector<StreamConnect> *connect_streams, |
| std::vector<StreamReconfig> *reconfig_streams, |
| std::vector<StreamType> *streams, |
| StreamControlType ops_type); |
| |
| bool Remove(std::vector<StreamType> streams, |
| StreamControlType ops_type); |
| |
| void RemoveByStates(std::vector<int> state_ids); |
| |
| std::map<StreamTracker * , std::vector<StreamType> > GetTrackersByType( |
| std::vector<StreamType> *streams); |
| |
| StreamTracker *FindByStreamsType(std::vector<StreamType> *streams); |
| |
| std::vector<StreamTracker *> GetTrackersByStates( |
| std::vector<int> *state_ids); |
| |
| bool ChangeOpType( StreamType stream_type, |
| StreamControlType new_ops_type); |
| |
| bool IsStreamTrackerValid(StreamTracker* Tracker, |
| std::vector<int> *state_ids); |
| |
| size_t size() { return (stream_trackers.size()); } |
| |
| std::vector<StreamTracker *> stream_trackers; |
| }; |
| |
| struct UcastAudioStream { |
| UcastAudioStream(uint8_t ase_id, uint8_t ase_state, uint8_t ase_direction) |
| : ase_id(ase_id) , ase_state(ase_state) { |
| ase_state = ascs::ASE_STATE_INVALID; |
| cig_state = CigState::INVALID; |
| cis_state = CisState::INVALID; |
| direction = ase_direction; |
| cig_id = 0XFF; |
| cis_id = 0xFF; |
| cis_retry_count = 0; |
| overall_state = StreamTracker::kStateIdle; |
| ase_pending_cmd = AscsPendingCmd::NONE; |
| cis_pending_cmd = CisPendingCmd::NONE; |
| } |
| bool is_active; |
| uint8_t ase_id; |
| uint8_t ase_state; |
| AseParams ase_params; |
| AseCodecConfigParams pref_qos_params; |
| uint8_t cig_id; |
| CigState cig_state; |
| uint8_t cis_id; |
| CisState cis_state; |
| uint8_t cis_retry_count; |
| int overall_state; // stream tracker state |
| StreamControlType control_type; |
| AscsPendingCmd ase_pending_cmd; |
| CisPendingCmd cis_pending_cmd; |
| uint16_t audio_context; |
| uint8_t direction; |
| uint32_t audio_location; |
| CodecConfig codec_config; |
| QosConfig qos_config; |
| QosConfig req_qos_config; |
| }; |
| |
| class UcastAudioStreams { |
| public: |
| |
| std::vector<UcastAudioStream *> FindByCigId(uint8_t cig_id, int state) { |
| std::vector<UcastAudioStream *> streams; |
| for (auto i = audio_streams.begin(); i != audio_streams.end();i++) { |
| if((*i)->cig_id == cig_id && |
| (*i)->overall_state == state) { |
| streams.push_back(*i); |
| } |
| } |
| return streams; |
| } |
| |
| std::vector<UcastAudioStream *> FindByCisId(uint8_t cig_id, uint8_t cis_id) { |
| std::vector<UcastAudioStream *> streams; |
| for (auto i = audio_streams.begin(); i != audio_streams.end();i++) { |
| if((*i)->cig_id == cig_id && (*i)->cis_id == cis_id) { |
| streams.push_back(*i); |
| } |
| } |
| return streams; |
| } |
| |
| UcastAudioStream *FindByStreamType(uint16_t audio_context, |
| uint8_t direction) { |
| auto it = audio_streams.begin(); |
| while (it != audio_streams.end()) { |
| if((*it)->audio_context == audio_context && |
| (*it)->direction & direction) { |
| break; |
| } |
| it++; |
| } |
| return (it == audio_streams.end()) ? nullptr : (*it); |
| } |
| |
| UcastAudioStream *FindByCisIdAndDir(uint8_t cig_id, uint8_t cis_id, |
| uint8_t dir) { |
| auto it = audio_streams.begin(); |
| while (it != audio_streams.end()) { |
| if((*it)->cig_id == cig_id && (*it)->cis_id == cis_id && |
| (*it)->direction & dir) { |
| break; |
| } |
| it++; |
| } |
| return (it == audio_streams.end()) ? nullptr : (*it); |
| } |
| |
| UcastAudioStream *FindByAseId(uint8_t ase_id) { |
| auto it = audio_streams.begin(); |
| while (it != audio_streams.end()) { |
| if((*it)->ase_id == ase_id) { |
| break; |
| } |
| it++; |
| } |
| return (it == audio_streams.end()) ? nullptr : (*it); |
| } |
| |
| UcastAudioStream *FindOrAddByAseId(uint8_t ase_id, uint8_t ase_state, |
| uint8_t ase_direction) { |
| auto iter = std::find_if(audio_streams.begin(), audio_streams.end(), |
| [&ase_id, &ase_direction](UcastAudioStream *stream) { |
| return (stream->ase_id == ase_id && |
| stream->direction == ase_direction); |
| }); |
| |
| if (iter == audio_streams.end()) { |
| UcastAudioStream *stream = new UcastAudioStream(ase_id, ase_state, |
| ase_direction); |
| stream->overall_state = StreamTracker::kStateIdle; |
| audio_streams.push_back(stream); |
| auto it = std::find_if(audio_streams.begin(), audio_streams.end(), |
| [&ase_id, &ase_direction](UcastAudioStream* stream) { |
| return (stream->ase_id == ase_id && |
| stream->direction == ase_direction); |
| }); |
| return (it == audio_streams.end()) ? nullptr : (*it); |
| } else { |
| return (*iter); |
| } |
| } |
| |
| std::vector<UcastAudioStream *> GetStreamsByStates( |
| std::vector<int> state_ids, |
| uint8_t directions) { |
| std::vector<UcastAudioStream *> streams; |
| for (auto i = audio_streams.begin(); i != audio_streams.end();i++) { |
| for (auto j = state_ids.begin(); j != state_ids.end();j++) { |
| if(((*i)->overall_state == *j) && ((*i)->direction & directions)) { |
| streams.push_back(*i); |
| } |
| } |
| } |
| return streams; |
| } |
| |
| void Remove(uint8_t ase_id) { |
| for (auto it = audio_streams.begin(); it != audio_streams.end();) { |
| if ((*it)->ase_id == ase_id) { |
| delete(*it); |
| it = audio_streams.erase(it); |
| } else { |
| it++; |
| } |
| } |
| } |
| |
| std::vector<UcastAudioStream *> *GetAllStreams() { |
| return &audio_streams; |
| } |
| |
| size_t size() { return (audio_streams.size()); } |
| // UcastAudioStream |
| private: |
| std::vector<UcastAudioStream *> audio_streams; |
| }; |
| |
| struct GattPendingData { |
| GattPendingData() { |
| ascs_pending_cmd = GattPendingCmd::NONE; |
| pacs_pending_cmd = GattPendingCmd::NONE; |
| } |
| GattPendingCmd ascs_pending_cmd; |
| GattPendingCmd pacs_pending_cmd; |
| }; |
| |
| class UstreamManager { |
| public: |
| UstreamManager(const RawAddress& address, PacsClient *pacs_client, |
| uint16_t pacs_client_id, |
| AscsClient *ascs_client, CisInterface *cis_intf, |
| UcastClientCallbacks* callbacks, |
| BapAlarm *bap_alarm) |
| : address(address) , pacs_client(pacs_client), |
| pacs_client_id(pacs_client_id), |
| ascs_client(ascs_client), cis_intf(cis_intf), |
| ucl_callbacks(callbacks), bap_alarm(bap_alarm) { |
| pacs_state = ConnectionState::DISCONNECTED; |
| gatt_pending_data.pacs_pending_cmd = GattPendingCmd::NONE; |
| gatt_pending_data.ascs_pending_cmd = GattPendingCmd::NONE; |
| ascs_state = GattState::DISCONNECTED; |
| dev_type = DeviceType::NONE; |
| } |
| |
| bool PushEventToTracker(uint32_t event, void *p_data, |
| std::vector<int> *state_ids); |
| |
| std::map<int , std::vector<StreamType> > SplitContextOnState( |
| std::vector<StreamType> *streams); |
| |
| void ProcessEvent(uint32_t event, void* p_data); |
| |
| uint16_t GetConnId(); |
| |
| std::list<uint16_t> GetCigId(); |
| |
| std::list<uint16_t> GetCisId(); |
| |
| void ReportStreamState (std::vector<StreamStateInfo> stream_info); |
| |
| RawAddress &GetAddress() { return address; }; |
| |
| PacsClient *GetPacsClient() { |
| return pacs_client; |
| } |
| |
| uint16_t GetPacsClientId() { |
| return pacs_client_id; |
| } |
| |
| GattPendingData *GetGattPendingData() { |
| return &gatt_pending_data; |
| } |
| |
| bool UpdatePacsState(ConnectionState state) { |
| pacs_state = state; |
| return true; |
| } |
| |
| bool UpdateAscsState(GattState state) { |
| ascs_state = state; |
| return true; |
| } |
| |
| ConnectionState GetPacsState() { |
| return pacs_state; |
| } |
| |
| GattState GetAscsState() { |
| return ascs_state; |
| } |
| |
| AscsClient *GetAscsClient() { |
| return ascs_client; |
| } |
| |
| CisInterface *GetCisInterface() { |
| return cis_intf; |
| } |
| |
| BapAlarm *GetBapAlarm() { |
| return bap_alarm; |
| } |
| |
| UcastAudioStreams *GetAudioStreams() { |
| return &audio_streams; |
| } |
| |
| StreamTrackers *GetStreamTrackers() { |
| return &stream_trackers; |
| } |
| |
| StreamContexts *GetStreamContexts() { |
| return &stream_contexts; |
| } |
| |
| UcastClientCallbacks *GetUclientCbacks() { |
| return ucl_callbacks; |
| } |
| |
| void UpdateDevType(DeviceType device_type) { |
| dev_type = device_type; |
| } |
| |
| DeviceType GetDevType() { |
| return dev_type; |
| } |
| |
| const char* GetEventName(uint32_t event) { |
| switch (event) { |
| CASE_RETURN_STR(BAP_CONNECT_REQ_EVT) |
| CASE_RETURN_STR(BAP_DISCONNECT_REQ_EVT) |
| CASE_RETURN_STR(BAP_START_REQ_EVT) |
| CASE_RETURN_STR(BAP_STOP_REQ_EVT) |
| CASE_RETURN_STR(BAP_RECONFIG_REQ_EVT) |
| CASE_RETURN_STR(BAP_STREAM_UPDATE_REQ_EVT) |
| CASE_RETURN_STR(PACS_CONNECTION_STATE_EVT) |
| CASE_RETURN_STR(PACS_DISCOVERY_RES_EVT) |
| CASE_RETURN_STR(PACS_AUDIO_CONTEXT_RES_EVT) |
| CASE_RETURN_STR(ASCS_CONNECTION_STATE_EVT) |
| CASE_RETURN_STR(ASCS_DISCOVERY_RES_EVT) |
| CASE_RETURN_STR(ASCS_ASE_STATE_EVT) |
| CASE_RETURN_STR(ASCS_ASE_OP_FAILED_EVT) |
| CASE_RETURN_STR(CIS_GROUP_STATE_EVT) |
| CASE_RETURN_STR(CIS_STATE_EVT) |
| CASE_RETURN_STR(BAP_TIME_OUT_EVT) |
| default: |
| return "Unknown Event"; |
| } |
| } |
| |
| private: |
| RawAddress address; |
| PacsClient *pacs_client; |
| uint16_t pacs_client_id; |
| AscsClient *ascs_client; |
| ConnectionState pacs_state; |
| CisInterface *cis_intf; |
| GattState ascs_state; |
| StreamOpsQueue ops_queue; |
| UcastAudioStreams audio_streams; |
| StreamTrackers stream_trackers; |
| StreamContexts stream_contexts; |
| GattPendingData gatt_pending_data; |
| UcastClientCallbacks* ucl_callbacks; |
| BapAlarm *bap_alarm; |
| DeviceType dev_type; |
| }; |
| |
| class UstreamManagers { |
| public: |
| UstreamManager* FindByAddress(const RawAddress& address); |
| |
| UstreamManager* FindorAddByAddress(const RawAddress& address, |
| PacsClient *pacs_client, uint16_t pacs_client_id, |
| AscsClient *ascs_client, CisInterface *cis_intf, |
| UcastClientCallbacks* callbacks, BapAlarm* bap_alarm); |
| |
| |
| std::vector<UstreamManager *> *GetAllManagers(); |
| |
| void Remove(const RawAddress& address); |
| |
| size_t size() { return (strm_mgrs.size()); } |
| |
| std::vector<UstreamManager *> strm_mgrs; |
| }; |
| |
| } // namespace ucast |
| } // namespace bap |
| } // namespace bluetooth |