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 namespace bluetooth::le_audio {
52 using types::acs_ac_record;
53 using types::LeAudioContextType;
54
55 namespace types {
56 using types::CodecConfigSetting;
57 using types::kLeAudioCodingFormatLC3;
58 using types::LeAudioCoreCodecConfig;
59
GetOctetsPerFrame() const60 uint16_t CodecConfigSetting::GetOctetsPerFrame() const {
61 switch (id.coding_format) {
62 case kLeAudioCodingFormatLC3:
63 return params.GetAsCoreCodecConfig().GetOctetsPerFrame();
64 default:
65 log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
66 return 0;
67 }
68 }
69
GetSamplingFrequencyHz() const70 uint32_t CodecConfigSetting::GetSamplingFrequencyHz() const {
71 // We also mandate the sampling frequency parameter for vendor spec. codecs
72 return params.GetAsCoreCodecConfig().GetSamplingFrequencyHz();
73 }
74
GetDataIntervalUs() const75 uint32_t CodecConfigSetting::GetDataIntervalUs() const {
76 switch (id.coding_format) {
77 case kLeAudioCodingFormatLC3:
78 return params.GetAsCoreCodecConfig().GetFrameDurationUs() *
79 params.GetAsCoreCodecConfig().codec_frames_blocks_per_sdu.value_or(1);
80 default:
81 log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
82 return 0;
83 }
84 }
85
GetBitsPerSample() const86 uint8_t CodecConfigSetting::GetBitsPerSample() const {
87 switch (id.coding_format) {
88 case kLeAudioCodingFormatLC3:
89 /* XXX LC3 supports 16, 24, 32 */
90 return 16;
91 default:
92 log::warn(", invalid codec id: 0x{:02x}", id.coding_format);
93 return 0;
94 }
95 }
96
operator <<(std::ostream & os,const QosConfigSetting & config)97 std::ostream& operator<<(std::ostream& os, const QosConfigSetting& config) {
98 os << "QosConfigSetting{";
99 os << "targetLatency: " << (int)config.target_latency;
100 os << ", retransmissionNum: " << (int)config.retransmission_number;
101 os << ", maxTransportLatency: " << (int)config.max_transport_latency;
102 os << ", sduIntervalUs: " << (int)config.sduIntervalUs;
103 os << ", maxSdu: " << (int)config.maxSdu;
104 os << "}";
105 return os;
106 }
107
operator <<(std::ostream & os,const AseConfiguration & config)108 std::ostream& operator<<(std::ostream& os, const AseConfiguration& config) {
109 os << "AseConfiguration{";
110 os << "dataPath: " << config.data_path_configuration;
111 os << ", codec: " << config.codec;
112 os << ", qos: " << config.qos;
113 os << "}";
114 return os;
115 }
116
operator <<(std::ostream & os,const AudioSetConfiguration & config)117 std::ostream& operator<<(std::ostream& os, const AudioSetConfiguration& config) {
118 os << "AudioSetConfiguration{";
119 os << "name: " << config.name;
120 os << ", packing: " << (int)config.packing;
121 os << ", sinkConfs: [";
122 for (auto const& conf : config.confs.sink) {
123 os << conf;
124 os << ", ";
125 }
126 os << "], sourceConfs: [";
127 for (auto const& conf : config.confs.source) {
128 os << conf;
129 os << ", ";
130 }
131 os << "]}";
132 return os;
133 }
134
operator <<(std::ostream & os,const CodecConfigSetting & config)135 std::ostream& operator<<(std::ostream& os, const CodecConfigSetting& config) {
136 os << "CodecConfigSetting{";
137 os << ", id: " << config.id;
138 os << ", codecSpecParams: " << config.params.GetAsCoreCodecConfig();
139 os << ", bitsPerSample: " << (int)config.GetBitsPerSample();
140 os << ", channelCountPerIsoStream: " << (int)config.GetChannelCountPerIsoStream();
141 if (!config.vendor_params.empty()) {
142 os << ", vendorParams: "
143 << base::HexEncode(config.vendor_params.data(), config.vendor_params.size());
144 }
145 os << "}";
146 return os;
147 }
148
149 /* Helper map for matching various frequency notations */
150 const std::map<uint8_t, uint32_t> LeAudioCoreCodecConfig::sampling_freq_map = {
151 {codec_spec_conf::kLeAudioSamplingFreq8000Hz, LeAudioCodecConfiguration::kSampleRate8000},
152 {codec_spec_conf::kLeAudioSamplingFreq16000Hz, LeAudioCodecConfiguration::kSampleRate16000},
153 {codec_spec_conf::kLeAudioSamplingFreq24000Hz, LeAudioCodecConfiguration::kSampleRate24000},
154 {codec_spec_conf::kLeAudioSamplingFreq32000Hz, LeAudioCodecConfiguration::kSampleRate32000},
155 {codec_spec_conf::kLeAudioSamplingFreq44100Hz, LeAudioCodecConfiguration::kSampleRate44100},
156 {codec_spec_conf::kLeAudioSamplingFreq48000Hz,
157 LeAudioCodecConfiguration::kSampleRate48000}};
158
159 /* Helper map for matching various frequency notations */
160 const std::map<uint32_t, uint8_t> LeAudioCoreCodecConfig::sample_rate_map = {
161 {LeAudioCodecConfiguration::kSampleRate8000, codec_spec_conf::kLeAudioSamplingFreq8000Hz},
162 {LeAudioCodecConfiguration::kSampleRate16000, codec_spec_conf::kLeAudioSamplingFreq16000Hz},
163 {LeAudioCodecConfiguration::kSampleRate24000, codec_spec_conf::kLeAudioSamplingFreq24000Hz},
164 {LeAudioCodecConfiguration::kSampleRate32000, codec_spec_conf::kLeAudioSamplingFreq32000Hz},
165 {LeAudioCodecConfiguration::kSampleRate44100, codec_spec_conf::kLeAudioSamplingFreq44100Hz},
166 {LeAudioCodecConfiguration::kSampleRate48000, codec_spec_conf::kLeAudioSamplingFreq48000Hz},
167 };
168
169 /* Helper map for matching various frame durations notations */
170 const std::map<uint8_t, uint32_t> LeAudioCoreCodecConfig::frame_duration_map = {
171 {codec_spec_conf::kLeAudioCodecFrameDur7500us, LeAudioCodecConfiguration::kInterval7500Us},
172 {codec_spec_conf::kLeAudioCodecFrameDur10000us,
173 LeAudioCodecConfiguration::kInterval10000Us}};
174
175 /* Helper map for matching various frame durations notations */
176 const std::map<uint32_t, uint8_t> LeAudioCoreCodecConfig::data_interval_map = {
177 {LeAudioCodecConfiguration::kInterval7500Us, codec_spec_conf::kLeAudioCodecFrameDur7500us},
178 {LeAudioCodecConfiguration::kInterval10000Us,
179 codec_spec_conf::kLeAudioCodecFrameDur10000us},
180 };
181
CapabilityTypeToStr(const uint8_t & type)182 static std::string CapabilityTypeToStr(const uint8_t& type) {
183 switch (type) {
184 case codec_spec_caps::kLeAudioLtvTypeSupportedSamplingFrequencies:
185 return "Supported Sampling Frequencies";
186 case codec_spec_caps::kLeAudioLtvTypeSupportedFrameDurations:
187 return "Supported Frame Durations";
188 case codec_spec_caps::kLeAudioLtvTypeSupportedAudioChannelCounts:
189 return "Supported Audio Channel Count";
190 case codec_spec_caps::kLeAudioLtvTypeSupportedOctetsPerCodecFrame:
191 return "Supported Octets Per Codec Frame";
192 case codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu:
193 return "Supported Max Codec Frames Per SDU";
194 default:
195 return "Unknown";
196 }
197 }
198
CapabilityValueToStr(const uint8_t & type,const std::vector<uint8_t> & value)199 static std::string CapabilityValueToStr(const uint8_t& type, const std::vector<uint8_t>& value) {
200 std::string string = "";
201
202 switch (type) {
203 case codec_spec_conf::kLeAudioLtvTypeSamplingFreq: {
204 if (value.size() != 2) {
205 return "Invalid size";
206 }
207
208 uint16_t u16_val = VEC_UINT8_TO_UINT16(value);
209
210 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq8000Hz) {
211 string += "8";
212 }
213 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq11025Hz) {
214 string += std::string(string.empty() ? "" : "|") + "11.025";
215 }
216 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq16000Hz) {
217 string += std::string(string.empty() ? "" : "|") + "16";
218 }
219 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq22050Hz) {
220 string += std::string(string.empty() ? "" : "|") + "22.050";
221 }
222 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq24000Hz) {
223 string += std::string(string.empty() ? "" : "|") + "24";
224 }
225 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq32000Hz) {
226 string += std::string(string.empty() ? "" : "|") + "32";
227 }
228 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq44100Hz) {
229 string += std::string(string.empty() ? "" : "|") + "44.1";
230 }
231 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq48000Hz) {
232 string += std::string(string.empty() ? "" : "|") + "48";
233 }
234 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq88200Hz) {
235 string += std::string(string.empty() ? "" : "|") + "88.2";
236 }
237 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq96000Hz) {
238 string += std::string(string.empty() ? "" : "|") + "96";
239 }
240 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq176400Hz) {
241 string += std::string(string.empty() ? "" : "|") + "176.4";
242 }
243 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq192000Hz) {
244 string += std::string(string.empty() ? "" : "|") + "192";
245 }
246 if (u16_val & codec_spec_caps::kLeAudioSamplingFreq384000Hz) {
247 string += std::string(string.empty() ? "" : "|") + "384";
248 }
249
250 return string += " [kHz]\n";
251 }
252 case codec_spec_conf::kLeAudioLtvTypeFrameDuration: {
253 if (value.size() != 1) {
254 return "Invalid size";
255 }
256
257 uint8_t u8_val = VEC_UINT8_TO_UINT8(value);
258
259 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDur7500us) {
260 string += "7.5";
261 }
262 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDur10000us) {
263 string += std::string(string.empty() ? "" : "|") + "10";
264 }
265 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDurPrefer7500us) {
266 string += std::string(string.empty() ? "" : "|") + "7.5 preferred";
267 }
268 if (u8_val & codec_spec_caps::kLeAudioCodecFrameDurPrefer10000us) {
269 string += std::string(string.empty() ? "" : "|") + "10 preferred";
270 }
271
272 return string += " [ms]\n";
273 }
274 case codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation: {
275 if (value.size() != 1) {
276 return "Invalid size";
277 }
278
279 uint8_t u8_val = VEC_UINT8_TO_UINT8(value);
280
281 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountNone) {
282 string += "0";
283 }
284 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSingleChannel) {
285 string += std::string(string.empty() ? "" : "|") + "1";
286 }
287 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountTwoChannel) {
288 string += std::string(string.empty() ? "" : "|") + "2";
289 }
290 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountThreeChannel) {
291 string += std::string(string.empty() ? "" : "|") + "3";
292 }
293 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountFourChannel) {
294 string += std::string(string.empty() ? "" : "|") + "4";
295 }
296 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountFiveChannel) {
297 string += std::string(string.empty() ? "" : "|") + "5";
298 }
299 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSixChannel) {
300 string += std::string(string.empty() ? "" : "|") + "6";
301 }
302 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSevenChannel) {
303 string += std::string(string.empty() ? "" : "|") + "7";
304 }
305 if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountEightChannel) {
306 string += std::string(string.empty() ? "" : "|") + "8";
307 }
308
309 return string += " channel/s\n";
310 }
311 case codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame: {
312 if (value.size() != 4) {
313 return "Invalid size";
314 }
315
316 uint16_t u16_min_number_of_octets = VEC_UINT8_TO_UINT16(value);
317 uint16_t u16_max_number_of_octets =
318 OFF_VEC_UINT8_TO_UINT16(value, sizeof(u16_min_number_of_octets));
319
320 string += "Minimum: " + std::to_string(u16_min_number_of_octets);
321 string += ", Maximum: " + std::to_string(u16_max_number_of_octets) + "\n";
322
323 return string;
324 }
325 case codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu: {
326 if (value.size() != 1) {
327 return "Invalid size";
328 }
329
330 uint8_t u8_val = VEC_UINT8_TO_UINT8(value);
331
332 string += std::to_string(u8_val) + " frame/s\n";
333
334 return string;
335 }
336 default:
337 return base::HexEncode(value.data(), value.size()) + "\n";
338 }
339 }
340
CodecCapabilitiesLtvFormat(const uint8_t & type,const std::vector<uint8_t> & value)341 std::string CodecCapabilitiesLtvFormat(const uint8_t& type, const std::vector<uint8_t>& value) {
342 std::string string = "";
343
344 string += CapabilityTypeToStr(type) + ": ";
345 string += CapabilityValueToStr(type, value);
346
347 return string;
348 }
349
Find(uint8_t type) const350 std::optional<std::vector<uint8_t>> LeAudioLtvMap::Find(uint8_t type) const {
351 auto iter = std::find_if(values.cbegin(), values.cend(),
352 [type](const auto& value) { return value.first == type; });
353
354 if (iter == values.cend()) {
355 return std::nullopt;
356 }
357
358 return iter->second;
359 }
360
RawPacket(uint8_t * p_buf) const361 uint8_t* LeAudioLtvMap::RawPacket(uint8_t* p_buf) const {
362 for (auto const& value : values) {
363 UINT8_TO_STREAM(p_buf, value.second.size() + 1);
364 UINT8_TO_STREAM(p_buf, value.first);
365 ARRAY_TO_STREAM(p_buf, value.second.data(), static_cast<int>(value.second.size()));
366 }
367
368 return p_buf;
369 }
370
RawPacket() const371 std::vector<uint8_t> LeAudioLtvMap::RawPacket() const {
372 std::vector<uint8_t> data(RawPacketSize());
373 RawPacket(data.data());
374 return data;
375 }
376
Append(const LeAudioLtvMap & other)377 void LeAudioLtvMap::Append(const LeAudioLtvMap& other) {
378 /* This will override values for the already existing keys */
379 for (auto& el : other.values) {
380 values[el.first] = el.second;
381 }
382
383 invalidate();
384 }
385
Parse(const uint8_t * p_value,uint8_t len,bool & success)386 LeAudioLtvMap LeAudioLtvMap::Parse(const uint8_t* p_value, uint8_t len, bool& success) {
387 LeAudioLtvMap ltv_map;
388 success = ltv_map.Parse(p_value, len);
389 if (!success) {
390 log::error("Error parsing LTV map");
391 }
392 return ltv_map;
393 }
394
Parse(const uint8_t * p_value,uint8_t len)395 bool LeAudioLtvMap::Parse(const uint8_t* p_value, uint8_t len) {
396 if (len > 0) {
397 const auto p_value_end = p_value + len;
398
399 while ((p_value_end - p_value) > 0) {
400 uint8_t ltv_len;
401 STREAM_TO_UINT8(ltv_len, p_value);
402
403 // Unusual, but possible case
404 if (ltv_len == 0) {
405 continue;
406 }
407
408 if (p_value_end < (p_value + ltv_len)) {
409 log::error("Invalid ltv_len: {}", static_cast<int>(ltv_len));
410 invalidate();
411 return false;
412 }
413
414 uint8_t ltv_type;
415 STREAM_TO_UINT8(ltv_type, p_value);
416 ltv_len -= sizeof(ltv_type);
417
418 const auto p_temp = p_value;
419 p_value += ltv_len;
420
421 std::vector<uint8_t> ltv_value(p_temp, p_value);
422 values.emplace(ltv_type, std::move(ltv_value));
423 }
424 }
425 invalidate();
426
427 return true;
428 }
429
RawPacketSize() const430 size_t LeAudioLtvMap::RawPacketSize() const {
431 size_t bytes = 0;
432
433 for (auto const& value : values) {
434 bytes += (/* ltv_len + ltv_type */ 2 + value.second.size());
435 }
436
437 return bytes;
438 }
439
ToString(const std::string & indent_string,std::string (* format)(const uint8_t &,const std::vector<uint8_t> &)) const440 std::string LeAudioLtvMap::ToString(const std::string& indent_string,
441 std::string (*format)(const uint8_t&,
442 const std::vector<uint8_t>&)) const {
443 std::string debug_str;
444
445 for (const auto& value : values) {
446 std::stringstream sstream;
447
448 if (format == nullptr) {
449 sstream << indent_string + "type: " << std::to_string(value.first)
450 << "\tlen: " << std::to_string(value.second.size())
451 << "\tdata: " << base::HexEncode(value.second.data(), value.second.size()) + "\n";
452 } else {
453 sstream << indent_string + format(value.first, value.second);
454 }
455
456 debug_str += sstream.str();
457 }
458
459 return debug_str;
460 }
461
GetAsCoreCodecConfig() const462 const struct LeAudioCoreCodecConfig& LeAudioLtvMap::GetAsCoreCodecConfig() const {
463 log::assert_that(!core_capabilities, "LTVs were already parsed for capabilities!");
464 log::assert_that(!metadata, "LTVs were already parsed for metadata!");
465
466 if (!core_config) {
467 core_config = LtvMapToCoreCodecConfig(*this);
468 }
469 return *core_config;
470 }
471
GetAsCoreCodecCapabilities() const472 const struct LeAudioCoreCodecCapabilities& LeAudioLtvMap::GetAsCoreCodecCapabilities() const {
473 log::assert_that(!core_config, "LTVs were already parsed for configurations!");
474 log::assert_that(!metadata, "LTVs were already parsed for metadata!");
475
476 if (!core_capabilities) {
477 core_capabilities = LtvMapToCoreCodecCapabilities(*this);
478 }
479 return *core_capabilities;
480 }
481
GetAsLeAudioMetadata() const482 const struct LeAudioMetadata& LeAudioLtvMap::GetAsLeAudioMetadata() const {
483 log::assert_that(!core_config, "LTVs were already parsed for configurations!");
484 log::assert_that(!core_capabilities, "LTVs were already parsed for capabilities!");
485
486 if (!metadata) {
487 metadata = LtvMapToMetadata(*this);
488 }
489 return *metadata;
490 }
491
RemoveAllTypes(const LeAudioLtvMap & other)492 void LeAudioLtvMap::RemoveAllTypes(const LeAudioLtvMap& other) {
493 for (auto const& [key, _] : other.values) {
494 Remove(key);
495 }
496 }
497
GetIntersection(const LeAudioLtvMap & other) const498 LeAudioLtvMap LeAudioLtvMap::GetIntersection(const LeAudioLtvMap& other) const {
499 LeAudioLtvMap result;
500 for (auto const& [key, value] : values) {
501 auto entry = other.Find(key);
502 if (entry->size() != value.size()) {
503 continue;
504 }
505 if (memcmp(entry->data(), value.data(), value.size()) == 0) {
506 result.Add(key, value);
507 }
508 }
509 return result;
510 }
511
512 } // namespace types
513
AppendMetadataLtvEntryForCcidList(std::vector<uint8_t> & metadata,const std::vector<uint8_t> & ccid_list)514 void AppendMetadataLtvEntryForCcidList(std::vector<uint8_t>& metadata,
515 const std::vector<uint8_t>& ccid_list) {
516 if (ccid_list.size() == 0) {
517 log::warn("Empty CCID list.");
518 return;
519 }
520
521 metadata.push_back(static_cast<uint8_t>(types::kLeAudioMetadataTypeLen + ccid_list.size()));
522 metadata.push_back(static_cast<uint8_t>(types::kLeAudioMetadataTypeCcidList));
523
524 metadata.insert(metadata.end(), ccid_list.begin(), ccid_list.end());
525 }
526
AppendMetadataLtvEntryForStreamingContext(std::vector<uint8_t> & metadata,types::AudioContexts context_type)527 void AppendMetadataLtvEntryForStreamingContext(std::vector<uint8_t>& metadata,
528 types::AudioContexts context_type) {
529 std::vector<uint8_t> streaming_context_ltv_entry;
530
531 streaming_context_ltv_entry.resize(types::kLeAudioMetadataTypeLen +
532 types::kLeAudioMetadataLenLen +
533 types::kLeAudioMetadataStreamingAudioContextLen);
534 uint8_t* streaming_context_ltv_entry_buf = streaming_context_ltv_entry.data();
535
536 UINT8_TO_STREAM(streaming_context_ltv_entry_buf,
537 types::kLeAudioMetadataTypeLen + types::kLeAudioMetadataStreamingAudioContextLen);
538 UINT8_TO_STREAM(streaming_context_ltv_entry_buf,
539 types::kLeAudioMetadataTypeStreamingAudioContext);
540 UINT16_TO_STREAM(streaming_context_ltv_entry_buf, context_type.value());
541
542 metadata.insert(metadata.end(), streaming_context_ltv_entry.begin(),
543 streaming_context_ltv_entry.end());
544 }
545
GetMaxCodecFramesPerSduFromPac(const acs_ac_record * pac)546 uint8_t GetMaxCodecFramesPerSduFromPac(const acs_ac_record* pac) {
547 if (utils::IsCodecUsingLtvFormat(pac->codec_id)) {
548 auto tlv_ent = pac->codec_spec_caps.Find(
549 codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu);
550
551 if (tlv_ent) {
552 return VEC_UINT8_TO_UINT8(tlv_ent.value());
553 }
554 }
555
556 return 1;
557 }
558
559 namespace types {
operator <<(std::ostream & os,const CisState & state)560 std::ostream& operator<<(std::ostream& os, const CisState& state) {
561 static const char* char_value_[5] = {"IDLE", "ASSIGNED", "CONNECTING", "CONNECTED",
562 "DISCONNECTING"};
563
564 os << char_value_[static_cast<uint8_t>(state)] << " (" << "0x" << std::setfill('0')
565 << std::setw(2) << static_cast<int>(state) << ")";
566 return os;
567 }
operator <<(std::ostream & os,const DataPathState & state)568 std::ostream& operator<<(std::ostream& os, const DataPathState& state) {
569 static const char* char_value_[4] = {"IDLE", "CONFIGURING", "CONFIGURED", "REMOVING"};
570
571 os << char_value_[static_cast<uint8_t>(state)] << " (" << "0x" << std::setfill('0')
572 << std::setw(2) << static_cast<int>(state) << ")";
573 return os;
574 }
operator <<(std::ostream & os,const types::CigState & state)575 std::ostream& operator<<(std::ostream& os, const types::CigState& state) {
576 static const char* char_value_[5] = {"NONE", "CREATING", "CREATED", "REMOVING", "RECOVERING"};
577
578 os << char_value_[static_cast<uint8_t>(state)] << " (" << "0x" << std::setfill('0')
579 << std::setw(2) << static_cast<int>(state) << ")";
580 return os;
581 }
operator <<(std::ostream & os,const types::AseState & state)582 std::ostream& operator<<(std::ostream& os, const types::AseState& state) {
583 static const char* char_value_[7] = {
584 "IDLE", "CODEC_CONFIGURED", "QOS_CONFIGURED", "ENABLING",
585 "STREAMING", "DISABLING", "RELEASING",
586 };
587
588 os << char_value_[static_cast<uint8_t>(state)] << " (" << "0x" << std::setfill('0')
589 << std::setw(2) << static_cast<int>(state) << ")";
590 return os;
591 }
592
operator <<(std::ostream & os,const LeAudioCodecId & codec_id)593 std::ostream& operator<<(std::ostream& os, const LeAudioCodecId& codec_id) {
594 os << "LeAudioCodecId{CodingFormat: " << loghex(codec_id.coding_format)
595 << ", CompanyId: " << loghex(codec_id.vendor_company_id)
596 << ", CodecId: " << loghex(codec_id.vendor_codec_id) << "}";
597 return os;
598 }
599
operator <<(std::ostream & os,const types::LeAudioCoreCodecConfig & config)600 std::ostream& operator<<(std::ostream& os, const types::LeAudioCoreCodecConfig& config) {
601 os << "LeAudioCoreCodecConfig{SamplFreq: " << loghex(*config.sampling_frequency)
602 << ", FrameDur: " << loghex(*config.frame_duration)
603 << ", OctetsPerFrame: " << int(*config.octets_per_codec_frame)
604 << ", CodecFramesBlocksPerSDU: " << int(*config.codec_frames_blocks_per_sdu)
605 << ", AudioChanLoc: " << loghex(*config.audio_channel_allocation) << "}";
606 return os;
607 }
608
contextTypeToStr(const LeAudioContextType & context)609 std::string contextTypeToStr(const LeAudioContextType& context) {
610 switch (context) {
611 case LeAudioContextType::UNINITIALIZED:
612 return "UNINITIALIZED";
613 case LeAudioContextType::UNSPECIFIED:
614 return "UNSPECIFIED";
615 case LeAudioContextType::CONVERSATIONAL:
616 return "CONVERSATIONAL";
617 case LeAudioContextType::MEDIA:
618 return "MEDIA";
619 case LeAudioContextType::GAME:
620 return "GAME";
621 case LeAudioContextType::INSTRUCTIONAL:
622 return "INSTRUCTIONAL";
623 case LeAudioContextType::VOICEASSISTANTS:
624 return "VOICEASSISTANTS";
625 case LeAudioContextType::LIVE:
626 return "LIVE";
627 case LeAudioContextType::SOUNDEFFECTS:
628 return "SOUNDEFFECTS";
629 case LeAudioContextType::NOTIFICATIONS:
630 return "NOTIFICATIONS";
631 case LeAudioContextType::RINGTONE:
632 return "RINGTONE";
633 case LeAudioContextType::ALERTS:
634 return "ALERTS";
635 case LeAudioContextType::EMERGENCYALARM:
636 return "EMERGENCYALARM";
637 default:
638 return "UNKNOWN";
639 }
640 }
641
operator <<(std::ostream & os,const LeAudioContextType & context)642 std::ostream& operator<<(std::ostream& os, const LeAudioContextType& context) {
643 os << contextTypeToStr(context);
644 return os;
645 }
646
operator |(std::underlying_type<LeAudioContextType>::type lhs,const LeAudioContextType rhs)647 AudioContexts operator|(std::underlying_type<LeAudioContextType>::type lhs,
648 const LeAudioContextType rhs) {
649 using T = std::underlying_type<LeAudioContextType>::type;
650 return AudioContexts(lhs | static_cast<T>(rhs));
651 }
652
operator |=(AudioContexts & lhs,AudioContexts const & rhs)653 AudioContexts& operator|=(AudioContexts& lhs, AudioContexts const& rhs) {
654 lhs = AudioContexts(lhs.value() | rhs.value());
655 return lhs;
656 }
657
operator &=(AudioContexts & lhs,AudioContexts const & rhs)658 AudioContexts& operator&=(AudioContexts& lhs, AudioContexts const& rhs) {
659 lhs = AudioContexts(lhs.value() & rhs.value());
660 return lhs;
661 }
662
ToHexString(const LeAudioContextType & value)663 std::string ToHexString(const LeAudioContextType& value) {
664 using T = std::underlying_type<LeAudioContextType>::type;
665 return bluetooth::common::ToHexString(static_cast<T>(value));
666 }
667
to_string() const668 std::string AudioContexts::to_string() const {
669 std::stringstream s;
670 s << bluetooth::common::ToHexString(mValue);
671 if (mValue != 0) {
672 s << " [";
673 auto initial_pos = s.tellp();
674 for (auto ctx : bluetooth::le_audio::types::kLeAudioContextAllTypesArray) {
675 if (test(ctx)) {
676 if (s.tellp() != initial_pos) {
677 s << " | ";
678 }
679 s << ctx;
680 }
681 }
682 s << "]";
683 }
684 return s.str();
685 }
686
operator <<(std::ostream & os,const AudioContexts & contexts)687 std::ostream& operator<<(std::ostream& os, const AudioContexts& contexts) {
688 os << contexts.to_string();
689 return os;
690 }
691
692 /* Bidirectional getter trait for AudioContexts bidirectional pair */
693 template <>
get_bidirectional(BidirectionalPair<AudioContexts> p)694 AudioContexts get_bidirectional(BidirectionalPair<AudioContexts> p) {
695 return p.sink | p.source;
696 }
697
698 template <>
get_bidirectional(BidirectionalPair<std::vector<uint8_t>> bidir)699 std::vector<uint8_t> get_bidirectional(BidirectionalPair<std::vector<uint8_t>> bidir) {
700 std::vector<uint8_t> res = bidir.sink;
701 res.insert(std::end(res), std::begin(bidir.source), std::end(bidir.source));
702 return res;
703 }
704
705 template <>
get_bidirectional(BidirectionalPair<AudioLocations> bidir)706 AudioLocations get_bidirectional(BidirectionalPair<AudioLocations> bidir) {
707 return bidir.sink | bidir.source;
708 }
709
operator <<(std::ostream & os,const le_audio::types::IsoDataPathConfiguration & config)710 std::ostream& operator<<(std::ostream& os,
711 const le_audio::types::IsoDataPathConfiguration& config) {
712 os << "IsoDataPathCfg{codecId: " << config.codecId << ", isTransparent: " << config.isTransparent
713 << ", controllerDelayUs: " << config.controllerDelayUs
714 << ", configuration.size: " << config.configuration.size() << "}";
715 return os;
716 }
717
operator <<(std::ostream & os,const le_audio::types::DataPathConfiguration & config)718 std::ostream& operator<<(std::ostream& os, const le_audio::types::DataPathConfiguration& config) {
719 os << "DataPathCfg{datapathId: " << +config.dataPathId
720 << ", dataPathCfg.size: " << +config.dataPathConfig.size()
721 << ", isoDataPathCfg: " << config.isoDataPathConfig << "}";
722 return os;
723 }
724
operator <<(std::ostream & os,const LeAudioMetadata & config)725 std::ostream& operator<<(std::ostream& os, const LeAudioMetadata& config) {
726 os << "LeAudioMetadata{";
727 if (config.preferred_audio_context) {
728 os << "preferred_audio_context: ";
729 os << AudioContexts(config.preferred_audio_context.value());
730 }
731 if (config.streaming_audio_context) {
732 os << ", streaming_audio_context: ";
733 os << AudioContexts(config.streaming_audio_context.value());
734 }
735 if (config.program_info) {
736 os << ", program_info: ";
737 os << config.program_info.value();
738 }
739 if (config.language) {
740 os << ", language: ";
741 os << config.language.value();
742 }
743 if (config.ccid_list) {
744 os << ", ccid_list: ";
745 os << base::HexEncode(config.ccid_list.value().data(), config.ccid_list.value().size());
746 }
747 if (config.parental_rating) {
748 os << ", parental_rating: ";
749 os << (int)config.parental_rating.value();
750 }
751 if (config.program_info_uri) {
752 os << ", program_info_uri: ";
753 os << config.program_info_uri.value();
754 }
755 if (config.extended_metadata) {
756 os << ", extended_metadata: ";
757 os << base::HexEncode(config.extended_metadata.value().data(),
758 config.extended_metadata.value().size());
759 }
760 if (config.vendor_specific) {
761 os << ", vendor_specific: ";
762 os << base::HexEncode(config.vendor_specific.value().data(),
763 config.vendor_specific.value().size());
764 }
765 if (config.audio_active_state) {
766 os << ", audio_active_state: ";
767 os << config.audio_active_state.value();
768 }
769 if (config.broadcast_audio_immediate_rendering) {
770 os << ", broadcast_audio_immediate_rendering: ";
771 os << config.broadcast_audio_immediate_rendering.value();
772 }
773 os << "}";
774 return os;
775 }
776
777 } // namespace types
778 } // namespace bluetooth::le_audio
779