1 /*
2 * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA
3 * - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "devices.h"
19
20 #include <base/strings/string_number_conversions.h>
21
22 #include <map>
23
24 #include "audio_hal_client/audio_hal_client.h"
25 #include "bta_csis_api.h"
26 #include "bta_gatt_queue.h"
27 #include "bta_groups.h"
28 #include "bta_le_audio_api.h"
29 #include "btif_storage.h"
30 #include "btm_iso_api.h"
31 #include "btm_iso_api_types.h"
32 #include "device/include/controller.h"
33 #include "gd/common/strings.h"
34 #include "le_audio_set_configuration_provider.h"
35 #include "metrics_collector.h"
36 #include "osi/include/log.h"
37 #include "stack/include/acl_api.h"
38
39 using bluetooth::hci::kIsoCigFramingFramed;
40 using bluetooth::hci::kIsoCigFramingUnframed;
41 using bluetooth::hci::kIsoCigPackingSequential;
42 using bluetooth::hci::kIsoCigPhy1M;
43 using bluetooth::hci::kIsoCigPhy2M;
44 using bluetooth::hci::iso_manager::kIsoSca0To20Ppm;
45 using le_audio::AudioSetConfigurationProvider;
46 using le_audio::DeviceConnectState;
47 using le_audio::set_configurations::CodecCapabilitySetting;
48 using le_audio::types::ase;
49 using le_audio::types::AseState;
50 using le_audio::types::AudioContexts;
51 using le_audio::types::AudioLocations;
52 using le_audio::types::AudioStreamDataPathState;
53 using le_audio::types::BidirectAsesPair;
54 using le_audio::types::CisType;
55 using le_audio::types::LeAudioCodecId;
56 using le_audio::types::LeAudioContextType;
57 using le_audio::types::LeAudioLc3Config;
58
59 namespace le_audio {
operator <<(std::ostream & os,const DeviceConnectState & state)60 std::ostream& operator<<(std::ostream& os, const DeviceConnectState& state) {
61 const char* char_value_ = "UNKNOWN";
62
63 switch (state) {
64 case DeviceConnectState::CONNECTED:
65 char_value_ = "CONNECTED";
66 break;
67 case DeviceConnectState::DISCONNECTED:
68 char_value_ = "DISCONNECTED";
69 break;
70 case DeviceConnectState::REMOVING:
71 char_value_ = "REMOVING";
72 break;
73 case DeviceConnectState::DISCONNECTING:
74 char_value_ = "DISCONNECTING";
75 break;
76 case DeviceConnectState::PENDING_REMOVAL:
77 char_value_ = "PENDING_REMOVAL";
78 break;
79 case DeviceConnectState::CONNECTING_BY_USER:
80 char_value_ = "CONNECTING_BY_USER";
81 break;
82 case DeviceConnectState::CONNECTED_BY_USER_GETTING_READY:
83 char_value_ = "CONNECTED_BY_USER_GETTING_READY";
84 break;
85 case DeviceConnectState::CONNECTING_AUTOCONNECT:
86 char_value_ = "CONNECTING_AUTOCONNECT";
87 break;
88 case DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY:
89 char_value_ = "CONNECTED_AUTOCONNECT_GETTING_READY";
90 break;
91 }
92
93 os << char_value_ << " ("
94 << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
95 << ")";
96 return os;
97 }
98
99 /* LeAudioDeviceGroup Class methods implementation */
AddNode(const std::shared_ptr<LeAudioDevice> & leAudioDevice)100 void LeAudioDeviceGroup::AddNode(
101 const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
102 leAudioDevice->group_id_ = group_id_;
103 leAudioDevices_.push_back(std::weak_ptr<LeAudioDevice>(leAudioDevice));
104 MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size());
105 }
106
RemoveNode(const std::shared_ptr<LeAudioDevice> & leAudioDevice)107 void LeAudioDeviceGroup::RemoveNode(
108 const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
109 /* Group information cleaning in the device. */
110 leAudioDevice->group_id_ = bluetooth::groups::kGroupUnknown;
111 for (auto ase : leAudioDevice->ases_) {
112 ase.active = false;
113 ase.cis_conn_hdl = 0;
114 }
115
116 leAudioDevices_.erase(
117 std::remove_if(
118 leAudioDevices_.begin(), leAudioDevices_.end(),
119 [&leAudioDevice](auto& d) { return d.lock() == leAudioDevice; }),
120 leAudioDevices_.end());
121 MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size());
122 }
123
IsEmpty(void)124 bool LeAudioDeviceGroup::IsEmpty(void) { return leAudioDevices_.size() == 0; }
125
IsAnyDeviceConnected(void)126 bool LeAudioDeviceGroup::IsAnyDeviceConnected(void) {
127 return (NumOfConnected() != 0);
128 }
129
Size(void)130 int LeAudioDeviceGroup::Size(void) { return leAudioDevices_.size(); }
131
NumOfConnected(types::LeAudioContextType context_type)132 int LeAudioDeviceGroup::NumOfConnected(types::LeAudioContextType context_type) {
133 if (leAudioDevices_.empty()) return 0;
134
135 bool check_context_type = (context_type != LeAudioContextType::RFU);
136 AudioContexts type_set(context_type);
137
138 /* return number of connected devices from the set*/
139 return std::count_if(
140 leAudioDevices_.begin(), leAudioDevices_.end(),
141 [type_set, check_context_type](auto& iter) {
142 if (iter.expired()) return false;
143 if (iter.lock()->conn_id_ == GATT_INVALID_CONN_ID) return false;
144
145 if (!check_context_type) return true;
146
147 return iter.lock()->GetAvailableContexts().test_any(type_set);
148 });
149 }
150
ClearSinksFromConfiguration(void)151 void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) {
152 LOG_INFO("Group %p, group_id %d", this, group_id_);
153 stream_conf.sink_streams.clear();
154 stream_conf.sink_offloader_streams_target_allocation.clear();
155 stream_conf.sink_offloader_streams_current_allocation.clear();
156 stream_conf.sink_audio_channel_allocation = 0;
157 stream_conf.sink_num_of_channels = 0;
158 stream_conf.sink_num_of_devices = 0;
159 stream_conf.sink_sample_frequency_hz = 0;
160 stream_conf.sink_codec_frames_blocks_per_sdu = 0;
161 stream_conf.sink_octets_per_codec_frame = 0;
162 stream_conf.sink_frame_duration_us = 0;
163 }
164
ClearSourcesFromConfiguration(void)165 void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) {
166 LOG_INFO("Group %p, group_id %d", this, group_id_);
167 stream_conf.source_streams.clear();
168 stream_conf.source_offloader_streams_target_allocation.clear();
169 stream_conf.source_offloader_streams_current_allocation.clear();
170 stream_conf.source_audio_channel_allocation = 0;
171 stream_conf.source_num_of_channels = 0;
172 stream_conf.source_num_of_devices = 0;
173 stream_conf.source_sample_frequency_hz = 0;
174 stream_conf.source_codec_frames_blocks_per_sdu = 0;
175 stream_conf.source_octets_per_codec_frame = 0;
176 stream_conf.source_frame_duration_us = 0;
177 }
178
CigClearCis(void)179 void LeAudioDeviceGroup::CigClearCis(void) {
180 LOG_INFO("group_id: %d", group_id_);
181 cises_.clear();
182 ClearSinksFromConfiguration();
183 ClearSourcesFromConfiguration();
184 }
185
Cleanup(void)186 void LeAudioDeviceGroup::Cleanup(void) {
187 /* Bluetooth is off while streaming - disconnect CISes and remove CIG */
188 if (GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
189 if (!stream_conf.sink_streams.empty()) {
190 for (auto [cis_handle, audio_location] : stream_conf.sink_streams) {
191 bluetooth::hci::IsoManager::GetInstance()->DisconnectCis(
192 cis_handle, HCI_ERR_PEER_USER);
193
194 if (stream_conf.source_streams.empty()) {
195 continue;
196 }
197 uint16_t cis_hdl = cis_handle;
198 stream_conf.source_streams.erase(
199 std::remove_if(
200 stream_conf.source_streams.begin(),
201 stream_conf.source_streams.end(),
202 [cis_hdl](auto& pair) { return pair.first == cis_hdl; }),
203 stream_conf.source_streams.end());
204 }
205 }
206
207 if (!stream_conf.source_streams.empty()) {
208 for (auto [cis_handle, audio_location] : stream_conf.source_streams) {
209 bluetooth::hci::IsoManager::GetInstance()->DisconnectCis(
210 cis_handle, HCI_ERR_PEER_USER);
211 }
212 }
213 }
214
215 /* Note: CIG will stay in the controller. We cannot remove it here, because
216 * Cises are not yet disconnected.
217 * When user start Bluetooth, HCI Reset should remove it
218 */
219
220 leAudioDevices_.clear();
221 this->CigClearCis();
222 }
223
Deactivate(void)224 void LeAudioDeviceGroup::Deactivate(void) {
225 for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
226 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
227 for (auto* ase = leAudioDevice->GetFirstActiveAse(); ase;
228 ase = leAudioDevice->GetNextActiveAse(ase)) {
229 ase->active = false;
230 }
231 }
232 }
233
GetCigState(void)234 le_audio::types::CigState LeAudioDeviceGroup::GetCigState(void) {
235 return cig_state_;
236 }
237
SetCigState(le_audio::types::CigState state)238 void LeAudioDeviceGroup::SetCigState(le_audio::types::CigState state) {
239 LOG_VERBOSE("%s -> %s", bluetooth::common::ToString(cig_state_).c_str(),
240 bluetooth::common::ToString(state).c_str());
241 cig_state_ = state;
242 }
243
Activate(LeAudioContextType context_type)244 bool LeAudioDeviceGroup::Activate(LeAudioContextType context_type) {
245 bool is_activate = false;
246 for (auto leAudioDevice : leAudioDevices_) {
247 if (leAudioDevice.expired()) continue;
248
249 bool activated = leAudioDevice.lock()->ActivateConfiguredAses(context_type);
250 LOG_INFO("Device %s is %s",
251 leAudioDevice.lock().get()->address_.ToString().c_str(),
252 activated ? "activated" : " not activated");
253 if (activated) {
254 if (!CigAssignCisIds(leAudioDevice.lock().get())) {
255 return false;
256 }
257 is_activate = true;
258 }
259 }
260 return is_activate;
261 }
262
GetFirstDevice(void)263 LeAudioDevice* LeAudioDeviceGroup::GetFirstDevice(void) {
264 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
265 [](auto& iter) { return !iter.expired(); });
266
267 if (iter == leAudioDevices_.end()) return nullptr;
268
269 return (iter->lock()).get();
270 }
271
GetFirstDeviceWithActiveContext(types::LeAudioContextType context_type)272 LeAudioDevice* LeAudioDeviceGroup::GetFirstDeviceWithActiveContext(
273 types::LeAudioContextType context_type) {
274 auto iter = std::find_if(
275 leAudioDevices_.begin(), leAudioDevices_.end(),
276 [&context_type](auto& iter) {
277 if (iter.expired()) return false;
278 return iter.lock()->GetAvailableContexts().test(context_type);
279 });
280
281 if ((iter == leAudioDevices_.end()) || (iter->expired())) return nullptr;
282
283 return (iter->lock()).get();
284 }
285
GetNextDevice(LeAudioDevice * leAudioDevice)286 LeAudioDevice* LeAudioDeviceGroup::GetNextDevice(LeAudioDevice* leAudioDevice) {
287 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
288 [&leAudioDevice](auto& d) {
289 if (d.expired())
290 return false;
291 else
292 return (d.lock()).get() == leAudioDevice;
293 });
294
295 /* If reference device not found */
296 if (iter == leAudioDevices_.end()) return nullptr;
297
298 std::advance(iter, 1);
299 /* If reference device is last in group */
300 if (iter == leAudioDevices_.end()) return nullptr;
301
302 if (iter->expired()) return nullptr;
303
304 return (iter->lock()).get();
305 }
306
GetNextDeviceWithActiveContext(LeAudioDevice * leAudioDevice,types::LeAudioContextType context_type)307 LeAudioDevice* LeAudioDeviceGroup::GetNextDeviceWithActiveContext(
308 LeAudioDevice* leAudioDevice, types::LeAudioContextType context_type) {
309 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
310 [&leAudioDevice](auto& d) {
311 if (d.expired())
312 return false;
313 else
314 return (d.lock()).get() == leAudioDevice;
315 });
316
317 /* If reference device not found */
318 if (iter == leAudioDevices_.end()) return nullptr;
319
320 std::advance(iter, 1);
321 /* If reference device is last in group */
322 if (iter == leAudioDevices_.end()) return nullptr;
323
324 iter = std::find_if(iter, leAudioDevices_.end(), [&context_type](auto& d) {
325 if (d.expired())
326 return false;
327 else
328 return d.lock()->GetAvailableContexts().test(context_type);
329 ;
330 });
331
332 return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
333 }
334
IsDeviceInTheGroup(LeAudioDevice * leAudioDevice)335 bool LeAudioDeviceGroup::IsDeviceInTheGroup(LeAudioDevice* leAudioDevice) {
336 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
337 [&leAudioDevice](auto& d) {
338 if (d.expired())
339 return false;
340 else
341 return (d.lock()).get() == leAudioDevice;
342 });
343
344 if ((iter == leAudioDevices_.end()) || (iter->expired())) return false;
345
346 return true;
347 }
348
HaveAllActiveDevicesAsesTheSameState(AseState state)349 bool LeAudioDeviceGroup::HaveAllActiveDevicesAsesTheSameState(AseState state) {
350 auto iter = std::find_if(
351 leAudioDevices_.begin(), leAudioDevices_.end(), [&state](auto& d) {
352 if (d.expired())
353 return false;
354 else
355 return !(((d.lock()).get())->HaveAllActiveAsesSameState(state));
356 });
357
358 return iter == leAudioDevices_.end();
359 }
360
GetFirstActiveDevice(void)361 LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDevice(void) {
362 auto iter =
363 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
364 if (d.expired())
365 return false;
366 else
367 return ((d.lock()).get())->HaveActiveAse();
368 });
369
370 if (iter == leAudioDevices_.end() || iter->expired()) return nullptr;
371
372 return (iter->lock()).get();
373 }
374
GetNextActiveDevice(LeAudioDevice * leAudioDevice)375 LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice(
376 LeAudioDevice* leAudioDevice) {
377 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
378 [&leAudioDevice](auto& d) {
379 if (d.expired())
380 return false;
381 else
382 return (d.lock()).get() == leAudioDevice;
383 });
384
385 if (iter == leAudioDevices_.end() ||
386 std::distance(iter, leAudioDevices_.end()) < 1)
387 return nullptr;
388
389 iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(), [](auto& d) {
390 if (d.expired())
391 return false;
392 else
393 return ((d.lock()).get())->HaveActiveAse();
394 });
395
396 return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
397 }
398
GetFirstActiveDeviceByDataPathState(AudioStreamDataPathState data_path_state)399 LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByDataPathState(
400 AudioStreamDataPathState data_path_state) {
401 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
402 [&data_path_state](auto& d) {
403 if (d.expired()) {
404 return false;
405 }
406
407 return (((d.lock()).get())
408 ->GetFirstActiveAseByDataPathState(
409 data_path_state) != nullptr);
410 });
411
412 if (iter == leAudioDevices_.end()) {
413 return nullptr;
414 }
415
416 return iter->lock().get();
417 }
418
GetNextActiveDeviceByDataPathState(LeAudioDevice * leAudioDevice,AudioStreamDataPathState data_path_state)419 LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByDataPathState(
420 LeAudioDevice* leAudioDevice, AudioStreamDataPathState data_path_state) {
421 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
422 [&leAudioDevice](auto& d) {
423 if (d.expired()) {
424 return false;
425 }
426
427 return d.lock().get() == leAudioDevice;
428 });
429
430 if (std::distance(iter, leAudioDevices_.end()) < 1) {
431 return nullptr;
432 }
433
434 iter = std::find_if(
435 std::next(iter, 1), leAudioDevices_.end(), [&data_path_state](auto& d) {
436 if (d.expired()) {
437 return false;
438 }
439
440 return (((d.lock()).get())
441 ->GetFirstActiveAseByDataPathState(data_path_state) !=
442 nullptr);
443 });
444
445 if (iter == leAudioDevices_.end()) {
446 return nullptr;
447 }
448
449 return iter->lock().get();
450 }
451
GetSduInterval(uint8_t direction)452 uint32_t LeAudioDeviceGroup::GetSduInterval(uint8_t direction) {
453 for (LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
454 leAudioDevice != nullptr;
455 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
456 struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
457 if (!ase) continue;
458
459 return ase->codec_config.GetFrameDurationUs();
460 }
461
462 return 0;
463 }
464
GetSCA(void)465 uint8_t LeAudioDeviceGroup::GetSCA(void) {
466 uint8_t sca = kIsoSca0To20Ppm;
467
468 for (const auto& leAudioDevice : leAudioDevices_) {
469 uint8_t dev_sca =
470 BTM_GetPeerSCA(leAudioDevice.lock()->address_, BT_TRANSPORT_LE);
471
472 /* If we could not read SCA from the peer device or sca is 0,
473 * then there is no reason to continue.
474 */
475 if ((dev_sca == 0xFF) || (dev_sca == 0)) return 0;
476
477 /* The Slaves_Clock_Accuracy parameter shall be the worst-case sleep clock
478 *accuracy of all the slaves that will participate in the CIG.
479 */
480 if (dev_sca < sca) {
481 sca = dev_sca;
482 }
483 }
484
485 return sca;
486 }
487
GetPacking(void)488 uint8_t LeAudioDeviceGroup::GetPacking(void) {
489 /* TODO: Decide about packing */
490 return kIsoCigPackingSequential;
491 }
492
GetFraming(void)493 uint8_t LeAudioDeviceGroup::GetFraming(void) {
494 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
495 LOG_ASSERT(leAudioDevice)
496 << __func__ << " Shouldn't be called without an active device.";
497
498 do {
499 struct ase* ase = leAudioDevice->GetFirstActiveAse();
500 if (!ase) continue;
501
502 do {
503 if (ase->framing == types::kFramingUnframedPduUnsupported)
504 return kIsoCigFramingFramed;
505 } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
506 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
507
508 return kIsoCigFramingUnframed;
509 }
510
511 /* TODO: Preferred parameter may be other than minimum */
find_max_transport_latency(LeAudioDeviceGroup * group,uint8_t direction)512 static uint16_t find_max_transport_latency(LeAudioDeviceGroup* group,
513 uint8_t direction) {
514 uint16_t max_transport_latency = 0;
515
516 for (LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
517 leAudioDevice != nullptr;
518 leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
519 for (ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
520 ase != nullptr;
521 ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)) {
522 if (!ase) break;
523
524 if (!max_transport_latency)
525 // first assignment
526 max_transport_latency = ase->max_transport_latency;
527 else if (ase->max_transport_latency < max_transport_latency)
528 max_transport_latency = ase->max_transport_latency;
529 }
530 }
531
532 if (max_transport_latency < types::kMaxTransportLatencyMin)
533 max_transport_latency = types::kMaxTransportLatencyMin;
534 else if (max_transport_latency > types::kMaxTransportLatencyMax)
535 max_transport_latency = types::kMaxTransportLatencyMax;
536
537 return max_transport_latency;
538 }
539
GetMaxTransportLatencyStom(void)540 uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyStom(void) {
541 return find_max_transport_latency(this, types::kLeAudioDirectionSource);
542 }
543
GetMaxTransportLatencyMtos(void)544 uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyMtos(void) {
545 return find_max_transport_latency(this, types::kLeAudioDirectionSink);
546 }
547
GetTransportLatencyUs(uint8_t direction)548 uint32_t LeAudioDeviceGroup::GetTransportLatencyUs(uint8_t direction) {
549 if (direction == types::kLeAudioDirectionSink) {
550 return transport_latency_mtos_us_;
551 } else if (direction == types::kLeAudioDirectionSource) {
552 return transport_latency_stom_us_ ;
553 } else {
554 LOG(ERROR) << __func__ << ", invalid direction";
555 return 0;
556 }
557 }
558
SetTransportLatency(uint8_t direction,uint32_t new_transport_latency_us)559 void LeAudioDeviceGroup::SetTransportLatency(uint8_t direction,
560 uint32_t new_transport_latency_us) {
561 uint32_t* transport_latency_us;
562
563 if (direction == types::kLeAudioDirectionSink) {
564 transport_latency_us = &transport_latency_mtos_us_;
565 } else if (direction == types::kLeAudioDirectionSource) {
566 transport_latency_us = &transport_latency_stom_us_;
567 } else {
568 LOG(ERROR) << __func__ << ", invalid direction";
569 return;
570 }
571
572 if (*transport_latency_us == new_transport_latency_us) return;
573
574 if ((*transport_latency_us != 0) &&
575 (*transport_latency_us != new_transport_latency_us)) {
576 LOG(WARNING) << __func__ << ", Different transport latency for group: "
577 << " old: " << static_cast<int>(*transport_latency_us)
578 << " [us], new: " << static_cast<int>(new_transport_latency_us)
579 << " [us]";
580 return;
581 }
582
583 LOG(INFO) << __func__ << ", updated group " << static_cast<int>(group_id_)
584 << " transport latency: " << static_cast<int>(new_transport_latency_us)
585 << " [us]";
586 *transport_latency_us = new_transport_latency_us;
587 }
588
GetRtn(uint8_t direction,uint8_t cis_id)589 uint8_t LeAudioDeviceGroup::GetRtn(uint8_t direction, uint8_t cis_id) {
590 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
591 LOG_ASSERT(leAudioDevice)
592 << __func__ << " Shouldn't be called without an active device.";
593
594 do {
595 auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id);
596
597 if (ases_pair.sink && direction == types::kLeAudioDirectionSink) {
598 return ases_pair.sink->retrans_nb;
599 } else if (ases_pair.source &&
600 direction == types::kLeAudioDirectionSource) {
601 return ases_pair.source->retrans_nb;
602 }
603 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
604
605 return 0;
606 }
607
GetMaxSduSize(uint8_t direction,uint8_t cis_id)608 uint16_t LeAudioDeviceGroup::GetMaxSduSize(uint8_t direction, uint8_t cis_id) {
609 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
610 LOG_ASSERT(leAudioDevice)
611 << __func__ << " Shouldn't be called without an active device.";
612
613 do {
614 auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id);
615
616 if (ases_pair.sink && direction == types::kLeAudioDirectionSink) {
617 return ases_pair.sink->max_sdu_size;
618 } else if (ases_pair.source &&
619 direction == types::kLeAudioDirectionSource) {
620 return ases_pair.source->max_sdu_size;
621 }
622 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
623
624 return 0;
625 }
626
GetPhyBitmask(uint8_t direction)627 uint8_t LeAudioDeviceGroup::GetPhyBitmask(uint8_t direction) {
628 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
629 LOG_ASSERT(leAudioDevice)
630 << __func__ << " Shouldn't be called without an active device.";
631
632 // local supported PHY's
633 uint8_t phy_bitfield = kIsoCigPhy1M;
634 if (controller_get_interface()->supports_ble_2m_phy())
635 phy_bitfield |= kIsoCigPhy2M;
636
637 if (!leAudioDevice) {
638 LOG(ERROR) << "No active leaudio device for direction?: " << +direction;
639 return phy_bitfield;
640 }
641
642 do {
643 struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
644 if (!ase) return phy_bitfield;
645
646 do {
647 if (direction == ase->direction) {
648 phy_bitfield &= leAudioDevice->GetPhyBitmask();
649
650 // A value of 0x00 denotes no preference
651 if (ase->preferred_phy && (phy_bitfield & ase->preferred_phy)) {
652 phy_bitfield &= ase->preferred_phy;
653 LOG_DEBUG("Using ASE preferred phy 0x%02x",
654 static_cast<int>(phy_bitfield));
655 } else {
656 LOG_WARN(
657 "ASE preferred 0x%02x has nothing common with phy_bitfield "
658 "0x%02x ",
659 static_cast<int>(ase->preferred_phy),
660 static_cast<int>(phy_bitfield));
661 }
662 }
663 } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)));
664 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
665
666 return phy_bitfield;
667 }
668
GetTargetPhy(uint8_t direction)669 uint8_t LeAudioDeviceGroup::GetTargetPhy(uint8_t direction) {
670 uint8_t phy_bitfield = GetPhyBitmask(direction);
671
672 // prefer to use 2M if supported
673 if (phy_bitfield & kIsoCigPhy2M)
674 return types::kTargetPhy2M;
675 else if (phy_bitfield & kIsoCigPhy1M)
676 return types::kTargetPhy1M;
677 else
678 return 0;
679 }
680
GetPresentationDelay(uint32_t * delay,uint8_t direction)681 bool LeAudioDeviceGroup::GetPresentationDelay(uint32_t* delay,
682 uint8_t direction) {
683 uint32_t delay_min = 0;
684 uint32_t delay_max = UINT32_MAX;
685 uint32_t preferred_delay_min = delay_min;
686 uint32_t preferred_delay_max = delay_max;
687
688 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
689 LOG_ASSERT(leAudioDevice)
690 << __func__ << " Shouldn't be called without an active device.";
691
692 do {
693 struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction);
694 if (!ase) continue; // device has no active ASEs in this direction
695
696 do {
697 /* No common range check */
698 if (ase->pres_delay_min > delay_max || ase->pres_delay_max < delay_min)
699 return false;
700
701 if (ase->pres_delay_min > delay_min) delay_min = ase->pres_delay_min;
702 if (ase->pres_delay_max < delay_max) delay_max = ase->pres_delay_max;
703 if (ase->preferred_pres_delay_min > preferred_delay_min)
704 preferred_delay_min = ase->preferred_pres_delay_min;
705 if (ase->preferred_pres_delay_max < preferred_delay_max &&
706 ase->preferred_pres_delay_max != types::kPresDelayNoPreference)
707 preferred_delay_max = ase->preferred_pres_delay_max;
708 } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)));
709 } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice)));
710
711 if (preferred_delay_min <= preferred_delay_max &&
712 preferred_delay_min > delay_min && preferred_delay_min < delay_max) {
713 *delay = preferred_delay_min;
714 } else {
715 *delay = delay_min;
716 }
717
718 return true;
719 }
720
GetRemoteDelay(uint8_t direction)721 uint16_t LeAudioDeviceGroup::GetRemoteDelay(uint8_t direction) {
722 uint16_t remote_delay_ms = 0;
723 uint32_t presentation_delay;
724
725 if (!GetPresentationDelay(&presentation_delay, direction)) {
726 /* This should never happens at stream request time but to be safe return
727 * some sample value to not break streaming
728 */
729 return 100;
730 }
731
732 /* us to ms */
733 remote_delay_ms = presentation_delay / 1000;
734 remote_delay_ms += GetTransportLatencyUs(direction) / 1000;
735
736 return remote_delay_ms;
737 }
738
UpdateAudioContextTypeAvailability(void)739 void LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(void) {
740 LOG_DEBUG(" group id: %d, available contexts: %s", group_id_,
741 group_available_contexts_.to_string().c_str());
742 UpdateAudioContextTypeAvailability(group_available_contexts_);
743 }
744
745 /* Returns true if support for any type in the whole group has changed,
746 * otherwise false. */
UpdateAudioContextTypeAvailability(AudioContexts update_contexts)747 bool LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(
748 AudioContexts update_contexts) {
749 auto new_contexts = AudioContexts();
750 bool active_contexts_has_been_modified = false;
751
752 if (update_contexts.none()) {
753 LOG_DEBUG("No context updated");
754 return false;
755 }
756
757 LOG_DEBUG("Updated context: %s", update_contexts.to_string().c_str());
758
759 for (LeAudioContextType ctx_type : types::kLeAudioContextAllTypesArray) {
760 LOG_DEBUG("Checking context: %s", ToHexString(ctx_type).c_str());
761
762 if (!update_contexts.test(ctx_type)) {
763 LOG_DEBUG("Configuration not in updated context");
764 /* Fill context bitset for possible returned value if updated */
765 if (available_context_to_configuration_map.count(ctx_type) > 0)
766 new_contexts.set(ctx_type);
767
768 continue;
769 }
770
771 auto new_conf = FindFirstSupportedConfiguration(ctx_type);
772
773 bool ctx_previously_not_supported =
774 (available_context_to_configuration_map.count(ctx_type) == 0 ||
775 available_context_to_configuration_map[ctx_type] == nullptr);
776 /* Check if support for context type has changed */
777 if (ctx_previously_not_supported) {
778 /* Current configuration for context type is empty */
779 if (new_conf == nullptr) {
780 /* Configuration remains empty */
781 continue;
782 } else {
783 /* Configuration changes from empty to some */
784 new_contexts.set(ctx_type);
785 active_contexts_has_been_modified = true;
786 }
787 } else {
788 /* Current configuration for context type is not empty */
789 if (new_conf == nullptr) {
790 /* Configuration changed to empty */
791 new_contexts.unset(ctx_type);
792 active_contexts_has_been_modified = true;
793 } else if (new_conf != available_context_to_configuration_map[ctx_type]) {
794 /* Configuration changed to any other */
795 new_contexts.set(ctx_type);
796 active_contexts_has_been_modified = true;
797 } else {
798 /* Configuration is the same */
799 new_contexts.set(ctx_type);
800 continue;
801 }
802 }
803
804 LOG_INFO(
805 "updated context: %s, %s -> %s", ToHexString(ctx_type).c_str(),
806 (ctx_previously_not_supported
807 ? "empty"
808 : available_context_to_configuration_map[ctx_type]->name.c_str()),
809 (new_conf != nullptr ? new_conf->name.c_str() : "empty"));
810
811 available_context_to_configuration_map[ctx_type] = new_conf;
812 }
813
814 /* Some contexts have changed, return new available context bitset */
815 if (active_contexts_has_been_modified) {
816 group_available_contexts_ = new_contexts;
817 }
818
819 return active_contexts_has_been_modified;
820 }
821
ReloadAudioLocations(void)822 bool LeAudioDeviceGroup::ReloadAudioLocations(void) {
823 AudioLocations updated_snk_audio_locations_ =
824 codec_spec_conf::kLeAudioLocationNotAllowed;
825 AudioLocations updated_src_audio_locations_ =
826 codec_spec_conf::kLeAudioLocationNotAllowed;
827
828 for (const auto& device : leAudioDevices_) {
829 if (device.expired() || (device.lock().get()->GetConnectionState() !=
830 DeviceConnectState::CONNECTED))
831 continue;
832 updated_snk_audio_locations_ |= device.lock().get()->snk_audio_locations_;
833 updated_src_audio_locations_ |= device.lock().get()->src_audio_locations_;
834 }
835
836 /* Nothing has changed */
837 if ((updated_snk_audio_locations_ == snk_audio_locations_) &&
838 (updated_src_audio_locations_ == src_audio_locations_))
839 return false;
840
841 snk_audio_locations_ = updated_snk_audio_locations_;
842 src_audio_locations_ = updated_src_audio_locations_;
843
844 return true;
845 }
846
ReloadAudioDirections(void)847 bool LeAudioDeviceGroup::ReloadAudioDirections(void) {
848 uint8_t updated_audio_directions = 0x00;
849
850 for (const auto& device : leAudioDevices_) {
851 if (device.expired() || (device.lock().get()->GetConnectionState() !=
852 DeviceConnectState::CONNECTED))
853 continue;
854 updated_audio_directions |= device.lock().get()->audio_directions_;
855 }
856
857 /* Nothing has changed */
858 if (updated_audio_directions == audio_directions_) return false;
859
860 audio_directions_ = updated_audio_directions;
861
862 return true;
863 }
864
IsInTransition(void)865 bool LeAudioDeviceGroup::IsInTransition(void) {
866 return target_state_ != current_state_;
867 }
868
IsReleasingOrIdle(void)869 bool LeAudioDeviceGroup::IsReleasingOrIdle(void) {
870 return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) ||
871 (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
872 }
873
IsGroupStreamReady(void)874 bool LeAudioDeviceGroup::IsGroupStreamReady(void) {
875 auto iter =
876 std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) {
877 if (d.expired())
878 return false;
879 else
880 return !(((d.lock()).get())->HaveAllActiveAsesCisEst());
881 });
882
883 return iter == leAudioDevices_.end();
884 }
885
HaveAllCisesDisconnected(void)886 bool LeAudioDeviceGroup::HaveAllCisesDisconnected(void) {
887 for (auto const dev : leAudioDevices_) {
888 if (dev.expired()) continue;
889 if (dev.lock().get()->HaveAnyCisConnected()) return false;
890 }
891 return true;
892 }
893
GetFirstFreeCisId(void)894 uint8_t LeAudioDeviceGroup::GetFirstFreeCisId(void) {
895 for (uint8_t id = 0; id < UINT8_MAX; id++) {
896 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
897 [id](auto& d) {
898 if (d.expired())
899 return false;
900 else
901 return ((d.lock()).get())->HasCisId(id);
902 });
903
904 if (iter == leAudioDevices_.end()) return id;
905 }
906
907 return kInvalidCisId;
908 }
909
GetFirstFreeCisId(CisType cis_type)910 uint8_t LeAudioDeviceGroup::GetFirstFreeCisId(CisType cis_type) {
911 LOG_DEBUG("Group: %p, group_id: %d cis_type: %d", this, group_id_,
912 static_cast<int>(cis_type));
913 for (size_t id = 0; id < cises_.size(); id++) {
914 if (cises_[id].addr.IsEmpty() && cises_[id].type == cis_type) {
915 return id;
916 }
917 }
918 return kInvalidCisId;
919 }
920
GetGroupStrategy(void)921 types::LeAudioConfigurationStrategy LeAudioDeviceGroup::GetGroupStrategy(void) {
922 /* Simple strategy picker */
923 LOG_INFO(" Group %d size %d", group_id_, Size());
924 if (Size() > 1) {
925 return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
926 }
927
928 LOG_INFO("audio location 0x%04lx", snk_audio_locations_.to_ulong());
929 if (!(snk_audio_locations_.to_ulong() &
930 codec_spec_conf::kLeAudioLocationAnyLeft) ||
931 !(snk_audio_locations_.to_ulong() &
932 codec_spec_conf::kLeAudioLocationAnyRight)) {
933 return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
934 }
935
936 auto device = GetFirstDevice();
937 auto channel_cnt =
938 device->GetLc3SupportedChannelCount(types::kLeAudioDirectionSink);
939 LOG_INFO("Channel count for group %d is %d (device %s)", group_id_,
940 channel_cnt, device->address_.ToString().c_str());
941 if (channel_cnt == 1) {
942 return types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE;
943 }
944
945 return types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE;
946 }
947
GetAseCount(uint8_t direction)948 int LeAudioDeviceGroup::GetAseCount(uint8_t direction) {
949 int result = 0;
950 for (const auto& device_iter : leAudioDevices_) {
951 result += device_iter.lock()->GetAseCount(direction);
952 }
953
954 return result;
955 }
956
CigGenerateCisIds(types::LeAudioContextType context_type)957 void LeAudioDeviceGroup::CigGenerateCisIds(
958 types::LeAudioContextType context_type) {
959 LOG_INFO("Group %p, group_id: %d, context_type: %s", this, group_id_,
960 bluetooth::common::ToString(context_type).c_str());
961
962 if (cises_.size() > 0) {
963 LOG_INFO("CIS IDs already generated");
964 return;
965 }
966
967 const set_configurations::AudioSetConfigurations* confs =
968 AudioSetConfigurationProvider::Get()->GetConfigurations(context_type);
969
970 uint8_t cis_count_bidir = 0;
971 uint8_t cis_count_unidir_sink = 0;
972 uint8_t cis_count_unidir_source = 0;
973 int csis_group_size =
974 bluetooth::csis::CsisClient::Get()->GetDesiredSize(group_id_);
975 /* If this is CSIS group, the csis_group_size will be > 0, otherwise -1.
976 * If the last happen it means, group size is 1 */
977 int group_size = csis_group_size > 0 ? csis_group_size : 1;
978
979 get_cis_count(*confs, group_size, GetGroupStrategy(),
980 GetAseCount(types::kLeAudioDirectionSink),
981 GetAseCount(types::kLeAudioDirectionSource), cis_count_bidir,
982 cis_count_unidir_sink, cis_count_unidir_source);
983
984 uint8_t idx = 0;
985 while (cis_count_bidir > 0) {
986 struct le_audio::types::cis cis_entry = {
987 .id = idx,
988 .addr = RawAddress::kEmpty,
989 .type = CisType::CIS_TYPE_BIDIRECTIONAL,
990 .conn_handle = 0,
991 };
992 cises_.push_back(cis_entry);
993 cis_count_bidir--;
994 idx++;
995 }
996
997 while (cis_count_unidir_sink > 0) {
998 struct le_audio::types::cis cis_entry = {
999 .id = idx,
1000 .addr = RawAddress::kEmpty,
1001 .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK,
1002 .conn_handle = 0,
1003 };
1004 cises_.push_back(cis_entry);
1005 cis_count_unidir_sink--;
1006 idx++;
1007 }
1008
1009 while (cis_count_unidir_source > 0) {
1010 struct le_audio::types::cis cis_entry = {
1011 .id = idx,
1012 .addr = RawAddress::kEmpty,
1013 .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE,
1014 .conn_handle = 0,
1015 };
1016 cises_.push_back(cis_entry);
1017 cis_count_unidir_source--;
1018 idx++;
1019 }
1020 }
1021
CigAssignCisIds(LeAudioDevice * leAudioDevice)1022 bool LeAudioDeviceGroup::CigAssignCisIds(LeAudioDevice* leAudioDevice) {
1023 ASSERT_LOG(leAudioDevice, "invalid device");
1024 LOG_INFO("device: %s", leAudioDevice->address_.ToString().c_str());
1025
1026 struct ase* ase = leAudioDevice->GetFirstActiveAse();
1027 if (!ase) {
1028 LOG_ERROR(" Device %s shouldn't be called without an active ASE",
1029 leAudioDevice->address_.ToString().c_str());
1030 return false;
1031 }
1032
1033 for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) {
1034 uint8_t cis_id = kInvalidCisId;
1035 /* CIS ID already set */
1036 if (ase->cis_id != kInvalidCisId) {
1037 LOG_INFO("ASE ID: %d, is already assigned CIS ID: %d, type %d", ase->id,
1038 ase->cis_id, cises_[ase->cis_id].type);
1039 if (!cises_[ase->cis_id].addr.IsEmpty()) {
1040 LOG_INFO("Bidirectional ASE already assigned");
1041 continue;
1042 }
1043 /* Reuse existing CIS ID if available*/
1044 cis_id = ase->cis_id;
1045 }
1046
1047 /* First check if we have bidirectional ASEs. If so, assign same CIS ID.*/
1048 struct ase* matching_bidir_ase =
1049 leAudioDevice->GetNextActiveAseWithDifferentDirection(ase);
1050
1051 if (matching_bidir_ase) {
1052 if (cis_id == kInvalidCisId) {
1053 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1054 }
1055
1056 if (cis_id != kInvalidCisId) {
1057 ase->cis_id = cis_id;
1058 matching_bidir_ase->cis_id = cis_id;
1059 cises_[cis_id].addr = leAudioDevice->address_;
1060
1061 LOG_INFO(
1062 " ASE ID: %d and ASE ID: %d, assigned Bi-Directional CIS ID: %d",
1063 +ase->id, +matching_bidir_ase->id, +ase->cis_id);
1064 continue;
1065 }
1066
1067 LOG_WARN(
1068 " ASE ID: %d, unable to get free Bi-Directional CIS ID but maybe "
1069 "thats fine. Try using unidirectional.",
1070 ase->id);
1071 }
1072
1073 if (ase->direction == types::kLeAudioDirectionSink) {
1074 if (cis_id == kInvalidCisId) {
1075 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SINK);
1076 }
1077
1078 if (cis_id == kInvalidCisId) {
1079 LOG_WARN(
1080 " Unable to get free Uni-Directional Sink CIS ID - maybe there is "
1081 "bi-directional available");
1082 /* This could happen when scenarios for given context type allows for
1083 * Sink and Source configuration but also only Sink configuration.
1084 */
1085 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1086 if (cis_id == kInvalidCisId) {
1087 LOG_ERROR("Unable to get free Uni-Directional Sink CIS ID");
1088 return false;
1089 }
1090 }
1091
1092 ase->cis_id = cis_id;
1093 cises_[cis_id].addr = leAudioDevice->address_;
1094 LOG_INFO("ASE ID: %d, assigned Uni-Directional Sink CIS ID: %d", ase->id,
1095 ase->cis_id);
1096 continue;
1097 }
1098
1099 /* Source direction */
1100 ASSERT_LOG(ase->direction == types::kLeAudioDirectionSource,
1101 "Expected Source direction, actual=%d", ase->direction);
1102
1103 if (cis_id == kInvalidCisId) {
1104 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE);
1105 }
1106
1107 if (cis_id == kInvalidCisId) {
1108 /* This could happen when scenarios for given context type allows for
1109 * Sink and Source configuration but also only Sink configuration.
1110 */
1111 LOG_WARN(
1112 "Unable to get free Uni-Directional Source CIS ID - maybe there "
1113 "is bi-directional available");
1114 cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
1115 if (cis_id == kInvalidCisId) {
1116 LOG_ERROR("Unable to get free Uni-Directional Source CIS ID");
1117 return false;
1118 }
1119 }
1120
1121 ase->cis_id = cis_id;
1122 cises_[cis_id].addr = leAudioDevice->address_;
1123 LOG_INFO("ASE ID: %d, assigned Uni-Directional Source CIS ID: %d", ase->id,
1124 ase->cis_id);
1125 }
1126
1127 return true;
1128 }
1129
CigAssignCisConnHandles(const std::vector<uint16_t> & conn_handles)1130 void LeAudioDeviceGroup::CigAssignCisConnHandles(
1131 const std::vector<uint16_t>& conn_handles) {
1132 LOG_INFO("num of cis handles %d", static_cast<int>(conn_handles.size()));
1133 for (size_t i = 0; i < cises_.size(); i++) {
1134 cises_[i].conn_handle = conn_handles[i];
1135 LOG_INFO("assigning cis[%d] conn_handle: %d", cises_[i].id,
1136 cises_[i].conn_handle);
1137 }
1138 }
1139
CigAssignCisConnHandlesToAses(LeAudioDevice * leAudioDevice)1140 void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses(
1141 LeAudioDevice* leAudioDevice) {
1142 ASSERT_LOG(leAudioDevice, "Invalid device");
1143 LOG_INFO("group: %p, group_id: %d, device: %s", this, group_id_,
1144 leAudioDevice->address_.ToString().c_str());
1145
1146 /* Assign all CIS connection handles to ases */
1147 struct le_audio::types::ase* ase =
1148 leAudioDevice->GetFirstActiveAseByDataPathState(
1149 AudioStreamDataPathState::IDLE);
1150 if (!ase) {
1151 LOG_WARN("No active ASE with AudioStreamDataPathState IDLE");
1152 return;
1153 }
1154
1155 for (; ase != nullptr; ase = leAudioDevice->GetFirstActiveAseByDataPathState(
1156 AudioStreamDataPathState::IDLE)) {
1157 auto ases_pair = leAudioDevice->GetAsesByCisId(ase->cis_id);
1158
1159 if (ases_pair.sink && ases_pair.sink->active) {
1160 ases_pair.sink->cis_conn_hdl = cises_[ase->cis_id].conn_handle;
1161 ases_pair.sink->data_path_state = AudioStreamDataPathState::CIS_ASSIGNED;
1162 }
1163 if (ases_pair.source && ases_pair.source->active) {
1164 ases_pair.source->cis_conn_hdl = cises_[ase->cis_id].conn_handle;
1165 ases_pair.source->data_path_state =
1166 AudioStreamDataPathState::CIS_ASSIGNED;
1167 }
1168 }
1169 }
1170
CigAssignCisConnHandlesToAses(void)1171 void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses(void) {
1172 LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
1173 ASSERT_LOG(leAudioDevice, "Shouldn't be called without an active device.");
1174
1175 LOG_INFO("Group %p, group_id %d", this, group_id_);
1176
1177 /* Assign all CIS connection handles to ases */
1178 for (; leAudioDevice != nullptr;
1179 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
1180 CigAssignCisConnHandlesToAses(leAudioDevice);
1181 }
1182 }
1183
CigUnassignCis(LeAudioDevice * leAudioDevice)1184 void LeAudioDeviceGroup::CigUnassignCis(LeAudioDevice* leAudioDevice) {
1185 ASSERT_LOG(leAudioDevice, "Invalid device");
1186
1187 LOG_INFO("Group %p, group_id %d, device: %s", this, group_id_,
1188 leAudioDevice->address_.ToString().c_str());
1189
1190 for (struct le_audio::types::cis& cis_entry : cises_) {
1191 if (cis_entry.addr == leAudioDevice->address_) {
1192 cis_entry.addr = RawAddress::kEmpty;
1193 }
1194 }
1195 }
1196
CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,types::AudioLocations audio_locations,uint8_t requested_channel_count,uint8_t channel_count_mask)1197 bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,
1198 types::AudioLocations audio_locations,
1199 uint8_t requested_channel_count,
1200 uint8_t channel_count_mask) {
1201 DLOG(INFO) << __func__ << " strategy: " << (int)strategy
1202 << " locations: " << +audio_locations.to_ulong();
1203
1204 switch (strategy) {
1205 case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1206 return audio_locations.any();
1207 case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
1208 if ((audio_locations.to_ulong() &
1209 codec_spec_conf::kLeAudioLocationAnyLeft) &&
1210 (audio_locations.to_ulong() &
1211 codec_spec_conf::kLeAudioLocationAnyRight))
1212 return true;
1213 else
1214 return false;
1215 case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
1216 if (!(audio_locations.to_ulong() &
1217 codec_spec_conf::kLeAudioLocationAnyLeft) ||
1218 !(audio_locations.to_ulong() &
1219 codec_spec_conf::kLeAudioLocationAnyRight))
1220 return false;
1221
1222 DLOG(INFO) << __func__ << " requested chan cnt "
1223 << +requested_channel_count
1224 << " chan mask: " << loghex(channel_count_mask);
1225
1226 /* Return true if requested channel count is set in the channel count
1227 * mask. In the channel_count_mask, bit0 is set when 1 channel is
1228 * supported.
1229 */
1230 return ((1 << (requested_channel_count - 1)) & channel_count_mask);
1231 default:
1232 return false;
1233 }
1234
1235 return false;
1236 }
1237
1238 /* This method check if group support given audio configuration
1239 * requirement for connected devices in the group and available ASEs
1240 * (no matter on the ASE state) and for given context type
1241 */
IsConfigurationSupported(const set_configurations::AudioSetConfiguration * audio_set_conf,types::LeAudioContextType context_type)1242 bool LeAudioDeviceGroup::IsConfigurationSupported(
1243 const set_configurations::AudioSetConfiguration* audio_set_conf,
1244 types::LeAudioContextType context_type) {
1245 if (!set_configurations::check_if_may_cover_scenario(
1246 audio_set_conf, NumOfConnected(context_type))) {
1247 LOG_DEBUG(" cannot cover scenario %s: size of for context type %d",
1248 bluetooth::common::ToString(context_type).c_str(),
1249 +NumOfConnected(context_type));
1250 return false;
1251 }
1252
1253 auto required_snk_strategy = GetGroupStrategy();
1254
1255 /* TODO For now: set ase if matching with first pac.
1256 * 1) We assume as well that devices will match requirements in order
1257 * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
1258 * 2) ASEs should be active only if best (according to priority list) full
1259 * scenarion will be covered.
1260 * 3) ASEs should be filled according to performance profile.
1261 */
1262 for (const auto& ent : (*audio_set_conf).confs) {
1263 LOG_DEBUG(" Looking for configuration: %s - %s",
1264 audio_set_conf->name.c_str(),
1265 (ent.direction == types::kLeAudioDirectionSink ? "snk" : "src"));
1266
1267 uint8_t required_device_cnt = ent.device_cnt;
1268 uint8_t max_required_ase_per_dev =
1269 ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt);
1270 uint8_t active_ase_num = 0;
1271 auto strategy = ent.strategy;
1272
1273 LOG_DEBUG(
1274 " Number of devices: %d, number of ASEs: %d, Max ASE per device: %d "
1275 "strategy: %d",
1276 +required_device_cnt, +ent.ase_cnt, +max_required_ase_per_dev,
1277 static_cast<int>(strategy));
1278
1279 if (ent.direction == types::kLeAudioDirectionSink &&
1280 strategy != required_snk_strategy) {
1281 LOG_INFO(" Sink strategy mismatch group!=cfg.entry (%d!=%d)",
1282 static_cast<int>(required_snk_strategy),
1283 static_cast<int>(strategy));
1284 return false;
1285 }
1286
1287 for (auto* device = GetFirstDeviceWithActiveContext(context_type);
1288 device != nullptr && required_device_cnt > 0;
1289 device = GetNextDeviceWithActiveContext(device, context_type)) {
1290 /* Skip if device has ASE configured in this direction already */
1291
1292 if (device->ases_.empty()) continue;
1293
1294 if (!device->GetCodecConfigurationSupportedPac(ent.direction, ent.codec))
1295 continue;
1296
1297 int needed_ase = std::min(static_cast<int>(max_required_ase_per_dev),
1298 static_cast<int>(ent.ase_cnt - active_ase_num));
1299
1300 /* If we required more ASEs per device which means we would like to
1301 * create more CISes to one device, we should also check the allocation
1302 * if it allows us to do this.
1303 */
1304
1305 types::AudioLocations audio_locations = 0;
1306 /* Check direction and if audio location allows to create more cise */
1307 if (ent.direction == types::kLeAudioDirectionSink)
1308 audio_locations = device->snk_audio_locations_;
1309 else
1310 audio_locations = device->src_audio_locations_;
1311
1312 /* TODO Make it no Lc3 specific */
1313 if (!CheckIfStrategySupported(
1314 strategy, audio_locations,
1315 std::get<LeAudioLc3Config>(ent.codec.config).GetChannelCount(),
1316 device->GetLc3SupportedChannelCount(ent.direction))) {
1317 LOG_DEBUG(" insufficient device audio allocation: %lu",
1318 audio_locations.to_ulong());
1319 continue;
1320 }
1321
1322 for (auto& ase : device->ases_) {
1323 if (ase.direction != ent.direction) continue;
1324
1325 active_ase_num++;
1326 needed_ase--;
1327
1328 if (needed_ase == 0) break;
1329 }
1330
1331 if (needed_ase > 0) {
1332 LOG_DEBUG("Device has too less ASEs. Still needed ases %d", needed_ase);
1333 return false;
1334 }
1335
1336 required_device_cnt--;
1337 }
1338
1339 if (required_device_cnt > 0) {
1340 /* Don't left any active devices if requirements are not met */
1341 LOG_DEBUG(" could not configure all the devices");
1342 return false;
1343 }
1344 }
1345
1346 LOG_DEBUG("Chosen ASE Configuration for group: %d, configuration: %s",
1347 this->group_id_, audio_set_conf->name.c_str());
1348 return true;
1349 }
1350
GetFirstLeft(const types::AudioLocations & audio_locations)1351 static uint32_t GetFirstLeft(const types::AudioLocations& audio_locations) {
1352 uint32_t audio_location_ulong = audio_locations.to_ulong();
1353
1354 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeft)
1355 return codec_spec_conf::kLeAudioLocationFrontLeft;
1356
1357 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackLeft)
1358 return codec_spec_conf::kLeAudioLocationBackLeft;
1359
1360 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftOfCenter)
1361 return codec_spec_conf::kLeAudioLocationFrontLeftOfCenter;
1362
1363 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideLeft)
1364 return codec_spec_conf::kLeAudioLocationSideLeft;
1365
1366 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontLeft)
1367 return codec_spec_conf::kLeAudioLocationTopFrontLeft;
1368
1369 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackLeft)
1370 return codec_spec_conf::kLeAudioLocationTopBackLeft;
1371
1372 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideLeft)
1373 return codec_spec_conf::kLeAudioLocationTopSideLeft;
1374
1375 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontLeft)
1376 return codec_spec_conf::kLeAudioLocationBottomFrontLeft;
1377
1378 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftWide)
1379 return codec_spec_conf::kLeAudioLocationFrontLeftWide;
1380
1381 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround)
1382 return codec_spec_conf::kLeAudioLocationLeftSurround;
1383
1384 return 0;
1385 }
1386
GetFirstRight(const types::AudioLocations & audio_locations)1387 static uint32_t GetFirstRight(const types::AudioLocations& audio_locations) {
1388 uint32_t audio_location_ulong = audio_locations.to_ulong();
1389
1390 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRight)
1391 return codec_spec_conf::kLeAudioLocationFrontRight;
1392
1393 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackRight)
1394 return codec_spec_conf::kLeAudioLocationBackRight;
1395
1396 if (audio_location_ulong &
1397 codec_spec_conf::kLeAudioLocationFrontRightOfCenter)
1398 return codec_spec_conf::kLeAudioLocationFrontRightOfCenter;
1399
1400 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideRight)
1401 return codec_spec_conf::kLeAudioLocationSideRight;
1402
1403 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontRight)
1404 return codec_spec_conf::kLeAudioLocationTopFrontRight;
1405
1406 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackRight)
1407 return codec_spec_conf::kLeAudioLocationTopBackRight;
1408
1409 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideRight)
1410 return codec_spec_conf::kLeAudioLocationTopSideRight;
1411
1412 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontRight)
1413 return codec_spec_conf::kLeAudioLocationBottomFrontRight;
1414
1415 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRightWide)
1416 return codec_spec_conf::kLeAudioLocationFrontRightWide;
1417
1418 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround)
1419 return codec_spec_conf::kLeAudioLocationRightSurround;
1420
1421 return 0;
1422 }
1423
PickAudioLocation(types::LeAudioConfigurationStrategy strategy,types::AudioLocations device_locations,types::AudioLocations * group_locations)1424 uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy,
1425 types::AudioLocations device_locations,
1426 types::AudioLocations* group_locations) {
1427 LOG_DEBUG("strategy: %d, locations: 0x%lx, group locations: 0x%lx",
1428 (int)strategy, device_locations.to_ulong(),
1429 group_locations->to_ulong());
1430
1431 auto is_left_not_yet_assigned =
1432 !(group_locations->to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft);
1433 auto is_right_not_yet_assigned = !(group_locations->to_ulong() &
1434 codec_spec_conf::kLeAudioLocationAnyRight);
1435 uint32_t left_device_loc = GetFirstLeft(device_locations);
1436 uint32_t right_device_loc = GetFirstRight(device_locations);
1437
1438 if (left_device_loc == 0 && right_device_loc == 0) {
1439 LOG_WARN("Can't find device able to render left and right audio channel");
1440 }
1441
1442 switch (strategy) {
1443 case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
1444 case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
1445 if (left_device_loc && is_left_not_yet_assigned) {
1446 *group_locations |= left_device_loc;
1447 return left_device_loc;
1448 }
1449
1450 if (right_device_loc && is_right_not_yet_assigned) {
1451 *group_locations |= right_device_loc;
1452 return right_device_loc;
1453 }
1454 break;
1455
1456 case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
1457 if (left_device_loc && right_device_loc) {
1458 *group_locations |= left_device_loc | right_device_loc;
1459 return left_device_loc | right_device_loc;
1460 }
1461 break;
1462 default:
1463 LOG_ALWAYS_FATAL("%s: Unknown strategy: %hhu", __func__, strategy);
1464 return 0;
1465 }
1466
1467 LOG_ERROR(
1468 "Can't find device for left/right channel. Strategy: %hhu, "
1469 "device_locations: %lx, group_locations: %lx.",
1470 strategy, device_locations.to_ulong(), group_locations->to_ulong());
1471
1472 /* Return either any left or any right audio location. It might result with
1473 * multiple devices within the group having the same location.
1474 */
1475 return left_device_loc ? left_device_loc : right_device_loc;
1476 }
1477
ConfigureAses(const le_audio::set_configurations::SetConfiguration & ent,types::LeAudioContextType context_type,uint8_t * number_of_already_active_group_ase,types::AudioLocations & group_snk_audio_locations,types::AudioLocations & group_src_audio_locations,bool reuse_cis_id,AudioContexts metadata_context_type,const std::vector<uint8_t> & ccid_list)1478 bool LeAudioDevice::ConfigureAses(
1479 const le_audio::set_configurations::SetConfiguration& ent,
1480 types::LeAudioContextType context_type,
1481 uint8_t* number_of_already_active_group_ase,
1482 types::AudioLocations& group_snk_audio_locations,
1483 types::AudioLocations& group_src_audio_locations, bool reuse_cis_id,
1484 AudioContexts metadata_context_type,
1485 const std::vector<uint8_t>& ccid_list) {
1486 /* First try to use the already configured ASE */
1487 auto ase = GetFirstActiveAseByDirection(ent.direction);
1488 if (ase) {
1489 LOG_INFO("Using an already active ASE id=%d", ase->id);
1490 } else {
1491 ase = GetFirstInactiveAse(ent.direction, reuse_cis_id);
1492 }
1493
1494 if (!ase) {
1495 LOG_ERROR("Unable to find an ASE to configure");
1496 return false;
1497 }
1498
1499 /* The number_of_already_active_group_ase keeps all the active ases
1500 * in other devices in the group.
1501 * This function counts active ases only for this device, and we count here
1502 * new active ases and already active ases which we want to reuse in the
1503 * scenario
1504 */
1505 uint8_t active_ases = *number_of_already_active_group_ase;
1506 uint8_t max_required_ase_per_dev =
1507 ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt);
1508 le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy;
1509
1510 auto pac = GetCodecConfigurationSupportedPac(ent.direction, ent.codec);
1511 if (!pac) return false;
1512
1513 int needed_ase = std::min((int)(max_required_ase_per_dev),
1514 (int)(ent.ase_cnt - active_ases));
1515
1516 types::AudioLocations audio_locations = 0;
1517 types::AudioLocations* group_audio_locations;
1518 /* Check direction and if audio location allows to create more cise */
1519 if (ent.direction == types::kLeAudioDirectionSink) {
1520 audio_locations = snk_audio_locations_;
1521 group_audio_locations = &group_snk_audio_locations;
1522 } else {
1523 audio_locations = src_audio_locations_;
1524 group_audio_locations = &group_src_audio_locations;
1525 }
1526
1527 for (; needed_ase && ase; needed_ase--) {
1528 ase->active = true;
1529 ase->configured_for_context_type = context_type;
1530 active_ases++;
1531
1532 /* In case of late connect, we could be here for STREAMING ase.
1533 * in such case, it is needed to mark ase as known active ase which
1534 * is important to validate scenario and is done already few lines above.
1535 * Nothing more to do is needed here.
1536 */
1537 if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
1538 if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED)
1539 ase->reconfigure = true;
1540
1541 ase->target_latency = ent.target_latency;
1542 ase->codec_id = ent.codec.id;
1543 /* TODO: find better way to not use LC3 explicitly */
1544 ase->codec_config = std::get<LeAudioLc3Config>(ent.codec.config);
1545
1546 /*Let's choose audio channel allocation if not set */
1547 ase->codec_config.audio_channel_allocation =
1548 PickAudioLocation(strategy, audio_locations, group_audio_locations);
1549
1550 /* Get default value if no requirement for specific frame blocks per sdu
1551 */
1552 if (!ase->codec_config.codec_frames_blocks_per_sdu) {
1553 ase->codec_config.codec_frames_blocks_per_sdu =
1554 GetMaxCodecFramesPerSduFromPac(pac);
1555 }
1556 ase->max_sdu_size = codec_spec_caps::GetAudioChannelCounts(
1557 *ase->codec_config.audio_channel_allocation) *
1558 *ase->codec_config.octets_per_codec_frame *
1559 *ase->codec_config.codec_frames_blocks_per_sdu;
1560
1561 ase->retrans_nb = ent.qos.retransmission_number;
1562 ase->max_transport_latency = ent.qos.max_transport_latency;
1563
1564 /* Filter multidirectional audio context for each ase direction */
1565 auto directional_audio_context =
1566 metadata_context_type & GetAvailableContexts(ase->direction);
1567 if (directional_audio_context.any()) {
1568 ase->metadata = GetMetadata(directional_audio_context, ccid_list);
1569 } else {
1570 ase->metadata =
1571 GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED),
1572 std::vector<uint8_t>());
1573 }
1574 }
1575
1576 LOG_DEBUG(
1577 "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, "
1578 "cis_id=%d, target_latency=%d",
1579 address_.ToString().c_str(), ase->id,
1580 (ent.direction == 1 ? "snk" : "src"), ase->max_sdu_size, ase->cis_id,
1581 ent.target_latency);
1582
1583 /* Try to use the already active ASE */
1584 ase = GetNextActiveAseWithSameDirection(ase);
1585 if (ase == nullptr) {
1586 ase = GetFirstInactiveAse(ent.direction, reuse_cis_id);
1587 }
1588 }
1589
1590 *number_of_already_active_group_ase = active_ases;
1591 return true;
1592 }
1593
1594 /* This method should choose aproperiate ASEs to be active and set a cached
1595 * configuration for codec and qos.
1596 */
ConfigureAses(const set_configurations::AudioSetConfiguration * audio_set_conf,types::LeAudioContextType context_type,AudioContexts metadata_context_type,const std::vector<uint8_t> & ccid_list)1597 bool LeAudioDeviceGroup::ConfigureAses(
1598 const set_configurations::AudioSetConfiguration* audio_set_conf,
1599 types::LeAudioContextType context_type, AudioContexts metadata_context_type,
1600 const std::vector<uint8_t>& ccid_list) {
1601 if (!set_configurations::check_if_may_cover_scenario(
1602 audio_set_conf, NumOfConnected(context_type)))
1603 return false;
1604
1605 bool reuse_cis_id =
1606 GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
1607
1608 /* TODO For now: set ase if matching with first pac.
1609 * 1) We assume as well that devices will match requirements in order
1610 * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
1611 * 2) ASEs should be active only if best (according to priority list) full
1612 * scenarion will be covered.
1613 * 3) ASEs should be filled according to performance profile.
1614 */
1615
1616 types::AudioLocations group_snk_audio_locations = 0;
1617 types::AudioLocations group_src_audio_locations = 0;
1618
1619 for (const auto& ent : (*audio_set_conf).confs) {
1620 LOG_DEBUG(" Looking for requirements: %s, - %s",
1621 audio_set_conf->name.c_str(),
1622 (ent.direction == 1 ? "snk" : "src"));
1623
1624 uint8_t required_device_cnt = ent.device_cnt;
1625 uint8_t max_required_ase_per_dev =
1626 ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt);
1627 uint8_t active_ase_num = 0;
1628 le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy;
1629
1630 LOG_DEBUG(
1631 "Number of devices: %d number of ASEs: %d, Max ASE per device: %d "
1632 "strategy: %d",
1633 required_device_cnt, ent.ase_cnt, max_required_ase_per_dev,
1634 (int)strategy);
1635
1636 for (auto* device = GetFirstDeviceWithActiveContext(context_type);
1637 device != nullptr && required_device_cnt > 0;
1638 device = GetNextDeviceWithActiveContext(device, context_type)) {
1639 /* For the moment, we configure only connected devices and when it is
1640 * ready to stream i.e. All ASEs are discovered and device is reported as
1641 * connected
1642 */
1643 if (device->GetConnectionState() != DeviceConnectState::CONNECTED) {
1644 LOG_WARN(
1645 "Device %s, in the state %s", device->address_.ToString().c_str(),
1646 bluetooth::common::ToString(device->GetConnectionState()).c_str());
1647 continue;
1648 }
1649
1650 if (!device->ConfigureAses(ent, context_type, &active_ase_num,
1651 group_snk_audio_locations,
1652 group_src_audio_locations, reuse_cis_id,
1653 metadata_context_type, ccid_list))
1654 continue;
1655
1656 required_device_cnt--;
1657 }
1658
1659 if (required_device_cnt > 0) {
1660 /* Don't left any active devices if requirements are not met */
1661 LOG_ERROR(" could not configure all the devices");
1662 Deactivate();
1663 return false;
1664 }
1665 }
1666
1667 LOG_INFO("Choosed ASE Configuration for group: %d, configuration: %s",
1668 group_id_, audio_set_conf->name.c_str());
1669
1670 configuration_context_type_ = context_type;
1671 metadata_context_type_ = metadata_context_type;
1672 return true;
1673 }
1674
1675 const set_configurations::AudioSetConfiguration*
GetActiveConfiguration(void)1676 LeAudioDeviceGroup::GetActiveConfiguration(void) {
1677 return available_context_to_configuration_map[configuration_context_type_];
1678 }
1679
1680 std::optional<LeAudioCodecConfiguration>
GetCodecConfigurationByDirection(types::LeAudioContextType group_context_type,uint8_t direction) const1681 LeAudioDeviceGroup::GetCodecConfigurationByDirection(
1682 types::LeAudioContextType group_context_type, uint8_t direction) const {
1683 if (available_context_to_configuration_map.count(group_context_type) == 0) {
1684 LOG_DEBUG("Context type %s, not supported",
1685 bluetooth::common::ToString(group_context_type).c_str());
1686 return std::nullopt;
1687 }
1688
1689 const set_configurations::AudioSetConfiguration* audio_set_conf =
1690 available_context_to_configuration_map.at(group_context_type);
1691 LeAudioCodecConfiguration group_config = {0, 0, 0, 0};
1692 if (!audio_set_conf) return std::nullopt;
1693
1694 for (const auto& conf : audio_set_conf->confs) {
1695 if (conf.direction != direction) continue;
1696
1697 if (group_config.sample_rate != 0 &&
1698 conf.codec.GetConfigSamplingFrequency() != group_config.sample_rate) {
1699 LOG(WARNING) << __func__
1700 << ", stream configuration could not be "
1701 "determined (sampling frequency differs) for direction: "
1702 << loghex(direction);
1703 return std::nullopt;
1704 }
1705 group_config.sample_rate = conf.codec.GetConfigSamplingFrequency();
1706
1707 if (group_config.data_interval_us != 0 &&
1708 conf.codec.GetConfigDataIntervalUs() != group_config.data_interval_us) {
1709 LOG(WARNING) << __func__
1710 << ", stream configuration could not be "
1711 "determined (data interval differs) for direction: "
1712 << loghex(direction);
1713 return std::nullopt;
1714 }
1715 group_config.data_interval_us = conf.codec.GetConfigDataIntervalUs();
1716
1717 if (group_config.bits_per_sample != 0 &&
1718 conf.codec.GetConfigBitsPerSample() != group_config.bits_per_sample) {
1719 LOG(WARNING) << __func__
1720 << ", stream configuration could not be "
1721 "determined (bits per sample differs) for direction: "
1722 << loghex(direction);
1723 return std::nullopt;
1724 }
1725 group_config.bits_per_sample = conf.codec.GetConfigBitsPerSample();
1726
1727 group_config.num_channels +=
1728 conf.codec.GetConfigChannelCount() * conf.device_cnt;
1729 }
1730
1731 if (group_config.IsInvalid()) return std::nullopt;
1732
1733 return group_config;
1734 }
1735
IsContextSupported(types::LeAudioContextType group_context_type)1736 bool LeAudioDeviceGroup::IsContextSupported(
1737 types::LeAudioContextType group_context_type) {
1738 auto iter = available_context_to_configuration_map.find(group_context_type);
1739 if (iter == available_context_to_configuration_map.end()) return false;
1740
1741 return available_context_to_configuration_map[group_context_type] != nullptr;
1742 }
1743
IsMetadataChanged(types::AudioContexts context_type,const std::vector<uint8_t> & ccid_list)1744 bool LeAudioDeviceGroup::IsMetadataChanged(
1745 types::AudioContexts context_type, const std::vector<uint8_t>& ccid_list) {
1746 for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice;
1747 leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
1748 if (leAudioDevice->IsMetadataChanged(context_type, ccid_list)) return true;
1749 }
1750
1751 return false;
1752 }
1753
StreamOffloaderUpdated(uint8_t direction)1754 void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) {
1755 if (direction == le_audio::types::kLeAudioDirectionSource) {
1756 stream_conf.source_is_initial = false;
1757 } else {
1758 stream_conf.sink_is_initial = false;
1759 }
1760 }
1761
CreateStreamVectorForOffloader(uint8_t direction)1762 void LeAudioDeviceGroup::CreateStreamVectorForOffloader(uint8_t direction) {
1763 if (CodecManager::GetInstance()->GetCodecLocation() !=
1764 le_audio::types::CodecLocation::ADSP) {
1765 return;
1766 }
1767
1768 CisType cis_type;
1769 std::vector<std::pair<uint16_t, uint32_t>>* streams;
1770 std::vector<std::pair<uint16_t, uint32_t>>*
1771 offloader_streams_target_allocation;
1772 std::vector<std::pair<uint16_t, uint32_t>>*
1773 offloader_streams_current_allocation;
1774 std::string tag;
1775 uint32_t available_allocations = 0;
1776 bool* changed_flag;
1777 bool* is_initial;
1778 if (direction == le_audio::types::kLeAudioDirectionSource) {
1779 changed_flag = &stream_conf.source_offloader_changed;
1780 is_initial = &stream_conf.source_is_initial;
1781 cis_type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE;
1782 streams = &stream_conf.source_streams;
1783 offloader_streams_target_allocation =
1784 &stream_conf.source_offloader_streams_target_allocation;
1785 offloader_streams_current_allocation =
1786 &stream_conf.source_offloader_streams_current_allocation;
1787 tag = "Source";
1788 available_allocations = AdjustAllocationForOffloader(
1789 stream_conf.source_audio_channel_allocation);
1790 } else {
1791 changed_flag = &stream_conf.sink_offloader_changed;
1792 is_initial = &stream_conf.sink_is_initial;
1793 cis_type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK;
1794 streams = &stream_conf.sink_streams;
1795 offloader_streams_target_allocation =
1796 &stream_conf.sink_offloader_streams_target_allocation;
1797 offloader_streams_current_allocation =
1798 &stream_conf.sink_offloader_streams_current_allocation;
1799 tag = "Sink";
1800 available_allocations =
1801 AdjustAllocationForOffloader(stream_conf.sink_audio_channel_allocation);
1802 }
1803
1804 if (available_allocations == 0) {
1805 LOG_ERROR("There is no CIS connected");
1806 return;
1807 }
1808
1809 if (offloader_streams_target_allocation->size() == 0) {
1810 *is_initial = true;
1811 } else if (*is_initial) {
1812 // As multiple CISes phone call case, the target_allocation already have the
1813 // previous data, but the is_initial flag not be cleared. We need to clear
1814 // here to avoid make duplicated target allocation stream map.
1815 offloader_streams_target_allocation->clear();
1816 }
1817
1818 offloader_streams_current_allocation->clear();
1819 *changed_flag = true;
1820 bool not_all_cises_connected = false;
1821 if (available_allocations != codec_spec_conf::kLeAudioLocationStereo) {
1822 not_all_cises_connected = true;
1823 }
1824
1825 /* If the all cises are connected as stream started, reset changed_flag that
1826 * the bt stack wouldn't send another audio configuration for the connection
1827 * status */
1828 if (*is_initial && !not_all_cises_connected) {
1829 *changed_flag = false;
1830 }
1831
1832 /* Note: For the offloader case we simplify allocation to only Left and Right.
1833 * If we need 2 CISes and only one is connected, the connected one will have
1834 * allocation set to stereo (left | right) and other one will have allocation
1835 * set to 0. Offloader in this case shall mix left and right and send it on
1836 * connected CIS. If there is only single CIS with stereo allocation, it means
1837 * that peer device support channel count 2 and offloader shall send two
1838 * channels in the single CIS.
1839 */
1840
1841 for (auto& cis_entry : cises_) {
1842 if ((cis_entry.type == CisType::CIS_TYPE_BIDIRECTIONAL ||
1843 cis_entry.type == cis_type) &&
1844 cis_entry.conn_handle != 0) {
1845 uint32_t target_allocation = 0;
1846 uint32_t current_allocation = 0;
1847 for (const auto& s : *streams) {
1848 if (s.first == cis_entry.conn_handle) {
1849 target_allocation = AdjustAllocationForOffloader(s.second);
1850 current_allocation = target_allocation;
1851 if (not_all_cises_connected) {
1852 /* Tell offloader to mix on this CIS.*/
1853 current_allocation = codec_spec_conf::kLeAudioLocationStereo;
1854 }
1855 break;
1856 }
1857 }
1858
1859 if (target_allocation == 0) {
1860 /* Take missing allocation for that one .*/
1861 target_allocation =
1862 codec_spec_conf::kLeAudioLocationStereo & ~available_allocations;
1863 }
1864
1865 LOG_INFO(
1866 "%s: Cis handle 0x%04x, target allocation 0x%08x, current "
1867 "allocation 0x%08x",
1868 tag.c_str(), cis_entry.conn_handle, target_allocation,
1869 current_allocation);
1870 if (*is_initial) {
1871 offloader_streams_target_allocation->emplace_back(
1872 std::make_pair(cis_entry.conn_handle, target_allocation));
1873 }
1874 offloader_streams_current_allocation->emplace_back(
1875 std::make_pair(cis_entry.conn_handle, current_allocation));
1876 }
1877 }
1878 }
1879
IsPendingConfiguration(void)1880 bool LeAudioDeviceGroup::IsPendingConfiguration(void) {
1881 return stream_conf.pending_configuration;
1882 }
1883
SetPendingConfiguration(void)1884 void LeAudioDeviceGroup::SetPendingConfiguration(void) {
1885 stream_conf.pending_configuration = true;
1886 }
1887
ClearPendingConfiguration(void)1888 void LeAudioDeviceGroup::ClearPendingConfiguration(void) {
1889 stream_conf.pending_configuration = false;
1890 }
1891
IsConfigurationSupported(LeAudioDevice * leAudioDevice,const set_configurations::AudioSetConfiguration * audio_set_conf)1892 bool LeAudioDeviceGroup::IsConfigurationSupported(
1893 LeAudioDevice* leAudioDevice,
1894 const set_configurations::AudioSetConfiguration* audio_set_conf) {
1895 for (const auto& ent : (*audio_set_conf).confs) {
1896 LOG_INFO("Looking for requirements: %s - %s", audio_set_conf->name.c_str(),
1897 (ent.direction == 1 ? "snk" : "src"));
1898 auto pac = leAudioDevice->GetCodecConfigurationSupportedPac(ent.direction,
1899 ent.codec);
1900 if (pac != nullptr) {
1901 LOG_INFO("Configuration is supported by device %s",
1902 leAudioDevice->address_.ToString().c_str());
1903 return true;
1904 }
1905 }
1906
1907 LOG_INFO("Configuration is NOT supported by device %s",
1908 leAudioDevice->address_.ToString().c_str());
1909 return false;
1910 }
1911
1912 const set_configurations::AudioSetConfiguration*
FindFirstSupportedConfiguration(LeAudioContextType context_type)1913 LeAudioDeviceGroup::FindFirstSupportedConfiguration(
1914 LeAudioContextType context_type) {
1915 const set_configurations::AudioSetConfigurations* confs =
1916 AudioSetConfigurationProvider::Get()->GetConfigurations(context_type);
1917
1918 LOG_DEBUG("context type: %s, number of connected devices: %d",
1919 bluetooth::common::ToString(context_type).c_str(),
1920 +NumOfConnected());
1921
1922 /* Filter out device set for all scenarios */
1923 if (!set_configurations::check_if_may_cover_scenario(confs,
1924 NumOfConnected())) {
1925 LOG_ERROR(", group is unable to cover scenario");
1926 return nullptr;
1927 }
1928
1929 /* Filter out device set for each end every scenario */
1930
1931 for (const auto& conf : *confs) {
1932 if (IsConfigurationSupported(conf, context_type)) {
1933 LOG_DEBUG("found: %s", conf->name.c_str());
1934 return conf;
1935 }
1936 }
1937
1938 return nullptr;
1939 }
1940
1941 /* This method should choose aproperiate ASEs to be active and set a cached
1942 * configuration for codec and qos.
1943 */
Configure(LeAudioContextType context_type,AudioContexts metadata_context_type,std::vector<uint8_t> ccid_list)1944 bool LeAudioDeviceGroup::Configure(LeAudioContextType context_type,
1945 AudioContexts metadata_context_type,
1946 std::vector<uint8_t> ccid_list) {
1947 const set_configurations::AudioSetConfiguration* conf =
1948 available_context_to_configuration_map[context_type];
1949
1950 if (!conf) {
1951 LOG_ERROR(
1952 ", requested context type: %s , is in mismatch with cached available "
1953 "contexts ",
1954 bluetooth::common::ToString(context_type).c_str());
1955 return false;
1956 }
1957
1958 LOG_DEBUG(" setting context type: %s",
1959 bluetooth::common::ToString(context_type).c_str());
1960
1961 if (!ConfigureAses(conf, context_type, metadata_context_type, ccid_list)) {
1962 LOG_ERROR(
1963 ", requested context type: %s , is in mismatch with cached available "
1964 "contexts",
1965 bluetooth::common::ToString(context_type).c_str());
1966 return false;
1967 }
1968
1969 /* Store selected configuration at once it is chosen.
1970 * It might happen it will get unavailable in some point of time
1971 */
1972 stream_conf.conf = conf;
1973 return true;
1974 }
1975
~LeAudioDeviceGroup(void)1976 LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); }
1977
PrintDebugState(void)1978 void LeAudioDeviceGroup::PrintDebugState(void) {
1979 auto* active_conf = GetActiveConfiguration();
1980 std::stringstream debug_str;
1981
1982 debug_str << "\n Groupd id: " << group_id_
1983 << ", state: " << bluetooth::common::ToString(GetState())
1984 << ", target state: "
1985 << bluetooth::common::ToString(GetTargetState())
1986 << ", cig state: " << bluetooth::common::ToString(cig_state_)
1987 << ", \n group available contexts: "
1988 << bluetooth::common::ToString(GetAvailableContexts())
1989 << ", \n configuration context type: "
1990 << bluetooth::common::ToString(GetConfigurationContextType())
1991 << ", \n active configuration name: "
1992 << (active_conf ? active_conf->name : " not set");
1993
1994 if (cises_.size() > 0) {
1995 LOG_INFO("\n Allocated CISes: %d", static_cast<int>(cises_.size()));
1996 for (auto cis : cises_) {
1997 LOG_INFO("\n cis id: %d, type: %d, conn_handle %d, addr: %s", cis.id,
1998 cis.type, cis.conn_handle, cis.addr.ToString().c_str());
1999 }
2000 }
2001
2002 if (GetFirstActiveDevice() != nullptr) {
2003 uint32_t sink_delay = 0;
2004 uint32_t source_delay = 0;
2005 GetPresentationDelay(&sink_delay, le_audio::types::kLeAudioDirectionSink);
2006 GetPresentationDelay(&source_delay,
2007 le_audio::types::kLeAudioDirectionSource);
2008 auto phy_mtos = GetPhyBitmask(le_audio::types::kLeAudioDirectionSink);
2009 auto phy_stom = GetPhyBitmask(le_audio::types::kLeAudioDirectionSource);
2010 auto max_transport_latency_mtos = GetMaxTransportLatencyMtos();
2011 auto max_transport_latency_stom = GetMaxTransportLatencyStom();
2012 auto sdu_mts = GetSduInterval(le_audio::types::kLeAudioDirectionSink);
2013 auto sdu_stom = GetSduInterval(le_audio::types::kLeAudioDirectionSource);
2014
2015 debug_str << "\n resentation_delay for sink (speaker): " << +sink_delay
2016 << " us, presentation_delay for source (microphone): "
2017 << +source_delay << "us, \n MtoS transport latency: "
2018 << +max_transport_latency_mtos
2019 << ", StoM transport latency: " << +max_transport_latency_stom
2020 << ", \n MtoS Phy: " << loghex(phy_mtos)
2021 << ", MtoS sdu: " << loghex(phy_stom)
2022 << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom;
2023 }
2024
2025 LOG_INFO("%s", debug_str.str().c_str());
2026
2027 for (const auto& device_iter : leAudioDevices_) {
2028 device_iter.lock()->PrintDebugState();
2029 }
2030 }
2031
Dump(int fd,int active_group_id)2032 void LeAudioDeviceGroup::Dump(int fd, int active_group_id) {
2033 bool is_active = (group_id_ == active_group_id);
2034 std::stringstream stream;
2035 auto* active_conf = GetActiveConfiguration();
2036
2037 stream << "\n == Group id: " << group_id_
2038 << " == " << (is_active ? ",\tActive\n" : ",\tInactive\n")
2039 << " state: " << GetState()
2040 << ",\ttarget state: " << GetTargetState()
2041 << ",\tcig state: " << cig_state_ << "\n"
2042 << " group available contexts: " << GetAvailableContexts()
2043 << " configuration context type: "
2044 << bluetooth::common::ToString(GetConfigurationContextType()).c_str()
2045 << " active configuration name: "
2046 << (active_conf ? active_conf->name : " not set") << "\n"
2047 << " stream configuration: "
2048 << (stream_conf.conf != nullptr ? stream_conf.conf->name : " unknown ")
2049 << "\n"
2050 << " codec id: " << +(stream_conf.id.coding_format)
2051 << ",\tpending_configuration: " << stream_conf.pending_configuration
2052 << "\n"
2053 << " num of devices(connected): " << Size() << "("
2054 << NumOfConnected() << ")\n"
2055 << ", num of sinks(connected): " << stream_conf.sink_num_of_devices
2056 << "(" << stream_conf.sink_streams.size() << ")\n"
2057 << " num of sources(connected): "
2058 << stream_conf.source_num_of_devices << "("
2059 << stream_conf.source_streams.size() << ")\n"
2060 << " allocated CISes: " << static_cast<int>(cises_.size());
2061
2062 if (cises_.size() > 0) {
2063 stream << "\n\t == CISes == ";
2064 for (auto cis : cises_) {
2065 stream << "\n\t cis id: " << static_cast<int>(cis.id)
2066 << ",\ttype: " << static_cast<int>(cis.type)
2067 << ",\tconn_handle: " << static_cast<int>(cis.conn_handle)
2068 << ",\taddr: " << cis.addr;
2069 }
2070 stream << "\n\t ====";
2071 }
2072
2073 if (GetFirstActiveDevice() != nullptr) {
2074 uint32_t sink_delay;
2075 if (GetPresentationDelay(&sink_delay,
2076 le_audio::types::kLeAudioDirectionSink)) {
2077 stream << "\n presentation_delay for sink (speaker): " << sink_delay
2078 << " us";
2079 }
2080
2081 uint32_t source_delay;
2082 if (GetPresentationDelay(&source_delay,
2083 le_audio::types::kLeAudioDirectionSource)) {
2084 stream << "\n presentation_delay for source (microphone): "
2085 << source_delay << " us";
2086 }
2087 }
2088
2089 stream << "\n == devices: ==";
2090
2091 dprintf(fd, "%s", stream.str().c_str());
2092
2093 for (const auto& device_iter : leAudioDevices_) {
2094 device_iter.lock()->Dump(fd);
2095 }
2096 }
2097
2098 /* LeAudioDevice Class methods implementation */
SetConnectionState(DeviceConnectState state)2099 void LeAudioDevice::SetConnectionState(DeviceConnectState state) {
2100 LOG_DEBUG(" %s --> %s",
2101 bluetooth::common::ToString(connection_state_).c_str(),
2102 bluetooth::common::ToString(state).c_str());
2103 connection_state_ = state;
2104 }
2105
GetConnectionState(void)2106 DeviceConnectState LeAudioDevice::GetConnectionState(void) {
2107 return connection_state_;
2108 }
2109
ClearPACs(void)2110 void LeAudioDevice::ClearPACs(void) {
2111 snk_pacs_.clear();
2112 src_pacs_.clear();
2113 }
2114
~LeAudioDevice(void)2115 LeAudioDevice::~LeAudioDevice(void) {
2116 alarm_free(link_quality_timer);
2117 this->ClearPACs();
2118 }
2119
RegisterPACs(std::vector<struct types::acs_ac_record> * pac_db,std::vector<struct types::acs_ac_record> * pac_recs)2120 void LeAudioDevice::RegisterPACs(
2121 std::vector<struct types::acs_ac_record>* pac_db,
2122 std::vector<struct types::acs_ac_record>* pac_recs) {
2123 /* Clear PAC database for characteristic in case if re-read, indicated */
2124 if (!pac_db->empty()) {
2125 DLOG(INFO) << __func__ << ", upgrade PACs for characteristic";
2126 pac_db->clear();
2127 }
2128
2129 /* TODO wrap this logging part with debug flag */
2130 for (const struct types::acs_ac_record& pac : *pac_recs) {
2131 LOG(INFO) << "Registering PAC"
2132 << "\n\tCoding format: " << loghex(pac.codec_id.coding_format)
2133 << "\n\tVendor codec company ID: "
2134 << loghex(pac.codec_id.vendor_company_id)
2135 << "\n\tVendor codec ID: " << loghex(pac.codec_id.vendor_codec_id)
2136 << "\n\tCodec spec caps:\n"
2137 << pac.codec_spec_caps.ToString() << "\n\tMetadata: "
2138 << base::HexEncode(pac.metadata.data(), pac.metadata.size());
2139 }
2140
2141 pac_db->insert(pac_db->begin(), pac_recs->begin(), pac_recs->end());
2142 }
2143
GetAseByValHandle(uint16_t val_hdl)2144 struct ase* LeAudioDevice::GetAseByValHandle(uint16_t val_hdl) {
2145 auto iter = std::find_if(
2146 ases_.begin(), ases_.end(),
2147 [&val_hdl](const auto& ase) { return ase.hdls.val_hdl == val_hdl; });
2148
2149 return (iter == ases_.end()) ? nullptr : &(*iter);
2150 }
2151
GetAseCount(uint8_t direction)2152 int LeAudioDevice::GetAseCount(uint8_t direction) {
2153 return std::count_if(ases_.begin(), ases_.end(), [direction](const auto& a) {
2154 return a.direction == direction;
2155 });
2156 }
2157
GetFirstAseWithState(uint8_t direction,AseState state)2158 struct ase* LeAudioDevice::GetFirstAseWithState(uint8_t direction,
2159 AseState state) {
2160 auto iter = std::find_if(
2161 ases_.begin(), ases_.end(), [direction, state](const auto& ase) {
2162 return ((ase.direction == direction) && (ase.state == state));
2163 });
2164
2165 return (iter == ases_.end()) ? nullptr : &(*iter);
2166 }
2167
GetFirstActiveAse(void)2168 struct ase* LeAudioDevice::GetFirstActiveAse(void) {
2169 auto iter = std::find_if(ases_.begin(), ases_.end(),
2170 [](const auto& ase) { return ase.active; });
2171
2172 return (iter == ases_.end()) ? nullptr : &(*iter);
2173 }
2174
GetFirstActiveAseByDirection(uint8_t direction)2175 struct ase* LeAudioDevice::GetFirstActiveAseByDirection(uint8_t direction) {
2176 auto iter =
2177 std::find_if(ases_.begin(), ases_.end(), [direction](const auto& ase) {
2178 return (ase.active && (ase.direction == direction));
2179 });
2180
2181 return (iter == ases_.end()) ? nullptr : &(*iter);
2182 }
2183
GetNextActiveAseWithSameDirection(struct ase * base_ase)2184 struct ase* LeAudioDevice::GetNextActiveAseWithSameDirection(
2185 struct ase* base_ase) {
2186 auto iter = std::find_if(ases_.begin(), ases_.end(),
2187 [&base_ase](auto& ase) { return base_ase == &ase; });
2188
2189 /* Invalid ase given */
2190 if (iter == ases_.end() || std::distance(iter, ases_.end()) < 1)
2191 return nullptr;
2192
2193 iter =
2194 std::find_if(std::next(iter, 1), ases_.end(), [&iter](const auto& ase) {
2195 return ase.active && (*iter).direction == ase.direction;
2196 });
2197
2198 return (iter == ases_.end()) ? nullptr : &(*iter);
2199 }
2200
GetNextActiveAseWithDifferentDirection(struct ase * base_ase)2201 struct ase* LeAudioDevice::GetNextActiveAseWithDifferentDirection(
2202 struct ase* base_ase) {
2203 auto iter = std::find_if(ases_.begin(), ases_.end(),
2204 [&base_ase](auto& ase) { return base_ase == &ase; });
2205
2206 /* Invalid ase given */
2207 if (std::distance(iter, ases_.end()) < 1) {
2208 LOG_DEBUG("ASE %d does not use bidirectional CIS", base_ase->id);
2209 return nullptr;
2210 }
2211
2212 iter =
2213 std::find_if(std::next(iter, 1), ases_.end(), [&iter](const auto& ase) {
2214 return ase.active && iter->direction != ase.direction;
2215 });
2216
2217 if (iter == ases_.end()) {
2218 return nullptr;
2219 }
2220
2221 return &(*iter);
2222 }
2223
GetFirstActiveAseByDataPathState(types::AudioStreamDataPathState state)2224 struct ase* LeAudioDevice::GetFirstActiveAseByDataPathState(
2225 types::AudioStreamDataPathState state) {
2226 auto iter =
2227 std::find_if(ases_.begin(), ases_.end(), [state](const auto& ase) {
2228 return (ase.active && (ase.data_path_state == state));
2229 });
2230
2231 return (iter == ases_.end()) ? nullptr : &(*iter);
2232 }
2233
GetFirstInactiveAse(uint8_t direction,bool reuse_cis_id)2234 struct ase* LeAudioDevice::GetFirstInactiveAse(uint8_t direction,
2235 bool reuse_cis_id) {
2236 auto iter = std::find_if(ases_.begin(), ases_.end(),
2237 [direction, reuse_cis_id](const auto& ase) {
2238 if (ase.active || (ase.direction != direction))
2239 return false;
2240
2241 if (!reuse_cis_id) return true;
2242
2243 return (ase.cis_id != kInvalidCisId);
2244 });
2245 /* If ASE is found, return it */
2246 if (iter != ases_.end()) return &(*iter);
2247
2248 /* If reuse was not set, that means there is no inactive ASE available. */
2249 if (!reuse_cis_id) return nullptr;
2250
2251 /* Since there is no ASE with assigned CIS ID, it means new configuration
2252 * needs more ASEs then it was configured before.
2253 * Let's find just inactive one */
2254 iter = std::find_if(ases_.begin(), ases_.end(),
2255 [direction](const auto& ase) {
2256 if (ase.active || (ase.direction != direction))
2257 return false;
2258 return true;
2259 });
2260
2261 return (iter == ases_.end()) ? nullptr : &(*iter);
2262 }
2263
GetNextActiveAse(struct ase * base_ase)2264 struct ase* LeAudioDevice::GetNextActiveAse(struct ase* base_ase) {
2265 auto iter = std::find_if(ases_.begin(), ases_.end(),
2266 [&base_ase](auto& ase) { return base_ase == &ase; });
2267
2268 /* Invalid ase given */
2269 if (iter == ases_.end() || std::distance(iter, ases_.end()) < 1)
2270 return nullptr;
2271
2272 iter = std::find_if(std::next(iter, 1), ases_.end(),
2273 [](const auto& ase) { return ase.active; });
2274
2275 return (iter == ases_.end()) ? nullptr : &(*iter);
2276 }
2277
GetAseToMatchBidirectionCis(struct ase * base_ase)2278 struct ase* LeAudioDevice::GetAseToMatchBidirectionCis(struct ase* base_ase) {
2279 auto iter = std::find_if(ases_.begin(), ases_.end(), [&base_ase](auto& ase) {
2280 return (base_ase->cis_conn_hdl == ase.cis_conn_hdl) &&
2281 (base_ase->direction != ase.direction);
2282 });
2283 return (iter == ases_.end()) ? nullptr : &(*iter);
2284 }
2285
GetAsesByCisConnHdl(uint16_t conn_hdl)2286 BidirectAsesPair LeAudioDevice::GetAsesByCisConnHdl(uint16_t conn_hdl) {
2287 BidirectAsesPair ases = {nullptr, nullptr};
2288
2289 for (auto& ase : ases_) {
2290 if (ase.cis_conn_hdl == conn_hdl) {
2291 if (ase.direction == types::kLeAudioDirectionSink) {
2292 ases.sink = &ase;
2293 } else {
2294 ases.source = &ase;
2295 }
2296 }
2297 }
2298
2299 return ases;
2300 }
2301
GetAsesByCisId(uint8_t cis_id)2302 BidirectAsesPair LeAudioDevice::GetAsesByCisId(uint8_t cis_id) {
2303 BidirectAsesPair ases = {nullptr, nullptr};
2304
2305 for (auto& ase : ases_) {
2306 if (ase.cis_id == cis_id) {
2307 if (ase.direction == types::kLeAudioDirectionSink) {
2308 ases.sink = &ase;
2309 } else {
2310 ases.source = &ase;
2311 }
2312 }
2313 }
2314
2315 return ases;
2316 }
2317
HaveActiveAse(void)2318 bool LeAudioDevice::HaveActiveAse(void) {
2319 auto iter = std::find_if(ases_.begin(), ases_.end(),
2320 [](const auto& ase) { return ase.active; });
2321
2322 return iter != ases_.end();
2323 }
2324
HaveAnyUnconfiguredAses(void)2325 bool LeAudioDevice::HaveAnyUnconfiguredAses(void) {
2326 /* In configuring state when active in Idle or Configured and reconfigure */
2327 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
2328 if (!ase.active) return false;
2329
2330 if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE ||
2331 ((ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) &&
2332 ase.reconfigure))
2333 return true;
2334
2335 return false;
2336 });
2337
2338 return iter != ases_.end();
2339 }
2340
HaveAllActiveAsesSameState(AseState state)2341 bool LeAudioDevice::HaveAllActiveAsesSameState(AseState state) {
2342 auto iter = std::find_if(
2343 ases_.begin(), ases_.end(),
2344 [&state](const auto& ase) { return ase.active && (ase.state != state); });
2345
2346 return iter == ases_.end();
2347 }
2348
IsReadyToCreateStream(void)2349 bool LeAudioDevice::IsReadyToCreateStream(void) {
2350 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
2351 if (!ase.active) return false;
2352
2353 if (ase.direction == types::kLeAudioDirectionSink &&
2354 (ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
2355 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING))
2356 return true;
2357
2358 if (ase.direction == types::kLeAudioDirectionSource &&
2359 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)
2360 return true;
2361
2362 return false;
2363 });
2364
2365 return iter == ases_.end();
2366 }
2367
IsReadyToSuspendStream(void)2368 bool LeAudioDevice::IsReadyToSuspendStream(void) {
2369 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
2370 if (!ase.active) return false;
2371
2372 if (ase.direction == types::kLeAudioDirectionSink &&
2373 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)
2374 return true;
2375
2376 if (ase.direction == types::kLeAudioDirectionSource &&
2377 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING)
2378 return true;
2379
2380 return false;
2381 });
2382
2383 return iter == ases_.end();
2384 }
2385
HaveAllActiveAsesCisEst(void)2386 bool LeAudioDevice::HaveAllActiveAsesCisEst(void) {
2387 if (ases_.empty()) {
2388 LOG_WARN("No ases for device %s", address_.ToString().c_str());
2389 return false;
2390 }
2391
2392 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
2393 return ase.active &&
2394 (ase.data_path_state != AudioStreamDataPathState::CIS_ESTABLISHED);
2395 });
2396
2397 return iter == ases_.end();
2398 }
2399
HaveAnyCisConnected(void)2400 bool LeAudioDevice::HaveAnyCisConnected(void) {
2401 /* Pending and Disconnecting is considered as connected in this function */
2402 for (auto const ase : ases_) {
2403 if (ase.data_path_state != AudioStreamDataPathState::CIS_ASSIGNED &&
2404 ase.data_path_state != AudioStreamDataPathState::IDLE) {
2405 return true;
2406 }
2407 }
2408 return false;
2409 }
2410
HasCisId(uint8_t id)2411 bool LeAudioDevice::HasCisId(uint8_t id) {
2412 struct ase* ase = GetFirstActiveAse();
2413
2414 while (ase) {
2415 if (ase->cis_id == id) return true;
2416 ase = GetNextActiveAse(ase);
2417 }
2418
2419 return false;
2420 }
2421
GetMatchingBidirectionCisId(const struct types::ase * base_ase)2422 uint8_t LeAudioDevice::GetMatchingBidirectionCisId(
2423 const struct types::ase* base_ase) {
2424 for (auto& ase : ases_) {
2425 auto& cis = ase.cis_id;
2426 if (!ase.active) continue;
2427
2428 int num_cises =
2429 std::count_if(ases_.begin(), ases_.end(), [&cis](const auto& iter_ase) {
2430 return iter_ase.active && iter_ase.cis_id == cis;
2431 });
2432
2433 /*
2434 * If there is only one ASE for device with unique CIS ID and opposite to
2435 * direction - it may be bi-directional/completive.
2436 */
2437 if (num_cises == 1 &&
2438 ((base_ase->direction == types::kLeAudioDirectionSink &&
2439 ase.direction == types::kLeAudioDirectionSource) ||
2440 (base_ase->direction == types::kLeAudioDirectionSource &&
2441 ase.direction == types::kLeAudioDirectionSink))) {
2442 return ase.cis_id;
2443 }
2444 }
2445
2446 return kInvalidCisId;
2447 }
2448
GetLc3SupportedChannelCount(uint8_t direction)2449 uint8_t LeAudioDevice::GetLc3SupportedChannelCount(uint8_t direction) {
2450 auto& pacs =
2451 direction == types::kLeAudioDirectionSink ? snk_pacs_ : src_pacs_;
2452
2453 if (pacs.size() == 0) {
2454 LOG(ERROR) << __func__ << " missing PAC for direction " << +direction;
2455 return 0;
2456 }
2457
2458 for (const auto& pac_tuple : pacs) {
2459 /* Get PAC records from tuple as second element from tuple */
2460 auto& pac_recs = std::get<1>(pac_tuple);
2461
2462 for (const auto pac : pac_recs) {
2463 if (pac.codec_id.coding_format != types::kLeAudioCodingFormatLC3)
2464 continue;
2465
2466 auto supported_channel_count_ltv = pac.codec_spec_caps.Find(
2467 codec_spec_caps::kLeAudioCodecLC3TypeAudioChannelCounts);
2468
2469 if (supported_channel_count_ltv == std::nullopt ||
2470 supported_channel_count_ltv->size() == 0L) {
2471 return 1;
2472 }
2473
2474 return VEC_UINT8_TO_UINT8(supported_channel_count_ltv.value());
2475 };
2476 }
2477
2478 return 0;
2479 }
2480
2481 const struct types::acs_ac_record*
GetCodecConfigurationSupportedPac(uint8_t direction,const CodecCapabilitySetting & codec_capability_setting)2482 LeAudioDevice::GetCodecConfigurationSupportedPac(
2483 uint8_t direction, const CodecCapabilitySetting& codec_capability_setting) {
2484 auto& pacs =
2485 direction == types::kLeAudioDirectionSink ? snk_pacs_ : src_pacs_;
2486
2487 if (pacs.size() == 0) {
2488 LOG_ERROR("missing PAC for direction %d", direction);
2489 return nullptr;
2490 }
2491
2492 /* TODO: Validate channel locations */
2493
2494 for (const auto& pac_tuple : pacs) {
2495 /* Get PAC records from tuple as second element from tuple */
2496 auto& pac_recs = std::get<1>(pac_tuple);
2497
2498 for (const auto& pac : pac_recs) {
2499 if (!IsCodecCapabilitySettingSupported(pac, codec_capability_setting))
2500 continue;
2501
2502 return &pac;
2503 };
2504 }
2505
2506 /* Doesn't match required configuration with any PAC */
2507 return nullptr;
2508 }
2509
2510 /**
2511 * Returns supported PHY's bitfield
2512 */
GetPhyBitmask(void)2513 uint8_t LeAudioDevice::GetPhyBitmask(void) {
2514 uint8_t phy_bitfield = kIsoCigPhy1M;
2515
2516 if (BTM_IsPhy2mSupported(address_, BT_TRANSPORT_LE))
2517 phy_bitfield |= kIsoCigPhy2M;
2518
2519 return phy_bitfield;
2520 }
2521
SetSupportedContexts(AudioContexts snk_contexts,AudioContexts src_contexts)2522 void LeAudioDevice::SetSupportedContexts(AudioContexts snk_contexts,
2523 AudioContexts src_contexts) {
2524 supp_contexts_.sink = snk_contexts;
2525 supp_contexts_.source = src_contexts;
2526 }
2527
PrintDebugState(void)2528 void LeAudioDevice::PrintDebugState(void) {
2529 std::stringstream debug_str;
2530
2531 debug_str << " address: " << address_ << ", "
2532 << bluetooth::common::ToString(connection_state_)
2533 << ", conn_id: " << +conn_id_ << ", mtu: " << +mtu_
2534 << ", num_of_ase: " << static_cast<int>(ases_.size());
2535
2536 if (ases_.size() > 0) {
2537 debug_str << "\n == ASEs == ";
2538 for (auto& ase : ases_) {
2539 debug_str << "\n id: " << +ase.id << ", active: " << ase.active
2540 << ", dir: "
2541 << (ase.direction == types::kLeAudioDirectionSink ? "sink"
2542 : "source")
2543 << ", cis_id: " << +ase.cis_id
2544 << ", cis_handle: " << +ase.cis_conn_hdl << ", state: "
2545 << bluetooth::common::ToString(ase.data_path_state)
2546 << "\n ase max_latency: " << +ase.max_transport_latency
2547 << ", rtn: " << +ase.retrans_nb
2548 << ", max_sdu: " << +ase.max_sdu_size
2549 << ", target latency: " << +ase.target_latency;
2550 }
2551 }
2552
2553 LOG_INFO("%s", debug_str.str().c_str());
2554 }
2555
Dump(int fd)2556 void LeAudioDevice::Dump(int fd) {
2557 uint16_t acl_handle = BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE);
2558 std::string location = "unknown location";
2559
2560 if (snk_audio_locations_.to_ulong() &
2561 codec_spec_conf::kLeAudioLocationAnyLeft) {
2562 std::string location_left = "left";
2563 location.swap(location_left);
2564 } else if (snk_audio_locations_.to_ulong() &
2565 codec_spec_conf::kLeAudioLocationAnyRight) {
2566 std::string location_right = "right";
2567 location.swap(location_right);
2568 }
2569
2570 std::stringstream stream;
2571 stream << "\n\taddress: " << address_ << ": " << connection_state_ << ": "
2572 << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_))
2573 << ", acl_handle: " << std::to_string(acl_handle) << ", " << location
2574 << ",\t" << (encrypted_ ? "Encrypted" : "Unecrypted")
2575 << ",mtu: " << std::to_string(mtu_)
2576 << "\n\tnumber of ases_: " << static_cast<int>(ases_.size());
2577
2578 if (ases_.size() > 0) {
2579 stream << "\n\t== ASEs == \n\t";
2580 stream
2581 << "id active dir cis_id cis_handle sdu latency rtn state";
2582 for (auto& ase : ases_) {
2583 stream << std::setfill('\xA0') << "\n\t" << std::left << std::setw(4)
2584 << static_cast<int>(ase.id) << std::left << std::setw(7)
2585 << (ase.active ? "true" : "false") << std::left << std::setw(8)
2586 << (ase.direction == types::kLeAudioDirectionSink ? "sink"
2587 : "source")
2588 << std::left << std::setw(8) << static_cast<int>(ase.cis_id)
2589 << std::left << std::setw(12) << ase.cis_conn_hdl << std::left
2590 << std::setw(5) << ase.max_sdu_size << std::left << std::setw(8)
2591 << ase.max_transport_latency << std::left << std::setw(5)
2592 << static_cast<int>(ase.retrans_nb) << std::left << std::setw(12)
2593 << bluetooth::common::ToString(ase.data_path_state);
2594 }
2595 }
2596 stream << "\n\t====";
2597
2598 dprintf(fd, "%s", stream.str().c_str());
2599 }
2600
DisconnectAcl(void)2601 void LeAudioDevice::DisconnectAcl(void) {
2602 if (conn_id_ == GATT_INVALID_CONN_ID) return;
2603
2604 uint16_t acl_handle =
2605 BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE);
2606 if (acl_handle != HCI_INVALID_HANDLE) {
2607 acl_disconnect_from_handle(acl_handle, HCI_ERR_PEER_USER,
2608 "bta::le_audio::client disconnect");
2609 }
2610 }
2611
GetAvailableContexts(int direction)2612 types::AudioContexts LeAudioDevice::GetAvailableContexts(int direction) {
2613 if (direction ==
2614 (types::kLeAudioDirectionSink | types::kLeAudioDirectionSource)) {
2615 return get_bidirectional(avail_contexts_);
2616 } else if (direction == types::kLeAudioDirectionSink) {
2617 return avail_contexts_.sink;
2618 }
2619 return avail_contexts_.source;
2620 }
2621
2622 /* Returns XOR of updated sink and source bitset context types */
SetAvailableContexts(AudioContexts snk_contexts,AudioContexts src_contexts)2623 AudioContexts LeAudioDevice::SetAvailableContexts(AudioContexts snk_contexts,
2624 AudioContexts src_contexts) {
2625 AudioContexts updated_contexts;
2626
2627 updated_contexts = snk_contexts ^ avail_contexts_.sink;
2628 updated_contexts |= src_contexts ^ avail_contexts_.source;
2629
2630 LOG_DEBUG(
2631 "\n\t avail_contexts_.sink: %s \n\t avail_contexts_.source: %s \n\t "
2632 "snk_contexts: %s \n\t src_contexts: %s \n\t updated_contexts: %s",
2633 avail_contexts_.sink.to_string().c_str(),
2634 avail_contexts_.source.to_string().c_str(),
2635 snk_contexts.to_string().c_str(), src_contexts.to_string().c_str(),
2636 updated_contexts.to_string().c_str());
2637
2638 avail_contexts_.sink = snk_contexts;
2639 avail_contexts_.source = src_contexts;
2640
2641 return updated_contexts;
2642 }
2643
ActivateConfiguredAses(LeAudioContextType context_type)2644 bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {
2645 if (conn_id_ == GATT_INVALID_CONN_ID) {
2646 LOG_WARN(" Device %s is not connected ", address_.ToString().c_str());
2647 return false;
2648 }
2649
2650 bool ret = false;
2651
2652 LOG_INFO(" Configuring device %s", address_.ToString().c_str());
2653 for (auto& ase : ases_) {
2654 if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
2655 ase.configured_for_context_type == context_type) {
2656 LOG_INFO(
2657 " conn_id: %d, ase id %d, cis id %d, cis_handle 0x%04x is activated.",
2658 conn_id_, ase.id, ase.cis_id, ase.cis_conn_hdl);
2659 ase.active = true;
2660 ret = true;
2661 }
2662 }
2663
2664 return ret;
2665 }
2666
DeactivateAllAses(void)2667 void LeAudioDevice::DeactivateAllAses(void) {
2668 for (auto& ase : ases_) {
2669 if (ase.active == false &&
2670 ase.data_path_state != AudioStreamDataPathState::IDLE) {
2671 LOG_WARN(
2672 " %s, ase_id: %d, ase.cis_id: %d, cis_handle: 0x%02x, "
2673 "ase.data_path=%s",
2674 address_.ToString().c_str(), ase.id, ase.cis_id, ase.cis_conn_hdl,
2675 bluetooth::common::ToString(ase.data_path_state).c_str());
2676 }
2677 ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
2678 ase.data_path_state = AudioStreamDataPathState::IDLE;
2679 ase.active = false;
2680 ase.cis_id = le_audio::kInvalidCisId;
2681 ase.cis_conn_hdl = 0;
2682 }
2683 }
2684
GetMetadata(AudioContexts context_type,const std::vector<uint8_t> & ccid_list)2685 std::vector<uint8_t> LeAudioDevice::GetMetadata(
2686 AudioContexts context_type, const std::vector<uint8_t>& ccid_list) {
2687 std::vector<uint8_t> metadata;
2688
2689 AppendMetadataLtvEntryForStreamingContext(metadata, context_type);
2690 AppendMetadataLtvEntryForCcidList(metadata, ccid_list);
2691
2692 return std::move(metadata);
2693 }
2694
IsMetadataChanged(AudioContexts context_type,const std::vector<uint8_t> & ccid_list)2695 bool LeAudioDevice::IsMetadataChanged(AudioContexts context_type,
2696 const std::vector<uint8_t>& ccid_list) {
2697 for (auto* ase = this->GetFirstActiveAse(); ase;
2698 ase = this->GetNextActiveAse(ase)) {
2699 if (this->GetMetadata(context_type, ccid_list) != ase->metadata)
2700 return true;
2701 }
2702
2703 return false;
2704 }
2705
Add(int group_id)2706 LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) {
2707 /* Get first free group id */
2708 if (FindById(group_id)) {
2709 LOG(ERROR) << __func__
2710 << ", group already exists, id: " << loghex(group_id);
2711 return nullptr;
2712 }
2713
2714 return (groups_.emplace_back(std::make_unique<LeAudioDeviceGroup>(group_id)))
2715 .get();
2716 }
2717
Remove(int group_id)2718 void LeAudioDeviceGroups::Remove(int group_id) {
2719 auto iter = std::find_if(
2720 groups_.begin(), groups_.end(),
2721 [&group_id](auto const& group) { return group->group_id_ == group_id; });
2722
2723 if (iter == groups_.end()) {
2724 LOG(ERROR) << __func__ << ", no such group_id: " << group_id;
2725 return;
2726 }
2727
2728 groups_.erase(iter);
2729 }
2730
FindById(int group_id)2731 LeAudioDeviceGroup* LeAudioDeviceGroups::FindById(int group_id) {
2732 auto iter = std::find_if(
2733 groups_.begin(), groups_.end(),
2734 [&group_id](auto const& group) { return group->group_id_ == group_id; });
2735
2736 return (iter == groups_.end()) ? nullptr : iter->get();
2737 }
2738
Cleanup(void)2739 void LeAudioDeviceGroups::Cleanup(void) {
2740 for (auto& g : groups_) {
2741 g->Cleanup();
2742 }
2743
2744 groups_.clear();
2745 }
2746
Dump(int fd,int active_group_id)2747 void LeAudioDeviceGroups::Dump(int fd, int active_group_id) {
2748 for (auto& g : groups_) {
2749 g->Dump(fd, active_group_id);
2750 }
2751 }
2752
IsAnyInTransition(void)2753 bool LeAudioDeviceGroups::IsAnyInTransition(void) {
2754 for (auto& g : groups_) {
2755 if (g->IsInTransition()) {
2756 DLOG(INFO) << __func__ << " group: " << g->group_id_
2757 << " is in transition";
2758 return true;
2759 }
2760 }
2761 return false;
2762 }
2763
Size()2764 size_t LeAudioDeviceGroups::Size() { return (groups_.size()); }
2765
GetGroupsIds(void)2766 std::vector<int> LeAudioDeviceGroups::GetGroupsIds(void) {
2767 std::vector<int> result;
2768
2769 for (auto const& group : groups_) {
2770 result.push_back(group->group_id_);
2771 }
2772
2773 return result;
2774 }
2775
2776 /* LeAudioDevices Class methods implementation */
Add(const RawAddress & address,DeviceConnectState state,int group_id)2777 void LeAudioDevices::Add(const RawAddress& address, DeviceConnectState state,
2778 int group_id) {
2779 auto device = FindByAddress(address);
2780 if (device != nullptr) {
2781 LOG(ERROR) << __func__ << ", address: " << address
2782 << " is already assigned to group: " << device->group_id_;
2783 return;
2784 }
2785
2786 leAudioDevices_.emplace_back(
2787 std::make_shared<LeAudioDevice>(address, state, group_id));
2788 }
2789
Remove(const RawAddress & address)2790 void LeAudioDevices::Remove(const RawAddress& address) {
2791 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
2792 [&address](auto const& leAudioDevice) {
2793 return leAudioDevice->address_ == address;
2794 });
2795
2796 if (iter == leAudioDevices_.end()) {
2797 LOG(ERROR) << __func__ << ", no such address: " << address;
2798 return;
2799 }
2800
2801 leAudioDevices_.erase(iter);
2802 }
2803
FindByAddress(const RawAddress & address)2804 LeAudioDevice* LeAudioDevices::FindByAddress(const RawAddress& address) {
2805 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
2806 [&address](auto const& leAudioDevice) {
2807 return leAudioDevice->address_ == address;
2808 });
2809
2810 return (iter == leAudioDevices_.end()) ? nullptr : iter->get();
2811 }
2812
GetByAddress(const RawAddress & address)2813 std::shared_ptr<LeAudioDevice> LeAudioDevices::GetByAddress(
2814 const RawAddress& address) {
2815 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
2816 [&address](auto const& leAudioDevice) {
2817 return leAudioDevice->address_ == address;
2818 });
2819
2820 return (iter == leAudioDevices_.end()) ? nullptr : *iter;
2821 }
2822
FindByConnId(uint16_t conn_id)2823 LeAudioDevice* LeAudioDevices::FindByConnId(uint16_t conn_id) {
2824 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
2825 [&conn_id](auto const& leAudioDevice) {
2826 return leAudioDevice->conn_id_ == conn_id;
2827 });
2828
2829 return (iter == leAudioDevices_.end()) ? nullptr : iter->get();
2830 }
2831
FindByCisConnHdl(uint8_t cig_id,uint16_t conn_hdl)2832 LeAudioDevice* LeAudioDevices::FindByCisConnHdl(uint8_t cig_id,
2833 uint16_t conn_hdl) {
2834 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
2835 [&conn_hdl, &cig_id](auto& d) {
2836 LeAudioDevice* dev;
2837 BidirectAsesPair ases;
2838
2839 dev = d.get();
2840 if (dev->group_id_ != cig_id) {
2841 return false;
2842 }
2843
2844 ases = dev->GetAsesByCisConnHdl(conn_hdl);
2845 if (ases.sink || ases.source)
2846 return true;
2847 else
2848 return false;
2849 });
2850
2851 if (iter == leAudioDevices_.end()) return nullptr;
2852
2853 return iter->get();
2854 }
2855
SetInitialGroupAutoconnectState(int group_id,int gatt_if,tBTM_BLE_CONN_TYPE reconnection_mode,bool current_dev_autoconnect_flag)2856 void LeAudioDevices::SetInitialGroupAutoconnectState(
2857 int group_id, int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode,
2858 bool current_dev_autoconnect_flag) {
2859 if (!current_dev_autoconnect_flag) {
2860 /* If current device autoconnect flag is false, check if there is other
2861 * device in the group which is in autoconnect mode.
2862 * If yes, assume whole group is in autoconnect.
2863 */
2864 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
2865 [&group_id](auto& d) {
2866 LeAudioDevice* dev;
2867 dev = d.get();
2868 if (dev->group_id_ != group_id) {
2869 return false;
2870 }
2871 return dev->autoconnect_flag_;
2872 });
2873
2874 current_dev_autoconnect_flag = !(iter == leAudioDevices_.end());
2875 }
2876
2877 if (!current_dev_autoconnect_flag) {
2878 return;
2879 }
2880
2881 for (auto dev : leAudioDevices_) {
2882 if ((dev->group_id_ == group_id) &&
2883 (dev->GetConnectionState() == DeviceConnectState::DISCONNECTED)) {
2884 dev->SetConnectionState(DeviceConnectState::CONNECTING_AUTOCONNECT);
2885 dev->autoconnect_flag_ = true;
2886 btif_storage_set_leaudio_autoconnect(dev->address_, true);
2887 BTA_GATTC_Open(gatt_if, dev->address_, reconnection_mode, false);
2888 }
2889 }
2890 }
2891
Size()2892 size_t LeAudioDevices::Size() { return (leAudioDevices_.size()); }
2893
Dump(int fd,int group_id)2894 void LeAudioDevices::Dump(int fd, int group_id) {
2895 for (auto const& device : leAudioDevices_) {
2896 if (device->group_id_ == group_id) {
2897 device->Dump(fd);
2898 }
2899 }
2900 }
2901
Cleanup(tGATT_IF client_if)2902 void LeAudioDevices::Cleanup(tGATT_IF client_if) {
2903 for (auto const& device : leAudioDevices_) {
2904 auto connection_state = device->GetConnectionState();
2905 if (connection_state == DeviceConnectState::DISCONNECTED) {
2906 continue;
2907 }
2908
2909 if (connection_state == DeviceConnectState::CONNECTING_AUTOCONNECT) {
2910 BTA_GATTC_CancelOpen(client_if, device->address_, false);
2911 } else {
2912 BtaGattQueue::Clean(device->conn_id_);
2913 BTA_GATTC_Close(device->conn_id_);
2914 device->DisconnectAcl();
2915 }
2916 }
2917 leAudioDevices_.clear();
2918 }
2919
2920 } // namespace le_audio
2921