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