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