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 #include <bluetooth/log.h>
22 #include <com_android_bluetooth_flags.h>
23 #include <stdio.h>
24
25 #include <algorithm>
26 #include <cstddef>
27 #include <cstdint>
28 #include <iomanip>
29 #include <ios>
30 #include <iterator>
31 #include <memory>
32 #include <optional>
33 #include <ostream>
34 #include <sstream>
35 #include <string>
36 #include <vector>
37
38 #include "acl_api.h"
39 #include "bta_gatt_api.h"
40 #include "bta_gatt_queue.h"
41 #include "btif/include/btif_storage.h"
42 #include "btm_ble_api_types.h"
43 #include "btm_iso_api_types.h"
44 #include "common/strings.h"
45 #include "gatt_api.h"
46 #include "hardware/bluetooth.h"
47 #include "hci/controller_interface.h"
48 #include "hci_error_code.h"
49 #include "hcidefs.h"
50 #include "internal_include/bt_trace.h"
51 #include "le_audio/codec_manager.h"
52 #include "le_audio/le_audio_types.h"
53 #include "le_audio_log_history.h"
54 #include "le_audio_utils.h"
55 #include "main/shim/entry.h"
56 #include "osi/include/alarm.h"
57 #include "osi/include/properties.h"
58 #include "stack/include/btm_client_interface.h"
59 #include "types/bt_transport.h"
60 #include "types/raw_address.h"
61
62 using bluetooth::hci::kIsoCigPhy1M;
63 using bluetooth::hci::kIsoCigPhy2M;
64 using bluetooth::le_audio::DeviceConnectState;
65 using bluetooth::le_audio::types::ase;
66 using bluetooth::le_audio::types::AseState;
67 using bluetooth::le_audio::types::AudioContexts;
68 using bluetooth::le_audio::types::AudioLocations;
69 using bluetooth::le_audio::types::BidirectionalPair;
70 using bluetooth::le_audio::types::CisState;
71 using bluetooth::le_audio::types::DataPathState;
72 using bluetooth::le_audio::types::LeAudioContextType;
73
74 namespace bluetooth::le_audio {
operator <<(std::ostream & os,const DeviceConnectState & state)75 std::ostream& operator<<(std::ostream& os, const DeviceConnectState& state) {
76 const char* char_value_ = "UNKNOWN";
77
78 switch (state) {
79 case DeviceConnectState::CONNECTED:
80 char_value_ = "CONNECTED";
81 break;
82 case DeviceConnectState::DISCONNECTED:
83 char_value_ = "DISCONNECTED";
84 break;
85 case DeviceConnectState::REMOVING:
86 char_value_ = "REMOVING";
87 break;
88 case DeviceConnectState::DISCONNECTING:
89 char_value_ = "DISCONNECTING";
90 break;
91 case DeviceConnectState::DISCONNECTING_AND_RECOVER:
92 char_value_ = "DISCONNECTING_AND_RECOVER";
93 break;
94 case DeviceConnectState::CONNECTING_BY_USER:
95 char_value_ = "CONNECTING_BY_USER";
96 break;
97 case DeviceConnectState::CONNECTED_BY_USER_GETTING_READY:
98 char_value_ = "CONNECTED_BY_USER_GETTING_READY";
99 break;
100 case DeviceConnectState::CONNECTING_AUTOCONNECT:
101 char_value_ = "CONNECTING_AUTOCONNECT";
102 break;
103 case DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY:
104 char_value_ = "CONNECTED_AUTOCONNECT_GETTING_READY";
105 break;
106 }
107
108 os << char_value_ << " (" << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
109 << ")";
110 return os;
111 }
112
GetFirstLeft(const AudioLocations & audio_locations)113 static uint32_t GetFirstLeft(const AudioLocations& audio_locations) {
114 uint32_t audio_location_ulong = audio_locations.to_ulong();
115
116 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeft) {
117 return codec_spec_conf::kLeAudioLocationFrontLeft;
118 }
119
120 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackLeft) {
121 return codec_spec_conf::kLeAudioLocationBackLeft;
122 }
123
124 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftOfCenter) {
125 return codec_spec_conf::kLeAudioLocationFrontLeftOfCenter;
126 }
127
128 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideLeft) {
129 return codec_spec_conf::kLeAudioLocationSideLeft;
130 }
131
132 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontLeft) {
133 return codec_spec_conf::kLeAudioLocationTopFrontLeft;
134 }
135
136 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackLeft) {
137 return codec_spec_conf::kLeAudioLocationTopBackLeft;
138 }
139
140 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideLeft) {
141 return codec_spec_conf::kLeAudioLocationTopSideLeft;
142 }
143
144 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontLeft) {
145 return codec_spec_conf::kLeAudioLocationBottomFrontLeft;
146 }
147
148 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftWide) {
149 return codec_spec_conf::kLeAudioLocationFrontLeftWide;
150 }
151
152 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) {
153 return codec_spec_conf::kLeAudioLocationLeftSurround;
154 }
155
156 return 0;
157 }
158
GetFirstRight(const AudioLocations & audio_locations)159 static uint32_t GetFirstRight(const AudioLocations& audio_locations) {
160 uint32_t audio_location_ulong = audio_locations.to_ulong();
161
162 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRight) {
163 return codec_spec_conf::kLeAudioLocationFrontRight;
164 }
165
166 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackRight) {
167 return codec_spec_conf::kLeAudioLocationBackRight;
168 }
169
170 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRightOfCenter) {
171 return codec_spec_conf::kLeAudioLocationFrontRightOfCenter;
172 }
173
174 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideRight) {
175 return codec_spec_conf::kLeAudioLocationSideRight;
176 }
177
178 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontRight) {
179 return codec_spec_conf::kLeAudioLocationTopFrontRight;
180 }
181
182 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackRight) {
183 return codec_spec_conf::kLeAudioLocationTopBackRight;
184 }
185
186 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideRight) {
187 return codec_spec_conf::kLeAudioLocationTopSideRight;
188 }
189
190 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontRight) {
191 return codec_spec_conf::kLeAudioLocationBottomFrontRight;
192 }
193
194 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRightWide) {
195 return codec_spec_conf::kLeAudioLocationFrontRightWide;
196 }
197
198 if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) {
199 return codec_spec_conf::kLeAudioLocationRightSurround;
200 }
201
202 return 0;
203 }
204
PickAudioLocation(types::LeAudioConfigurationStrategy strategy,uint8_t direction,const types::BidirectionalPair<std::optional<types::hdl_pair_wrapper<types::AudioLocations>>> & device_audio_locations,AudioLocations & group_locations)205 static uint32_t PickAudioLocation(
206 types::LeAudioConfigurationStrategy strategy, uint8_t direction,
207 const types::BidirectionalPair<
208 std::optional<types::hdl_pair_wrapper<types::AudioLocations>>>&
209 device_audio_locations,
210 AudioLocations& group_locations) {
211 if (!device_audio_locations.get(direction)) {
212 log::error("No valid location is available for direction {}", +direction);
213 return 0;
214 }
215 auto const device_locations = device_audio_locations.get(direction)->value;
216
217 log::debug("strategy: {}, locations: 0x{:x}, input group locations: 0x{:x}", (int)strategy,
218 device_locations.to_ulong(), group_locations.to_ulong());
219
220 auto is_left_not_yet_assigned =
221 !(group_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft);
222 auto is_right_not_yet_assigned =
223 !(group_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight);
224 uint32_t left_device_loc = GetFirstLeft(device_locations);
225 uint32_t right_device_loc = GetFirstRight(device_locations);
226
227 /* Sink locations should be either Left or Right - TMAP 1.0 Sec. 3.5.1.2.1 */
228 if (direction == le_audio::types::kLeAudioDirectionSink && left_device_loc == 0 &&
229 right_device_loc == 0) {
230 log::warn("Can't find device able to render left and right audio channel");
231 }
232
233 switch (strategy) {
234 case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
235 case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
236 if (left_device_loc && is_left_not_yet_assigned) {
237 group_locations |= left_device_loc;
238 return left_device_loc;
239 }
240
241 if (right_device_loc && is_right_not_yet_assigned) {
242 group_locations |= right_device_loc;
243 return right_device_loc;
244 }
245 break;
246
247 case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
248 if (left_device_loc && right_device_loc) {
249 group_locations |= left_device_loc | right_device_loc;
250 return left_device_loc | right_device_loc;
251 }
252 break;
253 default:
254 log::fatal("Unknown strategy: {}", strategy);
255 return 0;
256 }
257
258 /* Return either any left or any right audio location. It might result with
259 * multiple devices within the group having the same location.
260 */
261 auto location = left_device_loc ? left_device_loc : right_device_loc;
262
263 if (direction == le_audio::types::kLeAudioDirectionSink) {
264 log::error(
265 "Can't find device for left/right channel. Strategy: {}, device_locations: {:x}, "
266 "output group_locations: {:x}, chosen location: {}.",
267 strategy, device_locations.to_ulong(), group_locations.to_ulong(), location);
268 } else {
269 log::debug(
270 "No left or right audio location available. Strategy: {}, device_locations: {:x}, "
271 "output group_locations: {:x}, chosen location: {}.",
272 strategy, device_locations.to_ulong(), group_locations.to_ulong(), location);
273 }
274 return location;
275 }
276
IsAudioSetConfigurationSupported(const types::AudioSetConfiguration * audio_set_conf) const277 bool LeAudioDevice::IsAudioSetConfigurationSupported(
278 const types::AudioSetConfiguration* audio_set_conf) const {
279 for (auto direction :
280 {le_audio::types::kLeAudioDirectionSink, le_audio::types::kLeAudioDirectionSource}) {
281 const auto& confs = audio_set_conf->confs.get(direction);
282 if (confs.size() == 0) {
283 continue;
284 }
285
286 log::info("Looking for requirements: {} - {}", audio_set_conf->name,
287 direction == 1 ? "snk" : "src");
288
289 auto const& pacs = (direction == types::kLeAudioDirectionSink) ? snk_pacs_ : src_pacs_;
290 for (const auto& ent : confs) {
291 if (!utils::GetConfigurationSupportedPac(pacs, ent.codec)) {
292 log::info("Configuration is NOT supported by device {}", address_);
293 return false;
294 }
295 }
296 }
297
298 log::info("Configuration is supported by device {}", address_);
299 return true;
300 }
301
ConfigureAses(const types::AudioSetConfiguration * audio_set_conf,uint8_t num_of_devices,uint8_t direction,LeAudioContextType context_type,uint8_t * number_of_already_active_group_ase,AudioLocations & group_audio_locations_memo,const AudioContexts & metadata_context_types,const std::vector<uint8_t> & ccid_lists,bool reuse_cis_id)302 bool LeAudioDevice::ConfigureAses(const types::AudioSetConfiguration* audio_set_conf,
303 uint8_t num_of_devices, uint8_t direction,
304 LeAudioContextType context_type,
305 uint8_t* number_of_already_active_group_ase,
306 AudioLocations& group_audio_locations_memo,
307 const AudioContexts& metadata_context_types,
308 const std::vector<uint8_t>& ccid_lists, bool reuse_cis_id) {
309 if (num_of_devices == 0) {
310 log::error("No devices available for configuration.");
311 return false;
312 }
313
314 auto direction_str = (direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
315 /* First try to use the already configured ASE */
316 auto ase = GetFirstActiveAseByDirection(direction);
317 if (ase) {
318 log::info("{}, using an already active {} ASE id={}", address_, direction_str, ase->id);
319 } else {
320 ase = GetFirstInactiveAse(direction, reuse_cis_id);
321 }
322
323 if (!ase) {
324 log::error("{}, unable to find a {} ASE to configure", address_, direction_str);
325 PrintDebugState();
326 return false;
327 }
328
329 if (!audio_locations_.get(direction)) {
330 log::error("{}, unable to find a {} audio allocation", address_, direction_str);
331 return false;
332 }
333
334 auto const& audio_locations = audio_locations_.get(direction)->value;
335 auto const& group_ase_configs = audio_set_conf->confs.get(direction);
336 std::vector<types::AseConfiguration> ase_configs;
337 std::copy_if(group_ase_configs.cbegin(), group_ase_configs.cend(),
338 std::back_inserter(ase_configs), [&audio_locations](auto const& cfg) {
339 /* Pass as matching if config has no allocation to match
340 * (the legacy json config provider). Otherwise, with the codec
341 * extensibility feature enabled, we receive ASE configurations
342 * for the whole group and we should filter them by audio
343 * allocations to match with the locations supported by a
344 * particular device.
345 */
346 auto config = cfg.codec.params.GetAsCoreCodecConfig();
347 if (!config.audio_channel_allocation.has_value()) {
348 return true;
349 }
350
351 // No locations bits means mono audio
352 if (audio_locations.none()) {
353 return true;
354 }
355
356 // Filter-out not matching audio locations
357 return (cfg.codec.params.GetAsCoreCodecConfig().audio_channel_allocation.value() &
358 audio_locations.to_ulong()) != 0;
359 });
360
361 auto const& pacs = (direction == types::kLeAudioDirectionSink) ? snk_pacs_ : src_pacs_;
362 for (size_t i = 0; i < ase_configs.size() && ase; ++i) {
363 auto const& ase_cfg = ase_configs.at(i);
364 if (utils::IsCodecUsingLtvFormat(ase_cfg.codec.id) &&
365 !utils::GetConfigurationSupportedPac(pacs, ase_cfg.codec)) {
366 log::error("{}, No {} PAC found matching codec: {}. Stop the activation.", address_,
367 direction_str, common::ToString(ase_cfg.codec));
368 return false;
369 }
370 }
371
372 /* The number_of_already_active_group_ase keeps all the active ases
373 * in other devices in the group for the given direction.
374 * This function counts active ases only for this device, and we count here
375 * new active ases and already active ases which we want to reuse in the
376 * scenario
377 */
378 uint8_t active_ases = *number_of_already_active_group_ase;
379
380 // Before we activate the ASEs, make sure we have the right configuration
381 // Check for matching PACs only if we know that the LTV format is being used.
382 uint8_t max_required_ase_per_dev =
383 ase_configs.size() / num_of_devices + (ase_configs.size() % num_of_devices);
384 int needed_ase = std::min((int)(max_required_ase_per_dev), (int)(ase_configs.size()));
385 log::debug("{}, {} {} ASE(s) required for this configuration.", address_, needed_ase,
386 direction_str);
387
388 for (int i = 0; i < needed_ase; ++i) {
389 auto const& ase_cfg = ase_configs.at(i);
390 if (utils::IsCodecUsingLtvFormat(ase_cfg.codec.id) &&
391 !utils::GetConfigurationSupportedPac(pacs, ase_cfg.codec)) {
392 log::error("{}, No {} PAC found matching codec: {}. Stop the activation.", address_,
393 direction_str, common::ToString(ase_cfg.codec));
394 return false;
395 }
396 }
397
398 auto strategy = utils::GetStrategyForAseConfig(group_ase_configs, num_of_devices);
399
400 // Make sure we configure a single microphone if Dual Bidir SWB is not
401 // supported.
402 if (direction == types::kLeAudioDirectionSource &&
403 !CodecManager::GetInstance()->IsDualBiDirSwbSupported() && (active_ases != 0)) {
404 if (CodecManager::GetInstance()->CheckCodecConfigIsDualBiDirSwb(*audio_set_conf)) {
405 log::error(
406 "{}, trying to configure the dual bidir SWB, but the feature is "
407 "disabled. This should not happen! Skipping ASE activation.",
408 address_);
409 return true;
410 }
411 }
412
413 for (int i = 0; i < needed_ase && ase; ++i) {
414 auto const& ase_cfg = ase_configs.at(i);
415 ase->active = true;
416 ase->configured_for_context_type = context_type;
417 ase->data_path_configuration = ase_cfg.data_path_configuration;
418 active_ases++;
419
420 /* In case of late connect, we could be here for STREAMING ase.
421 * in such case, it is needed to mark ase as known active ase which
422 * is important to validate scenario and is done already few lines above.
423 * Nothing more to do is needed here.
424 */
425 if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
426 if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) {
427 ase->reconfigure = true;
428 }
429
430 ase->target_latency = ase_cfg.qos.target_latency;
431 ase->codec_config = ase_cfg.codec;
432
433 /* Let's choose audio channel allocation if not set */
434 ase->codec_config.params.Add(
435 codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation,
436 PickAudioLocation(strategy, direction, audio_locations_, group_audio_locations_memo));
437
438 /* Get default value if no requirement for specific frame blocks per sdu
439 */
440 if (utils::IsCodecUsingLtvFormat(ase->codec_config.id) &&
441 !ase->codec_config.params.Find(codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu)) {
442 ase->codec_config.params.Add(
443 codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
444 GetMaxCodecFramesPerSduFromPac(
445 utils::GetConfigurationSupportedPac(pacs, ase_cfg.codec)));
446 }
447
448 ase->qos_config.sdu_interval = ase_cfg.qos.sduIntervalUs;
449 ase->qos_config.max_sdu_size = ase_cfg.qos.maxSdu;
450 ase->qos_config.retrans_nb = ase_cfg.qos.retransmission_number;
451 ase->qos_config.max_transport_latency = ase_cfg.qos.max_transport_latency;
452
453 SetMetadataToAse(ase, ase_cfg.metadata, metadata_context_types, ccid_lists);
454 }
455
456 log::debug(
457 "device={}, activated ASE id={}, direction={}, max_sdu_size={}, "
458 "cis_id={}, target_latency={}",
459 address_, ase->id, direction_str, ase->qos_config.max_sdu_size, ase->cis_id,
460 ase_cfg.qos.target_latency);
461
462 /* Try to use the already active ASE */
463 ase = GetNextActiveAseWithSameDirection(ase);
464 if (ase == nullptr) {
465 ase = GetFirstInactiveAse(direction, reuse_cis_id);
466 }
467 }
468
469 *number_of_already_active_group_ase = active_ases;
470 return true;
471 }
472
473 /* LeAudioDevice Class methods implementation */
SetConnectionState(DeviceConnectState state)474 void LeAudioDevice::SetConnectionState(DeviceConnectState state) {
475 log::debug("{}, {} --> {}", address_, bluetooth::common::ToString(connection_state_),
476 bluetooth::common::ToString(state));
477 LeAudioLogHistory::Get()->AddLogHistory(kLogConnectionTag, group_id_, address_,
478 bluetooth::common::ToString(connection_state_) + " -> ",
479 "->" + bluetooth::common::ToString(state));
480 connection_state_ = state;
481 }
482
GetConnectionState(void)483 DeviceConnectState LeAudioDevice::GetConnectionState(void) { return connection_state_; }
484
ClearPACs(void)485 void LeAudioDevice::ClearPACs(void) {
486 snk_pacs_.clear();
487 src_pacs_.clear();
488 }
489
~LeAudioDevice(void)490 LeAudioDevice::~LeAudioDevice(void) {
491 alarm_free(link_quality_timer);
492 this->ClearPACs();
493 }
494
ParseHeadtrackingCodec(const struct types::acs_ac_record & pac)495 void LeAudioDevice::ParseHeadtrackingCodec(const struct types::acs_ac_record& pac) {
496 if (pac.codec_id == types::kLeAudioCodecHeadtracking) {
497 log::info("Headtracking supported");
498
499 // Assume LE-ISO is supported if metadata is not available
500 dsa_.modes = {
501 DsaMode::DISABLED,
502 DsaMode::ISO_SW,
503 DsaMode::ISO_HW,
504 };
505
506 /*
507 * Android Headtracker Codec Metadata description
508 * length: 5
509 * type: 0xFF
510 * value: {
511 * vendorId: 0x00E0 (Google)
512 * vendorSpecificMetadata: {
513 * length: 1
514 * type: 1 (Headtracker supported transports)
515 * value: x
516 * }
517 * }
518 */
519 std::vector<uint8_t> ltv = pac.metadata.RawPacket();
520 if (ltv.size() < 7) {
521 log::info("{}, headtracker codec does not have metadata", address_);
522 return;
523 }
524
525 if (ltv[0] < 5 || ltv[1] != types::kLeAudioMetadataTypeVendorSpecific ||
526 ltv[2] != (types::kLeAudioVendorCompanyIdGoogle & 0xFF) ||
527 ltv[3] != (types::kLeAudioVendorCompanyIdGoogle >> 8) ||
528 ltv[4] != types::kLeAudioMetadataHeadtrackerTransportLen ||
529 ltv[5] != types::kLeAudioMetadataHeadtrackerTransportVal) {
530 log::warn("{}, headtracker codec metadata invalid", address_);
531 return;
532 }
533
534 // Valid headtracker codec metadata available, so it must support reduced sdu size
535 dsa_.reduced_sdu = true;
536
537 uint8_t supported_transports = ltv[6];
538 DsaModes dsa_modes = {DsaMode::DISABLED};
539
540 if ((supported_transports & types::kLeAudioMetadataHeadtrackerTransportLeAcl) != 0) {
541 log::debug("{}, headtracking supported over LE-ACL", address_);
542 dsa_modes.push_back(DsaMode::ACL);
543 }
544
545 if ((supported_transports & types::kLeAudioMetadataHeadtrackerTransportLeIso) != 0) {
546 log::debug("{}, headtracking supported over LE-ISO", address_);
547 dsa_modes.push_back(DsaMode::ISO_SW);
548 dsa_modes.push_back(DsaMode::ISO_HW);
549 }
550
551 dsa_.modes = dsa_modes;
552 }
553 }
554
RegisterPACs(std::vector<struct types::acs_ac_record> * pac_db,std::vector<struct types::acs_ac_record> * pac_recs)555 void LeAudioDevice::RegisterPACs(std::vector<struct types::acs_ac_record>* pac_db,
556 std::vector<struct types::acs_ac_record>* pac_recs) {
557 /* Clear PAC database for characteristic in case if re-read, indicated */
558 if (!pac_db->empty()) {
559 log::debug("{}, upgrade PACs for characteristic", address_);
560 pac_db->clear();
561 }
562
563 dsa_.modes = {DsaMode::DISABLED};
564
565 /* TODO wrap this logging part with debug flag */
566 for (const struct types::acs_ac_record& pac : *pac_recs) {
567 std::stringstream debug_str;
568 debug_str << "Registering PAC" << "\n\tCoding format: " << loghex(pac.codec_id.coding_format)
569 << "\n\tVendor codec company ID: " << loghex(pac.codec_id.vendor_company_id)
570 << "\n\tVendor codec ID: " << loghex(pac.codec_id.vendor_codec_id)
571 << "\n\tCodec spec caps:\n";
572 if (utils::IsCodecUsingLtvFormat(pac.codec_id) && !pac.codec_spec_caps.IsEmpty()) {
573 debug_str << pac.codec_spec_caps.ToString("", types::CodecCapabilitiesLtvFormat);
574 } else {
575 debug_str << base::HexEncode(pac.codec_spec_caps_raw.data(), pac.codec_spec_caps_raw.size());
576 }
577
578 debug_str << "\n\tMetadata: " << pac.metadata.ToString();
579 log::debug("{}", debug_str.str());
580
581 ParseHeadtrackingCodec(pac);
582 }
583
584 pac_db->insert(pac_db->begin(), pac_recs->begin(), pac_recs->end());
585 }
586
GetAseByValHandle(uint16_t val_hdl)587 struct ase* LeAudioDevice::GetAseByValHandle(uint16_t val_hdl) {
588 auto iter = std::find_if(ases_.begin(), ases_.end(),
589 [&val_hdl](const auto& ase) { return ase.hdls.val_hdl == val_hdl; });
590
591 return (iter == ases_.end()) ? nullptr : &(*iter);
592 }
593
GetAseCount(uint8_t direction)594 int LeAudioDevice::GetAseCount(uint8_t direction) {
595 return std::count_if(ases_.begin(), ases_.end(),
596 [direction](const auto& a) { return a.direction == direction; });
597 }
598
GetFirstAseWithState(uint8_t direction,AseState state)599 struct ase* LeAudioDevice::GetFirstAseWithState(uint8_t direction, AseState state) {
600 auto iter = std::find_if(ases_.begin(), ases_.end(), [direction, state](const auto& ase) {
601 return (ase.direction == direction) && (ase.state == state);
602 });
603
604 return (iter == ases_.end()) ? nullptr : &(*iter);
605 }
606
GetFirstActiveAse(void)607 struct ase* LeAudioDevice::GetFirstActiveAse(void) {
608 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { return ase.active; });
609
610 return (iter == ases_.end()) ? nullptr : &(*iter);
611 }
612
GetFirstActiveAseByDirection(uint8_t direction)613 struct ase* LeAudioDevice::GetFirstActiveAseByDirection(uint8_t direction) {
614 auto iter = std::find_if(ases_.begin(), ases_.end(), [direction](const auto& ase) {
615 return ase.active && (ase.direction == direction);
616 });
617
618 return (iter == ases_.end()) ? nullptr : &(*iter);
619 }
620
GetNextActiveAseWithSameDirection(struct ase * base_ase)621 struct ase* LeAudioDevice::GetNextActiveAseWithSameDirection(struct ase* base_ase) {
622 auto iter = std::find_if(ases_.begin(), ases_.end(),
623 [&base_ase](auto& ase) { return base_ase == &ase; });
624
625 /* Invalid ase given */
626 if (iter == ases_.end() || std::distance(iter, ases_.end()) < 1) {
627 return nullptr;
628 }
629
630 iter = std::find_if(std::next(iter, 1), ases_.end(), [&iter](const auto& ase) {
631 return ase.active && (*iter).direction == ase.direction;
632 });
633
634 return (iter == ases_.end()) ? nullptr : &(*iter);
635 }
636
GetNextActiveAseWithDifferentDirection(struct ase * base_ase)637 struct ase* LeAudioDevice::GetNextActiveAseWithDifferentDirection(struct ase* base_ase) {
638 auto iter = std::find_if(ases_.begin(), ases_.end(),
639 [&base_ase](auto& ase) { return base_ase == &ase; });
640
641 /* Invalid ase given */
642 if (std::distance(iter, ases_.end()) < 1) {
643 log::debug("{}, ASE {} does not use bidirectional CIS", address_, base_ase->id);
644 return nullptr;
645 }
646
647 iter = std::find_if(std::next(iter, 1), ases_.end(), [&iter](const auto& ase) {
648 return ase.active && iter->direction != ase.direction;
649 });
650
651 if (iter == ases_.end()) {
652 return nullptr;
653 }
654
655 return &(*iter);
656 }
657
GetFirstActiveAseByCisAndDataPathState(CisState cis_state,DataPathState data_path_state)658 struct ase* LeAudioDevice::GetFirstActiveAseByCisAndDataPathState(CisState cis_state,
659 DataPathState data_path_state) {
660 auto iter =
661 std::find_if(ases_.begin(), ases_.end(), [cis_state, data_path_state](const auto& ase) {
662 return ase.active && (ase.data_path_state == data_path_state) &&
663 (ase.cis_state == cis_state);
664 });
665
666 return (iter == ases_.end()) ? nullptr : &(*iter);
667 }
668
GetFirstInactiveAse(uint8_t direction,bool reuse_cis_id)669 struct ase* LeAudioDevice::GetFirstInactiveAse(uint8_t direction, bool reuse_cis_id) {
670 auto iter = std::find_if(ases_.begin(), ases_.end(), [direction, reuse_cis_id](const auto& ase) {
671 if (ase.active || (ase.direction != direction)) {
672 return false;
673 }
674
675 if (!reuse_cis_id) {
676 return true;
677 }
678
679 return ase.cis_id != kInvalidCisId;
680 });
681 /* If ASE is found, return it */
682 if (iter != ases_.end()) {
683 return &(*iter);
684 }
685
686 /* If reuse was not set, that means there is no inactive ASE available. */
687 if (!reuse_cis_id) {
688 return nullptr;
689 }
690
691 /* Since there is no ASE with assigned CIS ID, it means new configuration
692 * needs more ASEs then it was configured before.
693 * Let's find just inactive one */
694 iter = std::find_if(ases_.begin(), ases_.end(), [direction](const auto& ase) {
695 if (ase.active || (ase.direction != direction)) {
696 return false;
697 }
698 return true;
699 });
700
701 return (iter == ases_.end()) ? nullptr : &(*iter);
702 }
703
GetNextActiveAse(struct ase * base_ase)704 struct ase* LeAudioDevice::GetNextActiveAse(struct ase* base_ase) {
705 auto iter = std::find_if(ases_.begin(), ases_.end(),
706 [&base_ase](auto& ase) { return base_ase == &ase; });
707
708 /* Invalid ase given */
709 if (iter == ases_.end() || std::distance(iter, ases_.end()) < 1) {
710 return nullptr;
711 }
712
713 iter = std::find_if(std::next(iter, 1), ases_.end(), [](const auto& ase) { return ase.active; });
714
715 return (iter == ases_.end()) ? nullptr : &(*iter);
716 }
717
GetAseToMatchBidirectionCis(struct ase * base_ase)718 struct ase* LeAudioDevice::GetAseToMatchBidirectionCis(struct ase* base_ase) {
719 auto iter = std::find_if(ases_.begin(), ases_.end(), [&base_ase](auto& ase) {
720 return (base_ase->cis_conn_hdl == ase.cis_conn_hdl) && (base_ase->direction != ase.direction);
721 });
722 return (iter == ases_.end()) ? nullptr : &(*iter);
723 }
724
GetAsesByCisConnHdl(uint16_t conn_hdl)725 BidirectionalPair<struct ase*> LeAudioDevice::GetAsesByCisConnHdl(uint16_t conn_hdl) {
726 BidirectionalPair<struct ase*> ases = {nullptr, nullptr};
727
728 for (auto& ase : ases_) {
729 if (ase.cis_conn_hdl == conn_hdl) {
730 if (ase.direction == types::kLeAudioDirectionSink) {
731 ases.sink = &ase;
732 } else {
733 ases.source = &ase;
734 }
735 }
736 }
737
738 return ases;
739 }
740
GetAsesByCisId(uint8_t cis_id)741 BidirectionalPair<struct ase*> LeAudioDevice::GetAsesByCisId(uint8_t cis_id) {
742 BidirectionalPair<struct ase*> ases = {nullptr, nullptr};
743
744 for (auto& ase : ases_) {
745 if (ase.cis_id == cis_id) {
746 if (ase.direction == types::kLeAudioDirectionSink) {
747 ases.sink = &ase;
748 } else {
749 ases.source = &ase;
750 }
751 }
752 }
753
754 return ases;
755 }
756
HaveActiveAse(void)757 bool LeAudioDevice::HaveActiveAse(void) {
758 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { return ase.active; });
759
760 return iter != ases_.end();
761 }
762
HaveAnyReleasingAse(void)763 bool LeAudioDevice::HaveAnyReleasingAse(void) {
764 /* In configuring state when active in Idle or Configured and reconfigure */
765 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
766 if (!ase.active) {
767 return false;
768 }
769 return ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING;
770 });
771
772 return iter != ases_.end();
773 }
774
HaveAnyStreamingAses(void)775 bool LeAudioDevice::HaveAnyStreamingAses(void) {
776 /* In configuring state when active in Idle or Configured and reconfigure */
777 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
778 if (!ase.active) {
779 return false;
780 }
781
782 if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
783 return true;
784 }
785
786 return false;
787 });
788
789 return iter != ases_.end();
790 }
791
HaveAnyUnconfiguredAses(void)792 bool LeAudioDevice::HaveAnyUnconfiguredAses(void) {
793 /* In configuring state when active in Idle or Configured and reconfigure */
794 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
795 if (!ase.active) {
796 return false;
797 }
798
799 if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE ||
800 ((ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) && ase.reconfigure)) {
801 return true;
802 }
803
804 return false;
805 });
806
807 return iter != ases_.end();
808 }
809
HaveAllActiveAsesSameState(AseState state)810 bool LeAudioDevice::HaveAllActiveAsesSameState(AseState state) {
811 log::verbose("{}", address_);
812 auto iter = std::find_if(ases_.begin(), ases_.end(), [&state](const auto& ase) {
813 log::verbose("ASE id: {}, active: {}, state: {}", ase.id, ase.active,
814 bluetooth::common::ToString(ase.state));
815 return ase.active && (ase.state != state);
816 });
817
818 return iter == ases_.end();
819 }
820
HaveAllActiveAsesSameDataPathState(types::DataPathState state) const821 bool LeAudioDevice::HaveAllActiveAsesSameDataPathState(types::DataPathState state) const {
822 log::verbose("{}", address_);
823 auto iter = std::find_if(ases_.begin(), ases_.end(), [&state](const auto& ase) {
824 log::verbose("ASE id: {}, active: {}, state: {}", ase.id, ase.active,
825 bluetooth::common::ToString(ase.data_path_state));
826 return ase.active && (ase.data_path_state != state);
827 });
828
829 return iter == ases_.end();
830 }
831
IsReadyToCreateStream(void)832 bool LeAudioDevice::IsReadyToCreateStream(void) {
833 log::verbose("{}", address_);
834 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
835 if (!ase.active) {
836 return false;
837 }
838
839 log::verbose("ASE id: {}, state: {}, direction: {}", ase.id,
840 bluetooth::common::ToString(ase.state), ase.direction);
841 if (ase.direction == types::kLeAudioDirectionSink &&
842 (ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
843 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)) {
844 return true;
845 }
846
847 if (ase.direction == types::kLeAudioDirectionSource &&
848 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING) {
849 return true;
850 }
851
852 return false;
853 });
854
855 return iter == ases_.end();
856 }
857
IsReadyToSuspendStream(void)858 bool LeAudioDevice::IsReadyToSuspendStream(void) {
859 auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
860 if (!ase.active) {
861 return false;
862 }
863
864 if (ase.direction == types::kLeAudioDirectionSink &&
865 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
866 return true;
867 }
868
869 if (ase.direction == types::kLeAudioDirectionSource &&
870 ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING) {
871 return true;
872 }
873
874 return false;
875 });
876
877 return iter == ases_.end();
878 }
879
HaveAllActiveAsesCisEst(void) const880 bool LeAudioDevice::HaveAllActiveAsesCisEst(void) const {
881 if (ases_.empty()) {
882 log::warn("No ases for device {}", address_);
883 /* If there is no ASEs at all, it means we are good here - meaning, it is
884 * not waiting for any CIS to be established.
885 */
886 return true;
887 }
888
889 log::verbose("{}", address_);
890
891 bool has_active_ase = false;
892 auto iter = std::find_if(ases_.begin(), ases_.end(), [&](const auto& ase) {
893 if (!has_active_ase && ase.active) {
894 has_active_ase = true;
895 }
896 log::verbose("ASE id: {}, cis_state: {}, direction: {}", ase.id,
897 bluetooth::common::ToString(ase.cis_state), ase.direction);
898
899 return ase.active && (ase.cis_state != CisState::CONNECTED);
900 });
901
902 return iter == ases_.end() && has_active_ase;
903 }
904
HaveAnyCisConnected(void)905 bool LeAudioDevice::HaveAnyCisConnected(void) {
906 /* Pending and Disconnecting is considered as connected in this function */
907 for (auto const ase : ases_) {
908 if (ase.cis_state == CisState::CONNECTED || ase.cis_state == CisState::CONNECTING ||
909 ase.cis_state == CisState::DISCONNECTING) {
910 return true;
911 }
912 }
913 return false;
914 }
915
GetSupportedAudioChannelCounts(uint8_t direction) const916 uint8_t LeAudioDevice::GetSupportedAudioChannelCounts(uint8_t direction) const {
917 auto& pacs = direction == types::kLeAudioDirectionSink ? snk_pacs_ : src_pacs_;
918
919 if (pacs.size() == 0) {
920 log::error("{}, missing PAC for direction {}", address_, direction);
921 return 0;
922 }
923
924 for (const auto& pac_tuple : pacs) {
925 /* Get PAC records from tuple as second element from tuple */
926 auto& pac_recs = std::get<1>(pac_tuple);
927
928 for (const auto pac : pac_recs) {
929 if (!utils::IsCodecUsingLtvFormat(pac.codec_id)) {
930 log::warn(" {} Unknown codec PAC record for codec: {}", address_,
931 bluetooth::common::ToString(pac.codec_id));
932 continue;
933 }
934 log::assert_that(!pac.codec_spec_caps.IsEmpty(),
935 "Codec specific capabilities are not parsed appropriately.");
936
937 auto supported_channel_count_ltv =
938 pac.codec_spec_caps.Find(codec_spec_caps::kLeAudioLtvTypeSupportedAudioChannelCounts);
939
940 if (supported_channel_count_ltv == std::nullopt ||
941 supported_channel_count_ltv->size() == 0L) {
942 return 1;
943 }
944
945 return VEC_UINT8_TO_UINT8(supported_channel_count_ltv.value());
946 };
947 }
948
949 return 0;
950 }
951
952 /**
953 * Returns supported PHY's bitfield
954 */
GetPhyBitmask(void) const955 uint8_t LeAudioDevice::GetPhyBitmask(void) const {
956 uint8_t phy_bitfield = kIsoCigPhy1M;
957
958 if (get_btm_client_interface().peer.BTM_IsPhy2mSupported(address_, BT_TRANSPORT_LE)) {
959 phy_bitfield |= kIsoCigPhy2M;
960 }
961
962 return phy_bitfield;
963 }
964
PrintDebugState(void)965 void LeAudioDevice::PrintDebugState(void) {
966 std::stringstream debug_str;
967
968 debug_str << " Address: " << address_ << ", " << bluetooth::common::ToString(connection_state_)
969 << ", conn_id: " << +conn_id_ << ", mtu: " << +mtu_
970 << ", num_of_ase: " << static_cast<int>(ases_.size());
971
972 if (ases_.size() > 0) {
973 debug_str << "\n == ASEs == ";
974 for (auto& ase : ases_) {
975 debug_str << " id: " << +ase.id << ", active: " << ase.active
976 << ", dir: " << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source")
977 << ", state: " << bluetooth::common::ToString(ase.state)
978 << ", cis_id: " << +ase.cis_id << ", cis_handle: " << +ase.cis_conn_hdl
979 << ", cis_state: " << bluetooth::common::ToString(ase.cis_state)
980 << ", data_path_state: " << bluetooth::common::ToString(ase.data_path_state)
981 << "\n ase max_latency: " << +ase.qos_config.max_transport_latency
982 << ", rtn: " << +ase.qos_config.retrans_nb
983 << ", max_sdu: " << +ase.qos_config.max_sdu_size
984 << ", sdu_interval: " << +ase.qos_config.sdu_interval
985 << ", presentation_delay: " << +ase.qos_config.presentation_delay
986 << ", framing: " << +ase.qos_config.framing << ", phy: " << +ase.qos_config.phy
987 << ", target latency: " << +ase.target_latency
988 << ", reconfigure: " << ase.reconfigure << "\n\n";
989 }
990 }
991
992 log::info("{}", debug_str.str());
993 }
994
GetPreferredPhyBitmask(uint8_t preferred_phy) const995 uint8_t LeAudioDevice::GetPreferredPhyBitmask(uint8_t preferred_phy) const {
996 // Start with full local phy support
997 uint8_t phy_bitmask = bluetooth::hci::kIsoCigPhy1M;
998 if (bluetooth::shim::GetController()->SupportsBle2mPhy()) {
999 phy_bitmask |= bluetooth::hci::kIsoCigPhy2M;
1000 }
1001 if (bluetooth::shim::GetController()->SupportsBleCodedPhy()) {
1002 phy_bitmask |= bluetooth::hci::kIsoCigPhyC;
1003 }
1004
1005 // Check against the remote device support
1006 phy_bitmask &= GetPhyBitmask();
1007
1008 // Take the preferences if possible
1009 if (preferred_phy && (phy_bitmask & preferred_phy)) {
1010 phy_bitmask &= preferred_phy;
1011 log::debug("{}, using ASE preferred phy 0x{:02x}", address_, static_cast<int>(phy_bitmask));
1012 } else {
1013 log::warn(
1014 " {}, ASE preferred 0x{:02x} has nothing common with phy_bitfield "
1015 "0x{:02x}",
1016 address_, static_cast<int>(preferred_phy), static_cast<int>(phy_bitmask));
1017 }
1018 return phy_bitmask;
1019 }
1020
DumpPacsDebugState(std::stringstream & stream,types::PublishedAudioCapabilities pacs)1021 void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream,
1022 types::PublishedAudioCapabilities pacs) {
1023 if (pacs.size() > 0) {
1024 for (auto& pac : pacs) {
1025 stream << "\t • Value handle: " << loghex(std::get<0>(pac).val_hdl)
1026 << ", CCC handle: " << loghex(std::get<0>(pac).ccc_hdl);
1027
1028 for (auto& record : std::get<1>(pac)) {
1029 stream << "\n\t\t· CodecId (Coding format: " << loghex(record.codec_id.coding_format)
1030 << ", Vendor company ID: " << loghex(record.codec_id.vendor_company_id)
1031 << ", Vendor codec ID: " << loghex(record.codec_id.vendor_codec_id) << ")";
1032 stream << "\n\t\t Codec specific capabilities:\n";
1033 if (utils::IsCodecUsingLtvFormat(record.codec_id)) {
1034 stream << record.codec_spec_caps.ToString("\t\t\t", types::CodecCapabilitiesLtvFormat);
1035 } else {
1036 stream << "\t\t\t"
1037 << base::HexEncode(record.codec_spec_caps_raw.data(),
1038 record.codec_spec_caps_raw.size())
1039 << "\n";
1040 }
1041 stream << "\t\t Metadata: " << record.metadata.ToString();
1042 }
1043 stream << "\n";
1044 }
1045 }
1046 }
1047
DumpPacsDebugState(std::stringstream & stream)1048 void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream) {
1049 stream << " ● Device PACS, address: " << address_.ToRedactedStringForLogging() << "\n";
1050 stream << "\t == Sink PACs:\n";
1051 DumpPacsDebugState(stream, snk_pacs_);
1052 stream << "\t == Source PACs:\n";
1053 DumpPacsDebugState(stream, src_pacs_);
1054 }
1055
locationToString(uint32_t location)1056 static std::string locationToString(uint32_t location) {
1057 if (location & codec_spec_conf::kLeAudioLocationAnyLeft &&
1058 location & codec_spec_conf::kLeAudioLocationAnyRight) {
1059 return "left/right";
1060 } else if (location & codec_spec_conf::kLeAudioLocationAnyLeft) {
1061 return "left";
1062 } else if (location & codec_spec_conf::kLeAudioLocationAnyRight) {
1063 return "right";
1064 } else if (location == codec_spec_conf::kLeAudioLocationMonoAudio) {
1065 return "mono";
1066 }
1067 return "unknown location";
1068 }
1069
Dump(std::stringstream & stream)1070 void LeAudioDevice::Dump(std::stringstream& stream) {
1071 uint16_t acl_handle =
1072 get_btm_client_interface().peer.BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE);
1073 std::string snk_location = audio_locations_.sink
1074 ? locationToString(audio_locations_.sink->value.to_ulong())
1075 : "None";
1076 std::string src_location = audio_locations_.source
1077 ? locationToString(audio_locations_.source->value.to_ulong())
1078 : "None";
1079
1080 stream << " ● Device address: " << address_.ToRedactedStringForLogging() << ", "
1081 << connection_state_
1082 << ", conn_id: " << (conn_id_ == GATT_INVALID_CONN_ID ? "-1" : std::to_string(conn_id_))
1083 << ", acl_handle: " << std::to_string(acl_handle) << ", snk_location: " << snk_location
1084 << ", src_location: " << src_location << ", mtu: " << std::to_string(mtu_) << ", "
1085 << (encrypted_ ? "Encrypted" : "Unecrypted")
1086 << "\n\t Sink avail. contexts: " << common::ToString(avail_contexts_.sink)
1087 << "\n\t Source avail. contexts: " << common::ToString(avail_contexts_.source) << "\n";
1088
1089 if (gmap_client_ != nullptr) {
1090 stream << "\t ";
1091 gmap_client_->DebugDump(stream);
1092 } else {
1093 stream << "\t ";
1094 stream << "GmapClient not initialized\n";
1095 }
1096
1097 if (ases_.size() > 0) {
1098 stream << "\t == ASEs (" << static_cast<int>(ases_.size()) << "):\n";
1099 stream << "\t id active dir cis_id cis_handle sdu latency rtn "
1100 "cis_state data_path_state\n";
1101 for (auto& ase : ases_) {
1102 stream << std::setfill('\x20') << "\t " << std::left << std::setw(4)
1103 << static_cast<int>(ase.id) << std::left << std::setw(7)
1104 << (ase.active ? "true" : "false") << std::left << std::setw(8)
1105 << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") << std::left
1106 << std::setw(8) << static_cast<int>(ase.cis_id) << std::left << std::setw(12)
1107 << ase.cis_conn_hdl << std::left << std::setw(5) << ase.qos_config.max_sdu_size
1108 << std::left << std::setw(8) << ase.qos_config.max_transport_latency << std::left
1109 << std::setw(5) << static_cast<int>(ase.qos_config.retrans_nb) << std::left
1110 << std::setw(21) << bluetooth::common::ToString(ase.cis_state) << std::setw(19)
1111 << bluetooth::common::ToString(ase.data_path_state) << "\n";
1112 }
1113 }
1114 }
1115
DisconnectAcl(void)1116 void LeAudioDevice::DisconnectAcl(void) {
1117 if (conn_id_ == GATT_INVALID_CONN_ID) {
1118 return;
1119 }
1120
1121 uint16_t acl_handle =
1122 get_btm_client_interface().peer.BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE);
1123 if (acl_handle != HCI_INVALID_HANDLE) {
1124 acl_disconnect_from_handle(acl_handle, HCI_ERR_PEER_USER,
1125 "bta::bluetooth::le_audio::client disconnect");
1126 }
1127 }
1128
SetAvailableContexts(BidirectionalPair<AudioContexts> contexts)1129 void LeAudioDevice::SetAvailableContexts(BidirectionalPair<AudioContexts> contexts) {
1130 log::debug(
1131 "{}: \n\t previous_contexts_.sink: {} \n\t previous_contexts_.source: {} "
1132 " "
1133 "\n\t new_contexts.sink: {} \n\t new_contexts.source: {} \n\t",
1134 address_, avail_contexts_.sink.to_string(), avail_contexts_.source.to_string(),
1135 contexts.sink.to_string(), contexts.source.to_string());
1136
1137 avail_contexts_.sink = contexts.sink;
1138 avail_contexts_.source = contexts.source;
1139 }
1140
SetMetadataToAse(struct types::ase * ase,const types::LeAudioLtvMap & base_metadata,const AudioContexts & metadata_context_types,const std::vector<uint8_t> & ccid_lists)1141 void LeAudioDevice::SetMetadataToAse(struct types::ase* ase,
1142 const types::LeAudioLtvMap& base_metadata,
1143 const AudioContexts& metadata_context_types,
1144 const std::vector<uint8_t>& ccid_lists) {
1145 /* Filter multidirectional audio context for each ase direction */
1146 auto directional_audio_context = metadata_context_types & GetAvailableContexts(ase->direction);
1147 /* Tha base metadata will be extended (or partially overridden if any key already exist) */
1148 ase->metadata = base_metadata;
1149 if (directional_audio_context.any()) {
1150 ase->metadata.Append(GetMetadata(directional_audio_context, ccid_lists));
1151 } else {
1152 ase->metadata.Append(
1153 GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), std::vector<uint8_t>()));
1154 }
1155 }
1156
ActivateConfiguredAses(LeAudioContextType context_type,const BidirectionalPair<AudioContexts> & metadata_context_types,BidirectionalPair<std::vector<uint8_t>> ccid_lists)1157 bool LeAudioDevice::ActivateConfiguredAses(
1158 LeAudioContextType context_type,
1159 const BidirectionalPair<AudioContexts>& metadata_context_types,
1160 BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
1161 if (conn_id_ == GATT_INVALID_CONN_ID) {
1162 log::warn("Device {} is not connected", address_);
1163 return false;
1164 }
1165
1166 bool ret = false;
1167
1168 log::info("Configuring device {}", address_);
1169 for (auto& ase : ases_) {
1170 if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
1171 ase.configured_for_context_type == context_type) {
1172 log::info(
1173 "conn_id: {}, ase id {}, cis id {}, cis_handle 0x{:04x} is "
1174 "activated.",
1175 conn_id_, ase.id, ase.cis_id, ase.cis_conn_hdl);
1176 ase.active = true;
1177 ret = true;
1178 /* update the already set metadata */
1179 SetMetadataToAse(&ase, ase.metadata, metadata_context_types.get(ase.direction),
1180 ccid_lists.get(ase.direction));
1181 }
1182 }
1183
1184 return ret;
1185 }
1186
DeactivateAllAses(void)1187 void LeAudioDevice::DeactivateAllAses(void) {
1188 for (auto& ase : ases_) {
1189 if (ase.active == false && ase.cis_state != CisState::IDLE &&
1190 ase.data_path_state != DataPathState::IDLE) {
1191 log::warn(
1192 "{}, ase_id: {}, ase.cis_id: {}, cis_handle: 0x{:02x}, "
1193 "ase.cis_state={}, ase.data_path_state={}",
1194 address_, ase.id, ase.cis_id, ase.cis_conn_hdl,
1195 bluetooth::common::ToString(ase.cis_state),
1196 bluetooth::common::ToString(ase.data_path_state));
1197 }
1198
1199 log::verbose("{}, ase_id {}", address_, ase.id);
1200
1201 ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
1202 ase.cis_state = CisState::IDLE;
1203 ase.data_path_state = DataPathState::IDLE;
1204 ase.active = false;
1205 ase.reconfigure = 0;
1206 ase.cis_id = bluetooth::le_audio::kInvalidCisId;
1207 ase.cis_conn_hdl = bluetooth::le_audio::kInvalidCisConnHandle;
1208 }
1209 }
1210
GetMetadata(AudioContexts context_type,const std::vector<uint8_t> & ccid_list)1211 types::LeAudioLtvMap LeAudioDevice::GetMetadata(AudioContexts context_type,
1212 const std::vector<uint8_t>& ccid_list) {
1213 types::LeAudioLtvMap metadata;
1214 metadata.Add(types::kLeAudioMetadataTypeStreamingAudioContext, context_type.value());
1215 if (ccid_list.size()) {
1216 metadata.Add(types::kLeAudioMetadataTypeCcidList, ccid_list);
1217 }
1218 return metadata;
1219 }
1220
IsMetadataChanged(const BidirectionalPair<AudioContexts> & context_types,const BidirectionalPair<std::vector<uint8_t>> & ccid_lists)1221 bool LeAudioDevice::IsMetadataChanged(const BidirectionalPair<AudioContexts>& context_types,
1222 const BidirectionalPair<std::vector<uint8_t>>& ccid_lists) {
1223 for (auto* ase = this->GetFirstActiveAse(); ase; ase = this->GetNextActiveAse(ase)) {
1224 if (this->GetMetadata(context_types.get(ase->direction), ccid_lists.get(ase->direction)) !=
1225 ase->metadata) {
1226 return true;
1227 }
1228 }
1229
1230 return false;
1231 }
1232
GetDeviceModelName(void)1233 void LeAudioDevice::GetDeviceModelName(void) {
1234 bt_property_t prop_name;
1235 bt_bdname_t prop_value = {0};
1236 // Retrieve model name from storage
1237 BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_MODEL_NUM, sizeof(bt_bdname_t),
1238 &prop_value);
1239 if (btif_storage_get_remote_device_property(&address_, &prop_name) == BT_STATUS_SUCCESS) {
1240 model_name_.assign((char*)prop_value.name);
1241 }
1242 }
1243
UpdateDeviceAllowlistFlag(void)1244 void LeAudioDevice::UpdateDeviceAllowlistFlag(void) {
1245 char allow_list[PROPERTY_VALUE_MAX] = {0};
1246 GetDeviceModelName();
1247 osi_property_get(kLeAudioDeviceAllowListProp, allow_list, "");
1248 if (allow_list[0] == '\0' || model_name_ == "") {
1249 // if device allow list is empty or no remote model name available
1250 // return allowlist_flag_ as default false
1251 return;
1252 }
1253
1254 std::istringstream stream(allow_list);
1255 std::string token;
1256 while (std::getline(stream, token, ',')) {
1257 if (token.compare(model_name_) == 0) {
1258 allowlist_flag_ = true;
1259 return;
1260 }
1261 }
1262 }
1263
GetDsaModes(void)1264 DsaModes LeAudioDevice::GetDsaModes(void) { return dsa_.modes; }
1265
DsaReducedSduSizeSupported()1266 bool LeAudioDevice::DsaReducedSduSizeSupported() { return dsa_.reduced_sdu; }
1267
GetDsaDataPathState(void)1268 types::DataPathState LeAudioDevice::GetDsaDataPathState(void) { return dsa_.state; }
1269
SetDsaDataPathState(types::DataPathState state)1270 void LeAudioDevice::SetDsaDataPathState(types::DataPathState state) { dsa_.state = state; }
1271
GetDsaCisHandle(void)1272 uint16_t LeAudioDevice::GetDsaCisHandle(void) { return dsa_.cis_handle; }
1273
SetDsaCisHandle(uint16_t cis_handle)1274 void LeAudioDevice::SetDsaCisHandle(uint16_t cis_handle) { dsa_.cis_handle = cis_handle; }
1275
1276 /* LeAudioDevices Class methods implementation */
Add(const RawAddress & address,DeviceConnectState state,int group_id)1277 void LeAudioDevices::Add(const RawAddress& address, DeviceConnectState state, int group_id) {
1278 auto device = FindByAddress(address);
1279 if (device != nullptr) {
1280 log::error("address: {} is already assigned to group: {}", address, device->group_id_);
1281 return;
1282 }
1283
1284 leAudioDevices_.emplace_back(std::make_shared<LeAudioDevice>(address, state, group_id));
1285 }
1286
Remove(const RawAddress & address)1287 void LeAudioDevices::Remove(const RawAddress& address) {
1288 auto iter = std::find_if(
1289 leAudioDevices_.begin(), leAudioDevices_.end(),
1290 [&address](auto const& leAudioDevice) { return leAudioDevice->address_ == address; });
1291
1292 if (iter == leAudioDevices_.end()) {
1293 log::error("no such address: {}", address);
1294 return;
1295 }
1296
1297 leAudioDevices_.erase(iter);
1298 }
1299
FindByAddress(const RawAddress & address) const1300 LeAudioDevice* LeAudioDevices::FindByAddress(const RawAddress& address) const {
1301 auto iter = std::find_if(
1302 leAudioDevices_.begin(), leAudioDevices_.end(),
1303 [&address](auto const& leAudioDevice) { return leAudioDevice->address_ == address; });
1304
1305 return (iter == leAudioDevices_.end()) ? nullptr : iter->get();
1306 }
1307
GetByAddress(const RawAddress & address) const1308 std::shared_ptr<LeAudioDevice> LeAudioDevices::GetByAddress(const RawAddress& address) const {
1309 auto iter = std::find_if(
1310 leAudioDevices_.begin(), leAudioDevices_.end(),
1311 [&address](auto const& leAudioDevice) { return leAudioDevice->address_ == address; });
1312
1313 return (iter == leAudioDevices_.end()) ? nullptr : *iter;
1314 }
1315
FindByConnId(tCONN_ID conn_id) const1316 LeAudioDevice* LeAudioDevices::FindByConnId(tCONN_ID conn_id) const {
1317 auto iter = std::find_if(
1318 leAudioDevices_.begin(), leAudioDevices_.end(),
1319 [&conn_id](auto const& leAudioDevice) { return leAudioDevice->conn_id_ == conn_id; });
1320
1321 return (iter == leAudioDevices_.end()) ? nullptr : iter->get();
1322 }
1323
FindByCisConnHdl(uint8_t cig_id,uint16_t conn_hdl) const1324 LeAudioDevice* LeAudioDevices::FindByCisConnHdl(uint8_t cig_id, uint16_t conn_hdl) const {
1325 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
1326 [&conn_hdl, &cig_id](auto& d) {
1327 LeAudioDevice* dev;
1328 BidirectionalPair<struct ase*> ases;
1329
1330 dev = d.get();
1331 if (dev->group_id_ != cig_id) {
1332 return false;
1333 }
1334
1335 ases = dev->GetAsesByCisConnHdl(conn_hdl);
1336 if (ases.sink || ases.source) {
1337 return true;
1338 } else {
1339 return false;
1340 }
1341 });
1342
1343 if (iter == leAudioDevices_.end()) {
1344 return nullptr;
1345 }
1346
1347 return iter->get();
1348 }
1349
SetInitialGroupAutoconnectState(int group_id,int gatt_if,tBTM_BLE_CONN_TYPE,bool current_dev_autoconnect_flag)1350 void LeAudioDevices::SetInitialGroupAutoconnectState(int group_id, int gatt_if,
1351 tBTM_BLE_CONN_TYPE /*reconnection_mode*/,
1352 bool current_dev_autoconnect_flag) {
1353 if (!current_dev_autoconnect_flag) {
1354 /* If current device autoconnect flag is false, check if there is other
1355 * device in the group which is in autoconnect mode.
1356 * If yes, assume whole group is in autoconnect.
1357 */
1358 auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&group_id](auto& d) {
1359 LeAudioDevice* dev;
1360 dev = d.get();
1361 if (dev->group_id_ != group_id) {
1362 return false;
1363 }
1364 return dev->autoconnect_flag_;
1365 });
1366
1367 current_dev_autoconnect_flag = !(iter == leAudioDevices_.end());
1368 }
1369
1370 if (!current_dev_autoconnect_flag) {
1371 return;
1372 }
1373
1374 /* This function is called when bluetooth started, therefore here we will
1375 * try direct connection, if that failes, we fallback to background connection
1376 */
1377 for (auto dev : leAudioDevices_) {
1378 if ((dev->group_id_ == group_id) &&
1379 (dev->GetConnectionState() == DeviceConnectState::DISCONNECTED)) {
1380 dev->SetConnectionState(DeviceConnectState::CONNECTING_AUTOCONNECT);
1381 dev->autoconnect_flag_ = true;
1382 btif_storage_set_leaudio_autoconnect(dev->address_, true);
1383 BTA_GATTC_Open(gatt_if, dev->address_, BTM_BLE_DIRECT_CONNECTION, false);
1384 }
1385 }
1386 }
1387
Size() const1388 size_t LeAudioDevices::Size() const { return leAudioDevices_.size(); }
1389
Dump(std::stringstream & stream,int group_id) const1390 void LeAudioDevices::Dump(std::stringstream& stream, int group_id) const {
1391 for (auto const& device : leAudioDevices_) {
1392 if (device->group_id_ == group_id) {
1393 device->Dump(stream);
1394
1395 stream << "\tAddress: " << device->address_ << "\n";
1396 device->DumpPacsDebugState(stream);
1397 stream << "\n";
1398 }
1399 }
1400 }
1401
Cleanup(tGATT_IF client_if)1402 void LeAudioDevices::Cleanup(tGATT_IF client_if) {
1403 for (auto const& device : leAudioDevices_) {
1404 auto connection_state = device->GetConnectionState();
1405 if (connection_state == DeviceConnectState::DISCONNECTED ||
1406 connection_state == DeviceConnectState::DISCONNECTING) {
1407 continue;
1408 }
1409
1410 // For connecting or connected device always remove background connect
1411 BTA_GATTC_CancelOpen(client_if, device->address_, false);
1412
1413 if (connection_state == DeviceConnectState::CONNECTING_BY_USER) {
1414 // When connecting by user, remove direct connect
1415 BTA_GATTC_CancelOpen(client_if, device->address_, true);
1416 } else if (connection_state != DeviceConnectState::CONNECTING_AUTOCONNECT) {
1417 // If connected, close the connection
1418 BtaGattQueue::Clean(device->conn_id_);
1419 BTA_GATTC_Close(device->conn_id_);
1420 device->DisconnectAcl();
1421 }
1422 }
1423 leAudioDevices_.clear();
1424 }
1425
1426 } // namespace bluetooth::le_audio
1427