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
23 #include <optional>
24
25 #include "bta/include/bta_gatt_api.h"
26 #include "bta_csis_api.h"
27 #include "btif/include/btif_profile_storage.h"
28 #include "btm_iso_api.h"
29 #include "hci/controller_interface.h"
30 #include "internal_include/bt_trace.h"
31 #include "le_audio/codec_manager.h"
32 #include "le_audio/devices.h"
33 #include "le_audio/le_audio_types.h"
34 #include "le_audio_set_configuration_provider.h"
35 #include "le_audio_utils.h"
36 #include "main/shim/entry.h"
37 #include "metrics_collector.h"
38 #include "os/log.h"
39
40 namespace bluetooth::le_audio {
41
42 using bluetooth::le_audio::types::ase;
43 using types::AseState;
44 using types::AudioContexts;
45 using types::AudioLocations;
46 using types::BidirectionalPair;
47 using types::CisState;
48 using types::CisType;
49 using types::DataPathState;
50 using types::LeAudioContextType;
51 using types::LeAudioCoreCodecConfig;
52
53 /* LeAudioDeviceGroup Class methods implementation */
AddNode(const std::shared_ptr<LeAudioDevice> & leAudioDevice)54 void LeAudioDeviceGroup::AddNode(
55 const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
56 leAudioDevice->group_id_ = group_id_;
57 leAudioDevices_.push_back(std::weak_ptr<LeAudioDevice>(leAudioDevice));
58 MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size());
59 }
60
RemoveNode(const std::shared_ptr<LeAudioDevice> & leAudioDevice)61 void LeAudioDeviceGroup::RemoveNode(
62 const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
63 /* Group information cleaning in the device. */
64 leAudioDevice->group_id_ = bluetooth::groups::kGroupUnknown;
65 for (auto ase : leAudioDevice->ases_) {
66 ase.active = false;
67 ase.cis_conn_hdl = 0;
68 }
69
70 leAudioDevices_.erase(
71 std::remove_if(
72 leAudioDevices_.begin(), leAudioDevices_.end(),
73 [&leAudioDevice](auto& d) { return d.lock() == leAudioDevice; }),
74 leAudioDevices_.end());
75 MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size());
76 }
77
IsEmpty(void) const78 bool LeAudioDeviceGroup::IsEmpty(void) const {
79 return leAudioDevices_.size() == 0;
80 }
81
IsAnyDeviceConnected(void) const82 bool LeAudioDeviceGroup::IsAnyDeviceConnected(void) const {
83 return (NumOfConnected() != 0);
84 }
85
Size(void) const86 int LeAudioDeviceGroup::Size(void) const { return leAudioDevices_.size(); }
87
DesiredSize(void) const88 int LeAudioDeviceGroup::DesiredSize(void) const {
89 int group_size = 0;
90 if (bluetooth::csis::CsisClient::IsCsisClientRunning()) {
91 group_size = bluetooth::csis::CsisClient::Get()->GetDesiredSize(group_id_);
92 }
93
94 return group_size > 0 ? group_size : leAudioDevices_.size();
95 }
96
NumOfConnected() const97 int LeAudioDeviceGroup::NumOfConnected() const {
98 /* return number of connected devices from the set*/
99 return std::count_if(
100 leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& iter) {
101 auto dev = iter.lock();
102 if (dev) {
103 return (dev->conn_id_ != GATT_INVALID_CONN_ID) &&
104 (dev->GetConnectionState() == DeviceConnectState::CONNECTED);
105 }
106 return false;
107 });
108 }
109
NumOfAvailableForDirection(int direction) const110 int LeAudioDeviceGroup::NumOfAvailableForDirection(int direction) const {
111 bool check_ase_count = direction < types::kLeAudioDirectionBoth;
112
113 /* return number of connected devices from the set with supported context */
114 return std::count_if(
115 leAudioDevices_.begin(), leAudioDevices_.end(), [&](auto& iter) {
116 auto dev = iter.lock();
117 if (dev) {
118 if (check_ase_count && (dev->GetAseCount(direction) == 0)) {
119 return false;
120 }
121 return (dev->conn_id_ != GATT_INVALID_CONN_ID) &&
122 (dev->GetConnectionState() == DeviceConnectState::CONNECTED);
123 }
124 return false;
125 });
126 }
127
ClearSinksFromConfiguration(void)128 void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) {
129 log::info("Group {}, group_id {}", fmt::ptr(this), group_id_);
130
131 auto direction = types::kLeAudioDirectionSink;
132 stream_conf.stream_params.get(direction).clear();
133 CodecManager::GetInstance()->ClearCisConfiguration(direction);
134 }
135
ClearSourcesFromConfiguration(void)136 void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) {
137 log::info("Group {}, group_id {}", fmt::ptr(this), group_id_);
138
139 auto direction = types::kLeAudioDirectionSource;
140 stream_conf.stream_params.get(direction).clear();
141 CodecManager::GetInstance()->ClearCisConfiguration(direction);
142 }
143
ClearAllCises(void)144 void LeAudioDeviceGroup::ClearAllCises(void) {
145 log::info("group_id: {}", group_id_);
146 cig.cises.clear();
147 ClearSinksFromConfiguration();
148 ClearSourcesFromConfiguration();
149 }
150
UpdateCisConfiguration(uint8_t direction)151 void LeAudioDeviceGroup::UpdateCisConfiguration(uint8_t direction) {
152 CodecManager::GetInstance()->UpdateCisConfiguration(
153 cig.cises, stream_conf.stream_params.get(direction), direction);
154 }
155
Cleanup(void)156 void LeAudioDeviceGroup::Cleanup(void) {
157 /* Bluetooth is off while streaming - disconnect CISes and remove CIG */
158 if (GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
159 auto& sink_stream_locations =
160 stream_conf.stream_params.sink.stream_locations;
161 auto& source_stream_locations =
162 stream_conf.stream_params.source.stream_locations;
163
164 if (!sink_stream_locations.empty()) {
165 for (const auto kv_pair : sink_stream_locations) {
166 auto cis_handle = kv_pair.first;
167 bluetooth::hci::IsoManager::GetInstance()->DisconnectCis(
168 cis_handle, HCI_ERR_PEER_USER);
169
170 /* Check the other direction if disconnecting bidirectional CIS */
171 if (source_stream_locations.empty()) {
172 continue;
173 }
174 source_stream_locations.erase(
175 std::remove_if(
176 source_stream_locations.begin(), source_stream_locations.end(),
177 [&cis_handle](auto& pair) { return pair.first == cis_handle; }),
178 source_stream_locations.end());
179 }
180 }
181
182 /* Take care of the non-bidirectional CISes */
183 if (!source_stream_locations.empty()) {
184 for (auto [cis_handle, _] : source_stream_locations) {
185 bluetooth::hci::IsoManager::GetInstance()->DisconnectCis(
186 cis_handle, HCI_ERR_PEER_USER);
187 }
188 }
189 }
190
191 /* Note: CIG will stay in the controller. We cannot remove it here, because
192 * Cises are not yet disconnected.
193 * When user start Bluetooth, HCI Reset should remove it
194 */
195
196 leAudioDevices_.clear();
197 ClearAllCises();
198 }
199
Deactivate(void)200 void LeAudioDeviceGroup::Deactivate(void) {
201 for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
202 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
203 for (auto* ase = leAudioDevice->GetFirstActiveAse(); ase;
204 ase = leAudioDevice->GetNextActiveAse(ase)) {
205 ase->active = false;
206 ase->reconfigure = 0;
207 }
208 }
209 }
210
Activate(LeAudioContextType context_type,const BidirectionalPair<AudioContexts> & metadata_context_types,BidirectionalPair<std::vector<uint8_t>> ccid_lists)211 bool LeAudioDeviceGroup::Activate(
212 LeAudioContextType context_type,
213 const BidirectionalPair<AudioContexts>& metadata_context_types,
214 BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
215 bool is_activate = false;
216 for (auto leAudioDevice : leAudioDevices_) {
217 if (leAudioDevice.expired()) continue;
218
219 bool activated = leAudioDevice.lock()->ActivateConfiguredAses(
220 context_type, metadata_context_types, ccid_lists);
221 log::info("Device {} is {}", leAudioDevice.lock().get()->address_,
222 activated ? "activated" : " not activated");
223 if (activated) {
224 if (!cig.AssignCisIds(leAudioDevice.lock().get())) {
225 return false;
226 }
227 is_activate = true;
228 }
229 }
230 return is_activate;
231 }
232
GetSupportedContexts(int direction) const233 AudioContexts LeAudioDeviceGroup::GetSupportedContexts(int direction) const {
234 AudioContexts context;
235 for (auto& device : leAudioDevices_) {
236 auto shared_dev = device.lock();
237 if (shared_dev) {
238 context |= shared_dev->GetSupportedContexts(direction);
239 }
240 }
241 return context;
242 }
243
GetFirstDevice(void) const244 LeAudioDevice* LeAudioDeviceGroup::GetFirstDevice(void) const {
245 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
246 [](auto& iter) { return !iter.expired(); });
247
248 if (iter == leAudioDevices_.end()) return nullptr;
249
250 return (iter->lock()).get();
251 }
252
GetFirstDeviceWithAvailableContext(LeAudioContextType context_type) const253 LeAudioDevice* LeAudioDeviceGroup::GetFirstDeviceWithAvailableContext(
254 LeAudioContextType context_type) const {
255 auto iter = std::find_if(
256 leAudioDevices_.begin(), leAudioDevices_.end(),
257 [&context_type](auto& iter) {
258 if (iter.expired()) return false;
259 return iter.lock()->GetAvailableContexts().test(context_type);
260 });
261
262 if ((iter == leAudioDevices_.end()) || (iter->expired())) return nullptr;
263
264 return (iter->lock()).get();
265 }
266
GetNextDevice(LeAudioDevice * leAudioDevice) const267 LeAudioDevice* LeAudioDeviceGroup::GetNextDevice(
268 LeAudioDevice* leAudioDevice) const {
269 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
270 [&leAudioDevice](auto& d) {
271 if (d.expired())
272 return false;
273 else
274 return (d.lock()).get() == leAudioDevice;
275 });
276
277 /* If reference device not found */
278 if (iter == leAudioDevices_.end()) return nullptr;
279
280 std::advance(iter, 1);
281 /* If reference device is last in group */
282 if (iter == leAudioDevices_.end()) return nullptr;
283
284 if (iter->expired()) return nullptr;
285
286 return (iter->lock()).get();
287 }
288
GetNextDeviceWithAvailableContext(LeAudioDevice * leAudioDevice,LeAudioContextType context_type) const289 LeAudioDevice* LeAudioDeviceGroup::GetNextDeviceWithAvailableContext(
290 LeAudioDevice* leAudioDevice, LeAudioContextType context_type) const {
291 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
292 [&leAudioDevice](auto& d) {
293 if (d.expired())
294 return false;
295 else
296 return (d.lock()).get() == leAudioDevice;
297 });
298
299 /* If reference device not found */
300 if (iter == leAudioDevices_.end()) return nullptr;
301
302 std::advance(iter, 1);
303 /* If reference device is last in group */
304 if (iter == leAudioDevices_.end()) return nullptr;
305
306 iter = std::find_if(iter, leAudioDevices_.end(), [&context_type](auto& d) {
307 if (d.expired())
308 return false;
309 else
310 return d.lock()->GetAvailableContexts().test(context_type);
311 ;
312 });
313
314 return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
315 }
316
IsDeviceInTheGroup(LeAudioDevice * leAudioDevice) const317 bool LeAudioDeviceGroup::IsDeviceInTheGroup(
318 LeAudioDevice* leAudioDevice) const {
319 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
320 [&leAudioDevice](auto& d) {
321 if (d.expired())
322 return false;
323 else
324 return (d.lock()).get() == leAudioDevice;
325 });
326
327 if ((iter == leAudioDevices_.end()) || (iter->expired())) return false;
328
329 return true;
330 }
331
IsGroupReadyToCreateStream(void) const332 bool LeAudioDeviceGroup::IsGroupReadyToCreateStream(void) const {
333 auto iter =
334 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
335 if (d.expired())
336 return false;
337 else
338 return !(((d.lock()).get())->IsReadyToCreateStream());
339 });
340
341 return iter == leAudioDevices_.end();
342 }
343
IsGroupReadyToSuspendStream(void) const344 bool LeAudioDeviceGroup::IsGroupReadyToSuspendStream(void) const {
345 auto iter =
346 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
347 if (d.expired())
348 return false;
349 else
350 return !(((d.lock()).get())->IsReadyToSuspendStream());
351 });
352
353 return iter == leAudioDevices_.end();
354 }
355
HaveAnyActiveDeviceInUnconfiguredState() const356 bool LeAudioDeviceGroup::HaveAnyActiveDeviceInUnconfiguredState() const {
357 auto iter =
358 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
359 if (d.expired())
360 return false;
361 else
362 return (((d.lock()).get())->HaveAnyUnconfiguredAses());
363 });
364
365 return iter != leAudioDevices_.end();
366 }
367
HaveAllActiveDevicesAsesTheSameState(AseState state) const368 bool LeAudioDeviceGroup::HaveAllActiveDevicesAsesTheSameState(
369 AseState state) const {
370 auto iter = std::find_if(
371 leAudioDevices_.begin(), leAudioDevices_.end(), [&state](auto& d) {
372 if (d.expired())
373 return false;
374 else
375 return !(((d.lock()).get())->HaveAllActiveAsesSameState(state));
376 });
377
378 return iter == leAudioDevices_.end();
379 }
380
GetFirstActiveDevice(void) const381 LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDevice(void) const {
382 auto iter =
383 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
384 if (d.expired())
385 return false;
386 else
387 return ((d.lock()).get())->HaveActiveAse();
388 });
389
390 if (iter == leAudioDevices_.end() || iter->expired()) return nullptr;
391
392 return (iter->lock()).get();
393 }
394
GetNextActiveDevice(LeAudioDevice * leAudioDevice) const395 LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice(
396 LeAudioDevice* leAudioDevice) const {
397 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
398 [&leAudioDevice](auto& d) {
399 if (d.expired())
400 return false;
401 else
402 return (d.lock()).get() == leAudioDevice;
403 });
404
405 if (iter == leAudioDevices_.end() ||
406 std::distance(iter, leAudioDevices_.end()) < 1)
407 return nullptr;
408
409 iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(), [](auto& d) {
410 if (d.expired())
411 return false;
412 else
413 return ((d.lock()).get())->HaveActiveAse();
414 });
415
416 return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
417 }
418
GetFirstActiveDeviceByCisAndDataPathState(CisState cis_state,DataPathState data_path_state) const419 LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByCisAndDataPathState(
420 CisState cis_state, DataPathState data_path_state) const {
421 auto iter =
422 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
423 [&data_path_state, &cis_state](auto& d) {
424 if (d.expired()) {
425 return false;
426 }
427
428 return (((d.lock()).get())
429 ->GetFirstActiveAseByCisAndDataPathState(
430 cis_state, data_path_state) != nullptr);
431 });
432
433 if (iter == leAudioDevices_.end()) {
434 return nullptr;
435 }
436
437 return iter->lock().get();
438 }
439
GetNextActiveDeviceByCisAndDataPathState(LeAudioDevice * leAudioDevice,CisState cis_state,DataPathState data_path_state) const440 LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByCisAndDataPathState(
441 LeAudioDevice* leAudioDevice, CisState cis_state,
442 DataPathState data_path_state) const {
443 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
444 [&leAudioDevice](auto& d) {
445 if (d.expired()) {
446 return false;
447 }
448
449 return d.lock().get() == leAudioDevice;
450 });
451
452 if (std::distance(iter, leAudioDevices_.end()) < 1) {
453 return nullptr;
454 }
455
456 iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(),
457 [&cis_state, &data_path_state](auto& d) {
458 if (d.expired()) {
459 return false;
460 }
461
462 return (((d.lock()).get())
463 ->GetFirstActiveAseByCisAndDataPathState(
464 cis_state, data_path_state) != nullptr);
465 });
466
467 if (iter == leAudioDevices_.end()) {
468 return nullptr;
469 }
470
471 return iter->lock().get();
472 }
473
GetSduInterval(uint8_t direction) const474 uint32_t LeAudioDeviceGroup::GetSduInterval(uint8_t direction) const {
475 for (LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
476 leAudioDevice != nullptr;
477 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
478 struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
479 if (!ase) continue;
480 return ase->qos_config.sdu_interval;
481 }
482
483 return 0;
484 }
485
GetSCA(void) const486 uint8_t LeAudioDeviceGroup::GetSCA(void) const {
487 uint8_t sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm;
488
489 for (const auto& leAudioDevice : leAudioDevices_) {
490 uint8_t dev_sca =
491 BTM_GetPeerSCA(leAudioDevice.lock()->address_, BT_TRANSPORT_LE);
492
493 /* If we could not read SCA from the peer device or sca is 0,
494 * then there is no reason to continue.
495 */
496 if ((dev_sca == 0xFF) || (dev_sca == 0)) return 0;
497
498 /* The Slaves_Clock_Accuracy parameter shall be the worst-case sleep clock
499 *accuracy of all the slaves that will participate in the CIG.
500 */
501 if (dev_sca < sca) {
502 sca = dev_sca;
503 }
504 }
505
506 return sca;
507 }
508
GetPacking(void) const509 uint8_t LeAudioDeviceGroup::GetPacking(void) const {
510 if (!stream_conf.conf) {
511 log::error("No stream configuration has been set.");
512 return bluetooth::hci::kIsoCigPackingSequential;
513 }
514 return stream_conf.conf->packing;
515 }
516
GetFraming(void) const517 uint8_t LeAudioDeviceGroup::GetFraming(void) const {
518 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
519 log::assert_that(leAudioDevice,
520 "Shouldn't be called without an active device.");
521
522 do {
523 struct ase* ase = leAudioDevice->GetFirstActiveAse();
524 if (!ase) continue;
525
526 do {
527 if (ase->qos_preferences.supported_framing ==
528 types::kFramingUnframedPduUnsupported)
529 return bluetooth::hci::kIsoCigFramingFramed;
530 } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
531 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
532
533 return bluetooth::hci::kIsoCigFramingUnframed;
534 }
535
536 /* TODO: Preferred parameter may be other than minimum */
find_max_transport_latency(const LeAudioDeviceGroup * group,uint8_t direction)537 static uint16_t find_max_transport_latency(const LeAudioDeviceGroup* group,
538 uint8_t direction) {
539 uint16_t max_transport_latency = 0;
540
541 for (LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
542 leAudioDevice != nullptr;
543 leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
544 for (ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
545 ase != nullptr;
546 ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)) {
547 if (!ase) break;
548
549 if (max_transport_latency == 0) {
550 // first assignment
551 max_transport_latency = ase->qos_config.max_transport_latency;
552 } else if (ase->qos_config.max_transport_latency <
553 max_transport_latency) {
554 if (ase->qos_config.max_transport_latency != 0) {
555 max_transport_latency = ase->qos_config.max_transport_latency;
556 } else {
557 log::warn("Trying to set latency back to 0, ASE ID {}", ase->id);
558 }
559 }
560 }
561 }
562
563 if (max_transport_latency < types::kMaxTransportLatencyMin) {
564 max_transport_latency = types::kMaxTransportLatencyMin;
565 } else if (max_transport_latency > types::kMaxTransportLatencyMax) {
566 max_transport_latency = types::kMaxTransportLatencyMax;
567 }
568
569 return max_transport_latency;
570 }
571
GetMaxTransportLatencyStom(void) const572 uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyStom(void) const {
573 return find_max_transport_latency(this, types::kLeAudioDirectionSource);
574 }
575
GetMaxTransportLatencyMtos(void) const576 uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyMtos(void) const {
577 return find_max_transport_latency(this, types::kLeAudioDirectionSink);
578 }
579
GetTransportLatencyUs(uint8_t direction) const580 uint32_t LeAudioDeviceGroup::GetTransportLatencyUs(uint8_t direction) const {
581 if (direction == types::kLeAudioDirectionSink) {
582 return transport_latency_mtos_us_;
583 } else if (direction == types::kLeAudioDirectionSource) {
584 return transport_latency_stom_us_;
585 } else {
586 log::error("invalid direction");
587 return 0;
588 }
589 }
590
SetTransportLatency(uint8_t direction,uint32_t new_transport_latency_us)591 void LeAudioDeviceGroup::SetTransportLatency(
592 uint8_t direction, uint32_t new_transport_latency_us) {
593 uint32_t* transport_latency_us;
594
595 if (direction == types::kLeAudioDirectionSink) {
596 transport_latency_us = &transport_latency_mtos_us_;
597 } else if (direction == types::kLeAudioDirectionSource) {
598 transport_latency_us = &transport_latency_stom_us_;
599 } else {
600 log::error("invalid direction");
601 return;
602 }
603
604 if (*transport_latency_us == new_transport_latency_us) return;
605
606 if ((*transport_latency_us != 0) &&
607 (*transport_latency_us != new_transport_latency_us)) {
608 log::warn(
609 "Different transport latency for group: old: {} [us], new: {} [us]",
610 static_cast<int>(*transport_latency_us),
611 static_cast<int>(new_transport_latency_us));
612 return;
613 }
614
615 log::info("updated group {} transport latency: {} [us]",
616 static_cast<int>(group_id_),
617 static_cast<int>(new_transport_latency_us));
618 *transport_latency_us = new_transport_latency_us;
619 }
620
GetRtn(uint8_t direction,uint8_t cis_id) const621 uint8_t LeAudioDeviceGroup::GetRtn(uint8_t direction, uint8_t cis_id) const {
622 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
623 log::assert_that(leAudioDevice,
624 "Shouldn't be called without an active device.");
625
626 do {
627 auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id);
628
629 if (ases_pair.sink && direction == types::kLeAudioDirectionSink) {
630 return ases_pair.sink->qos_config.retrans_nb;
631 } else if (ases_pair.source &&
632 direction == types::kLeAudioDirectionSource) {
633 return ases_pair.source->qos_config.retrans_nb;
634 }
635 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
636
637 return 0;
638 }
639
GetMaxSduSize(uint8_t direction,uint8_t cis_id) const640 uint16_t LeAudioDeviceGroup::GetMaxSduSize(uint8_t direction,
641 uint8_t cis_id) const {
642 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
643 log::assert_that(leAudioDevice,
644 "Shouldn't be called without an active device.");
645
646 do {
647 auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id);
648
649 if (ases_pair.sink && direction == types::kLeAudioDirectionSink) {
650 return ases_pair.sink->qos_config.max_sdu_size;
651 } else if (ases_pair.source &&
652 direction == types::kLeAudioDirectionSource) {
653 return ases_pair.source->qos_config.max_sdu_size;
654 }
655 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
656
657 return 0;
658 }
659
GetPhyBitmask(uint8_t direction) const660 uint8_t LeAudioDeviceGroup::GetPhyBitmask(uint8_t direction) const {
661 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
662 log::assert_that(leAudioDevice,
663 "Shouldn't be called without an active device.");
664
665 // local supported PHY's
666 uint8_t phy_bitfield = bluetooth::hci::kIsoCigPhy1M;
667 auto controller = bluetooth::shim::GetController();
668 if (controller && controller->SupportsBle2mPhy())
669 phy_bitfield |= bluetooth::hci::kIsoCigPhy2M;
670
671 if (!leAudioDevice) {
672 log::error("No active leaudio device for direction?: {}", direction);
673 return phy_bitfield;
674 }
675
676 do {
677 struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
678 if (!ase) return phy_bitfield;
679
680 do {
681 if (direction == ase->direction) {
682 phy_bitfield &= leAudioDevice->GetPhyBitmask();
683
684 // A value of 0x00 denotes no preference
685 if (ase->qos_preferences.preferred_phy &&
686 (phy_bitfield & ase->qos_preferences.preferred_phy)) {
687 phy_bitfield &= ase->qos_preferences.preferred_phy;
688 log::debug("Using ASE preferred phy 0x{:02x}",
689 static_cast<int>(phy_bitfield));
690 } else {
691 log::warn(
692 "ASE preferred 0x{:02x} has nothing common with phy_bitfield "
693 "0x{:02x}",
694 static_cast<int>(ase->qos_preferences.preferred_phy),
695 static_cast<int>(phy_bitfield));
696 }
697 }
698 } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)));
699 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
700
701 return phy_bitfield;
702 }
703
GetTargetPhy(uint8_t direction) const704 uint8_t LeAudioDeviceGroup::GetTargetPhy(uint8_t direction) const {
705 uint8_t phy_bitfield = GetPhyBitmask(direction);
706
707 // prefer to use 2M if supported
708 if (phy_bitfield & bluetooth::hci::kIsoCigPhy2M)
709 return types::kTargetPhy2M;
710 else if (phy_bitfield & bluetooth::hci::kIsoCigPhy1M)
711 return types::kTargetPhy1M;
712 else
713 return 0;
714 }
715
GetPresentationDelay(uint32_t * delay,uint8_t direction) const716 bool LeAudioDeviceGroup::GetPresentationDelay(uint32_t* delay,
717 uint8_t direction) const {
718 uint32_t delay_min = 0;
719 uint32_t delay_max = UINT32_MAX;
720 uint32_t preferred_delay_min = delay_min;
721 uint32_t preferred_delay_max = delay_max;
722
723 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
724 log::assert_that(leAudioDevice,
725 "Shouldn't be called without an active device.");
726
727 do {
728 struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
729 if (!ase) continue; // device has no active ASEs in this direction
730
731 do {
732 /* No common range check */
733 if (ase->qos_preferences.pres_delay_min > delay_max ||
734 ase->qos_preferences.pres_delay_max < delay_min)
735 return false;
736
737 if (ase->qos_preferences.pres_delay_min > delay_min)
738 delay_min = ase->qos_preferences.pres_delay_min;
739 if (ase->qos_preferences.pres_delay_max < delay_max)
740 delay_max = ase->qos_preferences.pres_delay_max;
741 if (ase->qos_preferences.preferred_pres_delay_min > preferred_delay_min)
742 preferred_delay_min = ase->qos_preferences.preferred_pres_delay_min;
743 if (ase->qos_preferences.preferred_pres_delay_max < preferred_delay_max &&
744 ase->qos_preferences.preferred_pres_delay_max !=
745 types::kPresDelayNoPreference)
746 preferred_delay_max = ase->qos_preferences.preferred_pres_delay_max;
747 } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)));
748 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
749
750 if (preferred_delay_min <= preferred_delay_max &&
751 preferred_delay_min > delay_min && preferred_delay_min < delay_max) {
752 *delay = preferred_delay_min;
753 } else {
754 *delay = delay_min;
755 }
756
757 return true;
758 }
759
GetRemoteDelay(uint8_t direction) const760 uint16_t LeAudioDeviceGroup::GetRemoteDelay(uint8_t direction) const {
761 uint16_t remote_delay_ms = 0;
762 uint32_t presentation_delay;
763
764 if (!GetFirstActiveDevice() ||
765 !GetPresentationDelay(&presentation_delay, direction)) {
766 /* This should never happens at stream request time but to be safe return
767 * some sample value to not break streaming
768 */
769 log::error("No active device available. Default value used.");
770 return 100;
771 }
772
773 /* us to ms */
774 remote_delay_ms = presentation_delay / 1000;
775 remote_delay_ms += GetTransportLatencyUs(direction) / 1000;
776
777 return remote_delay_ms;
778 }
779
UpdateAudioContextAvailability(void)780 bool LeAudioDeviceGroup::UpdateAudioContextAvailability(void) {
781 log::debug("{}", group_id_);
782 auto old_contexts = GetAvailableContexts();
783 SetAvailableContexts(GetLatestAvailableContexts());
784 return old_contexts != GetAvailableContexts();
785 }
786
787 CodecManager::UnicastConfigurationRequirements
GetAudioSetConfigurationRequirements(types::LeAudioContextType ctx_type) const788 LeAudioDeviceGroup::GetAudioSetConfigurationRequirements(
789 types::LeAudioContextType ctx_type) const {
790 auto new_req = CodecManager::UnicastConfigurationRequirements{
791 .audio_context_type = ctx_type,
792 };
793
794 // Define a requirement for each location. Knowing codec specific
795 // capabilities (i.e. multiplexing capability) the config provider can
796 // determine the number of ASEs to activate.
797 for (auto const& weak_dev_ptr : leAudioDevices_) {
798 auto device = weak_dev_ptr.lock();
799 BidirectionalPair<bool> has_location = {false, false};
800
801 for (auto direction :
802 {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
803 // Do not put any requirements on the Source if Sink only scenario is used
804 // Note: With the RINGTONE we should already prepare for a call.
805 if ((direction == types::kLeAudioDirectionSource) &&
806 ((types::kLeAudioContextAllRemoteSinkOnly.test(ctx_type) &&
807 (ctx_type != types::LeAudioContextType::RINGTONE)) ||
808 ctx_type == types::LeAudioContextType::UNSPECIFIED)) {
809 log::debug("Skipping the remote source requirements.");
810 continue;
811 }
812
813 if (device->GetAseCount(direction) == 0) {
814 log::warn("Device {} has no ASEs for direction: {}", device->address_,
815 (int)direction);
816 continue;
817 }
818
819 auto& dev_locations = (direction == types::kLeAudioDirectionSink)
820 ? device->snk_audio_locations_
821 : device->src_audio_locations_;
822 if (dev_locations.none()) {
823 log::warn("Device {} has no locations for direction: {}",
824 device->address_, (int)direction);
825 continue;
826 }
827
828 has_location.get(direction) = true;
829 auto& direction_req = (direction == types::kLeAudioDirectionSink)
830 ? new_req.sink_requirements
831 : new_req.source_requirements;
832 if (!direction_req) {
833 direction_req =
834 std::vector<CodecManager::UnicastConfigurationRequirements::
835 DeviceDirectionRequirements>();
836 }
837
838 // Pass the audio channel allocation requirement according to TMAP
839 auto locations = dev_locations.to_ulong() &
840 (codec_spec_conf::kLeAudioLocationFrontLeft |
841 codec_spec_conf::kLeAudioLocationFrontRight);
842 CodecManager::UnicastConfigurationRequirements::
843 DeviceDirectionRequirements config_req;
844 config_req.params.Add(
845 codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation,
846 (uint32_t)locations);
847 config_req.target_latency =
848 utils::GetTargetLatencyForAudioContext(ctx_type);
849 log::warn("Device {} pushes requirement, location: {}, direction: {}",
850 device->address_, (int)locations, (int)direction);
851 direction_req->push_back(std::move(config_req));
852 }
853
854 // Push sink PACs if there are some sink requirements
855 if (has_location.sink && !device->snk_pacs_.empty()) {
856 if (!new_req.sink_pacs) {
857 new_req.sink_pacs = std::vector<types::acs_ac_record>{};
858 }
859 for (auto const& [_, pac_char] : device->snk_pacs_) {
860 for (auto const& pac_record : pac_char) {
861 new_req.sink_pacs->push_back(pac_record);
862 }
863 }
864 }
865
866 // Push source PACs if there are some source requirements
867 if (has_location.source && !device->src_pacs_.empty()) {
868 if (!new_req.source_pacs) {
869 new_req.source_pacs = std::vector<types::acs_ac_record>{};
870 }
871 for (auto& [_, pac_char] : device->src_pacs_) {
872 for (auto const& pac_record : pac_char) {
873 new_req.source_pacs->push_back(pac_record);
874 }
875 }
876 }
877 }
878
879 return new_req;
880 }
881
UpdateAudioSetConfigurationCache(LeAudioContextType ctx_type) const882 bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache(
883 LeAudioContextType ctx_type) const {
884 auto requirements = GetAudioSetConfigurationRequirements(ctx_type);
885 auto new_conf = CodecManager::GetInstance()->GetCodecConfig(
886 requirements,
887 std::bind(&LeAudioDeviceGroup::FindFirstSupportedConfiguration, this,
888 std::placeholders::_1, std::placeholders::_2));
889 auto update_config = true;
890
891 if (context_to_configuration_cache_map.count(ctx_type) != 0) {
892 auto& [is_valid, existing_conf] =
893 context_to_configuration_cache_map.at(ctx_type);
894 update_config = (new_conf.get() != existing_conf.get());
895 /* Just mark it as still valid */
896 if (!update_config && !is_valid) {
897 context_to_configuration_cache_map.at(ctx_type).first = true;
898 return false;
899 }
900 }
901
902 if (update_config) {
903 log::info("config: {} -> {}", ToHexString(ctx_type),
904 (new_conf ? new_conf->name.c_str() : "(none)"));
905 context_to_configuration_cache_map.erase(ctx_type);
906 if (new_conf)
907 context_to_configuration_cache_map.insert(
908 std::make_pair(ctx_type, std::make_pair(true, std::move(new_conf))));
909 }
910 return update_config;
911 }
912
InvalidateCachedConfigurations(void)913 void LeAudioDeviceGroup::InvalidateCachedConfigurations(void) {
914 log::info("Group id: {}", group_id_);
915 context_to_configuration_cache_map.clear();
916 }
917
918 types::BidirectionalPair<AudioContexts>
GetLatestAvailableContexts() const919 LeAudioDeviceGroup::GetLatestAvailableContexts() const {
920 types::BidirectionalPair<AudioContexts> contexts;
921 for (const auto& device : leAudioDevices_) {
922 auto shared_ptr = device.lock();
923 if (shared_ptr &&
924 shared_ptr->GetConnectionState() == DeviceConnectState::CONNECTED) {
925 contexts.sink |=
926 shared_ptr->GetAvailableContexts(types::kLeAudioDirectionSink);
927 contexts.source |=
928 shared_ptr->GetAvailableContexts(types::kLeAudioDirectionSource);
929 }
930 }
931 return contexts;
932 }
933
ReloadAudioLocations(void)934 bool LeAudioDeviceGroup::ReloadAudioLocations(void) {
935 AudioLocations updated_snk_audio_locations_ =
936 codec_spec_conf::kLeAudioLocationNotAllowed;
937 AudioLocations updated_src_audio_locations_ =
938 codec_spec_conf::kLeAudioLocationNotAllowed;
939
940 for (const auto& device : leAudioDevices_) {
941 if (device.expired() || (device.lock().get()->GetConnectionState() !=
942 DeviceConnectState::CONNECTED))
943 continue;
944 updated_snk_audio_locations_ |= device.lock().get()->snk_audio_locations_;
945 updated_src_audio_locations_ |= device.lock().get()->src_audio_locations_;
946 }
947
948 /* Nothing has changed */
949 if ((updated_snk_audio_locations_ == snk_audio_locations_) &&
950 (updated_src_audio_locations_ == src_audio_locations_))
951 return false;
952
953 snk_audio_locations_ = updated_snk_audio_locations_;
954 src_audio_locations_ = updated_src_audio_locations_;
955
956 return true;
957 }
958
ReloadAudioDirections(void)959 bool LeAudioDeviceGroup::ReloadAudioDirections(void) {
960 uint8_t updated_audio_directions = 0x00;
961
962 for (const auto& device : leAudioDevices_) {
963 if (device.expired() || (device.lock().get()->GetConnectionState() !=
964 DeviceConnectState::CONNECTED))
965 continue;
966 updated_audio_directions |= device.lock().get()->audio_directions_;
967 }
968
969 /* Nothing has changed */
970 if (updated_audio_directions == audio_directions_) return false;
971
972 audio_directions_ = updated_audio_directions;
973
974 return true;
975 }
976
IsInTransition(void) const977 bool LeAudioDeviceGroup::IsInTransition(void) const { return in_transition_; }
978
IsStreaming(void) const979 bool LeAudioDeviceGroup::IsStreaming(void) const {
980 return current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;
981 }
982
IsReleasingOrIdle(void) const983 bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const {
984 return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) ||
985 (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
986 }
987
IsGroupStreamReady(void) const988 bool LeAudioDeviceGroup::IsGroupStreamReady(void) const {
989 bool is_device_ready = false;
990
991 /* All connected devices must be ready */
992 for (auto& weak : leAudioDevices_) {
993 auto dev = weak.lock();
994 if (!dev) return false;
995
996 /* We are interested here in devices which are connected on profile level
997 * and devices which are configured (meaning, have actived ASE(s))*/
998 if (dev->GetConnectionState() == DeviceConnectState::CONNECTED &&
999 dev->HaveActiveAse()) {
1000 if (!dev->IsReadyToStream()) {
1001 return false;
1002 }
1003 is_device_ready = true;
1004 }
1005 }
1006 return is_device_ready;
1007 }
1008
HaveAllCisesDisconnected(void) const1009 bool LeAudioDeviceGroup::HaveAllCisesDisconnected(void) const {
1010 for (auto const dev : leAudioDevices_) {
1011 if (dev.expired()) continue;
1012 if (dev.lock().get()->HaveAnyCisConnected()) return false;
1013 }
1014 return true;
1015 }
1016
GetFirstFreeCisId(CisType cis_type) const1017 uint8_t LeAudioDeviceGroup::CigConfiguration::GetFirstFreeCisId(
1018 CisType cis_type) const {
1019 log::info("Group: {}, group_id: {} cis_type: {}", fmt::ptr(group_),
1020 group_->group_id_, static_cast<int>(cis_type));
1021 for (size_t id = 0; id < cises.size(); id++) {
1022 if (cises[id].addr.IsEmpty() && cises[id].type == cis_type) {
1023 return id;
1024 }
1025 }
1026 return kInvalidCisId;
1027 }
1028
GetGroupSinkStrategy() const1029 types::LeAudioConfigurationStrategy LeAudioDeviceGroup::GetGroupSinkStrategy()
1030 const {
1031 /* Update the strategy if not set yet or was invalidated */
1032 if (!strategy_) {
1033 /* Choose the group configuration strategy based on PAC records */
1034 strategy_ = [this]() {
1035 int expected_group_size = Size();
1036
1037 /* Simple strategy picker */
1038 log::debug("Group {} size {}", group_id_, expected_group_size);
1039 if (expected_group_size > 1) {
1040 return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
1041 }
1042
1043 log::debug("audio location 0x{:04x}", snk_audio_locations_.to_ulong());
1044 if (!(snk_audio_locations_.to_ulong() &
1045 codec_spec_conf::kLeAudioLocationAnyLeft) ||
1046 !(snk_audio_locations_.to_ulong() &
1047 codec_spec_conf::kLeAudioLocationAnyRight)) {
1048 return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
1049 }
1050
1051 auto device = GetFirstDevice();
1052 /* Note: Currently, the audio channel counts LTV is only mandatory for
1053 * LC3. */
1054 auto channel_count_bitmap =
1055 device->GetSupportedAudioChannelCounts(types::kLeAudioDirectionSink);
1056 log::debug("Supported channel counts for group {} (device {}) is {}",
1057 group_id_, device->address_, channel_count_bitmap);
1058 if (channel_count_bitmap == 1) {
1059 return types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE;
1060 }
1061
1062 return types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE;
1063 }();
1064
1065 log::info(
1066 "Group strategy set to: {}",
1067 [](types::LeAudioConfigurationStrategy strategy) {
1068 switch (strategy) {
1069 case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1070 return "MONO_ONE_CIS_PER_DEVICE";
1071 case types::LeAudioConfigurationStrategy::
1072 STEREO_TWO_CISES_PER_DEVICE:
1073 return "STEREO_TWO_CISES_PER_DEVICE";
1074 case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
1075 return "STEREO_ONE_CIS_PER_DEVICE";
1076 default:
1077 return "RFU";
1078 }
1079 }(*strategy_));
1080 }
1081 return *strategy_;
1082 }
1083
GetAseCount(uint8_t direction) const1084 int LeAudioDeviceGroup::GetAseCount(uint8_t direction) const {
1085 int result = 0;
1086 for (const auto& device_iter : leAudioDevices_) {
1087 result += device_iter.lock()->GetAseCount(direction);
1088 }
1089
1090 return result;
1091 }
1092
GenerateCisIds(LeAudioContextType context_type)1093 void LeAudioDeviceGroup::CigConfiguration::GenerateCisIds(
1094 LeAudioContextType context_type) {
1095 log::info("Group {}, group_id: {}, context_type: {}", fmt::ptr(group_),
1096 group_->group_id_, bluetooth::common::ToString(context_type));
1097
1098 if (cises.size() > 0) {
1099 log::info("CIS IDs already generated");
1100 return;
1101 }
1102
1103 uint8_t cis_count_bidir = 0;
1104 uint8_t cis_count_unidir_sink = 0;
1105 uint8_t cis_count_unidir_source = 0;
1106 int group_size = group_->DesiredSize();
1107
1108 set_configurations::get_cis_count(
1109 context_type, group_size, group_->GetGroupSinkStrategy(),
1110 group_->GetAseCount(types::kLeAudioDirectionSink),
1111 group_->GetAseCount(types::kLeAudioDirectionSource), cis_count_bidir,
1112 cis_count_unidir_sink, cis_count_unidir_source);
1113
1114 uint8_t idx = 0;
1115 while (cis_count_bidir > 0) {
1116 struct bluetooth::le_audio::types::cis cis_entry = {
1117 .id = idx,
1118 .type = CisType::CIS_TYPE_BIDIRECTIONAL,
1119 .conn_handle = 0,
1120 .addr = RawAddress::kEmpty,
1121 };
1122 cises.push_back(cis_entry);
1123 cis_count_bidir--;
1124 idx++;
1125 }
1126
1127 while (cis_count_unidir_sink > 0) {
1128 struct bluetooth::le_audio::types::cis cis_entry = {
1129 .id = idx,
1130 .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK,
1131 .conn_handle = 0,
1132 .addr = RawAddress::kEmpty,
1133 };
1134 cises.push_back(cis_entry);
1135 cis_count_unidir_sink--;
1136 idx++;
1137 }
1138
1139 while (cis_count_unidir_source > 0) {
1140 struct bluetooth::le_audio::types::cis cis_entry = {
1141 .id = idx,
1142 .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE,
1143 .conn_handle = 0,
1144 .addr = RawAddress::kEmpty,
1145 };
1146 cises.push_back(cis_entry);
1147 cis_count_unidir_source--;
1148 idx++;
1149 }
1150 }
1151
AssignCisIds(LeAudioDevice * leAudioDevice)1152 bool LeAudioDeviceGroup::CigConfiguration::AssignCisIds(
1153 LeAudioDevice* leAudioDevice) {
1154 log::assert_that(leAudioDevice, "invalid device");
1155 log::info("device: {}", leAudioDevice->address_);
1156
1157 struct ase* ase = leAudioDevice->GetFirstActiveAse();
1158 if (!ase) {
1159 log::error("Device {} shouldn't be called without an active ASE",
1160 leAudioDevice->address_);
1161 return false;
1162 }
1163
1164 for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) {
1165 uint8_t cis_id = kInvalidCisId;
1166 /* CIS ID already set */
1167 if (ase->cis_id != kInvalidCisId) {
1168 log::info("ASE ID: {}, is already assigned CIS ID: {}, type {}", ase->id,
1169 ase->cis_id, cises[ase->cis_id].type);
1170 if (!cises[ase->cis_id].addr.IsEmpty()) {
1171 log::info("Bi-Directional CIS already assigned");
1172 continue;
1173 }
1174 /* Reuse existing CIS ID if available*/
1175 cis_id = ase->cis_id;
1176 }
1177
1178 /* First check if we have bidirectional ASEs. If so, assign same CIS ID.*/
1179 struct ase* matching_bidir_ase =
1180 leAudioDevice->GetNextActiveAseWithDifferentDirection(ase);
1181
1182 for (; matching_bidir_ase != nullptr;
1183 matching_bidir_ase = leAudioDevice->GetNextActiveAseWithSameDirection(
1184 matching_bidir_ase)) {
1185 if ((matching_bidir_ase->cis_id != kInvalidCisId) &&
1186 (matching_bidir_ase->cis_id != cis_id)) {
1187 log::info("Bi-Directional CIS is already used. ASE Id: {} cis_id={}",
1188 matching_bidir_ase->id, matching_bidir_ase->cis_id);
1189 continue;
1190 }
1191 break;
1192 }
1193
1194 if (matching_bidir_ase) {
1195 if (cis_id == kInvalidCisId) {
1196 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1197 }
1198
1199 if (cis_id != kInvalidCisId) {
1200 ase->cis_id = cis_id;
1201 matching_bidir_ase->cis_id = cis_id;
1202 cises[cis_id].addr = leAudioDevice->address_;
1203
1204 log::info(
1205 "ASE ID: {} and ASE ID: {}, assigned Bi-Directional CIS ID: {}",
1206 ase->id, matching_bidir_ase->id, ase->cis_id);
1207 continue;
1208 }
1209
1210 log::warn(
1211 "ASE ID: {}, unable to get free Bi-Directional CIS ID but maybe "
1212 "thats fine. Try using unidirectional.",
1213 ase->id);
1214 }
1215
1216 if (ase->direction == types::kLeAudioDirectionSink) {
1217 if (cis_id == kInvalidCisId) {
1218 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SINK);
1219 }
1220
1221 if (cis_id == kInvalidCisId) {
1222 log::warn(
1223 "Unable to get free Uni-Directional Sink CIS ID - maybe there is "
1224 "bi-directional available");
1225 /* This could happen when scenarios for given context type allows for
1226 * Sink and Source configuration but also only Sink configuration.
1227 */
1228 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1229 if (cis_id == kInvalidCisId) {
1230 log::error("Unable to get free Uni-Directional Sink CIS ID");
1231 return false;
1232 }
1233 }
1234
1235 ase->cis_id = cis_id;
1236 cises[cis_id].addr = leAudioDevice->address_;
1237 log::info("ASE ID: {}, assigned Uni-Directional Sink CIS ID: {}", ase->id,
1238 ase->cis_id);
1239 continue;
1240 }
1241
1242 /* Source direction */
1243 log::assert_that(ase->direction == types::kLeAudioDirectionSource,
1244 "Expected Source direction, actual={}", ase->direction);
1245
1246 if (cis_id == kInvalidCisId) {
1247 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE);
1248 }
1249
1250 if (cis_id == kInvalidCisId) {
1251 /* This could happen when scenarios for given context type allows for
1252 * Sink and Source configuration but also only Sink configuration.
1253 */
1254 log::warn(
1255 "Unable to get free Uni-Directional Source CIS ID - maybe there is "
1256 "bi-directional available");
1257 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1258 if (cis_id == kInvalidCisId) {
1259 log::error("Unable to get free Uni-Directional Source CIS ID");
1260 return false;
1261 }
1262 }
1263
1264 ase->cis_id = cis_id;
1265 cises[cis_id].addr = leAudioDevice->address_;
1266 log::info("ASE ID: {}, assigned Uni-Directional Source CIS ID: {}", ase->id,
1267 ase->cis_id);
1268 }
1269
1270 return true;
1271 }
1272
AssignCisConnHandles(const std::vector<uint16_t> & conn_handles)1273 void LeAudioDeviceGroup::CigConfiguration::AssignCisConnHandles(
1274 const std::vector<uint16_t>& conn_handles) {
1275 log::info("num of cis handles {}", static_cast<int>(conn_handles.size()));
1276 for (size_t i = 0; i < cises.size(); i++) {
1277 cises[i].conn_handle = conn_handles[i];
1278 log::info("assigning cis[{}] conn_handle: {}", cises[i].id,
1279 cises[i].conn_handle);
1280 }
1281 }
1282
AssignCisConnHandlesToAses(LeAudioDevice * leAudioDevice)1283 void LeAudioDeviceGroup::AssignCisConnHandlesToAses(
1284 LeAudioDevice* leAudioDevice) {
1285 log::assert_that(leAudioDevice, "Invalid device");
1286 log::info("group: {}, group_id: {}, device: {}", fmt::ptr(this), group_id_,
1287 leAudioDevice->address_);
1288
1289 /* Assign all CIS connection handles to ases */
1290 struct bluetooth::le_audio::types::ase* ase =
1291 leAudioDevice->GetFirstActiveAseByCisAndDataPathState(
1292 CisState::IDLE, DataPathState::IDLE);
1293 if (!ase) {
1294 log::warn("No active ASE with Cis and Data path state set to IDLE");
1295 return;
1296 }
1297
1298 for (; ase != nullptr;
1299 ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(
1300 CisState::IDLE, DataPathState::IDLE)) {
1301 auto ases_pair = leAudioDevice->GetAsesByCisId(ase->cis_id);
1302
1303 if (ases_pair.sink && ases_pair.sink->active) {
1304 ases_pair.sink->cis_conn_hdl = cig.cises[ase->cis_id].conn_handle;
1305 ases_pair.sink->cis_state = CisState::ASSIGNED;
1306 }
1307 if (ases_pair.source && ases_pair.source->active) {
1308 ases_pair.source->cis_conn_hdl = cig.cises[ase->cis_id].conn_handle;
1309 ases_pair.source->cis_state = CisState::ASSIGNED;
1310 }
1311 }
1312 }
1313
AssignCisConnHandlesToAses(void)1314 void LeAudioDeviceGroup::AssignCisConnHandlesToAses(void) {
1315 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
1316 log::assert_that(leAudioDevice,
1317 "Shouldn't be called without an active device.");
1318
1319 log::info("Group {}, group_id {}", fmt::ptr(this), group_id_);
1320
1321 /* Assign all CIS connection handles to ases */
1322 for (; leAudioDevice != nullptr;
1323 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
1324 AssignCisConnHandlesToAses(leAudioDevice);
1325 }
1326 }
1327
UnassignCis(LeAudioDevice * leAudioDevice)1328 void LeAudioDeviceGroup::CigConfiguration::UnassignCis(
1329 LeAudioDevice* leAudioDevice) {
1330 log::assert_that(leAudioDevice, "Invalid device");
1331
1332 log::info("Group {}, group_id {}, device: {}", fmt::ptr(group_),
1333 group_->group_id_, leAudioDevice->address_);
1334
1335 for (struct bluetooth::le_audio::types::cis& cis_entry : cises) {
1336 if (cis_entry.addr == leAudioDevice->address_) {
1337 cis_entry.addr = RawAddress::kEmpty;
1338 }
1339 }
1340 }
1341
CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,const set_configurations::AseConfiguration & conf,uint8_t direction,const LeAudioDevice & device)1342 bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,
1343 const set_configurations::AseConfiguration& conf,
1344 uint8_t direction, const LeAudioDevice& device) {
1345 /* Check direction and if audio location allows to create more cises to a
1346 * single device.
1347 */
1348 types::AudioLocations audio_locations =
1349 (direction == types::kLeAudioDirectionSink) ? device.snk_audio_locations_
1350 : device.src_audio_locations_;
1351
1352 log::debug("strategy: {}, locations: {}", (int)strategy,
1353 audio_locations.to_ulong());
1354
1355 switch (strategy) {
1356 case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1357 return audio_locations.any();
1358 case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
1359 if ((audio_locations.to_ulong() &
1360 codec_spec_conf::kLeAudioLocationAnyLeft) &&
1361 (audio_locations.to_ulong() &
1362 codec_spec_conf::kLeAudioLocationAnyRight))
1363 return true;
1364 else
1365 return false;
1366 case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: {
1367 if (!(audio_locations.to_ulong() &
1368 codec_spec_conf::kLeAudioLocationAnyLeft) ||
1369 !(audio_locations.to_ulong() &
1370 codec_spec_conf::kLeAudioLocationAnyRight))
1371 return false;
1372
1373 auto channel_count_mask =
1374 device.GetSupportedAudioChannelCounts(direction);
1375 auto requested_channel_count = conf.codec.GetChannelCountPerIsoStream();
1376 log::debug("Requested channel count: {}, supp. channel counts: 0x{:x}",
1377 requested_channel_count, channel_count_mask);
1378
1379 /* Return true if requested channel count is set in the supported channel
1380 * counts. In the channel_count_mask, bit 0 is set when 1 channel is
1381 * supported.
1382 */
1383 return ((1 << (requested_channel_count - 1)) & channel_count_mask);
1384 }
1385 default:
1386 return false;
1387 }
1388
1389 return false;
1390 }
1391
1392 /* This method check if group support given audio configuration
1393 * requirement for connected devices in the group and available ASEs
1394 * (no matter on the ASE state) and for given context type
1395 */
IsAudioSetConfigurationSupported(const CodecManager::UnicastConfigurationRequirements & requirements,const set_configurations::AudioSetConfiguration * audio_set_conf) const1396 bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported(
1397 const CodecManager::UnicastConfigurationRequirements& requirements,
1398 const set_configurations::AudioSetConfiguration* audio_set_conf) const {
1399 /* TODO For now: set ase if matching with first pac.
1400 * 1) We assume as well that devices will match requirements in order
1401 * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
1402 * 2) ASEs should be active only if best (according to priority list) full
1403 * scenarion will be covered.
1404 * 3) ASEs should be filled according to performance profile.
1405 */
1406 auto required_snk_strategy = GetGroupSinkStrategy();
1407 bool status = false;
1408 for (auto direction :
1409 {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
1410 log::debug("Looking for configuration: {} - {}", audio_set_conf->name,
1411 direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
1412 auto const& ase_confs = audio_set_conf->confs.get(direction);
1413 if (ase_confs.empty()) {
1414 log::debug("No configurations for direction {}, skip it.",
1415 (int)direction);
1416 continue;
1417 }
1418
1419 // In some tests we expect the configuration to be there even when the
1420 // contexts are not supported. Then we might want to configure the device
1421 // but use UNSPECIFIED which is always supported (but can be unavailable)
1422 auto device_cnt = NumOfAvailableForDirection(direction);
1423 if (device_cnt == 0) {
1424 device_cnt = DesiredSize();
1425 if (device_cnt == 0) {
1426 log::error("Device count is 0");
1427 continue;
1428 }
1429 }
1430
1431 auto const ase_cnt = ase_confs.size();
1432 if (ase_cnt == 0) {
1433 log::error("ASE count is 0");
1434 continue;
1435 }
1436
1437 uint8_t const max_required_ase_per_dev =
1438 ase_cnt / device_cnt + (ase_cnt % device_cnt);
1439
1440 // Use strategy for the whole group (not only the connected devices)
1441 auto const strategy = utils::GetStrategyForAseConfig(ase_confs, device_cnt);
1442
1443 log::debug(
1444 "Number of devices: {}, number of ASEs: {}, Max ASE per device: {} "
1445 "config strategy: {}, group strategy: {}",
1446 device_cnt, ase_cnt, max_required_ase_per_dev,
1447 static_cast<int>(strategy), (int)required_snk_strategy);
1448
1449 if (direction == types::kLeAudioDirectionSink &&
1450 strategy != required_snk_strategy) {
1451 log::debug("Sink strategy mismatch group!=cfg.entry ({}!={})",
1452 static_cast<int>(required_snk_strategy),
1453 static_cast<int>(strategy));
1454 return false;
1455 }
1456
1457 uint8_t required_device_cnt = device_cnt;
1458 uint8_t active_ase_cnt = 0;
1459 for (auto* device = GetFirstDevice();
1460 device != nullptr && required_device_cnt > 0;
1461 device = GetNextDevice(device)) {
1462 if (device->ases_.empty()) {
1463 log::error("Device has no ASEs.");
1464 continue;
1465 }
1466
1467 int needed_ase_per_dev =
1468 std::min(static_cast<int>(max_required_ase_per_dev),
1469 static_cast<int>(ase_cnt - active_ase_cnt));
1470
1471 for (auto const& ent : ase_confs) {
1472 // Verify PACS only if this is transparent LTV format
1473 auto const& pacs = (direction == types::kLeAudioDirectionSink)
1474 ? device->snk_pacs_
1475 : device->src_pacs_;
1476 if (utils::IsCodecUsingLtvFormat(ent.codec.id) &&
1477 !utils::GetConfigurationSupportedPac(pacs, ent.codec)) {
1478 log::debug(
1479 "Insufficient PAC for {}",
1480 direction == types::kLeAudioDirectionSink ? "sink" : "source");
1481 continue;
1482 }
1483
1484 if (!CheckIfStrategySupported(strategy, ent, direction, *device)) {
1485 log::debug("Strategy not supported");
1486 continue;
1487 }
1488 for (auto& ase : device->ases_) {
1489 if (ase.direction != direction) continue;
1490
1491 active_ase_cnt++;
1492 needed_ase_per_dev--;
1493
1494 if (needed_ase_per_dev == 0) break;
1495 }
1496 }
1497
1498 if (needed_ase_per_dev > 0) {
1499 log::debug("Not enough ASEs on the device (needs {} more).",
1500 needed_ase_per_dev);
1501 return false;
1502 }
1503
1504 required_device_cnt--;
1505 }
1506
1507 if (required_device_cnt > 0) {
1508 /* Don't left any active devices if requirements are not met */
1509 log::debug("Could not configure all the devices for direction: {}",
1510 direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
1511 return false;
1512 }
1513
1514 // At least one direction can be configured
1515 status = true;
1516 }
1517
1518 /* when disabling 32k dual mic, for later join case, we need to
1519 * make sure the device is always choosing the config that its
1520 * sampling rate matches with the sampling rate which is used
1521 * when all devices in the group are connected.
1522 */
1523 bool dual_bidirection_swb_supported_ =
1524 CodecManager::GetInstance()->IsDualBiDirSwbSupported();
1525 if (DesiredSize() > 1 &&
1526 CodecManager::GetInstance()->CheckCodecConfigIsBiDirSwb(
1527 *audio_set_conf)) {
1528 if (!dual_bidirection_swb_supported_) {
1529 return false;
1530 }
1531 }
1532
1533 if (status) {
1534 log::debug("Chosen ASE Configuration for group: {}, configuration: {}",
1535 group_id_, audio_set_conf->name);
1536 } else {
1537 log::error("Could not configure either direction for group {}", group_id_);
1538 }
1539 return status;
1540 }
1541
1542 /* This method should choose aproperiate ASEs to be active and set a cached
1543 * configuration for codec and qos.
1544 */
ConfigureAses(const set_configurations::AudioSetConfiguration * audio_set_conf,LeAudioContextType context_type,const types::BidirectionalPair<AudioContexts> & metadata_context_types,const types::BidirectionalPair<std::vector<uint8_t>> & ccid_lists)1545 bool LeAudioDeviceGroup::ConfigureAses(
1546 const set_configurations::AudioSetConfiguration* audio_set_conf,
1547 LeAudioContextType context_type,
1548 const types::BidirectionalPair<AudioContexts>& metadata_context_types,
1549 const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists) {
1550 bool reuse_cis_id =
1551 GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
1552
1553 /* TODO For now: set ase if matching with first pac.
1554 * 1) We assume as well that devices will match requirements in order
1555 * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
1556 * 2) ASEs should be active only if best (according to priority list) full
1557 * scenarion will be covered.
1558 * 3) ASEs should be filled according to performance profile.
1559 */
1560
1561 // WARNING: This may look like the results stored here are unused, but it
1562 // actually shares the intermediate values between the multiple
1563 // configuration calls within the configuration loop.
1564 BidirectionalPair<types::AudioLocations> group_audio_locations_memo = {
1565 .sink = 0, .source = 0};
1566
1567 for (auto direction :
1568 {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
1569 auto direction_str =
1570 (direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
1571 log::debug("{}: Looking for requirements: {}", direction_str,
1572 audio_set_conf->name);
1573
1574 if (audio_set_conf->confs.get(direction).empty()) {
1575 log::warn("No {} configuration available.", direction_str);
1576 continue;
1577 }
1578
1579 auto const max_required_device_cnt = NumOfAvailableForDirection(direction);
1580 auto required_device_cnt = max_required_device_cnt;
1581 uint8_t active_ase_cnt = 0;
1582
1583 auto configuration_closure = [&](LeAudioDevice* dev) -> void {
1584 /* For the moment, we configure only connected devices and when it is
1585 * ready to stream i.e. All ASEs are discovered and dev is reported as
1586 * connected
1587 */
1588 if (dev->GetConnectionState() != DeviceConnectState::CONNECTED) {
1589 log::warn("Device {}, in the state {}", dev->address_,
1590 bluetooth::common::ToString(dev->GetConnectionState()));
1591 return;
1592 }
1593
1594 if (!dev->ConfigureAses(audio_set_conf, max_required_device_cnt,
1595 direction, context_type, &active_ase_cnt,
1596 group_audio_locations_memo.get(direction),
1597 metadata_context_types.get(direction),
1598 ccid_lists.get(direction), reuse_cis_id)) {
1599 return;
1600 }
1601
1602 required_device_cnt--;
1603 };
1604
1605 // First use the devices claiming proper support
1606 for (auto* device = GetFirstDeviceWithAvailableContext(context_type);
1607 device != nullptr && required_device_cnt > 0;
1608 device = GetNextDeviceWithAvailableContext(device, context_type)) {
1609 configuration_closure(device);
1610 }
1611 // In case some devices do not support this scenario - us them anyway if
1612 // they are required for the scenario - we will not put this context into
1613 // their metadata anyway
1614 if (required_device_cnt > 0) {
1615 for (auto* device = GetFirstDevice();
1616 device != nullptr && required_device_cnt > 0;
1617 device = GetNextDevice(device)) {
1618 configuration_closure(device);
1619 }
1620 }
1621
1622 if (required_device_cnt > 0) {
1623 /* Don't left any active devices if requirements are not met */
1624 log::error("could not configure all the devices");
1625 Deactivate();
1626 return false;
1627 }
1628 }
1629
1630 log::info("Choosed ASE Configuration for group: {}, configuration: {}",
1631 group_id_, audio_set_conf->name);
1632
1633 configuration_context_type_ = context_type;
1634 metadata_context_type_ = metadata_context_types;
1635 return true;
1636 }
1637
1638 std::shared_ptr<const set_configurations::AudioSetConfiguration>
GetCachedConfiguration(LeAudioContextType context_type) const1639 LeAudioDeviceGroup::GetCachedConfiguration(
1640 LeAudioContextType context_type) const {
1641 if (context_to_configuration_cache_map.count(context_type) != 0) {
1642 return context_to_configuration_cache_map.at(context_type).second;
1643 }
1644 return nullptr;
1645 }
1646
1647 std::shared_ptr<const set_configurations::AudioSetConfiguration>
GetActiveConfiguration(void) const1648 LeAudioDeviceGroup::GetActiveConfiguration(void) const {
1649 return GetCachedConfiguration(configuration_context_type_);
1650 }
1651
1652 std::shared_ptr<const set_configurations::AudioSetConfiguration>
GetConfiguration(LeAudioContextType context_type) const1653 LeAudioDeviceGroup::GetConfiguration(LeAudioContextType context_type) const {
1654 if (context_type == LeAudioContextType::UNINITIALIZED) {
1655 return nullptr;
1656 }
1657
1658 const set_configurations::AudioSetConfiguration* conf = nullptr;
1659 bool is_valid = false;
1660
1661 /* Refresh the cache if there is no valid configuration */
1662 if (context_to_configuration_cache_map.count(context_type) != 0) {
1663 auto& valid_config_pair =
1664 context_to_configuration_cache_map.at(context_type);
1665 is_valid = valid_config_pair.first;
1666 conf = valid_config_pair.second.get();
1667 }
1668 if (!is_valid || (conf == nullptr)) {
1669 UpdateAudioSetConfigurationCache(context_type);
1670 }
1671
1672 return GetCachedConfiguration(context_type);
1673 }
1674
1675 LeAudioCodecConfiguration
GetAudioSessionCodecConfigForDirection(LeAudioContextType context_type,uint8_t direction) const1676 LeAudioDeviceGroup::GetAudioSessionCodecConfigForDirection(
1677 LeAudioContextType context_type, uint8_t direction) const {
1678 const set_configurations::AudioSetConfiguration* conf = nullptr;
1679 bool is_valid = false;
1680
1681 /* Refresh the cache if there is no valid configuration */
1682 if (context_to_configuration_cache_map.count(context_type) != 0) {
1683 auto& valid_config_pair =
1684 context_to_configuration_cache_map.at(context_type);
1685 is_valid = valid_config_pair.first;
1686 conf = valid_config_pair.second.get();
1687 }
1688 if (!is_valid || (conf == nullptr)) {
1689 UpdateAudioSetConfigurationCache(context_type);
1690 }
1691
1692 auto audio_set_conf = GetCachedConfiguration(context_type);
1693 if (!audio_set_conf) return {0, 0, 0, 0};
1694
1695 auto group_config =
1696 utils::GetAudioSessionCodecConfigFromAudioSetConfiguration(
1697 *audio_set_conf.get(), direction);
1698 return group_config;
1699 }
1700
HasCodecConfigurationForDirection(types::LeAudioContextType context_type,uint8_t direction) const1701 bool LeAudioDeviceGroup::HasCodecConfigurationForDirection(
1702 types::LeAudioContextType context_type, uint8_t direction) const {
1703 auto audio_set_conf = GetConfiguration(context_type);
1704 return audio_set_conf ? !audio_set_conf->confs.get(direction).empty() : false;
1705 }
1706
IsAudioSetConfigurationAvailable(LeAudioContextType group_context_type)1707 bool LeAudioDeviceGroup::IsAudioSetConfigurationAvailable(
1708 LeAudioContextType group_context_type) {
1709 return GetConfiguration(group_context_type) != nullptr;
1710 }
1711
IsMetadataChanged(const BidirectionalPair<AudioContexts> & context_types,const BidirectionalPair<std::vector<uint8_t>> & ccid_lists) const1712 bool LeAudioDeviceGroup::IsMetadataChanged(
1713 const BidirectionalPair<AudioContexts>& context_types,
1714 const BidirectionalPair<std::vector<uint8_t>>& ccid_lists) const {
1715 for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
1716 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
1717 if (leAudioDevice->IsMetadataChanged(context_types, ccid_lists))
1718 return true;
1719 }
1720
1721 return false;
1722 }
1723
IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const1724 bool LeAudioDeviceGroup::IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const {
1725 auto& sink_stream_locations = stream_conf.stream_params.sink.stream_locations;
1726 auto iter = std::find_if(
1727 sink_stream_locations.begin(), sink_stream_locations.end(),
1728 [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; });
1729
1730 if (iter != sink_stream_locations.end()) return true;
1731
1732 auto& source_stream_locations =
1733 stream_conf.stream_params.source.stream_locations;
1734 iter = std::find_if(
1735 source_stream_locations.begin(), source_stream_locations.end(),
1736 [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; });
1737
1738 return (iter != source_stream_locations.end());
1739 }
1740
RemoveCisFromStreamIfNeeded(LeAudioDevice * leAudioDevice,uint16_t cis_conn_hdl)1741 void LeAudioDeviceGroup::RemoveCisFromStreamIfNeeded(
1742 LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) {
1743 log::info("CIS Connection Handle: {}", cis_conn_hdl);
1744
1745 if (!IsCisPartOfCurrentStream(cis_conn_hdl)) return;
1746
1747 /* Cache the old values for comparison */
1748 auto old_sink_channels = stream_conf.stream_params.sink.num_of_channels;
1749 auto old_source_channels = stream_conf.stream_params.source.num_of_channels;
1750
1751 for (auto dir :
1752 {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) {
1753 auto& params = stream_conf.stream_params.get(dir);
1754 params.stream_locations.erase(
1755 std::remove_if(
1756 params.stream_locations.begin(), params.stream_locations.end(),
1757 [leAudioDevice, &cis_conn_hdl, ¶ms, dir](auto& pair) {
1758 if (!cis_conn_hdl) {
1759 cis_conn_hdl = pair.first;
1760 }
1761 auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl);
1762 if (ases_pair.get(dir) && cis_conn_hdl == pair.first) {
1763 params.num_of_devices--;
1764 params.num_of_channels -= ases_pair.get(dir)->channel_count;
1765 params.audio_channel_allocation &= ~pair.second;
1766 }
1767 return (ases_pair.get(dir) && cis_conn_hdl == pair.first);
1768 }),
1769 params.stream_locations.end());
1770 }
1771
1772 log::info(
1773 "Sink Number Of Devices: {}, Sink Number Of Channels: {}, Source Number "
1774 "Of Devices: {}, Source Number Of Channels: {}",
1775 stream_conf.stream_params.sink.num_of_devices,
1776 stream_conf.stream_params.sink.num_of_channels,
1777 stream_conf.stream_params.source.num_of_devices,
1778 stream_conf.stream_params.source.num_of_channels);
1779
1780 if (stream_conf.stream_params.sink.num_of_channels == 0) {
1781 ClearSinksFromConfiguration();
1782 }
1783
1784 if (stream_conf.stream_params.source.num_of_channels == 0) {
1785 ClearSourcesFromConfiguration();
1786 }
1787
1788 /* Update CodecManager CIS configuration */
1789 if (old_sink_channels > stream_conf.stream_params.sink.num_of_channels) {
1790 CodecManager::GetInstance()->UpdateCisConfiguration(
1791 cig.cises,
1792 stream_conf.stream_params.get(
1793 bluetooth::le_audio::types::kLeAudioDirectionSink),
1794 bluetooth::le_audio::types::kLeAudioDirectionSink);
1795 }
1796 if (old_source_channels > stream_conf.stream_params.source.num_of_channels) {
1797 CodecManager::GetInstance()->UpdateCisConfiguration(
1798 cig.cises,
1799 stream_conf.stream_params.get(
1800 bluetooth::le_audio::types::kLeAudioDirectionSource),
1801 bluetooth::le_audio::types::kLeAudioDirectionSource);
1802 }
1803
1804 cig.UnassignCis(leAudioDevice);
1805 }
1806
IsPendingConfiguration(void) const1807 bool LeAudioDeviceGroup::IsPendingConfiguration(void) const {
1808 return stream_conf.pending_configuration;
1809 }
1810
SetPendingConfiguration(void)1811 void LeAudioDeviceGroup::SetPendingConfiguration(void) {
1812 stream_conf.pending_configuration = true;
1813 }
1814
ClearPendingConfiguration(void)1815 void LeAudioDeviceGroup::ClearPendingConfiguration(void) {
1816 stream_conf.pending_configuration = false;
1817 }
1818
Disable(int gatt_if)1819 void LeAudioDeviceGroup::Disable(int gatt_if) {
1820 is_enabled_ = false;
1821
1822 for (auto& device_iter : leAudioDevices_) {
1823 if (!device_iter.lock()->autoconnect_flag_) {
1824 continue;
1825 }
1826
1827 auto connection_state = device_iter.lock()->GetConnectionState();
1828 auto address = device_iter.lock()->address_;
1829
1830 btif_storage_set_leaudio_autoconnect(address, false);
1831 device_iter.lock()->autoconnect_flag_ = false;
1832
1833 log::info("Group {} in state {}. Removing {} from background connect",
1834 group_id_, bluetooth::common::ToString(GetState()), address);
1835
1836 BTA_GATTC_CancelOpen(gatt_if, address, false);
1837
1838 if (connection_state == DeviceConnectState::CONNECTING_AUTOCONNECT) {
1839 device_iter.lock()->SetConnectionState(DeviceConnectState::DISCONNECTED);
1840 }
1841 }
1842 }
1843
Enable(int gatt_if,tBTM_BLE_CONN_TYPE reconnection_mode)1844 void LeAudioDeviceGroup::Enable(int gatt_if,
1845 tBTM_BLE_CONN_TYPE reconnection_mode) {
1846 is_enabled_ = true;
1847 for (auto& device_iter : leAudioDevices_) {
1848 if (device_iter.lock()->autoconnect_flag_) {
1849 continue;
1850 }
1851
1852 auto address = device_iter.lock()->address_;
1853 auto connection_state = device_iter.lock()->GetConnectionState();
1854
1855 btif_storage_set_leaudio_autoconnect(address, true);
1856 device_iter.lock()->autoconnect_flag_ = true;
1857
1858 log::info("Group {} in state {}. Adding {} from background connect",
1859 group_id_, bluetooth::common::ToString(GetState()), address);
1860
1861 if (connection_state == DeviceConnectState::DISCONNECTED) {
1862 BTA_GATTC_Open(gatt_if, address, reconnection_mode, false);
1863 device_iter.lock()->SetConnectionState(
1864 DeviceConnectState::CONNECTING_AUTOCONNECT);
1865 }
1866 }
1867 }
1868
IsEnabled(void) const1869 bool LeAudioDeviceGroup::IsEnabled(void) const { return is_enabled_; };
1870
AddToAllowListNotConnectedGroupMembers(int gatt_if)1871 void LeAudioDeviceGroup::AddToAllowListNotConnectedGroupMembers(int gatt_if) {
1872 for (const auto& device_iter : leAudioDevices_) {
1873 auto connection_state = device_iter.lock()->GetConnectionState();
1874 if (connection_state == DeviceConnectState::CONNECTED ||
1875 connection_state == DeviceConnectState::CONNECTING_BY_USER ||
1876 connection_state ==
1877 DeviceConnectState::CONNECTED_BY_USER_GETTING_READY ||
1878 connection_state ==
1879 DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY) {
1880 continue;
1881 }
1882
1883 auto address = device_iter.lock()->address_;
1884 log::info("Group {} in state {}. Adding {} to allow list", group_id_,
1885 bluetooth::common::ToString(GetState()), address);
1886
1887 /* When adding set members to allow list, let use direct connect first.
1888 * When it fails (i.e. device is not advertising), it will go to background
1889 * connect. We are doing that because for background connect, stack is using
1890 * slow scan parameters for connection which might delay connecting
1891 * available members.
1892 */
1893 BTA_GATTC_CancelOpen(gatt_if, address, false);
1894 BTA_GATTC_Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, false);
1895 device_iter.lock()->SetConnectionState(
1896 DeviceConnectState::CONNECTING_AUTOCONNECT);
1897 }
1898 }
1899
ApplyReconnectionMode(int gatt_if,tBTM_BLE_CONN_TYPE reconnection_mode)1900 void LeAudioDeviceGroup::ApplyReconnectionMode(
1901 int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode) {
1902 for (const auto& device_iter : leAudioDevices_) {
1903 BTA_GATTC_CancelOpen(gatt_if, device_iter.lock()->address_, false);
1904 BTA_GATTC_Open(gatt_if, device_iter.lock()->address_, reconnection_mode,
1905 false);
1906 log::info("Group {} in state {}. Adding {} to default reconnection mode",
1907 group_id_, bluetooth::common::ToString(GetState()),
1908 device_iter.lock()->address_);
1909 device_iter.lock()->SetConnectionState(
1910 DeviceConnectState::CONNECTING_AUTOCONNECT);
1911 }
1912 }
1913
IsConfiguredForContext(LeAudioContextType context_type) const1914 bool LeAudioDeviceGroup::IsConfiguredForContext(
1915 LeAudioContextType context_type) const {
1916 /* Check if all connected group members are configured */
1917 if (GetConfigurationContextType() != context_type) {
1918 return false;
1919 }
1920
1921 if (!stream_conf.conf) return false;
1922
1923 /* Check if used configuration is same as the active one.*/
1924 return (stream_conf.conf.get() == GetActiveConfiguration().get());
1925 }
1926
1927 const set_configurations::AudioSetConfiguration*
FindFirstSupportedConfiguration(const CodecManager::UnicastConfigurationRequirements & requirements,const set_configurations::AudioSetConfigurations * confs) const1928 LeAudioDeviceGroup::FindFirstSupportedConfiguration(
1929 const CodecManager::UnicastConfigurationRequirements& requirements,
1930 const set_configurations::AudioSetConfigurations* confs) const {
1931 log::assert_that(confs != nullptr, "confs should not be null");
1932
1933 log::debug("context type: {}, number of connected devices: {}",
1934 bluetooth::common::ToString(requirements.audio_context_type),
1935 NumOfConnected());
1936
1937 /* Filter out device set for each end every scenario */
1938 for (const auto& conf : *confs) {
1939 log::assert_that(conf != nullptr, "confs should not be null");
1940 if (IsAudioSetConfigurationSupported(requirements, conf)) {
1941 log::debug("found: {}", conf->name);
1942 return conf;
1943 }
1944 }
1945
1946 return nullptr;
1947 }
1948
1949 /* This method should choose aproperiate ASEs to be active and set a cached
1950 * configuration for codec and qos.
1951 */
Configure(LeAudioContextType context_type,const types::BidirectionalPair<AudioContexts> & metadata_context_types,types::BidirectionalPair<std::vector<uint8_t>> ccid_lists)1952 bool LeAudioDeviceGroup::Configure(
1953 LeAudioContextType context_type,
1954 const types::BidirectionalPair<AudioContexts>& metadata_context_types,
1955 types::BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
1956 auto conf = GetConfiguration(context_type);
1957 if (!conf) {
1958 log::error(
1959 ", requested context type: {} , is in mismatch with cached available "
1960 "contexts",
1961 bluetooth::common::ToString(context_type));
1962 return false;
1963 }
1964
1965 log::debug("setting context type: {}",
1966 bluetooth::common::ToString(context_type));
1967
1968 if (!ConfigureAses(conf.get(), context_type, metadata_context_types,
1969 ccid_lists)) {
1970 log::error(
1971 ", requested context type: {}, is in mismatch with cached available "
1972 "contexts",
1973 bluetooth::common::ToString(context_type));
1974 return false;
1975 }
1976
1977 /* Store selected configuration at once it is chosen.
1978 * It might happen it will get unavailable in some point of time
1979 */
1980 stream_conf.conf = conf;
1981 return true;
1982 }
1983
~LeAudioDeviceGroup(void)1984 LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); }
1985
PrintDebugState(void) const1986 void LeAudioDeviceGroup::PrintDebugState(void) const {
1987 auto active_conf = GetActiveConfiguration();
1988 std::stringstream debug_str;
1989
1990 debug_str << "\n Groupd id: " << group_id_
1991 << (is_enabled_ ? " enabled" : " disabled")
1992 << ", state: " << bluetooth::common::ToString(GetState())
1993 << ", target state: "
1994 << bluetooth::common::ToString(GetTargetState())
1995 << ", cig state: " << bluetooth::common::ToString(cig.GetState())
1996 << ", \n group supported contexts: "
1997 << bluetooth::common::ToString(GetSupportedContexts())
1998 << ", \n group available contexts: "
1999 << bluetooth::common::ToString(GetAvailableContexts())
2000 << ", \n group allowed contexts: "
2001 << bluetooth::common::ToString(GetAllowedContextMask())
2002 << ", \n configuration context type: "
2003 << bluetooth::common::ToString(GetConfigurationContextType())
2004 << ", \n active configuration name: "
2005 << (active_conf ? active_conf->name : " not set");
2006
2007 if (cig.cises.size() > 0) {
2008 log::info("\n Allocated CISes: {}", static_cast<int>(cig.cises.size()));
2009 for (auto cis : cig.cises) {
2010 log::info("\n cis id: {}, type: {}, conn_handle {}, addr: {}", cis.id,
2011 cis.type, cis.conn_handle, cis.addr.ToString());
2012 }
2013 }
2014
2015 if (GetFirstActiveDevice() != nullptr) {
2016 uint32_t sink_delay = 0;
2017 uint32_t source_delay = 0;
2018 GetPresentationDelay(&sink_delay,
2019 bluetooth::le_audio::types::kLeAudioDirectionSink);
2020 GetPresentationDelay(&source_delay,
2021 bluetooth::le_audio::types::kLeAudioDirectionSource);
2022 auto phy_mtos =
2023 GetPhyBitmask(bluetooth::le_audio::types::kLeAudioDirectionSink);
2024 auto phy_stom =
2025 GetPhyBitmask(bluetooth::le_audio::types::kLeAudioDirectionSource);
2026 auto max_transport_latency_mtos = GetMaxTransportLatencyMtos();
2027 auto max_transport_latency_stom = GetMaxTransportLatencyStom();
2028 auto sdu_mts =
2029 GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSink);
2030 auto sdu_stom =
2031 GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSource);
2032
2033 debug_str << "\n presentation_delay for sink (speaker): " << +sink_delay
2034 << " us, presentation_delay for source (microphone): "
2035 << +source_delay << "us, \n MtoS transport latency: "
2036 << +max_transport_latency_mtos
2037 << ", StoM transport latency: " << +max_transport_latency_stom
2038 << ", \n MtoS Phy: " << loghex(phy_mtos)
2039 << ", MtoS sdu: " << loghex(phy_stom)
2040 << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom;
2041 }
2042
2043 log::info("{}", debug_str.str());
2044
2045 for (const auto& device_iter : leAudioDevices_) {
2046 device_iter.lock()->PrintDebugState();
2047 }
2048 }
2049
Dump(int fd,int active_group_id) const2050 void LeAudioDeviceGroup::Dump(int fd, int active_group_id) const {
2051 bool is_active = (group_id_ == active_group_id);
2052 std::stringstream stream, stream_pacs;
2053 auto active_conf = GetActiveConfiguration();
2054
2055 stream << "\n == Group id: " << group_id_
2056 << (is_enabled_ ? " enabled" : " disabled")
2057 << " == " << (is_active ? ",\tActive\n" : ",\tInactive\n")
2058 << " state: " << GetState()
2059 << ",\ttarget state: " << GetTargetState()
2060 << ",\tcig state: " << cig.GetState() << "\n"
2061 << " group supported contexts: " << GetSupportedContexts() << "\n"
2062 << " group available contexts: " << GetAvailableContexts() << "\n"
2063 << " group allowed contexts: " << GetAllowedContextMask() << "\n"
2064 << " configuration context type: "
2065 << bluetooth::common::ToString(GetConfigurationContextType()).c_str()
2066 << "\n"
2067 << " active configuration name: "
2068 << (active_conf ? active_conf->name : " not set") << "\n"
2069 << " stream configuration: "
2070 << (stream_conf.conf != nullptr ? stream_conf.conf->name : " unknown ")
2071 << "\n"
2072 << " codec id: " << +(stream_conf.codec_id.coding_format)
2073 << ",\tpending_configuration: " << stream_conf.pending_configuration
2074 << "\n"
2075 << " num of devices(connected): " << Size() << "("
2076 << NumOfConnected() << ")\n"
2077 << ", num of sinks(connected): "
2078 << stream_conf.stream_params.sink.num_of_devices << "("
2079 << stream_conf.stream_params.sink.stream_locations.size() << ")\n"
2080 << " num of sources(connected): "
2081 << stream_conf.stream_params.source.num_of_devices << "("
2082 << stream_conf.stream_params.source.stream_locations.size() << ")\n"
2083 << " allocated CISes: " << static_cast<int>(cig.cises.size());
2084
2085 if (cig.cises.size() > 0) {
2086 stream << "\n\t == CISes == ";
2087 for (auto cis : cig.cises) {
2088 stream << "\n\t cis id: " << static_cast<int>(cis.id)
2089 << ",\ttype: " << static_cast<int>(cis.type)
2090 << ",\tconn_handle: " << static_cast<int>(cis.conn_handle)
2091 << ",\taddr: " << ADDRESS_TO_LOGGABLE_STR(cis.addr);
2092 }
2093 stream << "\n\t ====";
2094 }
2095
2096 if (GetFirstActiveDevice() != nullptr) {
2097 uint32_t sink_delay;
2098 if (GetPresentationDelay(
2099 &sink_delay, bluetooth::le_audio::types::kLeAudioDirectionSink)) {
2100 stream << "\n presentation_delay for sink (speaker): " << sink_delay
2101 << " us";
2102 }
2103
2104 uint32_t source_delay;
2105 if (GetPresentationDelay(
2106 &source_delay,
2107 bluetooth::le_audio::types::kLeAudioDirectionSource)) {
2108 stream << "\n presentation_delay for source (microphone): "
2109 << source_delay << " us";
2110 }
2111 }
2112
2113 stream << "\n == devices: ==";
2114
2115 dprintf(fd, "%s", stream.str().c_str());
2116
2117 for (const auto& device_iter : leAudioDevices_) {
2118 device_iter.lock()->Dump(fd);
2119 }
2120
2121 for (const auto& device_iter : leAudioDevices_) {
2122 auto device = device_iter.lock();
2123 stream_pacs << "\n\taddress: " << device->address_;
2124 device->DumpPacsDebugState(stream_pacs);
2125 }
2126 dprintf(fd, "%s", stream_pacs.str().c_str());
2127 }
2128
Add(int group_id)2129 LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) {
2130 /* Get first free group id */
2131 if (FindById(group_id)) {
2132 log::error("group already exists, id: 0x{:x}", group_id);
2133 return nullptr;
2134 }
2135
2136 return (groups_.emplace_back(std::make_unique<LeAudioDeviceGroup>(group_id)))
2137 .get();
2138 }
2139
Remove(int group_id)2140 void LeAudioDeviceGroups::Remove(int group_id) {
2141 auto iter = std::find_if(
2142 groups_.begin(), groups_.end(),
2143 [&group_id](auto const& group) { return group->group_id_ == group_id; });
2144
2145 if (iter == groups_.end()) {
2146 log::error("no such group_id: {}", group_id);
2147 return;
2148 }
2149
2150 groups_.erase(iter);
2151 }
2152
FindById(int group_id) const2153 LeAudioDeviceGroup* LeAudioDeviceGroups::FindById(int group_id) const {
2154 auto iter = std::find_if(
2155 groups_.begin(), groups_.end(),
2156 [&group_id](auto const& group) { return group->group_id_ == group_id; });
2157
2158 return (iter == groups_.end()) ? nullptr : iter->get();
2159 }
2160
Cleanup(void)2161 void LeAudioDeviceGroups::Cleanup(void) {
2162 for (auto& g : groups_) {
2163 g->Cleanup();
2164 }
2165
2166 groups_.clear();
2167 }
2168
Dump(int fd,int active_group_id) const2169 void LeAudioDeviceGroups::Dump(int fd, int active_group_id) const {
2170 /* Dump first active group */
2171 for (auto& g : groups_) {
2172 if (g->group_id_ == active_group_id) {
2173 g->Dump(fd, active_group_id);
2174 break;
2175 }
2176 }
2177
2178 /* Dump non active group */
2179 for (auto& g : groups_) {
2180 if (g->group_id_ != active_group_id) {
2181 g->Dump(fd, active_group_id);
2182 }
2183 }
2184 }
2185
IsAnyInTransition(void) const2186 bool LeAudioDeviceGroups::IsAnyInTransition(void) const {
2187 for (auto& g : groups_) {
2188 if (g->IsInTransition()) {
2189 log::debug("group: {} is in transition", g->group_id_);
2190 return true;
2191 }
2192 }
2193 return false;
2194 }
2195
Size() const2196 size_t LeAudioDeviceGroups::Size() const { return (groups_.size()); }
2197
GetGroupsIds(void) const2198 std::vector<int> LeAudioDeviceGroups::GetGroupsIds(void) const {
2199 std::vector<int> result;
2200
2201 for (auto const& group : groups_) {
2202 result.push_back(group->group_id_);
2203 }
2204
2205 return result;
2206 }
2207
2208 } // namespace bluetooth::le_audio
2209