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