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 /*
19 * This file contains definitions for Basic Audio Profile / Audio Stream Control
20 * and Published Audio Capabilities definitions, structures etc.
21 */
22
23 #include "le_audio_types.h"
24
25 #include <base/strings/string_number_conversions.h>
26 #include <bluetooth/log.h>
27
28 #include "audio_hal_client/audio_hal_client.h"
29 #include "common/strings.h"
30 #include "internal_include/bt_trace.h"
31 #include "le_audio_utils.h"
32 #include "stack/include/bt_types.h"
33
34 namespace bluetooth::le_audio {
35 using types::acs_ac_record;
36 using types::LeAudioContextType;
37
38 namespace set_configurations {
39 using set_configurations::CodecConfigSetting;
40 using types::CodecLocation;
41 using types::kLeAudioCodingFormatLC3;
42 using types::kLeAudioDirectionSink;
43 using types::kLeAudioDirectionSource;
44 using types::LeAudioCoreCodecConfig;
45
get_cis_count(LeAudioContextType context_type,int expected_device_cnt,types::LeAudioConfigurationStrategy strategy,int avail_group_ase_snk_cnt,int avail_group_ase_src_count,uint8_t & out_cis_count_bidir,uint8_t & out_cis_count_unidir_sink,uint8_t & out_cis_count_unidir_source)46 void get_cis_count(LeAudioContextType context_type, int expected_device_cnt,
47 types::LeAudioConfigurationStrategy strategy,
48 int avail_group_ase_snk_cnt, int avail_group_ase_src_count,
49 uint8_t& out_cis_count_bidir,
50 uint8_t& out_cis_count_unidir_sink,
51 uint8_t& out_cis_count_unidir_source) {
52 log::info(
53 "{} strategy {}, group avail sink ases: {}, group avail source ases {} "
54 "expected_device_count {}",
55 bluetooth::common::ToString(context_type), static_cast<int>(strategy),
56 avail_group_ase_snk_cnt, avail_group_ase_src_count, expected_device_cnt);
57
58 bool is_bidirectional = types::kLeAudioContextAllBidir.test(context_type);
59
60 switch (strategy) {
61 case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
62 /* This strategy is for the CSIS topology, e.g. two earbuds which are both
63 * connected with a Phone
64 */
65 case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
66 /* This strategy is for e.g. the banded headphones */
67 if (is_bidirectional) {
68 if ((avail_group_ase_snk_cnt > 0) && (avail_group_ase_src_count) > 0) {
69 /* Prepare CIG to enable all microphones */
70 out_cis_count_bidir = expected_device_cnt;
71 } else {
72 if (avail_group_ase_snk_cnt > 0) {
73 out_cis_count_unidir_sink = expected_device_cnt;
74 } else if (avail_group_ase_src_count > 0) {
75 out_cis_count_unidir_source = expected_device_cnt;
76 }
77 }
78 } else {
79 out_cis_count_unidir_sink = expected_device_cnt;
80 }
81
82 break;
83 case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
84 /* This strategy is for the old TWS topology. e.g. one earbud connected to
85 * the Phone but each channel is carried in separate CIS
86 */
87 if (is_bidirectional) {
88 if ((avail_group_ase_snk_cnt > 0) && (avail_group_ase_src_count) > 0) {
89 /* Prepare CIG to enable all microphones per device */
90 /* TODO: Support TWS style device with two source ASEs - two
91 * bidirectional CISes
92 */
93 out_cis_count_bidir = expected_device_cnt;
94 out_cis_count_unidir_sink = expected_device_cnt;
95 } else {
96 if (avail_group_ase_snk_cnt > 0) {
97 out_cis_count_unidir_sink = 2 * expected_device_cnt;
98 } else if (avail_group_ase_src_count > 0) {
99 out_cis_count_unidir_source = 2 * expected_device_cnt;
100 }
101 }
102 } else {
103 out_cis_count_unidir_sink = 2 * expected_device_cnt;
104 }
105 break;
106 case types::LeAudioConfigurationStrategy::RFU:
107 log::error("Should not happen;");
108 break;
109 }
110
111 log::info(
112 "Required cis count: Bi-Directional: {}, Uni-Directional Sink: {}, "
113 "Uni-Directional Source: {}",
114 out_cis_count_bidir, out_cis_count_unidir_sink,
115 out_cis_count_unidir_source);
116 }
117
GetOctectsPerFrame() const118 uint16_t CodecConfigSetting::GetOctectsPerFrame() const {
119 switch (id.coding_format) {
120 case kLeAudioCodingFormatLC3:
121 return params.GetAsCoreCodecConfig().GetOctectsPerFrame();
122 default:
123 log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
124 return 0;
125 }
126 };
127
GetSamplingFrequencyHz() const128 uint32_t CodecConfigSetting::GetSamplingFrequencyHz() const {
129 // We also mandate the sampling frequency parameter for vendor spec. codecs
130 return params.GetAsCoreCodecConfig().GetSamplingFrequencyHz();
131 };
132
GetDataIntervalUs() const133 uint32_t CodecConfigSetting::GetDataIntervalUs() const {
134 switch (id.coding_format) {
135 case kLeAudioCodingFormatLC3:
136 return params.GetAsCoreCodecConfig().GetFrameDurationUs();
137 default:
138 log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
139 return 0;
140 }
141 };
142
GetBitsPerSample() const143 uint8_t CodecConfigSetting::GetBitsPerSample() const {
144 switch (id.coding_format) {
145 case kLeAudioCodingFormatLC3:
146 /* XXX LC3 supports 16, 24, 32 */
147 return 16;
148 default:
149 log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
150 return 0;
151 }
152 };
153
operator <<(std::ostream & os,const QosConfigSetting & config)154 std::ostream& operator<<(std::ostream& os, const QosConfigSetting& config) {
155 os << "QosConfigSetting{";
156 os << "targetLatency: " << (int)config.target_latency;
157 os << ", retransmissionNum: " << (int)config.retransmission_number;
158 os << ", maxTransportLatency: " << (int)config.max_transport_latency;
159 os << ", sduIntervalUs: " << (int)config.sduIntervalUs;
160 os << ", maxSdu: " << (int)config.maxSdu;
161 os << "}";
162 return os;
163 }
164
operator <<(std::ostream & os,const AseConfiguration & config)165 std::ostream& operator<<(std::ostream& os, const AseConfiguration& config) {
166 os << "AseConfiguration{";
167 os << "dataPath: " << config.data_path_configuration;
168 os << ", codec: " << config.codec;
169 os << ", qos: " << config.qos;
170 os << "}";
171 return os;
172 }
173
operator <<(std::ostream & os,const AudioSetConfiguration & config)174 std::ostream& operator<<(std::ostream& os,
175 const AudioSetConfiguration& config) {
176 os << "AudioSetConfiguration{";
177 os << "name: " << config.name;
178 os << ", packing: " << (int)config.packing;
179 os << ", sinkConfs: [";
180 for (auto const& conf : config.confs.sink) {
181 os << conf;
182 os << ", ";
183 }
184 os << "], sourceConfs: [";
185 for (auto const& conf : config.confs.source) {
186 os << conf;
187 os << ", ";
188 }
189 os << "]}";
190 return os;
191 }
192
operator <<(std::ostream & os,const CodecConfigSetting & config)193 std::ostream& operator<<(std::ostream& os, const CodecConfigSetting& config) {
194 os << "CodecConfigSetting{";
195 os << ", id: " << config.id;
196 os << ", codecSpecParams: " << config.params.GetAsCoreCodecConfig();
197 os << ", bitsPerSample: " << (int)config.GetBitsPerSample();
198 os << ", channelCountPerIsoStream: "
199 << (int)config.GetChannelCountPerIsoStream();
200 if (!config.vendor_params.empty()) {
201 os << ", vendorParams: "
202 << base::HexEncode(config.vendor_params.data(),
203 config.vendor_params.size());
204 }
205 os << "}";
206 return os;
207 }
208
209 } // namespace set_configurations
210
211 namespace types {
212 /* Helper map for matching various frequency notations */
213 const std::map<uint8_t, uint32_t> LeAudioCoreCodecConfig::sampling_freq_map = {
214 {codec_spec_conf::kLeAudioSamplingFreq8000Hz,
215 LeAudioCodecConfiguration::kSampleRate8000},
216 {codec_spec_conf::kLeAudioSamplingFreq16000Hz,
217 LeAudioCodecConfiguration::kSampleRate16000},
218 {codec_spec_conf::kLeAudioSamplingFreq24000Hz,
219 LeAudioCodecConfiguration::kSampleRate24000},
220 {codec_spec_conf::kLeAudioSamplingFreq32000Hz,
221 LeAudioCodecConfiguration::kSampleRate32000},
222 {codec_spec_conf::kLeAudioSamplingFreq44100Hz,
223 LeAudioCodecConfiguration::kSampleRate44100},
224 {codec_spec_conf::kLeAudioSamplingFreq48000Hz,
225 LeAudioCodecConfiguration::kSampleRate48000}};
226
227 /* Helper map for matching various frequency notations */
228 const std::map<uint32_t, uint8_t> LeAudioCoreCodecConfig::sample_rate_map = {
229 {LeAudioCodecConfiguration::kSampleRate8000,
230 codec_spec_conf::kLeAudioSamplingFreq8000Hz},
231 {LeAudioCodecConfiguration::kSampleRate16000,
232 codec_spec_conf::kLeAudioSamplingFreq16000Hz},
233 {LeAudioCodecConfiguration::kSampleRate24000,
234 codec_spec_conf::kLeAudioSamplingFreq24000Hz},
235 {LeAudioCodecConfiguration::kSampleRate32000,
236 codec_spec_conf::kLeAudioSamplingFreq32000Hz},
237 {LeAudioCodecConfiguration::kSampleRate44100,
238 codec_spec_conf::kLeAudioSamplingFreq44100Hz},
239 {LeAudioCodecConfiguration::kSampleRate48000,
240 codec_spec_conf::kLeAudioSamplingFreq48000Hz},
241 };
242
243 /* Helper map for matching various frame durations notations */
244 const std::map<uint8_t, uint32_t> LeAudioCoreCodecConfig::frame_duration_map = {
245 {codec_spec_conf::kLeAudioCodecFrameDur7500us,
246 LeAudioCodecConfiguration::kInterval7500Us},
247 {codec_spec_conf::kLeAudioCodecFrameDur10000us,
248 LeAudioCodecConfiguration::kInterval10000Us}};
249
250 /* Helper map for matching various frame durations notations */
251 const std::map<uint32_t, uint8_t> LeAudioCoreCodecConfig::data_interval_map = {
252 {LeAudioCodecConfiguration::kInterval7500Us,
253 codec_spec_conf::kLeAudioCodecFrameDur7500us},
254 {LeAudioCodecConfiguration::kInterval10000Us,
255 codec_spec_conf::kLeAudioCodecFrameDur10000us},
256 };
257
CapabilityTypeToStr(const uint8_t & type)258 std::string CapabilityTypeToStr(const uint8_t& type) {
259 switch (type) {
260 case codec_spec_caps::kLeAudioLtvTypeSupportedSamplingFrequencies:
261 return "Supported Sampling Frequencies";
262 case codec_spec_caps::kLeAudioLtvTypeSupportedFrameDurations:
263 return "Supported Frame Durations";
264 case codec_spec_caps::kLeAudioLtvTypeSupportedAudioChannelCounts:
265 return "Supported Audio Channel Count";
266 case codec_spec_caps::kLeAudioLtvTypeSupportedOctetsPerCodecFrame:
267 return "Supported Octets Per Codec Frame";
268 case codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu:
269 return "Supported Max Codec Frames Per SDU";
270 default:
271 return "Unknown";
272 }
273 }
274
CapabilityValueToStr(const uint8_t & type,const std::vector<uint8_t> & value)275 std::string CapabilityValueToStr(const uint8_t& type,
276 const std::vector<uint8_t>& value) {
277 std::string string = "";
278
279 switch (type) {
280 case codec_spec_conf::kLeAudioLtvTypeSamplingFreq: {
281 if (value.size() != 2) {
282 return "Invalid size";
283 }
284
285 uint16_t u16_val = VEC_UINT8_TO_UINT16(value);
286
287 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq8000Hz) {
288 string += "8";
289 }
290 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq11025Hz) {
291 string += std::string((string.empty() ? "" : "|")) + "11.025";
292 }
293 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq16000Hz) {
294 string += std::string((string.empty() ? "" : "|")) + "16";
295 }
296 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq22050Hz) {
297 string += std::string((string.empty() ? "" : "|")) + "22.050";
298 }
299 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq24000Hz) {
300 string += std::string((string.empty() ? "" : "|")) + "24";
301 }
302 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq32000Hz) {
303 string += std::string((string.empty() ? "" : "|")) + "32";
304 }
305 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq44100Hz) {
306 string += std::string((string.empty() ? "" : "|")) + "44.1";
307 }
308 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq48000Hz) {
309 string += std::string((string.empty() ? "" : "|")) + "48";
310 }
311 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq88200Hz) {
312 string += std::string((string.empty() ? "" : "|")) + "88.2";
313 }
314 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq96000Hz) {
315 string += std::string((string.empty() ? "" : "|")) + "96";
316 }
317 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq176400Hz) {
318 string += std::string((string.empty() ? "" : "|")) + "176.4";
319 }
320 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq192000Hz) {
321 string += std::string((string.empty() ? "" : "|")) + "192";
322 }
323 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq384000Hz) {
324 string += std::string((string.empty() ? "" : "|")) + "384";
325 }
326
327 return string += " [kHz]\n";
328 }
329 case codec_spec_conf::kLeAudioLtvTypeFrameDuration: {
330 if (value.size() != 1) {
331 return "Invalid size";
332 }
333
334 uint8_t u8_val = VEC_UINT8_TO_UINT8(value);
335
336 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDur7500us) {
337 string += "7.5";
338 }
339 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDur10000us) {
340 string += std::string((string.empty() ? "" : "|")) + "10";
341 }
342 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDurPrefer7500us) {
343 string += std::string((string.empty() ? "" : "|")) + "7.5 preferred";
344 }
345 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDurPrefer10000us) {
346 string += std::string((string.empty() ? "" : "|")) + "10 preferred";
347 }
348
349 return string += " [ms]\n";
350 }
351 case codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation: {
352 if (value.size() != 1) {
353 return "Invalid size";
354 }
355
356 uint8_t u8_val = VEC_UINT8_TO_UINT8(value);
357
358 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountNone) {
359 string += "0";
360 }
361 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSingleChannel) {
362 string += std::string((string.empty() ? "" : "|")) + "1";
363 }
364 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountTwoChannel) {
365 string += std::string((string.empty() ? "" : "|")) + "2";
366 }
367 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountThreeChannel) {
368 string += std::string((string.empty() ? "" : "|")) + "3";
369 }
370 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountFourChannel) {
371 string += std::string((string.empty() ? "" : "|")) + "4";
372 }
373 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountFiveChannel) {
374 string += std::string((string.empty() ? "" : "|")) + "5";
375 }
376 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSixChannel) {
377 string += std::string((string.empty() ? "" : "|")) + "6";
378 }
379 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSevenChannel) {
380 string += std::string((string.empty() ? "" : "|")) + "7";
381 }
382 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountEightChannel) {
383 string += std::string((string.empty() ? "" : "|")) + "8";
384 }
385
386 return string += " channel/s\n";
387 }
388 case codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame: {
389 if (value.size() != 4) {
390 return "Invalid size";
391 }
392
393 uint16_t u16_min_number_of_octets = VEC_UINT8_TO_UINT16(value);
394 uint16_t u16_max_number_of_octets =
395 OFF_VEC_UINT8_TO_UINT16(value, sizeof(u16_min_number_of_octets));
396
397 string += "Minimum: " + std::to_string(u16_min_number_of_octets);
398 string += ", Maximum: " + std::to_string(u16_max_number_of_octets) + "\n";
399
400 return string;
401 }
402 case codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu: {
403 if (value.size() != 1) {
404 return "Invalid size";
405 }
406
407 uint8_t u8_val = VEC_UINT8_TO_UINT8(value);
408
409 string += std::to_string(u8_val) + " frame/s\n";
410
411 return string;
412 }
413 default:
414 return base::HexEncode(value.data(), value.size()) + "\n";
415 }
416 }
417
CodecCapabilitiesLtvFormat(const uint8_t & type,const std::vector<uint8_t> & value)418 std::string CodecCapabilitiesLtvFormat(const uint8_t& type,
419 const std::vector<uint8_t>& value) {
420 std::string string = "";
421
422 string += CapabilityTypeToStr(type) + ": ";
423 string += CapabilityValueToStr(type, value);
424
425 return string;
426 }
427
Find(uint8_t type) const428 std::optional<std::vector<uint8_t>> LeAudioLtvMap::Find(uint8_t type) const {
429 auto iter =
430 std::find_if(values.cbegin(), values.cend(),
431 [type](const auto& value) { return value.first == type; });
432
433 if (iter == values.cend()) return std::nullopt;
434
435 return iter->second;
436 }
437
RawPacket(uint8_t * p_buf) const438 uint8_t* LeAudioLtvMap::RawPacket(uint8_t* p_buf) const {
439 for (auto const& value : values) {
440 UINT8_TO_STREAM(p_buf, value.second.size() + 1);
441 UINT8_TO_STREAM(p_buf, value.first);
442 ARRAY_TO_STREAM(p_buf, value.second.data(),
443 static_cast<int>(value.second.size()));
444 }
445
446 return p_buf;
447 }
448
RawPacket() const449 std::vector<uint8_t> LeAudioLtvMap::RawPacket() const {
450 std::vector<uint8_t> data(RawPacketSize());
451 RawPacket(data.data());
452 return data;
453 }
454
Append(const LeAudioLtvMap & other)455 void LeAudioLtvMap::Append(const LeAudioLtvMap& other) {
456 /* This will override values for the already existing keys */
457 for (auto& el : other.values) {
458 values[el.first] = el.second;
459 }
460
461 invalidate();
462 }
463
Parse(const uint8_t * p_value,uint8_t len,bool & success)464 LeAudioLtvMap LeAudioLtvMap::Parse(const uint8_t* p_value, uint8_t len,
465 bool& success) {
466 LeAudioLtvMap ltv_map;
467 success = ltv_map.Parse(p_value, len);
468 if (!success) {
469 log::error("Error parsing LTV map");
470 }
471 return ltv_map;
472 }
473
Parse(const uint8_t * p_value,uint8_t len)474 bool LeAudioLtvMap::Parse(const uint8_t* p_value, uint8_t len) {
475 if (len > 0) {
476 const auto p_value_end = p_value + len;
477
478 while ((p_value_end - p_value) > 0) {
479 uint8_t ltv_len;
480 STREAM_TO_UINT8(ltv_len, p_value);
481
482 // Unusual, but possible case
483 if (ltv_len == 0) continue;
484
485 if (p_value_end < (p_value + ltv_len)) {
486 log::error("Invalid ltv_len: {}", static_cast<int>(ltv_len));
487 invalidate();
488 return false;
489 }
490
491 uint8_t ltv_type;
492 STREAM_TO_UINT8(ltv_type, p_value);
493 ltv_len -= sizeof(ltv_type);
494
495 const auto p_temp = p_value;
496 p_value += ltv_len;
497
498 std::vector<uint8_t> ltv_value(p_temp, p_value);
499 values.emplace(ltv_type, std::move(ltv_value));
500 }
501 }
502 invalidate();
503
504 return true;
505 }
506
RawPacketSize() const507 size_t LeAudioLtvMap::RawPacketSize() const {
508 size_t bytes = 0;
509
510 for (auto const& value : values) {
511 bytes += (/* ltv_len + ltv_type */ 2 + value.second.size());
512 }
513
514 return bytes;
515 }
516
ToString(const std::string & indent_string,std::string (* format)(const uint8_t &,const std::vector<uint8_t> &)) const517 std::string LeAudioLtvMap::ToString(
518 const std::string& indent_string,
519 std::string (*format)(const uint8_t&, const std::vector<uint8_t>&)) const {
520 std::string debug_str;
521
522 for (const auto& value : values) {
523 std::stringstream sstream;
524
525 if (format == nullptr) {
526 sstream << indent_string + "type: " << std::to_string(value.first)
527 << "\tlen: " << std::to_string(value.second.size()) << "\tdata: "
528 << base::HexEncode(value.second.data(), value.second.size()) +
529 "\n";
530 } else {
531 sstream << indent_string + format(value.first, value.second);
532 }
533
534 debug_str += sstream.str();
535 }
536
537 return debug_str;
538 }
539
GetAsCoreCodecConfig() const540 const struct LeAudioCoreCodecConfig& LeAudioLtvMap::GetAsCoreCodecConfig()
541 const {
542 log::assert_that(!core_capabilities,
543 "LTVs were already parsed for capabilities!");
544 log::assert_that(!metadata, "LTVs were already parsed for metadata!");
545
546 if (!core_config) {
547 core_config = LtvMapToCoreCodecConfig(*this);
548 }
549 return *core_config;
550 }
551
552 const struct LeAudioCoreCodecCapabilities&
GetAsCoreCodecCapabilities() const553 LeAudioLtvMap::GetAsCoreCodecCapabilities() const {
554 log::assert_that(!core_config,
555 "LTVs were already parsed for configurations!");
556 log::assert_that(!metadata, "LTVs were already parsed for metadata!");
557
558 if (!core_capabilities) {
559 core_capabilities = LtvMapToCoreCodecCapabilities(*this);
560 }
561 return *core_capabilities;
562 }
563
GetAsLeAudioMetadata() const564 const struct LeAudioMetadata& LeAudioLtvMap::GetAsLeAudioMetadata() const {
565 log::assert_that(!core_config,
566 "LTVs were already parsed for configurations!");
567 log::assert_that(!core_capabilities,
568 "LTVs were already parsed for capabilities!");
569
570 if (!metadata) {
571 metadata = LtvMapToMetadata(*this);
572 }
573 return *metadata;
574 }
575
RemoveAllTypes(const LeAudioLtvMap & other)576 void LeAudioLtvMap::RemoveAllTypes(const LeAudioLtvMap& other) {
577 for (auto const& [key, _] : other.values) {
578 Remove(key);
579 }
580 }
581
GetIntersection(const LeAudioLtvMap & other) const582 LeAudioLtvMap LeAudioLtvMap::GetIntersection(const LeAudioLtvMap& other) const {
583 LeAudioLtvMap result;
584 for (auto const& [key, value] : values) {
585 auto entry = other.Find(key);
586 if (entry->size() != value.size()) continue;
587 if (memcmp(entry->data(), value.data(), value.size()) == 0) {
588 result.Add(key, value);
589 }
590 }
591 return result;
592 }
593
594 } // namespace types
595
AppendMetadataLtvEntryForCcidList(std::vector<uint8_t> & metadata,const std::vector<uint8_t> & ccid_list)596 void AppendMetadataLtvEntryForCcidList(std::vector<uint8_t>& metadata,
597 const std::vector<uint8_t>& ccid_list) {
598 if (ccid_list.size() == 0) {
599 log::warn("Empty CCID list.");
600 return;
601 }
602
603 metadata.push_back(
604 static_cast<uint8_t>(types::kLeAudioMetadataTypeLen + ccid_list.size()));
605 metadata.push_back(static_cast<uint8_t>(types::kLeAudioMetadataTypeCcidList));
606
607 metadata.insert(metadata.end(), ccid_list.begin(), ccid_list.end());
608 }
609
AppendMetadataLtvEntryForStreamingContext(std::vector<uint8_t> & metadata,types::AudioContexts context_type)610 void AppendMetadataLtvEntryForStreamingContext(
611 std::vector<uint8_t>& metadata, types::AudioContexts context_type) {
612 std::vector<uint8_t> streaming_context_ltv_entry;
613
614 streaming_context_ltv_entry.resize(
615 types::kLeAudioMetadataTypeLen + types::kLeAudioMetadataLenLen +
616 types::kLeAudioMetadataStreamingAudioContextLen);
617 uint8_t* streaming_context_ltv_entry_buf = streaming_context_ltv_entry.data();
618
619 UINT8_TO_STREAM(streaming_context_ltv_entry_buf,
620 types::kLeAudioMetadataTypeLen +
621 types::kLeAudioMetadataStreamingAudioContextLen);
622 UINT8_TO_STREAM(streaming_context_ltv_entry_buf,
623 types::kLeAudioMetadataTypeStreamingAudioContext);
624 UINT16_TO_STREAM(streaming_context_ltv_entry_buf, context_type.value());
625
626 metadata.insert(metadata.end(), streaming_context_ltv_entry.begin(),
627 streaming_context_ltv_entry.end());
628 }
629
GetMaxCodecFramesPerSduFromPac(const acs_ac_record * pac)630 uint8_t GetMaxCodecFramesPerSduFromPac(const acs_ac_record* pac) {
631 if (utils::IsCodecUsingLtvFormat(pac->codec_id)) {
632 auto tlv_ent = pac->codec_spec_caps.Find(
633 codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu);
634
635 if (tlv_ent) return VEC_UINT8_TO_UINT8(tlv_ent.value());
636 }
637
638 return 1;
639 }
640
641 namespace types {
operator <<(std::ostream & os,const CisState & state)642 std::ostream& operator<<(std::ostream& os, const CisState& state) {
643 static const char* char_value_[5] = {"IDLE", "ASSIGNED", "CONNECTING",
644 "CONNECTED", "DISCONNECTING"};
645
646 os << char_value_[static_cast<uint8_t>(state)] << " ("
647 << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
648 << ")";
649 return os;
650 }
operator <<(std::ostream & os,const DataPathState & state)651 std::ostream& operator<<(std::ostream& os, const DataPathState& state) {
652 static const char* char_value_[4] = {"IDLE", "CONFIGURING", "CONFIGURED",
653 "REMOVING"};
654
655 os << char_value_[static_cast<uint8_t>(state)] << " ("
656 << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
657 << ")";
658 return os;
659 }
operator <<(std::ostream & os,const types::CigState & state)660 std::ostream& operator<<(std::ostream& os, const types::CigState& state) {
661 static const char* char_value_[5] = {"NONE", "CREATING", "CREATED",
662 "REMOVING", "RECOVERING"};
663
664 os << char_value_[static_cast<uint8_t>(state)] << " ("
665 << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
666 << ")";
667 return os;
668 }
operator <<(std::ostream & os,const types::AseState & state)669 std::ostream& operator<<(std::ostream& os, const types::AseState& state) {
670 static const char* char_value_[7] = {
671 "IDLE", "CODEC_CONFIGURED", "QOS_CONFIGURED", "ENABLING",
672 "STREAMING", "DISABLING", "RELEASING",
673 };
674
675 os << char_value_[static_cast<uint8_t>(state)] << " ("
676 << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
677 << ")";
678 return os;
679 }
680
operator <<(std::ostream & os,const LeAudioCodecId & codec_id)681 std::ostream& operator<<(std::ostream& os, const LeAudioCodecId& codec_id) {
682 os << "LeAudioCodecId{CodingFormat: " << loghex(codec_id.coding_format)
683 << ", CompanyId: " << loghex(codec_id.vendor_company_id)
684 << ", CodecId: " << loghex(codec_id.vendor_codec_id) << "}";
685 return os;
686 }
687
operator <<(std::ostream & os,const types::LeAudioCoreCodecConfig & config)688 std::ostream& operator<<(std::ostream& os,
689 const types::LeAudioCoreCodecConfig& config) {
690 os << "LeAudioCoreCodecConfig{SamplFreq: "
691 << loghex(*config.sampling_frequency)
692 << ", FrameDur: " << loghex(*config.frame_duration)
693 << ", OctetsPerFrame: " << int(*config.octets_per_codec_frame)
694 << ", CodecFramesBlocksPerSDU: "
695 << int(*config.codec_frames_blocks_per_sdu)
696 << ", AudioChanLoc: " << loghex(*config.audio_channel_allocation) << "}";
697 return os;
698 }
699
contextTypeToStr(const LeAudioContextType & context)700 std::string contextTypeToStr(const LeAudioContextType& context) {
701 switch (context) {
702 case LeAudioContextType::UNINITIALIZED:
703 return "UNINITIALIZED";
704 case LeAudioContextType::UNSPECIFIED:
705 return "UNSPECIFIED";
706 case LeAudioContextType::CONVERSATIONAL:
707 return "CONVERSATIONAL";
708 case LeAudioContextType::MEDIA:
709 return "MEDIA";
710 case LeAudioContextType::GAME:
711 return "GAME";
712 case LeAudioContextType::INSTRUCTIONAL:
713 return "INSTRUCTIONAL";
714 case LeAudioContextType::VOICEASSISTANTS:
715 return "VOICEASSISTANTS";
716 case LeAudioContextType::LIVE:
717 return "LIVE";
718 case LeAudioContextType::SOUNDEFFECTS:
719 return "SOUNDEFFECTS";
720 case LeAudioContextType::NOTIFICATIONS:
721 return "NOTIFICATIONS";
722 case LeAudioContextType::RINGTONE:
723 return "RINGTONE";
724 case LeAudioContextType::ALERTS:
725 return "ALERTS";
726 case LeAudioContextType::EMERGENCYALARM:
727 return "EMERGENCYALARM";
728 default:
729 return "UNKNOWN";
730 }
731 }
732
operator <<(std::ostream & os,const LeAudioContextType & context)733 std::ostream& operator<<(std::ostream& os, const LeAudioContextType& context) {
734 os << contextTypeToStr(context);
735 return os;
736 }
737
operator |(std::underlying_type<LeAudioContextType>::type lhs,const LeAudioContextType rhs)738 AudioContexts operator|(std::underlying_type<LeAudioContextType>::type lhs,
739 const LeAudioContextType rhs) {
740 using T = std::underlying_type<LeAudioContextType>::type;
741 return AudioContexts(lhs | static_cast<T>(rhs));
742 }
743
operator |=(AudioContexts & lhs,AudioContexts const & rhs)744 AudioContexts& operator|=(AudioContexts& lhs, AudioContexts const& rhs) {
745 lhs = AudioContexts(lhs.value() | rhs.value());
746 return lhs;
747 }
748
operator &=(AudioContexts & lhs,AudioContexts const & rhs)749 AudioContexts& operator&=(AudioContexts& lhs, AudioContexts const& rhs) {
750 lhs = AudioContexts(lhs.value() & rhs.value());
751 return lhs;
752 }
753
ToHexString(const LeAudioContextType & value)754 std::string ToHexString(const LeAudioContextType& value) {
755 using T = std::underlying_type<LeAudioContextType>::type;
756 return bluetooth::common::ToHexString(static_cast<T>(value));
757 }
758
to_string() const759 std::string AudioContexts::to_string() const {
760 std::stringstream s;
761 for (auto ctx : bluetooth::le_audio::types::kLeAudioContextAllTypesArray) {
762 if (test(ctx)) {
763 if (s.tellp() != 0) s << " | ";
764 s << ctx;
765 }
766 }
767 s << " (" << bluetooth::common::ToHexString(mValue) << ")";
768 return s.str();
769 }
770
operator <<(std::ostream & os,const AudioContexts & contexts)771 std::ostream& operator<<(std::ostream& os, const AudioContexts& contexts) {
772 os << contexts.to_string();
773 return os;
774 }
775
776 template <typename T>
get(uint8_t direction) const777 const T& BidirectionalPair<T>::get(uint8_t direction) const {
778 log::assert_that(direction < types::kLeAudioDirectionBoth,
779 "Unsupported complex direction. Consider using "
780 "get_bidirectional<>() instead.");
781 return (direction == types::kLeAudioDirectionSink) ? sink : source;
782 }
783
784 template <typename T>
get(uint8_t direction)785 T& BidirectionalPair<T>::get(uint8_t direction) {
786 log::assert_that(direction < types::kLeAudioDirectionBoth,
787 "Unsupported complex direction. Reference to a single "
788 "complex direction value is not supported.");
789 return (direction == types::kLeAudioDirectionSink) ? sink : source;
790 }
791
792 /* Bidirectional getter trait for AudioContexts bidirectional pair */
793 template <>
get_bidirectional(BidirectionalPair<AudioContexts> p)794 AudioContexts get_bidirectional(BidirectionalPair<AudioContexts> p) {
795 return p.sink | p.source;
796 }
797
798 template <>
get_bidirectional(BidirectionalPair<std::vector<uint8_t>> bidir)799 std::vector<uint8_t> get_bidirectional(
800 BidirectionalPair<std::vector<uint8_t>> bidir) {
801 std::vector<uint8_t> res = bidir.sink;
802 res.insert(std::end(res), std::begin(bidir.source), std::end(bidir.source));
803 return res;
804 }
805
806 template <>
get_bidirectional(BidirectionalPair<AudioLocations> bidir)807 AudioLocations get_bidirectional(BidirectionalPair<AudioLocations> bidir) {
808 return bidir.sink | bidir.source;
809 }
810
operator <<(std::ostream & os,const le_audio::types::IsoDataPathConfiguration & config)811 std::ostream& operator<<(
812 std::ostream& os, const le_audio::types::IsoDataPathConfiguration& config) {
813 os << "IsoDataPathCfg{codecId: " << config.codecId
814 << ", isTransparent: " << config.isTransparent
815 << ", controllerDelayUs: " << config.controllerDelayUs
816 << ", configuration.size: " << config.configuration.size() << "}";
817 return os;
818 }
819
operator <<(std::ostream & os,const le_audio::types::DataPathConfiguration & config)820 std::ostream& operator<<(std::ostream& os,
821 const le_audio::types::DataPathConfiguration& config) {
822 os << "DataPathCfg{datapathId: " << +config.dataPathId
823 << ", dataPathCfg.size: " << +config.dataPathConfig.size()
824 << ", isoDataPathCfg: " << config.isoDataPathConfig << "}";
825 return os;
826 }
827
operator <<(std::ostream & os,const LeAudioMetadata & config)828 std::ostream& operator<<(std::ostream& os, const LeAudioMetadata& config) {
829 os << "LeAudioMetadata{";
830 if (config.preferred_audio_context) {
831 os << "preferred_audio_context: ";
832 os << AudioContexts(config.preferred_audio_context.value());
833 }
834 if (config.streaming_audio_context) {
835 os << ", streaming_audio_context: ";
836 os << AudioContexts(config.streaming_audio_context.value());
837 }
838 if (config.program_info) {
839 os << ", program_info: ";
840 os << config.program_info.value();
841 }
842 if (config.language) {
843 os << ", language: ";
844 os << config.language.value();
845 }
846 if (config.ccid_list) {
847 os << ", ccid_list: ";
848 os << base::HexEncode(config.ccid_list.value().data(),
849 config.ccid_list.value().size());
850 }
851 if (config.parental_rating) {
852 os << ", parental_rating: ";
853 os << (int)config.parental_rating.value();
854 }
855 if (config.program_info_uri) {
856 os << ", program_info_uri: ";
857 os << config.program_info_uri.value();
858 }
859 if (config.extended_metadata) {
860 os << ", extended_metadata: ";
861 os << base::HexEncode(config.extended_metadata.value().data(),
862 config.extended_metadata.value().size());
863 }
864 if (config.vendor_specific) {
865 os << ", vendor_specific: ";
866 os << base::HexEncode(config.vendor_specific.value().data(),
867 config.vendor_specific.value().size());
868 }
869 if (config.audio_active_state) {
870 os << ", audio_active_state: ";
871 os << config.audio_active_state.value();
872 }
873 if (config.broadcast_audio_immediate_rendering) {
874 os << ", broadcast_audio_immediate_rendering: ";
875 os << config.broadcast_audio_immediate_rendering.value();
876 }
877 os << "}";
878 return os;
879 }
880
881 template struct BidirectionalPair<AudioContexts>;
882 template struct BidirectionalPair<AudioLocations>;
883 template struct BidirectionalPair<CisType>;
884 template struct BidirectionalPair<LeAudioConfigurationStrategy>;
885 template struct BidirectionalPair<ase*>;
886 template struct BidirectionalPair<std::string>;
887 template struct BidirectionalPair<std::vector<uint8_t>>;
888 template struct BidirectionalPair<stream_configuration>;
889 template struct BidirectionalPair<stream_parameters>;
890 template struct BidirectionalPair<uint16_t>;
891 template struct BidirectionalPair<uint8_t>;
892 template struct BidirectionalPair<bool>;
893 template struct BidirectionalPair<int>;
894 template struct BidirectionalPair<
895 std::vector<set_configurations::AseConfiguration>>;
896 template struct BidirectionalPair<set_configurations::QosConfigSetting>;
897
898 } // namespace types
899 } // namespace bluetooth::le_audio
900