• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "device_groups.h"
20 
21 #include <bluetooth/log.h>
22 #include <stdio.h>
23 
24 #include <algorithm>
25 #include <cstddef>
26 #include <cstdint>
27 #include <functional>
28 #include <iterator>
29 #include <memory>
30 #include <optional>
31 #include <sstream>
32 #include <utility>
33 #include <vector>
34 
35 #include "audio_hal_client/audio_hal_client.h"
36 #include "bta/include/bta_gatt_api.h"
37 #include "bta/le_audio/gmap_server.h"
38 #include "bta_csis_api.h"
39 #include "bta_groups.h"
40 #include "btif/include/btif_profile_storage.h"
41 #include "btm_ble_api_types.h"
42 #include "btm_iso_api.h"
43 #include "btm_iso_api_types.h"
44 #include "client_parser.h"
45 #include "com_android_bluetooth_flags.h"
46 #include "common/strings.h"
47 #include "gatt_api.h"
48 #include "hardware/bt_le_audio.h"
49 #include "hci/controller_interface.h"
50 #include "hci_error_code.h"
51 #include "internal_include/bt_trace.h"
52 #include "le_audio/codec_manager.h"
53 #include "le_audio/devices.h"
54 #include "le_audio/le_audio_types.h"
55 #include "le_audio_utils.h"
56 #include "main/shim/entry.h"
57 #include "metrics_collector.h"
58 #include "stack/include/btm_client_interface.h"
59 #include "types/bt_transport.h"
60 
61 namespace bluetooth::le_audio {
62 
63 using bluetooth::le_audio::types::ase;
64 using types::AseState;
65 using types::AudioContexts;
66 using types::AudioLocations;
67 using types::BidirectionalPair;
68 using types::CisState;
69 using types::CisType;
70 using types::DataPathState;
71 using types::LeAudioContextType;
72 
73 /* LeAudioDeviceGroup Class methods implementation */
AddNode(const std::shared_ptr<LeAudioDevice> & leAudioDevice)74 void LeAudioDeviceGroup::AddNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
75   leAudioDevice->group_id_ = group_id_;
76   leAudioDevices_.push_back(std::weak_ptr<LeAudioDevice>(leAudioDevice));
77   MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size());
78 }
79 
RemoveNode(const std::shared_ptr<LeAudioDevice> & leAudioDevice)80 void LeAudioDeviceGroup::RemoveNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
81   /* Group information cleaning in the device. */
82   leAudioDevice->group_id_ = bluetooth::groups::kGroupUnknown;
83   for (auto ase : leAudioDevice->ases_) {
84     ase.active = false;
85     ase.cis_conn_hdl = kInvalidCisConnHandle;
86   }
87 
88   leAudioDevices_.erase(
89           std::remove_if(leAudioDevices_.begin(), leAudioDevices_.end(),
90                          [&leAudioDevice](auto& d) { return d.lock() == leAudioDevice; }),
91           leAudioDevices_.end());
92   MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size());
93 }
94 
IsEmpty(void) const95 bool LeAudioDeviceGroup::IsEmpty(void) const { return leAudioDevices_.size() == 0; }
96 
IsAnyDeviceConnected(void) const97 bool LeAudioDeviceGroup::IsAnyDeviceConnected(void) const { return NumOfConnected() != 0; }
98 
Size(void) const99 int LeAudioDeviceGroup::Size(void) const { return leAudioDevices_.size(); }
100 
DesiredSize(void) const101 int LeAudioDeviceGroup::DesiredSize(void) const {
102   int group_size = 0;
103   if (bluetooth::csis::CsisClient::IsCsisClientRunning()) {
104     group_size = bluetooth::csis::CsisClient::Get()->GetDesiredSize(group_id_);
105   }
106 
107   return group_size > 0 ? group_size : leAudioDevices_.size();
108 }
109 
NumOfConnected() const110 int LeAudioDeviceGroup::NumOfConnected() const {
111   /* return number of connected devices from the set*/
112   return std::count_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& iter) {
113     auto dev = iter.lock();
114     if (dev) {
115       return (dev->conn_id_ != GATT_INVALID_CONN_ID) &&
116              (dev->GetConnectionState() == DeviceConnectState::CONNECTED);
117     }
118     return false;
119   });
120 }
121 
NumOfAvailableForDirection(int direction) const122 int LeAudioDeviceGroup::NumOfAvailableForDirection(int direction) const {
123   bool check_ase_count = direction < types::kLeAudioDirectionBoth;
124 
125   /* return number of connected devices from the set with supported context */
126   return std::count_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&](auto& iter) {
127     auto dev = iter.lock();
128     if (dev) {
129       if (check_ase_count && (dev->GetAseCount(direction) == 0)) {
130         return false;
131       }
132       return (dev->conn_id_ != GATT_INVALID_CONN_ID) &&
133              (dev->GetConnectionState() == DeviceConnectState::CONNECTED);
134     }
135     return false;
136   });
137 }
138 
ClearSinksFromConfiguration(void)139 void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) {
140   log::info("Group {}, group_id {}", std::format_ptr(this), group_id_);
141 
142   auto direction = types::kLeAudioDirectionSink;
143   stream_conf.stream_params.get(direction).clear();
144   CodecManager::GetInstance()->ClearCisConfiguration(direction);
145 }
146 
ClearSourcesFromConfiguration(void)147 void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) {
148   log::info("Group {}, group_id {}", std::format_ptr(this), group_id_);
149 
150   auto direction = types::kLeAudioDirectionSource;
151   stream_conf.stream_params.get(direction).clear();
152   CodecManager::GetInstance()->ClearCisConfiguration(direction);
153 }
154 
ClearAllCises(void)155 void LeAudioDeviceGroup::ClearAllCises(void) {
156   log::info("group_id: {}", group_id_);
157   cig.cises.clear();
158   ClearSinksFromConfiguration();
159   ClearSourcesFromConfiguration();
160 }
161 
UpdateCisConfiguration(uint8_t direction)162 void LeAudioDeviceGroup::UpdateCisConfiguration(uint8_t direction) {
163   CodecManager::GetInstance()->UpdateCisConfiguration(
164           cig.cises, stream_conf.stream_params.get(direction), direction);
165 }
166 
Cleanup(void)167 void LeAudioDeviceGroup::Cleanup(void) {
168   /* Bluetooth is off while streaming - disconnect CISes and remove CIG */
169   if (GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
170     auto& sink_stream_locations = stream_conf.stream_params.sink.stream_config.stream_map;
171     auto& source_stream_locations = stream_conf.stream_params.source.stream_config.stream_map;
172 
173     if (!sink_stream_locations.empty()) {
174       for (const auto info : sink_stream_locations) {
175         auto cis_handle = info.stream_handle;
176         bluetooth::hci::IsoManager::GetInstance()->DisconnectCis(cis_handle, HCI_ERR_PEER_USER);
177 
178         /* Check the other direction if disconnecting bidirectional CIS */
179         if (source_stream_locations.empty()) {
180           continue;
181         }
182         source_stream_locations.erase(
183                 std::remove_if(
184                         source_stream_locations.begin(), source_stream_locations.end(),
185                         [&cis_handle](auto& inf) { return inf.stream_handle == cis_handle; }),
186                 source_stream_locations.end());
187       }
188     }
189 
190     /* Take care of the non-bidirectional CISes */
191     if (!source_stream_locations.empty()) {
192       for (auto info : source_stream_locations) {
193         bluetooth::hci::IsoManager::GetInstance()->DisconnectCis(info.stream_handle,
194                                                                  HCI_ERR_PEER_USER);
195       }
196     }
197   }
198 
199   /* Note: CIG will stay in the controller. We cannot remove it here, because
200    * Cises are not yet disconnected.
201    * When user start Bluetooth, HCI Reset should remove it
202    */
203 
204   leAudioDevices_.clear();
205   ClearAllCises();
206 }
207 
Deactivate(void)208 void LeAudioDeviceGroup::Deactivate(void) {
209   for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
210        leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
211     for (auto* ase = leAudioDevice->GetFirstActiveAse(); ase;
212          ase = leAudioDevice->GetNextActiveAse(ase)) {
213       ase->active = false;
214       ase->reconfigure = 0;
215     }
216   }
217 }
218 
Activate(LeAudioContextType context_type,const BidirectionalPair<AudioContexts> & metadata_context_types,BidirectionalPair<std::vector<uint8_t>> ccid_lists)219 bool LeAudioDeviceGroup::Activate(LeAudioContextType context_type,
220                                   const BidirectionalPair<AudioContexts>& metadata_context_types,
221                                   BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
222   bool is_activate = false;
223   for (auto leAudioDevice : leAudioDevices_) {
224     if (leAudioDevice.expired()) {
225       continue;
226     }
227 
228     bool activated = leAudioDevice.lock()->ActivateConfiguredAses(
229             context_type, metadata_context_types, ccid_lists);
230     log::info("Device {} is {}", leAudioDevice.lock().get()->address_,
231               activated ? "activated" : " not activated");
232     if (activated) {
233       if (!cig.AssignCisIds(leAudioDevice.lock().get())) {
234         return false;
235       }
236       is_activate = true;
237       SetMetadataContexts(metadata_context_types);
238     }
239   }
240   return is_activate;
241 }
242 
GetSupportedContexts(int direction) const243 AudioContexts LeAudioDeviceGroup::GetSupportedContexts(int direction) const {
244   AudioContexts context;
245   for (auto& device : leAudioDevices_) {
246     auto shared_dev = device.lock();
247     if (shared_dev) {
248       context |= shared_dev->GetSupportedContexts(direction);
249     }
250   }
251   return context;
252 }
253 
GetFirstDevice(void) const254 LeAudioDevice* LeAudioDeviceGroup::GetFirstDevice(void) const {
255   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
256                            [](auto& iter) { return !iter.expired(); });
257 
258   if (iter == leAudioDevices_.end()) {
259     return nullptr;
260   }
261 
262   return (iter->lock()).get();
263 }
264 
GetFirstDeviceWithAvailableContext(LeAudioContextType context_type) const265 LeAudioDevice* LeAudioDeviceGroup::GetFirstDeviceWithAvailableContext(
266         LeAudioContextType context_type) const {
267   auto iter =
268           std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&context_type](auto& iter) {
269             if (iter.expired()) {
270               return false;
271             }
272             return iter.lock()->GetAvailableContexts().test(context_type);
273           });
274 
275   if ((iter == leAudioDevices_.end()) || (iter->expired())) {
276     return nullptr;
277   }
278 
279   return (iter->lock()).get();
280 }
281 
GetNextDevice(LeAudioDevice * leAudioDevice) const282 LeAudioDevice* LeAudioDeviceGroup::GetNextDevice(LeAudioDevice* leAudioDevice) const {
283   auto iter =
284           std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&leAudioDevice](auto& d) {
285             if (d.expired()) {
286               return false;
287             } else {
288               return (d.lock()).get() == leAudioDevice;
289             }
290           });
291 
292   /* If reference device not found */
293   if (iter == leAudioDevices_.end()) {
294     return nullptr;
295   }
296 
297   std::advance(iter, 1);
298   /* If reference device is last in group */
299   if (iter == leAudioDevices_.end()) {
300     return nullptr;
301   }
302 
303   if (iter->expired()) {
304     return nullptr;
305   }
306 
307   return (iter->lock()).get();
308 }
309 
GetNextDeviceWithAvailableContext(LeAudioDevice * leAudioDevice,LeAudioContextType context_type) const310 LeAudioDevice* LeAudioDeviceGroup::GetNextDeviceWithAvailableContext(
311         LeAudioDevice* leAudioDevice, LeAudioContextType context_type) const {
312   auto iter =
313           std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&leAudioDevice](auto& d) {
314             if (d.expired()) {
315               return false;
316             } else {
317               return (d.lock()).get() == leAudioDevice;
318             }
319           });
320 
321   /* If reference device not found */
322   if (iter == leAudioDevices_.end()) {
323     return nullptr;
324   }
325 
326   std::advance(iter, 1);
327   /* If reference device is last in group */
328   if (iter == leAudioDevices_.end()) {
329     return nullptr;
330   }
331 
332   iter = std::find_if(iter, leAudioDevices_.end(), [&context_type](auto& d) {
333     if (d.expired()) {
334       return false;
335     } else {
336       return d.lock()->GetAvailableContexts().test(context_type);
337     };
338   });
339 
340   return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
341 }
342 
IsDeviceInTheGroup(LeAudioDevice * leAudioDevice) const343 bool LeAudioDeviceGroup::IsDeviceInTheGroup(LeAudioDevice* leAudioDevice) const {
344   auto iter =
345           std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&leAudioDevice](auto& d) {
346             if (d.expired()) {
347               return false;
348             } else {
349               return (d.lock()).get() == leAudioDevice;
350             }
351           });
352 
353   if ((iter == leAudioDevices_.end()) || (iter->expired())) {
354     return false;
355   }
356 
357   return true;
358 }
359 
IsGroupReadyToCreateStream(void) const360 bool LeAudioDeviceGroup::IsGroupReadyToCreateStream(void) const {
361   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
362     if (d.expired()) {
363       return false;
364     } else {
365       return !(((d.lock()).get())->IsReadyToCreateStream());
366     }
367   });
368 
369   return iter == leAudioDevices_.end();
370 }
371 
IsGroupReadyToSuspendStream(void) const372 bool LeAudioDeviceGroup::IsGroupReadyToSuspendStream(void) const {
373   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
374     if (d.expired()) {
375       return false;
376     } else {
377       return !(((d.lock()).get())->IsReadyToSuspendStream());
378     }
379   });
380 
381   return iter == leAudioDevices_.end();
382 }
383 
HaveAnyActiveDeviceInStreamingState() const384 bool LeAudioDeviceGroup::HaveAnyActiveDeviceInStreamingState() const {
385   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
386     if (d.expired()) {
387       return false;
388     } else {
389       return ((d.lock()).get())->HaveAnyStreamingAses();
390     }
391   });
392 
393   return iter != leAudioDevices_.end();
394 }
395 
HaveAnyActiveDeviceInUnconfiguredState() const396 bool LeAudioDeviceGroup::HaveAnyActiveDeviceInUnconfiguredState() const {
397   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
398     if (d.expired()) {
399       return false;
400     } else {
401       return ((d.lock()).get())->HaveAnyUnconfiguredAses();
402     }
403   });
404 
405   return iter != leAudioDevices_.end();
406 }
407 
HaveAllActiveDevicesAsesTheSameState(AseState state) const408 bool LeAudioDeviceGroup::HaveAllActiveDevicesAsesTheSameState(AseState state) const {
409   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&state](auto& d) {
410     if (d.expired()) {
411       return false;
412     } else {
413       return !(((d.lock()).get())->HaveAllActiveAsesSameState(state));
414     }
415   });
416 
417   return iter == leAudioDevices_.end();
418 }
419 
GetFirstActiveDevice(void) const420 LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDevice(void) const {
421   auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
422     if (d.expired()) {
423       return false;
424     } else {
425       return ((d.lock()).get())->HaveActiveAse();
426     }
427   });
428 
429   if (iter == leAudioDevices_.end() || iter->expired()) {
430     return nullptr;
431   }
432 
433   return (iter->lock()).get();
434 }
435 
GetNextActiveDevice(LeAudioDevice * leAudioDevice) const436 LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice(LeAudioDevice* leAudioDevice) const {
437   auto iter =
438           std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&leAudioDevice](auto& d) {
439             if (d.expired()) {
440               return false;
441             } else {
442               return (d.lock()).get() == leAudioDevice;
443             }
444           });
445 
446   if (iter == leAudioDevices_.end() || std::distance(iter, leAudioDevices_.end()) < 1) {
447     return nullptr;
448   }
449 
450   iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(), [](auto& d) {
451     if (d.expired()) {
452       return false;
453     } else {
454       return ((d.lock()).get())->HaveActiveAse();
455     }
456   });
457 
458   return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
459 }
460 
GetNumOfActiveDevices(void) const461 int LeAudioDeviceGroup::GetNumOfActiveDevices(void) const {
462   int result = 0;
463   for (auto dev = GetFirstActiveDevice(); dev; dev = GetNextActiveDevice(dev)) {
464     result++;
465   }
466   return result;
467 }
468 
GetFirstActiveDeviceByCisAndDataPathState(CisState cis_state,DataPathState data_path_state) const469 LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByCisAndDataPathState(
470         CisState cis_state, DataPathState data_path_state) const {
471   auto iter = std::find_if(
472           leAudioDevices_.begin(), leAudioDevices_.end(), [&data_path_state, &cis_state](auto& d) {
473             if (d.expired()) {
474               return false;
475             }
476 
477             return ((d.lock()).get())
478                            ->GetFirstActiveAseByCisAndDataPathState(cis_state, data_path_state) !=
479                    nullptr;
480           });
481 
482   if (iter == leAudioDevices_.end()) {
483     return nullptr;
484   }
485 
486   return iter->lock().get();
487 }
488 
GetNextActiveDeviceByCisAndDataPathState(LeAudioDevice * leAudioDevice,CisState cis_state,DataPathState data_path_state) const489 LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByCisAndDataPathState(
490         LeAudioDevice* leAudioDevice, CisState cis_state, DataPathState data_path_state) const {
491   auto iter =
492           std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&leAudioDevice](auto& d) {
493             if (d.expired()) {
494               return false;
495             }
496 
497             return d.lock().get() == leAudioDevice;
498           });
499 
500   if (std::distance(iter, leAudioDevices_.end()) < 1) {
501     return nullptr;
502   }
503 
504   iter = std::find_if(
505           std::next(iter, 1), leAudioDevices_.end(), [&cis_state, &data_path_state](auto& d) {
506             if (d.expired()) {
507               return false;
508             }
509 
510             return ((d.lock()).get())
511                            ->GetFirstActiveAseByCisAndDataPathState(cis_state, data_path_state) !=
512                    nullptr;
513           });
514 
515   if (iter == leAudioDevices_.end()) {
516     return nullptr;
517   }
518 
519   return iter->lock().get();
520 }
521 
GetSduInterval(uint8_t direction) const522 uint32_t LeAudioDeviceGroup::GetSduInterval(uint8_t direction) const {
523   for (LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); leAudioDevice != nullptr;
524        leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
525     struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
526     if (!ase) {
527       continue;
528     }
529     return ase->qos_config.sdu_interval;
530   }
531 
532   return 0;
533 }
534 
GetSCA(void) const535 uint8_t LeAudioDeviceGroup::GetSCA(void) const {
536   uint8_t sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm;
537 
538   for (const auto& leAudioDevice : leAudioDevices_) {
539     uint8_t dev_sca = get_btm_client_interface().peer.BTM_GetPeerSCA(leAudioDevice.lock()->address_,
540                                                                      BT_TRANSPORT_LE);
541 
542     /* If we could not read SCA from the peer device or sca is 0,
543      * then there is no reason to continue.
544      */
545     if ((dev_sca == 0xFF) || (dev_sca == 0)) {
546       return 0;
547     }
548 
549     /* The Slaves_Clock_Accuracy parameter shall be the worst-case sleep clock
550      *accuracy of all the slaves that will participate in the CIG.
551      */
552     if (dev_sca < sca) {
553       sca = dev_sca;
554     }
555   }
556 
557   return sca;
558 }
559 
GetPacking(void) const560 uint8_t LeAudioDeviceGroup::GetPacking(void) const {
561   if (!stream_conf.conf) {
562     log::error("No stream configuration has been set.");
563     return bluetooth::hci::kIsoCigPackingSequential;
564   }
565   return stream_conf.conf->packing;
566 }
567 
GetFraming(void) const568 uint8_t LeAudioDeviceGroup::GetFraming(void) const {
569   LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
570   log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
571 
572   do {
573     struct ase* ase = leAudioDevice->GetFirstActiveAse();
574     if (!ase) {
575       continue;
576     }
577 
578     do {
579       if (ase->qos_preferences.supported_framing == types::kFramingUnframedPduUnsupported) {
580         return bluetooth::hci::kIsoCigFramingFramed;
581       }
582     } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
583   } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
584 
585   return bluetooth::hci::kIsoCigFramingUnframed;
586 }
587 
588 /* TODO: Preferred parameter may be other than minimum */
find_max_transport_latency(const LeAudioDeviceGroup * group,uint8_t direction)589 static uint16_t find_max_transport_latency(const LeAudioDeviceGroup* group, uint8_t direction) {
590   uint16_t max_transport_latency = 0;
591 
592   for (LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice(); leAudioDevice != nullptr;
593        leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
594     for (ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); ase != nullptr;
595          ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)) {
596       if (!ase) {
597         break;
598       }
599 
600       if (max_transport_latency == 0) {
601         // first assignment
602         max_transport_latency = ase->qos_config.max_transport_latency;
603       } else if (ase->qos_config.max_transport_latency < max_transport_latency) {
604         if (ase->qos_config.max_transport_latency != 0) {
605           max_transport_latency = ase->qos_config.max_transport_latency;
606         } else {
607           log::warn("Trying to set latency back to 0, ASE ID {}", ase->id);
608         }
609       }
610     }
611   }
612 
613   if (max_transport_latency < types::kMaxTransportLatencyMin) {
614     max_transport_latency = types::kMaxTransportLatencyMin;
615   } else if (max_transport_latency > types::kMaxTransportLatencyMax) {
616     max_transport_latency = types::kMaxTransportLatencyMax;
617   }
618 
619   return max_transport_latency;
620 }
621 
GetMaxTransportLatencyStom(void) const622 uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyStom(void) const {
623   return find_max_transport_latency(this, types::kLeAudioDirectionSource);
624 }
625 
GetMaxTransportLatencyMtos(void) const626 uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyMtos(void) const {
627   return find_max_transport_latency(this, types::kLeAudioDirectionSink);
628 }
629 
GetTransportLatencyUs(uint8_t direction) const630 uint32_t LeAudioDeviceGroup::GetTransportLatencyUs(uint8_t direction) const {
631   if (direction == types::kLeAudioDirectionSink) {
632     return transport_latency_mtos_us_;
633   } else if (direction == types::kLeAudioDirectionSource) {
634     return transport_latency_stom_us_;
635   } else {
636     log::error("invalid direction");
637     return 0;
638   }
639 }
640 
SetTransportLatency(uint8_t direction,uint32_t new_transport_latency_us)641 void LeAudioDeviceGroup::SetTransportLatency(uint8_t direction, uint32_t new_transport_latency_us) {
642   uint32_t* transport_latency_us;
643 
644   if (direction == types::kLeAudioDirectionSink) {
645     transport_latency_us = &transport_latency_mtos_us_;
646   } else if (direction == types::kLeAudioDirectionSource) {
647     transport_latency_us = &transport_latency_stom_us_;
648   } else {
649     log::error("invalid direction");
650     return;
651   }
652 
653   if (*transport_latency_us == new_transport_latency_us) {
654     return;
655   }
656 
657   if ((*transport_latency_us != 0) && (*transport_latency_us != new_transport_latency_us)) {
658     log::warn("Different transport latency for group:  old: {} [us], new: {} [us]",
659               static_cast<int>(*transport_latency_us), static_cast<int>(new_transport_latency_us));
660     return;
661   }
662 
663   log::info("updated group {} transport latency: {} [us]", static_cast<int>(group_id_),
664             static_cast<int>(new_transport_latency_us));
665   *transport_latency_us = new_transport_latency_us;
666 }
667 
GetRtn(uint8_t direction,uint8_t cis_id) const668 uint8_t LeAudioDeviceGroup::GetRtn(uint8_t direction, uint8_t cis_id) const {
669   LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
670   log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
671 
672   do {
673     auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id);
674 
675     if (ases_pair.sink && direction == types::kLeAudioDirectionSink) {
676       return ases_pair.sink->qos_config.retrans_nb;
677     } else if (ases_pair.source && direction == types::kLeAudioDirectionSource) {
678       return ases_pair.source->qos_config.retrans_nb;
679     }
680   } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
681 
682   return 0;
683 }
684 
GetMaxSduSize(uint8_t direction,uint8_t cis_id) const685 uint16_t LeAudioDeviceGroup::GetMaxSduSize(uint8_t direction, uint8_t cis_id) const {
686   LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
687   log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
688 
689   do {
690     auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id);
691 
692     if (ases_pair.sink && direction == types::kLeAudioDirectionSink) {
693       return ases_pair.sink->qos_config.max_sdu_size;
694     } else if (ases_pair.source && direction == types::kLeAudioDirectionSource) {
695       return ases_pair.source->qos_config.max_sdu_size;
696     }
697   } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
698 
699   return 0;
700 }
701 
GetPhyBitmask(uint8_t direction) const702 uint8_t LeAudioDeviceGroup::GetPhyBitmask(uint8_t direction) const {
703   LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
704   log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
705 
706   // local supported PHY's
707   uint8_t phy_bitfield = bluetooth::hci::kIsoCigPhy1M;
708   auto controller = bluetooth::shim::GetController();
709   if (controller && controller->SupportsBle2mPhy()) {
710     phy_bitfield |= bluetooth::hci::kIsoCigPhy2M;
711   }
712 
713   if (!leAudioDevice) {
714     log::error("No active leaudio device for direction?: {}", direction);
715     return phy_bitfield;
716   }
717 
718   do {
719     struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
720     if (!ase) {
721       return phy_bitfield;
722     }
723 
724     do {
725       if (direction == ase->direction) {
726         phy_bitfield &= leAudioDevice->GetPhyBitmask();
727 
728         // A value of 0x00 denotes no preference
729         if (ase->qos_preferences.preferred_phy &&
730             (phy_bitfield & ase->qos_preferences.preferred_phy)) {
731           phy_bitfield &= ase->qos_preferences.preferred_phy;
732           log::debug("Using ASE preferred phy 0x{:02x}", static_cast<int>(phy_bitfield));
733         } else {
734           log::warn(
735                   "ASE preferred 0x{:02x} has nothing common with phy_bitfield "
736                   "0x{:02x}",
737                   static_cast<int>(ase->qos_preferences.preferred_phy),
738                   static_cast<int>(phy_bitfield));
739         }
740       }
741     } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)));
742   } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
743 
744   return phy_bitfield;
745 }
746 
GetTargetPhy(uint8_t direction) const747 uint8_t LeAudioDeviceGroup::GetTargetPhy(uint8_t direction) const {
748   uint8_t phy_bitfield = GetPhyBitmask(direction);
749 
750   // prefer to use 2M if supported
751   if (phy_bitfield & bluetooth::hci::kIsoCigPhy2M) {
752     return types::kTargetPhy2M;
753   } else if (phy_bitfield & bluetooth::hci::kIsoCigPhy1M) {
754     return types::kTargetPhy1M;
755   } else {
756     return 0;
757   }
758 }
759 
GetPresentationDelay(uint32_t * delay,uint8_t direction) const760 bool LeAudioDeviceGroup::GetPresentationDelay(uint32_t* delay, uint8_t direction) const {
761   uint32_t delay_min = 0;
762   uint32_t delay_max = UINT32_MAX;
763   uint32_t preferred_delay_min = delay_min;
764   uint32_t preferred_delay_max = delay_max;
765 
766   LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
767   log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
768 
769   do {
770     struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
771     if (!ase) {
772       continue;  // device has no active ASEs in this direction
773     }
774 
775     do {
776       /* No common range check */
777       if (ase->qos_preferences.pres_delay_min > delay_max ||
778           ase->qos_preferences.pres_delay_max < delay_min) {
779         return false;
780       }
781 
782       if (ase->qos_preferences.pres_delay_min > delay_min) {
783         delay_min = ase->qos_preferences.pres_delay_min;
784       }
785       if (ase->qos_preferences.pres_delay_max < delay_max) {
786         delay_max = ase->qos_preferences.pres_delay_max;
787       }
788       if (ase->qos_preferences.preferred_pres_delay_min > preferred_delay_min) {
789         preferred_delay_min = ase->qos_preferences.preferred_pres_delay_min;
790       }
791       if (ase->qos_preferences.preferred_pres_delay_max < preferred_delay_max &&
792           ase->qos_preferences.preferred_pres_delay_max != types::kPresDelayNoPreference) {
793         preferred_delay_max = ase->qos_preferences.preferred_pres_delay_max;
794       }
795     } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)));
796   } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
797 
798   if (preferred_delay_min <= preferred_delay_max && preferred_delay_min >= delay_min &&
799       preferred_delay_min <= delay_max) {
800     *delay = preferred_delay_min;
801   } else {
802     *delay = delay_min;
803   }
804 
805   return true;
806 }
807 
GetRemoteDelay(uint8_t direction) const808 uint16_t LeAudioDeviceGroup::GetRemoteDelay(uint8_t direction) const {
809   uint16_t remote_delay_ms = 0;
810   uint32_t presentation_delay;
811 
812   if (!GetFirstActiveDevice() || !GetPresentationDelay(&presentation_delay, direction)) {
813     /* This should never happens at stream request time but to be safe return
814      * some sample value to not break streaming
815      */
816     log::error("No active device available. Default value used.");
817     return 100;
818   }
819 
820   /* us to ms */
821   remote_delay_ms = presentation_delay / 1000;
822   remote_delay_ms += GetTransportLatencyUs(direction) / 1000;
823 
824   return remote_delay_ms;
825 }
826 
827 CodecManager::UnicastConfigurationRequirements
GetAudioSetConfigurationRequirements(types::LeAudioContextType ctx_type) const828 LeAudioDeviceGroup::GetAudioSetConfigurationRequirements(types::LeAudioContextType ctx_type) const {
829   auto new_req = CodecManager::UnicastConfigurationRequirements{
830           .audio_context_type = ctx_type,
831           .flags = CodecManager::Flags::NONE,
832   };
833 
834   bool remote_has_gmap = false;
835 
836   // Define a requirement for each location. Knowing codec specific
837   // capabilities (i.e. multiplexing capability) the config provider can
838   // determine the number of ASEs to activate.
839   for (auto const& weak_dev_ptr : leAudioDevices_) {
840     auto device = weak_dev_ptr.lock();
841     BidirectionalPair<bool> has_location = {false, false};
842 
843     for (auto direction : {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
844       if (!device->audio_locations_.get(direction)) {
845         log::debug("Device {} has no audio allocation for direction: {}", device->address_,
846                    (int)direction);
847         continue;
848       }
849 
850       // Do not put any requirements on the Source if Sink only scenario is used
851       // Note: With the RINGTONE we should already prepare for a call.
852       if ((direction == types::kLeAudioDirectionSource) &&
853           ((types::kLeAudioContextAllRemoteSinkOnly.test(ctx_type) &&
854             (ctx_type != types::LeAudioContextType::RINGTONE)) ||
855            ctx_type == types::LeAudioContextType::UNSPECIFIED)) {
856         log::debug("Skipping the remote source requirements.");
857         continue;
858       }
859 
860       if (device->GetAseCount(direction) == 0) {
861         log::warn("Device {} has no ASEs for direction: {}", device->address_, (int)direction);
862         continue;
863       }
864 
865       if (ctx_type == types::LeAudioContextType::VOICEASSISTANTS ||
866           ctx_type == types::LeAudioContextType::GAME) {
867         // For GAME and VOICE ASSISTANT, ignore direction if it is not supported only on a single
868         // direction.
869         auto group_contexts = GetSupportedContexts(types::kLeAudioDirectionBoth);
870         if (group_contexts.test(ctx_type)) {
871           auto direction_contexs = device->GetSupportedContexts(direction);
872           if (!direction_contexs.test(ctx_type)) {
873             log::warn("Device {} has no {} context support", device->address_,
874                       common::ToString(ctx_type));
875             continue;
876           }
877         }
878       }
879 
880       auto const& dev_locations = device->audio_locations_.get(direction);
881       if (dev_locations == std::nullopt) {
882         log::warn("Device {} has no specified locations for direction: {}", device->address_,
883                   (int)direction);
884       }
885 
886       has_location.get(direction) = true;
887       auto& direction_req = (direction == types::kLeAudioDirectionSink)
888                                     ? new_req.sink_requirements
889                                     : new_req.source_requirements;
890       if (!direction_req) {
891         direction_req = std::vector<
892                 CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements>();
893       }
894 
895       // Pass the audio channel allocation requirement according to TMAP
896       auto locations =
897               dev_locations->value.to_ulong() & (codec_spec_conf::kLeAudioLocationFrontLeft |
898                                                  codec_spec_conf::kLeAudioLocationFrontRight);
899       CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements config_req;
900       config_req.params.Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation,
901                             (uint32_t)locations);
902       if (preferred_config_.get(direction) &&
903           preferred_config_.get(direction)->codec_priority != -1) {
904         config_req.params.Add(
905                 codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
906                 UINT8_TO_VEC_UINT8(codec_spec_conf::SingleSamplingFreqCapability2Config(
907                         preferred_config_.get(direction)->sample_rate)));
908         config_req.params.Add(
909                 codec_spec_conf::kLeAudioLtvTypeFrameDuration,
910                 UINT8_TO_VEC_UINT8(codec_spec_conf::SingleFrameDurationCapability2Config(
911                         preferred_config_.get(direction)->frame_duration)));
912         config_req.params.Add(
913                 codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame,
914                 UINT16_TO_VEC_UINT8(preferred_config_.get(direction)->octets_per_frame));
915       }
916       config_req.target_latency = utils::GetTargetLatencyForAudioContext(ctx_type);
917       log::warn("Device {} pushes requirement, location: {}, direction: {}", device->address_,
918                 (int)locations, (int)direction);
919       direction_req->push_back(std::move(config_req));
920     }
921 
922     // Push sink PACs if there are some sink requirements
923     if (has_location.sink && !device->snk_pacs_.empty()) {
924       if (!new_req.sink_pacs) {
925         new_req.sink_pacs = std::vector<types::acs_ac_record>{};
926       }
927       for (auto const& [_, pac_char] : device->snk_pacs_) {
928         for (auto const& pac_record : pac_char) {
929           new_req.sink_pacs->push_back(pac_record);
930         }
931       }
932     }
933 
934     // Push source PACs if there are some source requirements
935     if (has_location.source && !device->src_pacs_.empty()) {
936       if (!new_req.source_pacs) {
937         new_req.source_pacs = std::vector<types::acs_ac_record>{};
938       }
939       for (auto& [_, pac_char] : device->src_pacs_) {
940         for (auto const& pac_record : pac_char) {
941           new_req.source_pacs->push_back(pac_record);
942         }
943       }
944     }
945 
946     if (device->gmap_client_) {
947       remote_has_gmap = true;
948     }
949   }
950 
951   if ((ctx_type == ::bluetooth::le_audio::types::LeAudioContextType::GAME) &&
952       GmapClient::IsGmapClientEnabled() && GmapServer::IsGmapServerEnabled() && remote_has_gmap) {
953     // Allow asymmetric configurations for the low latency GAME scenarios
954     new_req.flags = CodecManager::Flags(CodecManager::Flags::ALLOW_ASYMMETRIC |
955                                         CodecManager::Flags::LOW_LATENCY);
956     log::debug(
957             "GMAP is enabled. Set asymmetric flag for the GAME audio context configuration "
958             "requests.");
959   } else {
960     log::debug(
961             "GMAP is disabled, remote_has_gmap: {}, gmap_client_enabled: {}, gmap_server_enabled: "
962             "{}",
963             remote_has_gmap, GmapClient::IsGmapClientEnabled(), GmapServer::IsGmapServerEnabled());
964   }
965 
966   return new_req;
967 }
968 
UpdateAudioSetConfigurationCache(LeAudioContextType ctx_type,bool use_preference) const969 bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache(LeAudioContextType ctx_type,
970                                                           bool use_preference) const {
971   auto requirements = GetAudioSetConfigurationRequirements(ctx_type);
972   auto new_conf = CodecManager::GetInstance()->GetCodecConfig(
973           requirements, std::bind(&LeAudioDeviceGroup::FindFirstSupportedConfiguration, this,
974                                   std::placeholders::_1, std::placeholders::_2, use_preference));
975   auto update_config = true;
976 
977   auto& cached_map = use_preference ? context_to_preferred_configuration_cache_map_
978                                     : context_to_configuration_cache_map_;
979 
980   if (cached_map.count(ctx_type) != 0) {
981     auto& [is_valid, existing_conf] = cached_map.at(ctx_type);
982     update_config = (new_conf.get() != existing_conf.get());
983     /* Just mark it as still valid */
984     if (!update_config && !is_valid) {
985       cached_map.at(ctx_type).first = true;
986       return false;
987     }
988   }
989 
990   if (update_config) {
991     log::info("config: {} -> {}, use_preference: {}", ToHexString(ctx_type),
992               (new_conf ? new_conf->name.c_str() : "(none)"), use_preference);
993     cached_map.erase(ctx_type);
994     if (new_conf) {
995       cached_map.insert(std::make_pair(ctx_type, std::make_pair(true, std::move(new_conf))));
996     }
997   }
998 
999   return update_config;
1000 }
1001 
SetPreferredAudioSetConfiguration(const bluetooth::le_audio::btle_audio_codec_config_t & input_codec_config,const bluetooth::le_audio::btle_audio_codec_config_t & output_codec_config) const1002 bool LeAudioDeviceGroup::SetPreferredAudioSetConfiguration(
1003         const bluetooth::le_audio::btle_audio_codec_config_t& input_codec_config,
1004         const bluetooth::le_audio::btle_audio_codec_config_t& output_codec_config) const {
1005   if (input_codec_config.codec_priority == -1 || output_codec_config.codec_priority == -1) {
1006     log::info("Clear codec config");
1007     ResetPreferredAudioSetConfiguration();
1008     return true;
1009   }
1010 
1011   preferred_config_.sink = std::make_unique<btle_audio_codec_config_t>(output_codec_config);
1012   preferred_config_.source = std::make_unique<btle_audio_codec_config_t>(input_codec_config);
1013 
1014   bool is_updated = false;
1015 
1016   for (LeAudioContextType ctx_type : types::kLeAudioContextAllTypesArray) {
1017     is_updated |= UpdateAudioSetConfigurationCache(ctx_type, true);
1018   }
1019 
1020   return is_updated;
1021 }
1022 
IsUsingPreferredAudioSetConfiguration(const LeAudioContextType & context_type) const1023 bool LeAudioDeviceGroup::IsUsingPreferredAudioSetConfiguration(
1024         const LeAudioContextType& context_type) const {
1025   if (!preferred_config_.sink || !preferred_config_.source) {
1026     log::assert_that(!preferred_config_.sink && !preferred_config_.source,
1027                      "Preferred config should be null for both direction");
1028     return false;
1029   }
1030 
1031   if (preferred_config_.sink->codec_priority == -1 ||
1032       preferred_config_.source->codec_priority == -1) {
1033     return false;
1034   }
1035 
1036   return GetPreferredConfiguration(context_type).get();
1037 }
1038 
ResetPreferredAudioSetConfiguration(void) const1039 void LeAudioDeviceGroup::ResetPreferredAudioSetConfiguration(void) const {
1040   log::info("Reset preferred configuration cached for all cotexts.");
1041   context_to_preferred_configuration_cache_map_.clear();
1042   preferred_config_.sink = nullptr;
1043   preferred_config_.source = nullptr;
1044 }
1045 
InvalidateCachedConfigurations(void)1046 void LeAudioDeviceGroup::InvalidateCachedConfigurations(void) {
1047   log::info("Group id: {}", group_id_);
1048   context_to_configuration_cache_map_.clear();
1049   context_to_preferred_configuration_cache_map_.clear();
1050 }
1051 
GetLatestAvailableContexts() const1052 types::BidirectionalPair<AudioContexts> LeAudioDeviceGroup::GetLatestAvailableContexts() const {
1053   types::BidirectionalPair<AudioContexts> contexts;
1054   for (const auto& device : leAudioDevices_) {
1055     auto shared_ptr = device.lock();
1056     if (shared_ptr && shared_ptr->GetConnectionState() == DeviceConnectState::CONNECTED) {
1057       contexts.sink |= shared_ptr->GetAvailableContexts(types::kLeAudioDirectionSink);
1058       contexts.source |= shared_ptr->GetAvailableContexts(types::kLeAudioDirectionSource);
1059     }
1060   }
1061   return contexts;
1062 }
1063 
ReloadAudioLocations(void)1064 bool LeAudioDeviceGroup::ReloadAudioLocations(void) {
1065   types::BidirectionalPair<std::optional<AudioLocations>> updated_audio_locations = {
1066           .sink = std::nullopt, .source = std::nullopt};
1067 
1068   for (const auto& device_locked : leAudioDevices_) {
1069     auto device = device_locked.lock();
1070     if (device && device->GetConnectionState() == DeviceConnectState::CONNECTED) {
1071       if (device->audio_locations_.sink) {
1072         updated_audio_locations.sink =
1073                 updated_audio_locations.sink.value_or(0) | device->audio_locations_.sink->value;
1074       }
1075       if (device->audio_locations_.source) {
1076         updated_audio_locations.source =
1077                 updated_audio_locations.source.value_or(0) | device->audio_locations_.source->value;
1078       }
1079     }
1080   }
1081 
1082   /* Nothing has changed */
1083   if (updated_audio_locations == audio_locations_) {
1084     return false;
1085   }
1086 
1087   audio_locations_ = updated_audio_locations;
1088   return true;
1089 }
1090 
ReloadAudioDirections(void)1091 bool LeAudioDeviceGroup::ReloadAudioDirections(void) {
1092   uint8_t updated_audio_directions = 0x00;
1093 
1094   for (const auto& device : leAudioDevices_) {
1095     if (device.expired() ||
1096         (device.lock().get()->GetConnectionState() != DeviceConnectState::CONNECTED)) {
1097       continue;
1098     }
1099     updated_audio_directions |= device.lock().get()->audio_directions_;
1100   }
1101 
1102   /* Nothing has changed */
1103   if (updated_audio_directions == audio_directions_) {
1104     return false;
1105   }
1106 
1107   audio_directions_ = updated_audio_directions;
1108 
1109   return true;
1110 }
1111 
GetAllSupportedBidirectionalContextTypes(void) const1112 AudioContexts LeAudioDeviceGroup::GetAllSupportedBidirectionalContextTypes(void) const {
1113   auto result = GetSupportedContexts(types::kLeAudioDirectionSink) &
1114                 GetSupportedContexts(types::kLeAudioDirectionSource);
1115 
1116   result &= types::kLeAudioContextAllBidir;
1117 
1118   return result;
1119 }
1120 
GetAllSupportedSingleDirectionOnlyContextTypes(uint8_t remote_direction) const1121 AudioContexts LeAudioDeviceGroup::GetAllSupportedSingleDirectionOnlyContextTypes(
1122         uint8_t remote_direction) const {
1123   AudioContexts result;
1124 
1125   /* Remote device present supported context types on the different directions.
1126    * It might happen that some "single directional" contexts are exposed on both
1127    * directions on the remote side.
1128    * Android takes the decision on the stream configuration based on the contexts therefore
1129    * there is defined list of host bidirectional and host single directional context
1130    * types. This function helps to filter out some missconfigurations on the remote side and return
1131    * single directional context types.
1132    * One of the use cases we want to handle here is is that usually VoiceAssistant and GAME are
1133    * bidirectional but some devices might remove it on purpose from one direction.
1134    */
1135   auto group_single_dir_only_contexts =
1136           GetSupportedContexts(remote_direction) & ~GetAllSupportedBidirectionalContextTypes();
1137 
1138   if (remote_direction == types::kLeAudioDirectionSink) {
1139     auto host_all_sink_contexts =
1140             types::kLeAudioContextAllRemoteSinkOnly | types::kLeAudioContextAllBidir;
1141     result = host_all_sink_contexts & group_single_dir_only_contexts;
1142 
1143   } else {
1144     auto host_all_source_contexts =
1145             types::kLeAudioContextAllRemoteSource | types::kLeAudioContextAllBidir;
1146     result = host_all_source_contexts & group_single_dir_only_contexts;
1147   }
1148 
1149   return result;
1150 }
1151 
IsInTransition(void) const1152 bool LeAudioDeviceGroup::IsInTransition(void) const { return in_transition_; }
1153 
IsStreaming(void) const1154 bool LeAudioDeviceGroup::IsStreaming(void) const {
1155   return current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;
1156 }
1157 
IsReleasingOrIdle(void) const1158 bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const {
1159   /* If target state is IDLE then for sure group is either releasing or idle.
1160    * Otherwise, we have "idle states" - Idle or Configured when caching is
1161    * supported on the remote side. In both cases to check it is to make sure
1162    * group is not in transition.
1163    */
1164   return target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE ||
1165          ((current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE ||
1166            current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) &&
1167           !in_transition_);
1168 }
1169 
IsReleasing(void) const1170 bool LeAudioDeviceGroup::IsReleasing(void) const {
1171   return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) && in_transition_;
1172 }
1173 
IsGroupStreamReady(void) const1174 bool LeAudioDeviceGroup::IsGroupStreamReady(void) const {
1175   bool is_device_ready = false;
1176 
1177   /* All connected devices must be ready */
1178   for (auto& weak : leAudioDevices_) {
1179     auto dev = weak.lock();
1180     if (!dev) {
1181       return false;
1182     }
1183 
1184     /* We are interested here in devices which are connected on profile level
1185      * and devices which are configured (meaning, have actived ASE(s))*/
1186     if (dev->GetConnectionState() == DeviceConnectState::CONNECTED && dev->HaveActiveAse()) {
1187       if (!dev->IsReadyToStream()) {
1188         return false;
1189       }
1190       is_device_ready = true;
1191     }
1192   }
1193   return is_device_ready;
1194 }
1195 
HaveAllCisesDisconnected(void) const1196 bool LeAudioDeviceGroup::HaveAllCisesDisconnected(void) const {
1197   for (auto const dev : leAudioDevices_) {
1198     if (dev.expired()) {
1199       continue;
1200     }
1201     if (dev.lock().get()->HaveAnyCisConnected()) {
1202       return false;
1203     }
1204   }
1205   return true;
1206 }
1207 
GetFirstFreeCisId(CisType cis_type) const1208 uint8_t LeAudioDeviceGroup::CigConfiguration::GetFirstFreeCisId(CisType cis_type) const {
1209   log::info("Group: {}, group_id: {} cis_type: {}", std::format_ptr(group_), group_->group_id_,
1210             static_cast<int>(cis_type));
1211   for (size_t id = 0; id < cises.size(); id++) {
1212     if (cises[id].addr.IsEmpty() && cises[id].type == cis_type) {
1213       return id;
1214     }
1215   }
1216   return kInvalidCisId;
1217 }
1218 
GetGroupSinkStrategy() const1219 types::LeAudioConfigurationStrategy LeAudioDeviceGroup::GetGroupSinkStrategy() const {
1220   /* Update the strategy if not set yet or was invalidated */
1221   if (!strategy_) {
1222     /* Choose the group configuration strategy based on PAC records */
1223     auto strategy_selector = [&, this](uint8_t direction) {
1224       int expected_group_size = Size();
1225 
1226       if (!audio_locations_.get(direction)) {
1227         log::error("No audio locations for direction: {} available in the group", +direction);
1228         return types::LeAudioConfigurationStrategy::RFU;
1229       }
1230 
1231       /* Simple strategy picker */
1232       log::debug("Group {} size {}", group_id_, expected_group_size);
1233       if (expected_group_size > 1) {
1234         return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
1235       }
1236 
1237       /* Check supported audio locations */
1238       auto const& locations = audio_locations_.get(direction).value();
1239 
1240       log::verbose("audio location 0x{:04x}", locations.to_ulong());
1241       if (!(locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft) ||
1242           !(locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight) || locations.none()) {
1243         return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
1244       }
1245 
1246       auto device = GetFirstDevice();
1247       /* Note: Currently, the audio channel counts LTV is only mandatory for
1248        * LC3. */
1249       auto channel_count_bitmap = device->GetSupportedAudioChannelCounts(direction);
1250       log::debug("Supported channel counts for group {} (device {}) is {}", group_id_,
1251                  device->address_, channel_count_bitmap);
1252       if (channel_count_bitmap == 1) {
1253         return types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE;
1254       }
1255 
1256       return types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE;
1257     };
1258     strategy_ = strategy_selector(types::kLeAudioDirectionSink);
1259     if (strategy_ == types::LeAudioConfigurationStrategy::RFU) {
1260       log::warn("Unable to find the proper remote sink strategy. Trying source direction instead");
1261       strategy_ = strategy_selector(types::kLeAudioDirectionSource);
1262     }
1263 
1264     log::info("Group strategy set to: {}", [](types::LeAudioConfigurationStrategy strategy) {
1265       switch (strategy) {
1266         case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1267           return "MONO_ONE_CIS_PER_DEVICE";
1268         case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
1269           return "STEREO_TWO_CISES_PER_DEVICE";
1270         case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
1271           return "STEREO_ONE_CIS_PER_DEVICE";
1272         default:
1273           return "RFU";
1274       }
1275     }(*strategy_));
1276   }
1277   return *strategy_;
1278 }
1279 
GetAseCount(uint8_t direction) const1280 int LeAudioDeviceGroup::GetAseCount(uint8_t direction) const {
1281   int result = 0;
1282   for (const auto& device_iter : leAudioDevices_) {
1283     result += device_iter.lock()->GetAseCount(direction);
1284   }
1285 
1286   return result;
1287 }
1288 
1289 /* Calculate the total number of sink, source and bidirectional CISes required by the CIG,
1290  * for the given configuration audio context.
1291  */
GetCisCount(LeAudioContextType context_type,uint8_t & out_cis_count_bidir,uint8_t & out_cis_count_unidir_sink,uint8_t & out_cis_count_unidir_source) const1292 void LeAudioDeviceGroup::CigConfiguration::GetCisCount(LeAudioContextType context_type,
1293                                                        uint8_t& out_cis_count_bidir,
1294                                                        uint8_t& out_cis_count_unidir_sink,
1295                                                        uint8_t& out_cis_count_unidir_source) const {
1296   auto expected_device_cnt = group_->DesiredSize();
1297   auto avail_group_ase_snk_cnt = group_->GetAseCount(types::kLeAudioDirectionSink);
1298   auto avail_group_ase_src_count = group_->GetAseCount(types::kLeAudioDirectionSource);
1299   auto strategy = group_->GetGroupSinkStrategy();
1300 
1301   bool is_bidirectional = group_->GetAllSupportedBidirectionalContextTypes().test(context_type);
1302   bool is_source_only = !is_bidirectional && group_->GetAllSupportedSingleDirectionOnlyContextTypes(
1303                                                            types::kLeAudioDirectionSource)
1304                                                      .test(context_type);
1305   log::debug(
1306           "{} {}, strategy {}, group avail sink ases: {}, "
1307           "group avail source ases {} "
1308           "expected_device_count {}",
1309           bluetooth::common::ToString(context_type),
1310           is_bidirectional ? "is bidirectional"
1311                            : (is_source_only ? "is source only" : "is sink only"),
1312           static_cast<int>(strategy), avail_group_ase_snk_cnt, avail_group_ase_src_count,
1313           expected_device_cnt);
1314 
1315   switch (strategy) {
1316     case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1317     /* This strategy is for the CSIS topology, e.g. two earbuds which are both
1318      * connected with a Phone
1319      */
1320     case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
1321       /* This strategy is for e.g. the banded headphones */
1322       if (is_bidirectional) {
1323         if ((avail_group_ase_snk_cnt > 0) && (avail_group_ase_src_count) > 0) {
1324           /* Prepare CIG to enable all microphones */
1325           out_cis_count_bidir = expected_device_cnt;
1326         } else {
1327           if (avail_group_ase_snk_cnt > 0) {
1328             out_cis_count_unidir_sink = expected_device_cnt;
1329           } else if (avail_group_ase_src_count > 0) {
1330             out_cis_count_unidir_source = expected_device_cnt;
1331           }
1332         }
1333       } else if (is_source_only) {
1334         out_cis_count_unidir_source = expected_device_cnt;
1335       } else {
1336         out_cis_count_unidir_sink = expected_device_cnt;
1337       }
1338 
1339       break;
1340     case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
1341       /* This strategy is for the old TWS topology. e.g. one earbud connected to
1342        * the Phone but each channel is carried in separate CIS
1343        */
1344       if (is_bidirectional) {
1345         if ((avail_group_ase_snk_cnt > 0) && (avail_group_ase_src_count) > 0) {
1346           /* Prepare CIG to enable all microphones per device */
1347           out_cis_count_bidir = expected_device_cnt;
1348           if (avail_group_ase_src_count > 1) {
1349             out_cis_count_bidir++;
1350           } else {
1351             out_cis_count_unidir_sink = expected_device_cnt;
1352           }
1353         } else {
1354           if (avail_group_ase_snk_cnt > 0) {
1355             out_cis_count_unidir_sink = 2 * expected_device_cnt;
1356           } else if (avail_group_ase_src_count > 0) {
1357             out_cis_count_unidir_source = 2 * expected_device_cnt;
1358           }
1359         }
1360       } else if (is_source_only) {
1361         out_cis_count_unidir_source = 2 * expected_device_cnt;
1362       } else {
1363         out_cis_count_unidir_sink = 2 * expected_device_cnt;
1364       }
1365       break;
1366     case types::LeAudioConfigurationStrategy::RFU:
1367       log::error("Should not happen;");
1368       break;
1369   }
1370 
1371   log::info(
1372           "Required cis count: Bi-Directional: {}, Uni-Directional Sink: {}, "
1373           "Uni-Directional Source: {}",
1374           out_cis_count_bidir, out_cis_count_unidir_sink, out_cis_count_unidir_source);
1375 }
1376 
GenerateCisIds(LeAudioContextType context_type)1377 void LeAudioDeviceGroup::CigConfiguration::GenerateCisIds(LeAudioContextType context_type) {
1378   log::info("Group {}, group_id: {}, context_type: {}", std::format_ptr(group_), group_->group_id_,
1379             bluetooth::common::ToString(context_type));
1380 
1381   if (cises.size() > 0) {
1382     log::info("CIS IDs already generated");
1383     return;
1384   }
1385 
1386   uint8_t cis_count_bidir = 0;
1387   uint8_t cis_count_unidir_sink = 0;
1388   uint8_t cis_count_unidir_source = 0;
1389   GetCisCount(context_type, cis_count_bidir, cis_count_unidir_sink, cis_count_unidir_source);
1390 
1391   uint8_t idx = 0;
1392   while (cis_count_bidir > 0) {
1393     struct bluetooth::le_audio::types::cis cis_entry = {
1394             .id = idx,
1395             .type = CisType::CIS_TYPE_BIDIRECTIONAL,
1396             .conn_handle = 0,
1397             .addr = RawAddress::kEmpty,
1398     };
1399     cises.push_back(cis_entry);
1400     cis_count_bidir--;
1401     idx++;
1402   }
1403 
1404   while (cis_count_unidir_sink > 0) {
1405     struct bluetooth::le_audio::types::cis cis_entry = {
1406             .id = idx,
1407             .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK,
1408             .conn_handle = 0,
1409             .addr = RawAddress::kEmpty,
1410     };
1411     cises.push_back(cis_entry);
1412     cis_count_unidir_sink--;
1413     idx++;
1414   }
1415 
1416   while (cis_count_unidir_source > 0) {
1417     struct bluetooth::le_audio::types::cis cis_entry = {
1418             .id = idx,
1419             .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE,
1420             .conn_handle = 0,
1421             .addr = RawAddress::kEmpty,
1422     };
1423     cises.push_back(cis_entry);
1424     cis_count_unidir_source--;
1425     idx++;
1426   }
1427 }
1428 
AssignCisIds(LeAudioDevice * leAudioDevice)1429 bool LeAudioDeviceGroup::CigConfiguration::AssignCisIds(LeAudioDevice* leAudioDevice) {
1430   log::assert_that(leAudioDevice, "invalid device");
1431   log::info("device: {}", leAudioDevice->address_);
1432 
1433   struct ase* ase = leAudioDevice->GetFirstActiveAse();
1434   if (!ase) {
1435     log::error("Device {} shouldn't be called without an active ASE", leAudioDevice->address_);
1436     return false;
1437   }
1438 
1439   for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) {
1440     uint8_t cis_id = kInvalidCisId;
1441     /* CIS ID already set */
1442     if (ase->cis_id != kInvalidCisId) {
1443       log::info("ASE ID: {}, is already assigned CIS ID: {}, type {}", ase->id, ase->cis_id,
1444                 cises[ase->cis_id].type);
1445       if (!cises[ase->cis_id].addr.IsEmpty()) {
1446         log::info("Bi-Directional CIS already assigned");
1447         continue;
1448       }
1449       /* Reuse existing CIS ID if available*/
1450       cis_id = ase->cis_id;
1451     }
1452 
1453     /* First check if we have bidirectional ASEs. If so, assign same CIS ID.*/
1454     struct ase* matching_bidir_ase = leAudioDevice->GetNextActiveAseWithDifferentDirection(ase);
1455 
1456     for (; matching_bidir_ase != nullptr;
1457          matching_bidir_ase =
1458                  leAudioDevice->GetNextActiveAseWithSameDirection(matching_bidir_ase)) {
1459       if ((matching_bidir_ase->cis_id != kInvalidCisId) && (matching_bidir_ase->cis_id != cis_id)) {
1460         log::info("Bi-Directional CIS is already used. ASE Id: {} cis_id={}",
1461                   matching_bidir_ase->id, matching_bidir_ase->cis_id);
1462         continue;
1463       }
1464       break;
1465     }
1466 
1467     if (matching_bidir_ase) {
1468       if (cis_id == kInvalidCisId) {
1469         cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1470       }
1471 
1472       if (cis_id != kInvalidCisId) {
1473         ase->cis_id = cis_id;
1474         matching_bidir_ase->cis_id = cis_id;
1475         cises[cis_id].addr = leAudioDevice->address_;
1476 
1477         log::info("ASE ID: {} and ASE ID: {}, assigned Bi-Directional CIS ID: {}", ase->id,
1478                   matching_bidir_ase->id, ase->cis_id);
1479         continue;
1480       }
1481 
1482       log::warn(
1483               "ASE ID: {}, unable to get free Bi-Directional CIS ID but maybe "
1484               "thats fine. Try using unidirectional.",
1485               ase->id);
1486     }
1487 
1488     if (ase->direction == types::kLeAudioDirectionSink) {
1489       if (cis_id == kInvalidCisId) {
1490         cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SINK);
1491       }
1492 
1493       if (cis_id == kInvalidCisId) {
1494         log::warn(
1495                 "Unable to get free Uni-Directional Sink CIS ID - maybe there is "
1496                 "bi-directional available");
1497         /* This could happen when scenarios for given context type allows for
1498          * Sink and Source configuration but also only Sink configuration.
1499          */
1500         cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1501         if (cis_id == kInvalidCisId) {
1502           log::error("Unable to get free Bi-Directional CIS ID for Sink ASE");
1503           return false;
1504         }
1505         log::info("ASE ID: {}, assigned Bi-Directional CIS ID: {} for Sink ASE", ase->id, cis_id);
1506       } else {
1507         log::info("ASE ID: {}, assigned Uni-Directional CIS ID: {} for Sink ASE", ase->id, cis_id);
1508       }
1509 
1510       ase->cis_id = cis_id;
1511       cises[cis_id].addr = leAudioDevice->address_;
1512       continue;
1513     }
1514 
1515     /* Source direction */
1516     log::assert_that(ase->direction == types::kLeAudioDirectionSource,
1517                      "Expected Source direction, actual={}", ase->direction);
1518 
1519     if (cis_id == kInvalidCisId) {
1520       cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE);
1521     }
1522 
1523     if (cis_id == kInvalidCisId) {
1524       /* This could happen when scenarios for given context type allows for
1525        * Sink and Source configuration but also only Sink configuration.
1526        */
1527       log::warn(
1528               "Unable to get free Uni-Directional Source CIS ID - maybe there is "
1529               "bi-directional available");
1530       cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1531       if (cis_id == kInvalidCisId) {
1532         log::error("Unable to get free Bi-Directional CIS ID for Source ASE");
1533         return false;
1534       }
1535       log::info("ASE ID: {}, assigned Bi-Directional CIS ID: {} for Source ASE", ase->id, cis_id);
1536     } else {
1537       log::info("ASE ID: {}, assigned Uni-Directional CIS ID: {} for Source ASE", ase->id, cis_id);
1538     }
1539 
1540     ase->cis_id = cis_id;
1541     cises[cis_id].addr = leAudioDevice->address_;
1542   }
1543 
1544   return true;
1545 }
1546 
AssignCisConnHandles(const std::vector<uint16_t> & conn_handles)1547 void LeAudioDeviceGroup::CigConfiguration::AssignCisConnHandles(
1548         const std::vector<uint16_t>& conn_handles) {
1549   log::info("num of cis handles {}", static_cast<int>(conn_handles.size()));
1550   for (size_t i = 0; i < cises.size(); i++) {
1551     cises[i].conn_handle = conn_handles[i];
1552     log::info("assigning cis[{}] conn_handle: {}", cises[i].id, cises[i].conn_handle);
1553   }
1554 }
1555 
AssignCisConnHandlesToAses(LeAudioDevice * leAudioDevice)1556 void LeAudioDeviceGroup::AssignCisConnHandlesToAses(LeAudioDevice* leAudioDevice) {
1557   log::assert_that(leAudioDevice, "Invalid device");
1558   log::info("group: {}, group_id: {}, device: {}", std::format_ptr(this), group_id_,
1559             leAudioDevice->address_);
1560 
1561   /* Assign all CIS connection handles to ases */
1562   struct bluetooth::le_audio::types::ase* ase =
1563           leAudioDevice->GetFirstActiveAseByCisAndDataPathState(CisState::IDLE,
1564                                                                 DataPathState::IDLE);
1565   if (!ase) {
1566     log::warn("No active ASE with Cis and Data path state set to IDLE");
1567     return;
1568   }
1569 
1570   for (; ase != nullptr; ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(
1571                                  CisState::IDLE, DataPathState::IDLE)) {
1572     auto ases_pair = leAudioDevice->GetAsesByCisId(ase->cis_id);
1573 
1574     if (ases_pair.sink && ases_pair.sink->active) {
1575       ases_pair.sink->cis_conn_hdl = cig.cises[ase->cis_id].conn_handle;
1576       ases_pair.sink->cis_state = CisState::ASSIGNED;
1577     }
1578     if (ases_pair.source && ases_pair.source->active) {
1579       ases_pair.source->cis_conn_hdl = cig.cises[ase->cis_id].conn_handle;
1580       ases_pair.source->cis_state = CisState::ASSIGNED;
1581     }
1582   }
1583 }
1584 
AssignCisConnHandlesToAses(void)1585 void LeAudioDeviceGroup::AssignCisConnHandlesToAses(void) {
1586   LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
1587   log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
1588 
1589   log::info("Group {}, group_id {}", std::format_ptr(this), group_id_);
1590 
1591   /* Assign all CIS connection handles to ases */
1592   for (; leAudioDevice != nullptr; leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
1593     AssignCisConnHandlesToAses(leAudioDevice);
1594   }
1595 }
1596 
UnassignCis(LeAudioDevice * leAudioDevice,uint16_t conn_handle)1597 void LeAudioDeviceGroup::CigConfiguration::UnassignCis(LeAudioDevice* leAudioDevice,
1598                                                        uint16_t conn_handle) {
1599   log::assert_that(leAudioDevice, "Invalid device");
1600 
1601   log::info("Group {}, group_id {}, device: {}, conn_handle: {:#x}", std::format_ptr(group_),
1602             group_->group_id_, leAudioDevice->address_, conn_handle);
1603 
1604   for (struct bluetooth::le_audio::types::cis& cis_entry : cises) {
1605     if (cis_entry.conn_handle == conn_handle && cis_entry.addr == leAudioDevice->address_) {
1606       cis_entry.addr = RawAddress::kEmpty;
1607     }
1608   }
1609 }
1610 
CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,const types::AseConfiguration & conf,uint8_t direction,const LeAudioDevice & device)1611 static bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,
1612                                      const types::AseConfiguration& conf, uint8_t direction,
1613                                      const LeAudioDevice& device) {
1614   if (strategy == types::LeAudioConfigurationStrategy::RFU) {
1615     log::error("Device {}: No valid strategy for direction: {}", device.address_, +direction);
1616     return false;
1617   }
1618 
1619   if (!device.audio_locations_.get(direction)) {
1620     log::error("Device {}: No valid audio locations for direction: {}", device.address_,
1621                +direction);
1622     return false;
1623   }
1624 
1625   /* Check direction and if audio location allows to create more cises to a
1626    * single device.
1627    */
1628   auto const& audio_locations = device.audio_locations_.get(direction)->value;
1629   log::debug("Device {}: strategy: {}, locations: {}", device.address_, (int)strategy,
1630              audio_locations.to_ulong());
1631 
1632   switch (strategy) {
1633     case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1634       return true;
1635     case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
1636       if ((audio_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft) &&
1637           (audio_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight)) {
1638         return true;
1639       } else {
1640         return false;
1641       }
1642     case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: {
1643       if (!(audio_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft) ||
1644           !(audio_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight)) {
1645         return false;
1646       }
1647 
1648       auto channel_count_mask = device.GetSupportedAudioChannelCounts(direction);
1649       auto requested_channel_count = conf.codec.GetChannelCountPerIsoStream();
1650       log::debug("Requested channel count: {}, supp. channel counts: 0x{:x}",
1651                  requested_channel_count, channel_count_mask);
1652 
1653       /* Return true if requested channel count is set in the supported channel
1654        * counts. In the channel_count_mask, bit 0 is set when 1 channel is
1655        * supported.
1656        */
1657       return (1 << (requested_channel_count - 1)) & channel_count_mask;
1658     }
1659     default:
1660       return false;
1661   }
1662 
1663   return false;
1664 }
1665 
1666 /* This method check if group support given audio configuration
1667  * requirement for connected devices in the group and available ASEs
1668  * (no matter on the ASE state) and for given context type
1669  */
IsAudioSetConfigurationSupported(const CodecManager::UnicastConfigurationRequirements & requirements,const types::AudioSetConfiguration * audio_set_conf,bool use_preference) const1670 bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported(
1671         const CodecManager::UnicastConfigurationRequirements& requirements,
1672         const types::AudioSetConfiguration* audio_set_conf, bool use_preference) const {
1673   /* TODO For now: set ase if matching with first pac.
1674    * 1) We assume as well that devices will match requirements in order
1675    *    e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
1676    * 2) ASEs should be active only if best (according to priority list) full
1677    *    scenarion will be covered.
1678    * 3) ASEs should be filled according to performance profile.
1679    */
1680   auto required_snk_strategy = GetGroupSinkStrategy();
1681   bool status = false;
1682   for (auto direction : {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
1683     log::debug("Looking for configuration: {} - {}", audio_set_conf->name,
1684                direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
1685     auto const& ase_confs = audio_set_conf->confs.get(direction);
1686     if (ase_confs.empty()) {
1687       log::debug("No configurations for direction {}, skip it.", (int)direction);
1688       continue;
1689     }
1690 
1691     // Verify the direction requirements.
1692     if (direction == types::kLeAudioDirectionSink && requirements.sink_requirements->size() == 0) {
1693       log::debug("There is no requirement for Sink direction.");
1694       return false;
1695     }
1696 
1697     if (direction == types::kLeAudioDirectionSource &&
1698         requirements.source_requirements->size() == 0) {
1699       log::debug("There is no requirement for source direction.");
1700       return false;
1701     }
1702 
1703     // Match with requirement first if we have
1704     if (use_preference) {
1705       auto& direction_req = (direction == types::kLeAudioDirectionSink)
1706                                     ? requirements.sink_requirements
1707                                     : requirements.source_requirements;
1708       if (!direction_req.has_value() || !preferred_config_.get(direction)) {
1709         return false;
1710       }
1711       if (!utils::IsAseConfigMatchedWithPreferredRequirements(
1712                   ase_confs, direction_req.value(),
1713                   codec_spec_conf::SingleChannelCountCapability2Config(
1714                           preferred_config_.get(direction)->channel_count))) {
1715         return false;
1716       }
1717     }
1718 
1719     // In some tests we expect the configuration to be there even when the
1720     // contexts are not supported. Then we might want to configure the device
1721     // but use UNSPECIFIED which is always supported (but can be unavailable)
1722     auto device_cnt = NumOfAvailableForDirection(direction);
1723     if (device_cnt == 0) {
1724       device_cnt = DesiredSize();
1725       if (device_cnt == 0) {
1726         log::error("Device count is 0");
1727         continue;
1728       }
1729     }
1730 
1731     auto const ase_cnt = ase_confs.size();
1732     if (ase_cnt == 0) {
1733       log::error("ASE count is 0");
1734       continue;
1735     }
1736 
1737     uint8_t const max_required_ase_per_dev = ase_cnt / device_cnt + (ase_cnt % device_cnt);
1738 
1739     // Use strategy for the whole group (not only the connected devices)
1740     auto const strategy = utils::GetStrategyForAseConfig(ase_confs, device_cnt);
1741 
1742     log::debug(
1743             "Number of devices: {}, number of ASEs: {},  Max ASE per device: {} "
1744             "config strategy: {}, group strategy: {}",
1745             device_cnt, ase_cnt, max_required_ase_per_dev, static_cast<int>(strategy),
1746             (int)required_snk_strategy);
1747 
1748     if (direction == types::kLeAudioDirectionSink && strategy != required_snk_strategy) {
1749       log::debug("Sink strategy mismatch group!=cfg.entry ({}!={})",
1750                  static_cast<int>(required_snk_strategy), static_cast<int>(strategy));
1751       return false;
1752     }
1753 
1754     uint8_t required_device_cnt = device_cnt;
1755     uint8_t active_ase_cnt = 0;
1756     for (auto* device = GetFirstDevice(); device != nullptr && required_device_cnt > 0;
1757          device = GetNextDevice(device)) {
1758       if (device->ases_.empty()) {
1759         log::error("Device has no ASEs.");
1760         continue;
1761       }
1762 
1763       int needed_ase_per_dev = std::min(static_cast<int>(max_required_ase_per_dev),
1764                                         static_cast<int>(ase_cnt - active_ase_cnt));
1765 
1766       for (auto const& ent : ase_confs) {
1767         // Verify PACS only if this is transparent LTV format
1768         auto const& pacs =
1769                 (direction == types::kLeAudioDirectionSink) ? device->snk_pacs_ : device->src_pacs_;
1770         if (utils::IsCodecUsingLtvFormat(ent.codec.id) &&
1771             !utils::GetConfigurationSupportedPac(pacs, ent.codec)) {
1772           log::debug("Insufficient PAC for {}",
1773                      direction == types::kLeAudioDirectionSink ? "sink" : "source");
1774           continue;
1775         }
1776 
1777         if (!CheckIfStrategySupported(strategy, ent, direction, *device)) {
1778           log::debug("Strategy not supported");
1779           continue;
1780         }
1781         for (auto& ase : device->ases_) {
1782           if (ase.direction != direction) {
1783             continue;
1784           }
1785 
1786           active_ase_cnt++;
1787           needed_ase_per_dev--;
1788 
1789           if (needed_ase_per_dev == 0) {
1790             break;
1791           }
1792         }
1793       }
1794 
1795       if (needed_ase_per_dev > 0) {
1796         log::debug("Not enough ASEs on the device (needs {} more).", needed_ase_per_dev);
1797         return false;
1798       }
1799 
1800       required_device_cnt--;
1801     }
1802 
1803     if (required_device_cnt > 0) {
1804       /* Don't left any active devices if requirements are not met */
1805       log::debug("Could not configure all the devices for direction: {}",
1806                  direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
1807       return false;
1808     }
1809 
1810     // At least one direction can be configured
1811     status = true;
1812   }
1813 
1814   /* when disabling 32k dual mic, for later join case, we need to
1815    * make sure the device is always choosing the config that its
1816    * sampling rate matches with the sampling rate which is used
1817    * when all devices in the group are connected.
1818    */
1819   bool dual_bidirection_swb_supported_ = CodecManager::GetInstance()->IsDualBiDirSwbSupported();
1820   if (DesiredSize() > 1 &&
1821       CodecManager::GetInstance()->CheckCodecConfigIsBiDirSwb(*audio_set_conf)) {
1822     if (!dual_bidirection_swb_supported_) {
1823       return false;
1824     }
1825   }
1826 
1827   if (status) {
1828     log::debug("Chosen ASE Configuration for group: {}, configuration: {}", group_id_,
1829                audio_set_conf->name);
1830   } else {
1831     log::error("Could not configure either direction for group {}", group_id_);
1832   }
1833   return status;
1834 }
1835 
1836 /* This method should choose aproperiate ASEs to be active and set a cached
1837  * configuration for codec and qos.
1838  */
ConfigureAses(const types::AudioSetConfiguration * audio_set_conf,LeAudioContextType context_type,const types::BidirectionalPair<AudioContexts> & metadata_context_types,const types::BidirectionalPair<std::vector<uint8_t>> & ccid_lists)1839 bool LeAudioDeviceGroup::ConfigureAses(
1840         const types::AudioSetConfiguration* audio_set_conf, LeAudioContextType context_type,
1841         const types::BidirectionalPair<AudioContexts>& metadata_context_types,
1842         const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists) {
1843   bool reuse_cis_id = GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
1844 
1845   /* TODO For now: set ase if matching with first pac.
1846    * 1) We assume as well that devices will match requirements in order
1847    *    e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
1848    * 2) ASEs should be active only if best (according to priority list) full
1849    *    scenarion will be covered.
1850    * 3) ASEs should be filled according to performance profile.
1851    */
1852 
1853   // WARNING: This may look like the results stored here are unused, but it
1854   //          actually shares the intermediate values between the multiple
1855   //          configuration calls within the configuration loop.
1856   BidirectionalPair<types::AudioLocations> group_audio_locations_memo = {.sink = 0, .source = 0};
1857 
1858   for (auto direction : {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
1859     auto direction_str = (direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
1860     log::debug("{}: Looking for requirements: {}", direction_str, audio_set_conf->name);
1861 
1862     if (audio_set_conf->confs.get(direction).empty()) {
1863       log::warn("No {} configuration available.", direction_str);
1864       continue;
1865     }
1866 
1867     auto const max_required_device_cnt = NumOfAvailableForDirection(direction);
1868     auto required_device_cnt = max_required_device_cnt;
1869     log::debug("Maximum {} device(s) required for {}", max_required_device_cnt, direction_str);
1870 
1871     uint8_t active_ase_cnt = 0;
1872 
1873     log::debug("Required device count: {}", required_device_cnt);
1874     if (required_device_cnt == 0) {
1875       return false;
1876     }
1877 
1878     std::vector<LeAudioDevice*> configuredDevices;
1879 
1880     auto configuration_closure = [&](LeAudioDevice* dev, LeAudioContextType context_type) -> bool {
1881       /* For the moment, we configure only connected devices and when it is
1882        * ready to stream i.e. All ASEs are discovered and dev is reported as
1883        * connected
1884        */
1885       if (dev->GetConnectionState() != DeviceConnectState::CONNECTED) {
1886         log::warn("Device {}, in the state {}", dev->address_,
1887                   bluetooth::common::ToString(dev->GetConnectionState()));
1888         return false;
1889       }
1890 
1891       if (!dev->GetAvailableContexts().test(context_type)) {
1892         log::debug("Device {} not available for context {}", dev->address_,
1893                    bluetooth::common::ToString(context_type));
1894         return false;
1895       }
1896 
1897       return dev->ConfigureAses(audio_set_conf, max_required_device_cnt, direction, context_type,
1898                                 &active_ase_cnt, group_audio_locations_memo.get(direction),
1899                                 metadata_context_types.get(direction), ccid_lists.get(direction),
1900                                 reuse_cis_id);
1901     };
1902 
1903     auto group_configuration_closure = [&](LeAudioContextType context_type) -> void {
1904       for (const auto& dev_iter : leAudioDevices_) {
1905         auto dev = dev_iter.lock();
1906         if (dev == nullptr) {
1907           continue;
1908         }
1909 
1910         if (std::find(configuredDevices.begin(), configuredDevices.end(), dev.get()) !=
1911             configuredDevices.end()) {
1912           continue;
1913         }
1914 
1915         if (configuration_closure(dev.get(), context_type)) {
1916           configuredDevices.push_back(dev.get());
1917           required_device_cnt--;
1918         }
1919 
1920         if (required_device_cnt == 0) {
1921           break;
1922         }
1923       }
1924     };
1925 
1926     // First use the devices claiming proper support
1927     if (required_device_cnt > 0) {
1928       group_configuration_closure(context_type);
1929     }
1930     // In case some devices do not support this scenario - us them anyway if
1931     // they are required for the scenario - we will not put this context into
1932     // their metadata anyway
1933     if (required_device_cnt > 0) {
1934       group_configuration_closure(LeAudioContextType::UNSPECIFIED);
1935     }
1936 
1937     if (configuredDevices.empty()) {
1938       log::error("could not configure any device");
1939       Deactivate();
1940       return false;
1941     }
1942 
1943     log::info("Configured {}/{}", configuredDevices.size(), max_required_device_cnt);
1944   }
1945 
1946   log::info("Choosed ASE Configuration for group: {}, configuration: {}", group_id_,
1947             audio_set_conf->name);
1948 
1949   configuration_context_type_ = context_type;
1950   SetMetadataContexts(metadata_context_types);
1951   return true;
1952 }
1953 
GetCachedConfiguration(LeAudioContextType context_type) const1954 std::shared_ptr<const types::AudioSetConfiguration> LeAudioDeviceGroup::GetCachedConfiguration(
1955         LeAudioContextType context_type) const {
1956   if (context_to_configuration_cache_map_.count(context_type) != 0) {
1957     return context_to_configuration_cache_map_.at(context_type).second;
1958   }
1959   return nullptr;
1960 }
1961 
1962 std::shared_ptr<const types::AudioSetConfiguration>
GetCachedPreferredConfiguration(LeAudioContextType context_type) const1963 LeAudioDeviceGroup::GetCachedPreferredConfiguration(LeAudioContextType context_type) const {
1964   if (context_to_preferred_configuration_cache_map_.count(context_type) != 0) {
1965     return context_to_preferred_configuration_cache_map_.at(context_type).second;
1966   }
1967   return nullptr;
1968 }
1969 
GetActiveConfiguration(void) const1970 std::shared_ptr<const types::AudioSetConfiguration> LeAudioDeviceGroup::GetActiveConfiguration(
1971         void) const {
1972   return IsUsingPreferredAudioSetConfiguration(configuration_context_type_)
1973                  ? GetCachedPreferredConfiguration(configuration_context_type_)
1974                  : GetCachedConfiguration(configuration_context_type_);
1975 }
1976 
GetConfiguration(LeAudioContextType context_type) const1977 std::shared_ptr<const types::AudioSetConfiguration> LeAudioDeviceGroup::GetConfiguration(
1978         LeAudioContextType context_type) const {
1979   if (context_type == LeAudioContextType::UNINITIALIZED) {
1980     return nullptr;
1981   }
1982 
1983   if (IsUsingPreferredAudioSetConfiguration(context_type)) {
1984     log::debug("Using preferred codec config: {}", common::ToString(context_type));
1985     return GetCachedPreferredConfiguration(context_type);
1986   }
1987 
1988   const types::AudioSetConfiguration* conf = nullptr;
1989   bool is_valid = false;
1990 
1991   /* Refresh the cache if there is no valid configuration */
1992   if (context_to_configuration_cache_map_.count(context_type) != 0) {
1993     auto& valid_config_pair = context_to_configuration_cache_map_.at(context_type);
1994     is_valid = valid_config_pair.first;
1995     conf = valid_config_pair.second.get();
1996   }
1997   if (!is_valid || (conf == nullptr)) {
1998     UpdateAudioSetConfigurationCache(context_type);
1999   }
2000 
2001   return GetCachedConfiguration(context_type);
2002 }
2003 
GetPreferredConfiguration(LeAudioContextType context_type) const2004 std::shared_ptr<const types::AudioSetConfiguration> LeAudioDeviceGroup::GetPreferredConfiguration(
2005         LeAudioContextType context_type) const {
2006   if (context_type == LeAudioContextType::UNINITIALIZED) {
2007     return nullptr;
2008   }
2009 
2010   const types::AudioSetConfiguration* conf = nullptr;
2011   bool is_valid = false;
2012 
2013   if (context_to_preferred_configuration_cache_map_.count(context_type) != 0) {
2014     auto& valid_config_pair = context_to_preferred_configuration_cache_map_.at(context_type);
2015     is_valid = valid_config_pair.first;
2016     conf = valid_config_pair.second.get();
2017   }
2018   if (!is_valid || conf == nullptr) {
2019     UpdateAudioSetConfigurationCache(context_type, true);
2020   }
2021 
2022   return GetCachedPreferredConfiguration(context_type);
2023 }
2024 
GetAudioSessionCodecConfigForDirection(LeAudioContextType context_type,uint8_t direction) const2025 LeAudioCodecConfiguration LeAudioDeviceGroup::GetAudioSessionCodecConfigForDirection(
2026         LeAudioContextType context_type, uint8_t direction) const {
2027   auto audio_set_conf = GetConfiguration(context_type);
2028   if (!audio_set_conf) {
2029     return {0, 0, 0, 0};
2030   }
2031 
2032   auto group_config = utils::GetAudioSessionCodecConfigFromAudioSetConfiguration(
2033           *audio_set_conf.get(), direction);
2034   return group_config;
2035 }
2036 
HasCodecConfigurationForDirection(types::LeAudioContextType context_type,uint8_t direction) const2037 bool LeAudioDeviceGroup::HasCodecConfigurationForDirection(types::LeAudioContextType context_type,
2038                                                            uint8_t direction) const {
2039   auto audio_set_conf = GetConfiguration(context_type);
2040   return audio_set_conf ? !audio_set_conf->confs.get(direction).empty() : false;
2041 }
2042 
IsAudioSetConfigurationAvailable(LeAudioContextType group_context_type)2043 bool LeAudioDeviceGroup::IsAudioSetConfigurationAvailable(LeAudioContextType group_context_type) {
2044   return GetConfiguration(group_context_type) != nullptr;
2045 }
2046 
IsMetadataChanged(const BidirectionalPair<AudioContexts> & context_types,const BidirectionalPair<std::vector<uint8_t>> & ccid_lists) const2047 bool LeAudioDeviceGroup::IsMetadataChanged(
2048         const BidirectionalPair<AudioContexts>& context_types,
2049         const BidirectionalPair<std::vector<uint8_t>>& ccid_lists) const {
2050   for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
2051        leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
2052     if (leAudioDevice->IsMetadataChanged(context_types, ccid_lists)) {
2053       return true;
2054     }
2055   }
2056 
2057   return false;
2058 }
2059 
IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const2060 bool LeAudioDeviceGroup::IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const {
2061   auto& sink_stream_locations = stream_conf.stream_params.sink.stream_config.stream_map;
2062   auto iter =
2063           std::find_if(sink_stream_locations.begin(), sink_stream_locations.end(),
2064                        [cis_conn_hdl](auto& info) { return cis_conn_hdl == info.stream_handle; });
2065 
2066   if (iter != sink_stream_locations.end()) {
2067     return true;
2068   }
2069 
2070   auto& source_stream_locations = stream_conf.stream_params.source.stream_config.stream_map;
2071   iter = std::find_if(source_stream_locations.begin(), source_stream_locations.end(),
2072                       [cis_conn_hdl](auto& info) { return cis_conn_hdl == info.stream_handle; });
2073 
2074   return iter != source_stream_locations.end();
2075 }
2076 
RemoveCisFromStreamIfNeeded(LeAudioDevice * leAudioDevice,uint16_t cis_conn_hdl)2077 void LeAudioDeviceGroup::RemoveCisFromStreamIfNeeded(LeAudioDevice* leAudioDevice,
2078                                                      uint16_t cis_conn_hdl) {
2079   log::info("CIS Connection Handle: {}", cis_conn_hdl);
2080 
2081   if (!IsCisPartOfCurrentStream(cis_conn_hdl)) {
2082     cig.UnassignCis(leAudioDevice, cis_conn_hdl);
2083     return;
2084   }
2085 
2086   /* Cache the old values for comparison */
2087   auto old_sink_channels = stream_conf.stream_params.sink.num_of_channels;
2088   auto old_source_channels = stream_conf.stream_params.source.num_of_channels;
2089 
2090   for (auto dir : {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
2091     auto& params = stream_conf.stream_params.get(dir);
2092     params.stream_config.stream_map.erase(
2093             std::remove_if(params.stream_config.stream_map.begin(),
2094                            params.stream_config.stream_map.end(),
2095                            [leAudioDevice, &cis_conn_hdl, &params, dir](auto& info) {
2096                              if (!cis_conn_hdl) {
2097                                cis_conn_hdl = info.stream_handle;
2098                              }
2099                              auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl);
2100                              if (ases_pair.get(dir) && cis_conn_hdl == info.stream_handle) {
2101                                params.num_of_devices--;
2102                                params.num_of_channels -=
2103                                        ases_pair.get(dir)
2104                                                ->codec_config.channel_count_per_iso_stream;
2105                                params.audio_channel_allocation &= ~info.audio_channel_allocation;
2106                              }
2107                              return ases_pair.get(dir) && cis_conn_hdl == info.stream_handle;
2108                            }),
2109             params.stream_config.stream_map.end());
2110   }
2111 
2112   log::info(
2113           "Sink Number Of Devices: {}, Sink Number Of Channels: {}, Source Number "
2114           "Of Devices: {}, Source Number Of Channels: {}",
2115           stream_conf.stream_params.sink.num_of_devices,
2116           stream_conf.stream_params.sink.num_of_channels,
2117           stream_conf.stream_params.source.num_of_devices,
2118           stream_conf.stream_params.source.num_of_channels);
2119 
2120   cig.UnassignCis(leAudioDevice, cis_conn_hdl);
2121 
2122   if (old_sink_channels > 0) {
2123     if (stream_conf.stream_params.sink.num_of_channels == 0) {
2124       ClearSinksFromConfiguration();
2125     } else if (old_sink_channels > stream_conf.stream_params.sink.num_of_channels) {
2126       CodecManager::GetInstance()->UpdateCisConfiguration(
2127               cig.cises,
2128               stream_conf.stream_params.get(bluetooth::le_audio::types::kLeAudioDirectionSink),
2129               bluetooth::le_audio::types::kLeAudioDirectionSink);
2130     }
2131   }
2132 
2133   if (old_source_channels > 0) {
2134     if (stream_conf.stream_params.source.num_of_channels == 0) {
2135       ClearSourcesFromConfiguration();
2136     } else if (old_source_channels > stream_conf.stream_params.source.num_of_channels) {
2137       CodecManager::GetInstance()->UpdateCisConfiguration(
2138               cig.cises,
2139               stream_conf.stream_params.get(bluetooth::le_audio::types::kLeAudioDirectionSource),
2140               bluetooth::le_audio::types::kLeAudioDirectionSource);
2141     }
2142   }
2143 }
2144 
IsPendingConfiguration(void) const2145 bool LeAudioDeviceGroup::IsPendingConfiguration(void) const {
2146   log::verbose("group {}, is pending: {} ", group_id_, stream_conf.pending_configuration);
2147   return stream_conf.pending_configuration;
2148 }
2149 
SetPendingConfiguration(void)2150 void LeAudioDeviceGroup::SetPendingConfiguration(void) {
2151   log::verbose("group {}, is pending from {} to true", group_id_,
2152                stream_conf.pending_configuration);
2153   stream_conf.pending_configuration = true;
2154 }
2155 
ClearPendingConfiguration(void)2156 void LeAudioDeviceGroup::ClearPendingConfiguration(void) {
2157   log::verbose("group {}, is pending from {} to false", group_id_,
2158                stream_conf.pending_configuration);
2159   stream_conf.pending_configuration = false;
2160 }
2161 
Disable(int gatt_if)2162 void LeAudioDeviceGroup::Disable(int gatt_if) {
2163   is_enabled_ = false;
2164 
2165   for (auto& device_iter : leAudioDevices_) {
2166     if (!device_iter.lock()->autoconnect_flag_) {
2167       continue;
2168     }
2169 
2170     auto connection_state = device_iter.lock()->GetConnectionState();
2171     auto address = device_iter.lock()->address_;
2172 
2173     btif_storage_set_leaudio_autoconnect(address, false);
2174     device_iter.lock()->autoconnect_flag_ = false;
2175 
2176     log::info("Group {} in state {}. Removing {} from background connect", group_id_,
2177               bluetooth::common::ToString(GetState()), address);
2178 
2179     BTA_GATTC_CancelOpen(gatt_if, address, false);
2180 
2181     if (connection_state == DeviceConnectState::CONNECTING_AUTOCONNECT) {
2182       device_iter.lock()->SetConnectionState(DeviceConnectState::DISCONNECTED);
2183     }
2184   }
2185 }
2186 
Enable(int gatt_if,tBTM_BLE_CONN_TYPE reconnection_mode)2187 void LeAudioDeviceGroup::Enable(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode) {
2188   is_enabled_ = true;
2189   for (auto& device_iter : leAudioDevices_) {
2190     if (device_iter.lock()->autoconnect_flag_) {
2191       continue;
2192     }
2193 
2194     auto address = device_iter.lock()->address_;
2195     auto connection_state = device_iter.lock()->GetConnectionState();
2196 
2197     btif_storage_set_leaudio_autoconnect(address, true);
2198     device_iter.lock()->autoconnect_flag_ = true;
2199 
2200     log::info("Group {} in state {}. Adding {} from background connect", group_id_,
2201               bluetooth::common::ToString(GetState()), address);
2202 
2203     if (connection_state == DeviceConnectState::DISCONNECTED) {
2204       BTA_GATTC_Open(gatt_if, address, reconnection_mode, false);
2205       device_iter.lock()->SetConnectionState(DeviceConnectState::CONNECTING_AUTOCONNECT);
2206     }
2207   }
2208 }
2209 
IsEnabled(void) const2210 bool LeAudioDeviceGroup::IsEnabled(void) const { return is_enabled_; }
2211 
AddToAllowListNotConnectedGroupMembers(int gatt_if)2212 void LeAudioDeviceGroup::AddToAllowListNotConnectedGroupMembers(int gatt_if) {
2213   for (const auto& device_iter : leAudioDevices_) {
2214     auto connection_state = device_iter.lock()->GetConnectionState();
2215     if (connection_state == DeviceConnectState::CONNECTED ||
2216         connection_state == DeviceConnectState::CONNECTING_BY_USER ||
2217         connection_state == DeviceConnectState::CONNECTED_BY_USER_GETTING_READY ||
2218         connection_state == DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY) {
2219       continue;
2220     }
2221 
2222     auto address = device_iter.lock()->address_;
2223     log::info("Group {} in state {}. Adding {} to allow list", group_id_,
2224               bluetooth::common::ToString(GetState()), address);
2225 
2226     /* When adding set members to allow list, let use direct connect first.
2227      * When it fails (i.e. device is not advertising), it will go to background
2228      * connect. We are doing that because for background connect, stack is using
2229      * slow scan parameters for connection which might delay connecting
2230      * available members.
2231      */
2232     BTA_GATTC_CancelOpen(gatt_if, address, false);
2233     BTA_GATTC_Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, false);
2234     device_iter.lock()->SetConnectionState(DeviceConnectState::CONNECTING_AUTOCONNECT);
2235   }
2236 }
2237 
ApplyReconnectionMode(int gatt_if,tBTM_BLE_CONN_TYPE reconnection_mode)2238 void LeAudioDeviceGroup::ApplyReconnectionMode(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode) {
2239   for (const auto& device_iter : leAudioDevices_) {
2240     BTA_GATTC_CancelOpen(gatt_if, device_iter.lock()->address_, false);
2241     BTA_GATTC_Open(gatt_if, device_iter.lock()->address_, reconnection_mode, false);
2242     log::info("Group {} in state {}. Adding {} to default reconnection mode", group_id_,
2243               bluetooth::common::ToString(GetState()), device_iter.lock()->address_);
2244     device_iter.lock()->SetConnectionState(DeviceConnectState::CONNECTING_AUTOCONNECT);
2245   }
2246 }
2247 
IsConfiguredForContext(LeAudioContextType context_type) const2248 bool LeAudioDeviceGroup::IsConfiguredForContext(LeAudioContextType context_type) const {
2249   /* Check if all connected group members are configured */
2250   if (GetConfigurationContextType() != context_type) {
2251     return false;
2252   }
2253 
2254   if (!stream_conf.conf) {
2255     return false;
2256   }
2257 
2258   /* Check if used configuration is same as the active one.*/
2259   return stream_conf.conf.get() == GetActiveConfiguration().get();
2260 }
2261 
FindFirstSupportedConfiguration(const CodecManager::UnicastConfigurationRequirements & requirements,const types::AudioSetConfigurations * confs,bool use_preference) const2262 std::unique_ptr<types::AudioSetConfiguration> LeAudioDeviceGroup::FindFirstSupportedConfiguration(
2263         const CodecManager::UnicastConfigurationRequirements& requirements,
2264         const types::AudioSetConfigurations* confs, bool use_preference) const {
2265   log::assert_that(confs != nullptr, "confs should not be null");
2266 
2267   log::debug("context type: {},  number of connected devices: {}",
2268              bluetooth::common::ToString(requirements.audio_context_type), NumOfConnected());
2269 
2270   /* Filter out device set for each end every scenario */
2271   for (const auto& conf : *confs) {
2272     log::assert_that(conf != nullptr, "confs should not be null");
2273     if (IsAudioSetConfigurationSupported(requirements, conf, use_preference)) {
2274       log::debug("found: {}", conf->name);
2275       return std::make_unique<types::AudioSetConfiguration>(*conf);
2276     }
2277   }
2278 
2279   return nullptr;
2280 }
2281 
2282 /* This method should choose aproperiate ASEs to be active and set a cached
2283  * configuration for codec and qos.
2284  */
Configure(LeAudioContextType context_type,const types::BidirectionalPair<AudioContexts> & metadata_context_types,types::BidirectionalPair<std::vector<uint8_t>> ccid_lists)2285 bool LeAudioDeviceGroup::Configure(
2286         LeAudioContextType context_type,
2287         const types::BidirectionalPair<AudioContexts>& metadata_context_types,
2288         types::BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
2289   auto conf = GetConfiguration(context_type);
2290   if (!conf) {
2291     log::error("Requested context type: {} , is in mismatch with cached available contexts",
2292                bluetooth::common::ToString(context_type));
2293     return false;
2294   }
2295 
2296   log::debug("setting context type: {}", bluetooth::common::ToString(context_type));
2297 
2298   if (!ConfigureAses(conf.get(), context_type, metadata_context_types, ccid_lists)) {
2299     log::error(
2300             ", requested context type: {}, is in mismatch with cached available "
2301             "contexts",
2302             bluetooth::common::ToString(context_type));
2303     return false;
2304   }
2305 
2306   /* Store selected configuration at once it is chosen.
2307    * It might happen it will get unavailable in some point of time
2308    */
2309   stream_conf.conf = conf;
2310   return true;
2311 }
2312 
~LeAudioDeviceGroup(void)2313 LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); }
2314 
PrintDebugState(void) const2315 void LeAudioDeviceGroup::PrintDebugState(void) const {
2316   auto active_conf = GetActiveConfiguration();
2317   std::stringstream debug_str;
2318 
2319   debug_str << "\n Groupd id: " << group_id_ << (is_enabled_ ? " enabled" : " disabled")
2320             << ", state: " << bluetooth::common::ToString(GetState())
2321             << ", target state: " << bluetooth::common::ToString(GetTargetState())
2322             << ", cig state: " << bluetooth::common::ToString(cig.GetState())
2323             << ", \n group supported contexts: "
2324             << bluetooth::common::ToString(GetSupportedContexts())
2325             << ", \n group available contexts: "
2326             << bluetooth::common::ToString(GetAvailableContexts())
2327             << ", \n group user allowed contexts: "
2328             << bluetooth::common::ToString(GetAllowedContextMask())
2329             << ", \n configuration context type: "
2330             << bluetooth::common::ToString(GetConfigurationContextType())
2331             << ", \n active configuration name: " << (active_conf ? active_conf->name : " not set");
2332 
2333   if (cig.cises.size() > 0) {
2334     log::info("\n Allocated CISes: {}", static_cast<int>(cig.cises.size()));
2335     for (auto cis : cig.cises) {
2336       log::info("\n cis id: {}, type: {}, conn_handle {}, addr: {}", cis.id, cis.type,
2337                 cis.conn_handle, cis.addr.ToString());
2338     }
2339   }
2340 
2341   if (GetFirstActiveDevice() != nullptr) {
2342     uint32_t sink_delay = 0;
2343     uint32_t source_delay = 0;
2344     GetPresentationDelay(&sink_delay, bluetooth::le_audio::types::kLeAudioDirectionSink);
2345     GetPresentationDelay(&source_delay, bluetooth::le_audio::types::kLeAudioDirectionSource);
2346     auto phy_mtos = GetPhyBitmask(bluetooth::le_audio::types::kLeAudioDirectionSink);
2347     auto phy_stom = GetPhyBitmask(bluetooth::le_audio::types::kLeAudioDirectionSource);
2348     auto max_transport_latency_mtos = GetMaxTransportLatencyMtos();
2349     auto max_transport_latency_stom = GetMaxTransportLatencyStom();
2350     auto sdu_mts = GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSink);
2351     auto sdu_stom = GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSource);
2352 
2353     debug_str << "\n presentation_delay for sink (speaker): " << +sink_delay
2354               << " us, presentation_delay for source (microphone): " << +source_delay
2355               << "us, \n MtoS transport latency:  " << +max_transport_latency_mtos
2356               << ", StoM transport latency: " << +max_transport_latency_stom
2357               << ", \n MtoS Phy: " << loghex(phy_mtos) << ", MtoS sdu: " << loghex(phy_stom)
2358               << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom;
2359   }
2360 
2361   log::info("{}", debug_str.str());
2362 
2363   for (const auto& device_iter : leAudioDevices_) {
2364     device_iter.lock()->PrintDebugState();
2365   }
2366 }
2367 
Dump(std::stringstream & stream,int active_group_id) const2368 void LeAudioDeviceGroup::Dump(std::stringstream& stream, int active_group_id) const {
2369   bool is_active = (group_id_ == active_group_id);
2370   auto active_conf = GetActiveConfiguration();
2371 
2372   stream << "    ■ Group id: " << group_id_ << ", " << (is_enabled_ ? "Enabled" : "Disabled")
2373          << ", " << (is_active ? "Active\n" : "Inactive\n") << "      Current state: " << GetState()
2374          << ",\ttarget state: " << GetTargetState() << ",\tcig state: " << cig.GetState() << "\n"
2375          << "      Group supported contexts: " << GetSupportedContexts() << "\n"
2376          << "      Group available contexts: " << GetAvailableContexts() << "\n"
2377          << "      Group user allowed contexts: " << GetAllowedContextMask() << "\n"
2378          << "      Configuration context type: "
2379          << bluetooth::common::ToString(GetConfigurationContextType()).c_str() << "\n"
2380          << "      Active configuration name:\t" << (active_conf ? active_conf->name : "Not set")
2381          << "\n"
2382          << "      Stream configuration:\t\t"
2383          << (stream_conf.conf != nullptr ? stream_conf.conf->name : "Not set ") << "\n"
2384          << "      Codec ID: " << +(stream_conf.codec_id.coding_format)
2385          << ",\tpending reconfiguration: " << stream_conf.pending_configuration << "\n"
2386          << "      Num of devices:\t" << Size() << " (" << NumOfConnected() << " connected)\n"
2387          << "      Num of sinks:\t" << stream_conf.stream_params.sink.num_of_devices << " ("
2388          << stream_conf.stream_params.sink.stream_config.stream_map.size() << " connected)\n"
2389          << "      Num of sources:\t" << stream_conf.stream_params.source.num_of_devices << " ("
2390          << stream_conf.stream_params.source.stream_config.stream_map.size() << " connected)";
2391 
2392   if (GetFirstActiveDevice() != nullptr) {
2393     uint32_t sink_delay;
2394     if (GetPresentationDelay(&sink_delay, bluetooth::le_audio::types::kLeAudioDirectionSink)) {
2395       stream << "\n      presentation_delay for sink (speaker): " << sink_delay << " us";
2396     }
2397 
2398     uint32_t source_delay;
2399     if (GetPresentationDelay(&source_delay, bluetooth::le_audio::types::kLeAudioDirectionSource)) {
2400       stream << "\n      presentation_delay for source (microphone): " << source_delay << " us";
2401     }
2402   }
2403   stream << "\n";
2404 
2405   stream << "      == CISes (" << static_cast<int>(cig.cises.size()) << "):";
2406   if (cig.cises.size() > 0) {
2407     for (auto cis : cig.cises) {
2408       stream << "\n\t cis id: " << static_cast<int>(cis.id)
2409              << ",\ttype: " << static_cast<int>(cis.type)
2410              << ",\tconn_handle: " << static_cast<int>(cis.conn_handle)
2411              << ",\taddr: " << cis.addr.ToRedactedStringForLogging();
2412     }
2413   }
2414   stream << "\n";
2415 
2416   for (const auto& device_iter : leAudioDevices_) {
2417     device_iter.lock()->Dump(stream);
2418   }
2419 
2420   for (const auto& device_iter : leAudioDevices_) {
2421     device_iter.lock()->DumpPacsDebugState(stream);
2422   }
2423   stream << "\n";
2424 }
2425 
Add(int group_id)2426 LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) {
2427   /* Get first free group id */
2428   if (FindById(group_id)) {
2429     log::error("group already exists, id: 0x{:x}", group_id);
2430     return nullptr;
2431   }
2432 
2433   return (groups_.emplace_back(std::make_unique<LeAudioDeviceGroup>(group_id))).get();
2434 }
2435 
Remove(int group_id)2436 void LeAudioDeviceGroups::Remove(int group_id) {
2437   auto iter = std::find_if(groups_.begin(), groups_.end(),
2438                            [&group_id](auto const& group) { return group->group_id_ == group_id; });
2439 
2440   if (iter == groups_.end()) {
2441     log::error("no such group_id: {}", group_id);
2442     return;
2443   }
2444 
2445   groups_.erase(iter);
2446 }
2447 
FindById(int group_id) const2448 LeAudioDeviceGroup* LeAudioDeviceGroups::FindById(int group_id) const {
2449   auto iter = std::find_if(groups_.begin(), groups_.end(),
2450                            [&group_id](auto const& group) { return group->group_id_ == group_id; });
2451 
2452   return (iter == groups_.end()) ? nullptr : iter->get();
2453 }
2454 
Cleanup(void)2455 void LeAudioDeviceGroups::Cleanup(void) {
2456   for (auto& g : groups_) {
2457     g->Cleanup();
2458   }
2459 
2460   groups_.clear();
2461 }
2462 
Dump(std::stringstream & stream,int active_group_id) const2463 void LeAudioDeviceGroups::Dump(std::stringstream& stream, int active_group_id) const {
2464   /* Dump first active group */
2465   stream << "  == Active Groups:\n";
2466   for (auto& g : groups_) {
2467     if (g->group_id_ == active_group_id) {
2468       g->Dump(stream, active_group_id);
2469       break;
2470     }
2471   }
2472 
2473   /* Dump non active group */
2474   stream << "  == Inactive Groups:\n";
2475   for (auto& g : groups_) {
2476     if (g->group_id_ != active_group_id) {
2477       g->Dump(stream, active_group_id);
2478     }
2479   }
2480 }
2481 
IsAnyInTransition(void) const2482 bool LeAudioDeviceGroups::IsAnyInTransition(void) const {
2483   for (auto& g : groups_) {
2484     if (g->IsInTransition()) {
2485       log::debug("group: {} is in transition", g->group_id_);
2486       return true;
2487     }
2488   }
2489   return false;
2490 }
2491 
Size() const2492 size_t LeAudioDeviceGroups::Size() const { return groups_.size(); }
2493 
GetGroupsIds(void) const2494 std::vector<int> LeAudioDeviceGroups::GetGroupsIds(void) const {
2495   std::vector<int> result;
2496 
2497   for (auto const& group : groups_) {
2498     result.push_back(group->group_id_);
2499   }
2500 
2501   return result;
2502 }
2503 
2504 }  // namespace bluetooth::le_audio
2505