1 /* 2 * Copyright 2023 The Android Open Source Project 3 * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA 4 * - www.ehima.com 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 /* LeAudioDeviceGroup class represents group of LeAudioDevices and allows to 20 * perform operations on them. Group states are ASE states due to nature of 21 * group which operates finally of ASEs. 22 * 23 * Group is created after adding a node to new group id (which is not on list). 24 */ 25 26 #pragma once 27 28 #include <map> 29 #include <memory> 30 #include <optional> 31 #include <utility> // for std::pair 32 #include <vector> 33 34 #ifdef __ANDROID__ 35 #include <android/sysprop/BluetoothProperties.sysprop.h> 36 #endif 37 38 #include <bluetooth/log.h> 39 #include <com_android_bluetooth_flags.h> 40 41 #include "common/strings.h" 42 #include "devices.h" 43 #include "le_audio_log_history.h" 44 #include "le_audio_types.h" 45 46 namespace bluetooth::le_audio { 47 48 class LeAudioDeviceGroup { 49 public: 50 const int group_id_; 51 52 class CigConfiguration { 53 public: 54 CigConfiguration() = delete; CigConfiguration(LeAudioDeviceGroup * group)55 CigConfiguration(LeAudioDeviceGroup* group) 56 : group_(group), state_(types::CigState::NONE) {} 57 GetState(void)58 types::CigState GetState(void) const { return state_; } SetState(bluetooth::le_audio::types::CigState state)59 void SetState(bluetooth::le_audio::types::CigState state) { 60 log::verbose("{} -> {}", bluetooth::common::ToString(state_), 61 bluetooth::common::ToString(state)); 62 state_ = state; 63 } 64 65 void GenerateCisIds(types::LeAudioContextType context_type); 66 bool AssignCisIds(LeAudioDevice* leAudioDevice); 67 void AssignCisConnHandles(const std::vector<uint16_t>& conn_handles); 68 void UnassignCis(LeAudioDevice* leAudioDevice); 69 70 std::vector<struct types::cis> cises; 71 72 private: 73 uint8_t GetFirstFreeCisId(types::CisType cis_type) const; 74 75 LeAudioDeviceGroup* group_; 76 types::CigState state_; 77 } cig; 78 IsGroupConfiguredTo(const set_configurations::AudioSetConfiguration & cfg)79 bool IsGroupConfiguredTo( 80 const set_configurations::AudioSetConfiguration& cfg) { 81 if (!stream_conf.conf) return false; 82 return cfg == *stream_conf.conf; 83 } 84 85 /* Current configuration strategy - recalculated on demand */ 86 mutable std::optional<types::LeAudioConfigurationStrategy> strategy_ = 87 std::nullopt; 88 89 /* Current audio stream configuration */ 90 struct stream_configuration stream_conf; 91 bool notify_streaming_when_cises_are_ready_; 92 93 uint8_t audio_directions_; 94 types::AudioLocations snk_audio_locations_; 95 types::AudioLocations src_audio_locations_; 96 97 /* Whether LE Audio is preferred for OUTPUT_ONLY and DUPLEX cases */ 98 bool is_output_preference_le_audio; 99 bool is_duplex_preference_le_audio; 100 101 struct { 102 DsaMode mode; 103 bool active; 104 } dsa_; 105 bool asymmetric_phy_for_unidirectional_cis_supported; 106 LeAudioDeviceGroup(const int group_id)107 explicit LeAudioDeviceGroup(const int group_id) 108 : group_id_(group_id), 109 cig(this), 110 stream_conf({}), 111 notify_streaming_when_cises_are_ready_(false), 112 audio_directions_(0), 113 dsa_({DsaMode::DISABLED, false}), 114 is_enabled_(true), 115 transport_latency_mtos_us_(0), 116 transport_latency_stom_us_(0), 117 configuration_context_type_(types::LeAudioContextType::UNINITIALIZED), 118 metadata_context_type_({.sink = types::AudioContexts( 119 types::LeAudioContextType::UNINITIALIZED), 120 .source = types::AudioContexts( 121 types::LeAudioContextType::UNINITIALIZED)}), 122 group_available_contexts_( 123 {.sink = 124 types::AudioContexts(types::LeAudioContextType::UNINITIALIZED), 125 .source = types::AudioContexts( 126 types::LeAudioContextType::UNINITIALIZED)}), 127 pending_group_available_contexts_change_( 128 types::LeAudioContextType::UNINITIALIZED), 129 group_user_allowed_context_mask_( 130 {.sink = types::AudioContexts(types::kLeAudioContextAllTypes), 131 .source = types::AudioContexts(types::kLeAudioContextAllTypes)}), 132 target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), 133 current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), 134 in_transition_(false) { 135 #ifdef __ANDROID__ 136 // 22 maps to BluetoothProfile#LE_AUDIO 137 is_output_preference_le_audio = android::sysprop::BluetoothProperties:: 138 getDefaultOutputOnlyAudioProfile() == 139 LE_AUDIO_PROFILE_CONSTANT; 140 is_duplex_preference_le_audio = 141 android::sysprop::BluetoothProperties::getDefaultDuplexAudioProfile() == 142 LE_AUDIO_PROFILE_CONSTANT; 143 #else 144 is_output_preference_le_audio = true; 145 is_duplex_preference_le_audio = true; 146 #endif 147 asymmetric_phy_for_unidirectional_cis_supported = 148 com::android::bluetooth::flags::asymmetric_phy_for_unidirectional_cis(); 149 } 150 ~LeAudioDeviceGroup(void); 151 152 void AddNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice); 153 void RemoveNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice); 154 bool IsEmpty(void) const; 155 bool IsAnyDeviceConnected(void) const; 156 int Size(void) const; 157 int DesiredSize(void) const; 158 int NumOfConnected() const; 159 int NumOfAvailableForDirection(int direction) const; 160 bool Activate(types::LeAudioContextType context_type, 161 const types::BidirectionalPair<types::AudioContexts>& 162 metadata_context_types, 163 types::BidirectionalPair<std::vector<uint8_t>> ccid_lists); 164 void Deactivate(void); 165 void ClearSinksFromConfiguration(void); 166 void ClearSourcesFromConfiguration(void); 167 void Cleanup(void); 168 LeAudioDevice* GetFirstDevice(void) const; 169 LeAudioDevice* GetFirstDeviceWithAvailableContext( 170 types::LeAudioContextType context_type) const; 171 types::LeAudioConfigurationStrategy GetGroupSinkStrategy(void) const; InvalidateGroupStrategy(void)172 inline void InvalidateGroupStrategy(void) { strategy_ = std::nullopt; } 173 int GetAseCount(uint8_t direction) const; 174 LeAudioDevice* GetNextDevice(LeAudioDevice* leAudioDevice) const; 175 LeAudioDevice* GetNextDeviceWithAvailableContext( 176 LeAudioDevice* leAudioDevice, 177 types::LeAudioContextType context_type) const; 178 LeAudioDevice* GetFirstActiveDevice(void) const; 179 LeAudioDevice* GetNextActiveDevice(LeAudioDevice* leAudioDevice) const; 180 LeAudioDevice* GetFirstActiveDeviceByCisAndDataPathState( 181 types::CisState cis_state, types::DataPathState data_path_state) const; 182 LeAudioDevice* GetNextActiveDeviceByCisAndDataPathState( 183 LeAudioDevice* leAudioDevice, types::CisState cis_state, 184 types::DataPathState data_path_state) const; 185 bool IsDeviceInTheGroup(LeAudioDevice* leAudioDevice) const; 186 bool HaveAllActiveDevicesAsesTheSameState(types::AseState state) const; 187 bool HaveAnyActiveDeviceInUnconfiguredState() const; 188 bool IsGroupStreamReady(void) const; 189 bool IsGroupReadyToCreateStream(void) const; 190 bool IsGroupReadyToSuspendStream(void) const; 191 bool HaveAllCisesDisconnected(void) const; 192 void ClearAllCises(void); 193 void UpdateCisConfiguration(uint8_t direction); 194 void AssignCisConnHandlesToAses(LeAudioDevice* leAudioDevice); 195 void AssignCisConnHandlesToAses(void); 196 bool Configure(types::LeAudioContextType context_type, 197 const types::BidirectionalPair<types::AudioContexts>& 198 metadata_context_types, 199 types::BidirectionalPair<std::vector<uint8_t>> ccid_lists = { 200 .sink = {}, .source = {}}); 201 uint32_t GetSduInterval(uint8_t direction) const; 202 uint8_t GetSCA(void) const; 203 uint8_t GetPacking(void) const; 204 uint8_t GetFraming(void) const; 205 uint16_t GetMaxTransportLatencyStom(void) const; 206 uint16_t GetMaxTransportLatencyMtos(void) const; 207 void SetTransportLatency(uint8_t direction, uint32_t transport_latency_us); 208 uint8_t GetRtn(uint8_t direction, uint8_t cis_id) const; 209 uint16_t GetMaxSduSize(uint8_t direction, uint8_t cis_id) const; 210 uint8_t GetPhyBitmask(uint8_t direction) const; 211 uint8_t GetTargetPhy(uint8_t direction) const; 212 bool GetPresentationDelay(uint32_t* delay, uint8_t direction) const; 213 uint16_t GetRemoteDelay(uint8_t direction) const; 214 bool UpdateAudioContextAvailability(void); 215 bool UpdateAudioSetConfigurationCache( 216 types::LeAudioContextType ctx_type) const; 217 CodecManager::UnicastConfigurationRequirements 218 GetAudioSetConfigurationRequirements( 219 types::LeAudioContextType ctx_type) const; 220 bool ReloadAudioLocations(void); 221 bool ReloadAudioDirections(void); 222 std::shared_ptr<const set_configurations::AudioSetConfiguration> 223 GetActiveConfiguration(void) const; 224 bool IsPendingConfiguration(void) const; 225 std::shared_ptr<const set_configurations::AudioSetConfiguration> 226 GetConfiguration(types::LeAudioContextType ctx_type) const; 227 std::shared_ptr<const set_configurations::AudioSetConfiguration> 228 GetCachedConfiguration(types::LeAudioContextType ctx_type) const; 229 void InvalidateCachedConfigurations(void); 230 void SetPendingConfiguration(void); 231 void ClearPendingConfiguration(void); 232 void AddToAllowListNotConnectedGroupMembers(int gatt_if); 233 void ApplyReconnectionMode(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode); 234 void Disable(int gatt_if); 235 void Enable(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode); 236 bool IsEnabled(void) const; 237 LeAudioCodecConfiguration GetAudioSessionCodecConfigForDirection( 238 types::LeAudioContextType group_context_type, uint8_t direction) const; 239 bool HasCodecConfigurationForDirection( 240 types::LeAudioContextType group_context_type, uint8_t direction) const; 241 bool IsAudioSetConfigurationAvailable( 242 types::LeAudioContextType group_context_type); 243 bool IsMetadataChanged( 244 const types::BidirectionalPair<types::AudioContexts>& context_types, 245 const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists) const; 246 bool IsConfiguredForContext(types::LeAudioContextType context_type) const; 247 void RemoveCisFromStreamIfNeeded(LeAudioDevice* leAudioDevice, 248 uint16_t cis_conn_hdl); 249 GetState(void)250 inline types::AseState GetState(void) const { return current_state_; } SetState(types::AseState state)251 void SetState(types::AseState state) { 252 log::info("current state: {}, new state {}, in_transition_ {}", 253 bluetooth::common::ToString(current_state_), 254 bluetooth::common::ToString(state), in_transition_); 255 LeAudioLogHistory::Get()->AddLogHistory( 256 kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogStateChangedOp, 257 bluetooth::common::ToString(current_state_) + "->" + 258 bluetooth::common::ToString(state)); 259 current_state_ = state; 260 261 if (target_state_ == current_state_) { 262 in_transition_ = false; 263 log::info("In transition flag cleared"); 264 } 265 } 266 GetTargetState(void)267 inline types::AseState GetTargetState(void) const { return target_state_; } SetNotifyStreamingWhenCisesAreReadyFlag(bool value)268 inline void SetNotifyStreamingWhenCisesAreReadyFlag(bool value) { 269 notify_streaming_when_cises_are_ready_ = value; 270 } GetNotifyStreamingWhenCisesAreReadyFlag(void)271 inline bool GetNotifyStreamingWhenCisesAreReadyFlag(void) { 272 return notify_streaming_when_cises_are_ready_; 273 } SetTargetState(types::AseState state)274 void SetTargetState(types::AseState state) { 275 log::info("target state: {}, new target state: {}, in_transition_ {}", 276 bluetooth::common::ToString(target_state_), 277 bluetooth::common::ToString(state), in_transition_); 278 LeAudioLogHistory::Get()->AddLogHistory( 279 kLogStateMachineTag, group_id_, RawAddress::kEmpty, 280 kLogTargetStateChangedOp, 281 bluetooth::common::ToString(target_state_) + "->" + 282 bluetooth::common::ToString(state)); 283 284 target_state_ = state; 285 286 in_transition_ = target_state_ != current_state_; 287 log::info("In transition flag = {}", in_transition_); 288 } 289 290 /* Returns context types for which support was recently added or removed */ GetPendingAvailableContextsChange()291 inline types::AudioContexts GetPendingAvailableContextsChange() const { 292 return pending_group_available_contexts_change_; 293 } 294 295 /* Set which context types were recently added or removed */ SetPendingAvailableContextsChange(types::AudioContexts audio_contexts)296 inline void SetPendingAvailableContextsChange( 297 types::AudioContexts audio_contexts) { 298 pending_group_available_contexts_change_ = audio_contexts; 299 } 300 ClearPendingAvailableContextsChange()301 inline void ClearPendingAvailableContextsChange() { 302 pending_group_available_contexts_change_.clear(); 303 } 304 SetConfigurationContextType(types::LeAudioContextType context_type)305 inline void SetConfigurationContextType( 306 types::LeAudioContextType context_type) { 307 configuration_context_type_ = context_type; 308 } 309 GetConfigurationContextType(void)310 inline types::LeAudioContextType GetConfigurationContextType(void) const { 311 return configuration_context_type_; 312 } 313 GetMetadataContexts()314 inline types::BidirectionalPair<types::AudioContexts> GetMetadataContexts() 315 const { 316 return metadata_context_type_; 317 } 318 SetAvailableContexts(types::BidirectionalPair<types::AudioContexts> new_contexts)319 inline void SetAvailableContexts( 320 types::BidirectionalPair<types::AudioContexts> new_contexts) { 321 group_available_contexts_ = new_contexts; 322 log::debug( 323 "group id: {}, available contexts sink: {}, available contexts source: " 324 "{}", 325 group_id_, group_available_contexts_.sink.to_string(), 326 group_available_contexts_.source.to_string()); 327 } 328 329 types::AudioContexts GetAvailableContexts( 330 int direction = types::kLeAudioDirectionBoth) const { 331 log::assert_that(direction <= (types::kLeAudioDirectionBoth), 332 "Invalid direction used."); 333 if (direction < types::kLeAudioDirectionBoth) { 334 log::debug( 335 "group id: {}, available contexts sink: {}, available contexts " 336 "source: {}", 337 group_id_, group_available_contexts_.sink.to_string(), 338 group_available_contexts_.source.to_string()); 339 return group_available_contexts_.get(direction); 340 } else { 341 return types::get_bidirectional(group_available_contexts_); 342 } 343 } 344 SetAllowedContextMask(types::BidirectionalPair<types::AudioContexts> & context_types)345 inline void SetAllowedContextMask( 346 types::BidirectionalPair<types::AudioContexts>& context_types) { 347 group_user_allowed_context_mask_ = context_types; 348 log::debug( 349 "group id: {}, allowed contexts sink: {}, allowed contexts source: " 350 "{}", 351 group_id_, group_user_allowed_context_mask_.sink.to_string(), 352 group_user_allowed_context_mask_.source.to_string()); 353 } 354 355 types::AudioContexts GetAllowedContextMask( 356 int direction = types::kLeAudioDirectionBoth) const { 357 log::assert_that(direction <= (types::kLeAudioDirectionBoth), 358 "Invalid direction used."); 359 if (direction < types::kLeAudioDirectionBoth) { 360 log::debug( 361 "group id: {}, allowed contexts sink: {}, allowed contexts " 362 "source: {}", 363 group_id_, group_user_allowed_context_mask_.sink.to_string(), 364 group_user_allowed_context_mask_.source.to_string()); 365 return group_user_allowed_context_mask_.get(direction); 366 } else { 367 return types::get_bidirectional(group_user_allowed_context_mask_); 368 } 369 } 370 371 types::AudioContexts GetSupportedContexts( 372 int direction = types::kLeAudioDirectionBoth) const; 373 GetAllowedDsaModes()374 DsaModes GetAllowedDsaModes() { 375 if (!com::android::bluetooth::flags::leaudio_dynamic_spatial_audio()) { 376 return {DsaMode::DISABLED}; 377 } 378 379 DsaModes dsa_modes{}; 380 std::set<DsaMode> dsa_mode_set{}; 381 382 for (auto leAudioDevice : leAudioDevices_) { 383 if (leAudioDevice.expired()) continue; 384 385 auto device_dsa_modes = leAudioDevice.lock()->GetDsaModes(); 386 387 dsa_mode_set.insert(device_dsa_modes.begin(), device_dsa_modes.end()); 388 } 389 390 dsa_modes.assign(dsa_mode_set.begin(), dsa_mode_set.end()); 391 392 return dsa_modes; 393 } 394 GetAllowedDsaModesList()395 std::vector<DsaModes> GetAllowedDsaModesList() { 396 std::vector<DsaModes> dsa_modes_list = {}; 397 for (auto leAudioDevice : leAudioDevices_) { 398 DsaModes dsa_modes = {}; 399 400 if (!leAudioDevice.expired()) { 401 dsa_modes = leAudioDevice.lock()->GetDsaModes(); 402 } 403 dsa_modes_list.push_back(dsa_modes); 404 } 405 return dsa_modes_list; 406 } 407 408 types::BidirectionalPair<types::AudioContexts> GetLatestAvailableContexts( 409 void) const; 410 411 bool IsInTransition(void) const; 412 bool IsStreaming(void) const; 413 bool IsReleasingOrIdle(void) const; 414 415 void PrintDebugState(void) const; 416 void Dump(int fd, int active_group_id) const; 417 418 /* Codec configuration matcher supporting the legacy configuration provider 419 * mechanism for the non-vendor and software codecs. Only if the codec 420 * parameters are using the common LTV data format, the BT stack can verify 421 * them against the remote device capabilities and find the best possible 422 * configurations. This will not be used for finding best possible vendor 423 * codec configuration. 424 */ 425 const set_configurations::AudioSetConfiguration* 426 FindFirstSupportedConfiguration( 427 const CodecManager::UnicastConfigurationRequirements& requirements, 428 const set_configurations::AudioSetConfigurations* confs) const; 429 430 private: 431 bool is_enabled_; 432 433 uint32_t transport_latency_mtos_us_; 434 uint32_t transport_latency_stom_us_; 435 436 bool ConfigureAses( 437 const set_configurations::AudioSetConfiguration* audio_set_conf, 438 types::LeAudioContextType context_type, 439 const types::BidirectionalPair<types::AudioContexts>& 440 metadata_context_types, 441 const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists); 442 bool IsAudioSetConfigurationSupported( 443 const CodecManager::UnicastConfigurationRequirements& requirements, 444 const set_configurations::AudioSetConfiguration* audio_set_configuration) 445 const; 446 uint32_t GetTransportLatencyUs(uint8_t direction) const; 447 bool IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const; 448 449 /* Current configuration and metadata context types */ 450 types::LeAudioContextType configuration_context_type_; 451 types::BidirectionalPair<types::AudioContexts> metadata_context_type_; 452 453 /* Mask of contexts that the whole group can handle at its current state 454 * It's being updated each time group members connect, disconnect or their 455 * individual available audio contexts are changed. 456 */ 457 types::BidirectionalPair<types::AudioContexts> group_available_contexts_; 458 459 /* A temporary mask for bits which were either added or removed when the 460 * group available context type changes. It usually means we should refresh 461 * our group configuration capabilities to clear this. 462 */ 463 types::AudioContexts pending_group_available_contexts_change_; 464 465 /* Mask of currently allowed context types. Not set a value not set will 466 * result in streaming rejection. 467 */ 468 types::BidirectionalPair<types::AudioContexts> 469 group_user_allowed_context_mask_; 470 471 /* Possible configuration cache - refreshed on each group context availability 472 * change. Stored as a pair of (is_valid_cache, configuration*). `pair.first` 473 * being `false` means that the cached value should be refreshed. 474 */ 475 mutable std::map< 476 types::LeAudioContextType, 477 std::pair<bool, const std::shared_ptr< 478 set_configurations::AudioSetConfiguration>>> 479 context_to_configuration_cache_map; 480 481 types::AseState target_state_; 482 types::AseState current_state_; 483 bool in_transition_; 484 std::vector<std::weak_ptr<LeAudioDevice>> leAudioDevices_; 485 }; 486 487 /* LeAudioDeviceGroup class represents a wraper helper over all device groups in 488 * le audio implementation. It allows to operate on device group from a list 489 * (vector container) using determinants like id. 490 */ 491 class LeAudioDeviceGroups { 492 public: 493 LeAudioDeviceGroup* Add(int group_id); 494 void Remove(const int group_id); 495 LeAudioDeviceGroup* FindById(int group_id) const; 496 std::vector<int> GetGroupsIds(void) const; 497 size_t Size() const; 498 bool IsAnyInTransition() const; 499 void Cleanup(void); 500 void Dump(int fd, int active_group_id) const; 501 502 private: 503 std::vector<std::unique_ptr<LeAudioDeviceGroup>> groups_; 504 }; 505 506 } // namespace bluetooth::le_audio 507