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