1 /* 2 * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA 3 * - www.ehima.com 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #pragma once 19 20 #include <memory> 21 #include <utility> // for std::pair 22 #include <vector> 23 24 #include "audio_hal_client/audio_hal_client.h" 25 #include "bta_groups.h" 26 #include "gatt_api.h" 27 #include "gmap_client.h" 28 #include "le_audio_types.h" 29 #include "osi/include/alarm.h" 30 #include "stack/btm/btm_dev.h" 31 #include "types/raw_address.h" 32 33 namespace bluetooth::le_audio { 34 35 // Maps to BluetoothProfile#LE_AUDIO 36 #define LE_AUDIO_PROFILE_CONSTANT 22 37 #define LE_AUDIO_INVALID_CIS_HANDLE 0xFFFF 38 39 /* Enums */ 40 enum class DeviceConnectState : uint8_t { 41 /* Initial state */ 42 DISCONNECTED, 43 /* When ACL connected, encrypted, CCC registered and initial characteristics 44 read is completed */ 45 CONNECTED, 46 /* Used when device is unbonding (RemoveDevice() API is called) */ 47 REMOVING, 48 /* Disconnecting */ 49 DISCONNECTING, 50 /* Disconnecting for recover - after that we want direct connect to be 51 initiated */ 52 DISCONNECTING_AND_RECOVER, 53 /* 2 states below are used when user creates connection. Connect API is 54 called. */ 55 CONNECTING_BY_USER, 56 /* Always used after CONNECTING_BY_USER */ 57 CONNECTED_BY_USER_GETTING_READY, 58 /* 2 states are used when autoconnect was used for the connection.*/ 59 CONNECTING_AUTOCONNECT, 60 /* Always used after CONNECTING_AUTOCONNECT */ 61 CONNECTED_AUTOCONNECT_GETTING_READY, 62 }; 63 64 std::ostream& operator<<(std::ostream& os, const DeviceConnectState& state); 65 66 /* Class definitions */ 67 68 /* LeAudioDevice class represents GATT server device with ASCS, PAC services as 69 * mandatory. Device may contain multiple ASEs, PACs, audio locations. ASEs from 70 * multiple devices may be formed in group. 71 * 72 * Device is created after connection or after storage restoration. 73 * 74 * Active device means that device has at least one ASE which will participate 75 * in any state transition of state machine. ASEs and devices will be activated 76 * according to requested by upper context type. 77 */ 78 class LeAudioDevice { 79 public: 80 RawAddress address_; 81 82 DeviceConnectState connection_state_; 83 bool known_service_handles_; 84 bool notify_connected_after_read_; 85 bool closing_stream_for_disconnection_; 86 bool autoconnect_flag_; 87 tCONN_ID conn_id_; 88 uint16_t mtu_; 89 bool encrypted_; 90 int group_id_; 91 bool csis_member_; 92 int cis_failed_to_be_established_retry_cnt_; 93 std::bitset<16> tmap_role_; 94 95 uint8_t audio_directions_; 96 types::BidirectionalPair<std::optional<types::hdl_pair_wrapper<types::AudioLocations>>> 97 audio_locations_; 98 99 types::PublishedAudioCapabilities snk_pacs_; 100 types::PublishedAudioCapabilities src_pacs_; 101 102 struct types::hdl_pair audio_avail_hdls_; 103 struct types::hdl_pair audio_supp_cont_hdls_; 104 std::vector<struct types::ase> ases_; 105 struct types::hdl_pair ctp_hdls_; 106 uint16_t tmap_role_hdl_; 107 std::string model_name_; 108 bool allowlist_flag_; 109 bool acl_asymmetric_; 110 bool acl_phy_update_done_; 111 std::unique_ptr<GmapClient> gmap_client_; 112 113 alarm_t* link_quality_timer; 114 uint16_t link_quality_timer_data; 115 116 uint8_t last_ase_ctp_command_sent; 117 118 LeAudioDevice(const RawAddress& address, DeviceConnectState state, 119 int group_id = bluetooth::groups::kGroupUnknown) address_(address)120 : address_(address), 121 connection_state_(state), 122 known_service_handles_(false), 123 notify_connected_after_read_(false), 124 closing_stream_for_disconnection_(false), 125 autoconnect_flag_(false), 126 conn_id_(GATT_INVALID_CONN_ID), 127 mtu_(0), 128 encrypted_(false), 129 group_id_(group_id), 130 csis_member_(false), 131 cis_failed_to_be_established_retry_cnt_(0), 132 audio_directions_(0), 133 model_name_(""), 134 allowlist_flag_(false), 135 acl_asymmetric_(false), 136 acl_phy_update_done_(false), 137 link_quality_timer(nullptr), 138 last_ase_ctp_command_sent(0x00), 139 dsa_({{DsaMode::DISABLED}, 140 types::DataPathState::IDLE, 141 LE_AUDIO_INVALID_CIS_HANDLE, 142 false}) {} 143 ~LeAudioDevice(void); GetAddressWithType()144 inline tBLE_BD_ADDR GetAddressWithType() const { return BTM_Sec_GetAddressWithType(address_); } 145 146 void SetConnectionState(DeviceConnectState state); 147 DeviceConnectState GetConnectionState(void); 148 void ClearPACs(void); 149 void RegisterPACs(std::vector<struct types::acs_ac_record>* apr_db, 150 std::vector<struct types::acs_ac_record>* apr); 151 struct types::ase* GetAseByValHandle(uint16_t val_hdl); 152 int GetAseCount(uint8_t direction); 153 struct types::ase* GetFirstActiveAse(void); 154 struct types::ase* GetFirstActiveAseByDirection(uint8_t direction); 155 struct types::ase* GetNextActiveAseWithSameDirection(struct types::ase* base_ase); 156 struct types::ase* GetNextActiveAseWithDifferentDirection(struct types::ase* base_ase); 157 struct types::ase* GetFirstActiveAseByCisAndDataPathState(types::CisState cis_state, 158 types::DataPathState data_path_state); 159 struct types::ase* GetFirstInactiveAse(uint8_t direction, bool reconnect = false); 160 struct types::ase* GetFirstAseWithState(uint8_t direction, types::AseState state); 161 struct types::ase* GetNextActiveAse(struct types::ase* ase); 162 struct types::ase* GetAseToMatchBidirectionCis(struct types::ase* ase); 163 types::BidirectionalPair<struct types::ase*> GetAsesByCisConnHdl(uint16_t conn_hdl); 164 types::BidirectionalPair<struct types::ase*> GetAsesByCisId(uint8_t cis_id); 165 bool HaveActiveAse(void); 166 bool HaveAllActiveAsesSameState(types::AseState state); 167 bool HaveAllActiveAsesSameDataPathState(types::DataPathState state) const; 168 bool HaveAnyUnconfiguredAses(void); 169 bool HaveAnyStreamingAses(void); 170 bool HaveAnyReleasingAse(void); 171 bool IsReadyToCreateStream(void); IsReadyToStream(void)172 bool IsReadyToStream(void) const { 173 return HaveAllActiveAsesCisEst() && 174 HaveAllActiveAsesSameDataPathState(types::DataPathState::CONFIGURED); 175 } 176 bool IsReadyToSuspendStream(void); 177 bool HaveAllActiveAsesCisEst(void) const; 178 bool HaveAnyCisConnected(void); 179 uint8_t GetSupportedAudioChannelCounts(uint8_t direction) const; 180 uint8_t GetPhyBitmask(void) const; 181 uint8_t GetPreferredPhyBitmask(uint8_t preferred_phy) const; 182 bool IsAudioSetConfigurationSupported(const types::AudioSetConfiguration* audio_set_conf) const; 183 bool ConfigureAses(const types::AudioSetConfiguration* audio_set_conf, uint8_t group_size, 184 uint8_t direction, types::LeAudioContextType context_type, 185 uint8_t* number_of_already_active_group_ase, 186 types::AudioLocations& group_audio_locations_out, 187 const types::AudioContexts& metadata_context_types, 188 const std::vector<uint8_t>& ccid_lists, bool reuse_cis_id); 189 190 inline types::AudioContexts GetSupportedContexts( 191 int direction = types::kLeAudioDirectionBoth) const { 192 log::assert_that(direction <= (types::kLeAudioDirectionBoth), "Invalid direction used."); 193 194 if (direction < types::kLeAudioDirectionBoth) { 195 return supp_contexts_.get(direction); 196 } else { 197 return types::get_bidirectional(supp_contexts_); 198 } 199 } SetSupportedContexts(types::BidirectionalPair<types::AudioContexts> contexts)200 inline void SetSupportedContexts(types::BidirectionalPair<types::AudioContexts> contexts) { 201 supp_contexts_ = contexts; 202 } 203 204 inline types::AudioContexts GetAvailableContexts( 205 int direction = types::kLeAudioDirectionBoth) const { 206 log::assert_that(direction <= (types::kLeAudioDirectionBoth), "Invalid direction used."); 207 208 if (direction < types::kLeAudioDirectionBoth) { 209 return avail_contexts_.get(direction); 210 } else { 211 return types::get_bidirectional(avail_contexts_); 212 } 213 } 214 void SetAvailableContexts(types::BidirectionalPair<types::AudioContexts> cont_val); 215 216 void DeactivateAllAses(void); 217 bool ActivateConfiguredAses( 218 types::LeAudioContextType context_type, 219 const types::BidirectionalPair<types::AudioContexts>& metadata_context_types, 220 types::BidirectionalPair<std::vector<uint8_t>> ccid_lists); 221 void SetMetadataToAse(struct types::ase* ase, const types::LeAudioLtvMap& base_metadata, 222 const types::AudioContexts& metadata_context_types, 223 const std::vector<uint8_t>& ccid_lists); 224 225 void PrintDebugState(void); 226 void DumpPacsDebugState(std::stringstream& stream); 227 void Dump(std::stringstream& stream); 228 229 void DisconnectAcl(void); 230 types::LeAudioLtvMap GetMetadata(types::AudioContexts context_type, 231 const std::vector<uint8_t>& ccid_list); 232 bool IsMetadataChanged(const types::BidirectionalPair<types::AudioContexts>& context_types, 233 const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists); 234 235 void GetDeviceModelName(void); 236 void UpdateDeviceAllowlistFlag(void); 237 DsaModes GetDsaModes(void); 238 bool DsaReducedSduSizeSupported(); 239 types::DataPathState GetDsaDataPathState(void); 240 void SetDsaDataPathState(types::DataPathState state); 241 uint16_t GetDsaCisHandle(void); 242 void SetDsaCisHandle(uint16_t cis_handle); 243 244 private: 245 types::BidirectionalPair<types::AudioContexts> avail_contexts_; 246 types::BidirectionalPair<types::AudioContexts> supp_contexts_; 247 struct { 248 DsaModes modes; 249 types::DataPathState state; 250 uint16_t cis_handle; 251 bool reduced_sdu; // TODO: Remove when earbud implementations move to approved DSA 2.0 standard 252 } dsa_; 253 254 static constexpr char kLeAudioDeviceAllowListProp[] = "persist.bluetooth.leaudio.allow_list"; 255 256 void DumpPacsDebugState(std::stringstream& stream, types::PublishedAudioCapabilities pacs); 257 void ParseHeadtrackingCodec(const struct types::acs_ac_record& pac); 258 }; 259 260 /* LeAudioDevices class represents a wraper helper over all devices in le audio 261 * implementation. It allows to operate on device from a list (vector container) 262 * using determinants like address, connection id etc. 263 */ 264 class LeAudioDevices { 265 public: 266 void Add(const RawAddress& address, bluetooth::le_audio::DeviceConnectState state, 267 int group_id = bluetooth::groups::kGroupUnknown); 268 void Remove(const RawAddress& address); 269 LeAudioDevice* FindByAddress(const RawAddress& address) const; 270 std::shared_ptr<LeAudioDevice> GetByAddress(const RawAddress& address) const; 271 LeAudioDevice* FindByConnId(tCONN_ID conn_id) const; 272 LeAudioDevice* FindByCisConnHdl(uint8_t cig_id, uint16_t conn_hdl) const; 273 void SetInitialGroupAutoconnectState(int group_id, int gatt_if, 274 tBTM_BLE_CONN_TYPE reconnection_mode, 275 bool current_dev_autoconnect_flag); 276 size_t Size(void) const; 277 void Dump(std::stringstream& stream, int group_id) const; 278 void Cleanup(tGATT_IF client_if); 279 280 private: 281 std::vector<std::shared_ptr<LeAudioDevice>> leAudioDevices_; 282 }; 283 284 } // namespace bluetooth::le_audio 285