1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "broadcaster_types.h"
19
20 #include <vector>
21
22 #include "bt_types.h"
23 #include "bta_le_audio_broadcaster_api.h"
24 #include "btm_ble_api_types.h"
25 #include "embdrv/lc3/include/lc3.h"
26 #include "internal_include/stack_config.h"
27 #include "osi/include/properties.h"
28
29 using bluetooth::le_audio::BasicAudioAnnouncementBisConfig;
30 using bluetooth::le_audio::BasicAudioAnnouncementCodecConfig;
31 using bluetooth::le_audio::BasicAudioAnnouncementData;
32 using bluetooth::le_audio::BasicAudioAnnouncementSubgroup;
33 using le_audio::types::LeAudioContextType;
34
35 namespace le_audio {
36 namespace broadcaster {
37
EmitHeader(const BasicAudioAnnouncementData & announcement_data,std::vector<uint8_t> & data)38 static void EmitHeader(const BasicAudioAnnouncementData& announcement_data,
39 std::vector<uint8_t>& data) {
40 size_t old_size = data.size();
41 data.resize(old_size + 3);
42
43 // Set the cursor behind the old data
44 uint8_t* p_value = data.data() + old_size;
45
46 UINT24_TO_STREAM(p_value, announcement_data.presentation_delay);
47 }
48
EmitCodecConfiguration(const BasicAudioAnnouncementCodecConfig & config,std::vector<uint8_t> & data,const BasicAudioAnnouncementCodecConfig * lower_lvl_config)49 static void EmitCodecConfiguration(
50 const BasicAudioAnnouncementCodecConfig& config, std::vector<uint8_t>& data,
51 const BasicAudioAnnouncementCodecConfig* lower_lvl_config) {
52 size_t old_size = data.size();
53
54 // Add 5 for full, or 1 for short Codec ID
55 uint8_t codec_config_length = 5;
56
57 auto ltv = types::LeAudioLtvMap(config.codec_specific_params);
58 auto ltv_raw_sz = ltv.RawPacketSize();
59
60 // Add 1 for the codec spec. config length + config spec. data itself
61 codec_config_length += 1 + ltv_raw_sz;
62
63 // Resize and set the cursor behind the old data
64 data.resize(old_size + codec_config_length);
65 uint8_t* p_value = data.data() + old_size;
66
67 // Codec ID
68 UINT8_TO_STREAM(p_value, config.codec_id);
69 UINT16_TO_STREAM(p_value, config.vendor_company_id);
70 UINT16_TO_STREAM(p_value, config.vendor_codec_id);
71
72 // Codec specific config length and data
73 UINT8_TO_STREAM(p_value, ltv_raw_sz);
74 p_value = ltv.RawPacket(p_value);
75 }
76
EmitMetadata(const std::map<uint8_t,std::vector<uint8_t>> & metadata,std::vector<uint8_t> & data)77 static void EmitMetadata(
78 const std::map<uint8_t, std::vector<uint8_t>>& metadata,
79 std::vector<uint8_t>& data) {
80 auto ltv = types::LeAudioLtvMap(metadata);
81 auto ltv_raw_sz = ltv.RawPacketSize();
82
83 size_t old_size = data.size();
84 data.resize(old_size + ltv_raw_sz + 1);
85
86 // Set the cursor behind the old data
87 uint8_t* p_value = data.data() + old_size;
88
89 UINT8_TO_STREAM(p_value, ltv_raw_sz);
90 if (ltv_raw_sz > 0) {
91 p_value = ltv.RawPacket(p_value);
92 }
93 }
94
EmitBroadcastName(const std::string & name,std::vector<uint8_t> & data)95 static void EmitBroadcastName(const std::string& name,
96 std::vector<uint8_t>& data) {
97 int name_len = name.length();
98 size_t old_size = data.size();
99 data.resize(old_size + name_len + 2);
100
101 // Set the cursor behind the old data
102 uint8_t* p_value = data.data() + old_size;
103 UINT8_TO_STREAM(p_value, name_len + 1);
104 UINT8_TO_STREAM(p_value, BTM_BLE_AD_TYPE_BROADCAST_NAME);
105
106 std::vector<uint8_t> vec(name.begin(), name.end());
107 ARRAY_TO_STREAM(p_value, vec.data(), name_len);
108 }
109
EmitBisConfigs(const std::vector<BasicAudioAnnouncementBisConfig> & bis_configs,std::vector<uint8_t> & data)110 static void EmitBisConfigs(
111 const std::vector<BasicAudioAnnouncementBisConfig>& bis_configs,
112 std::vector<uint8_t>& data) {
113 // Emit each BIS config - that's the level 3 data
114 for (auto const& bis_config : bis_configs) {
115 auto ltv = types::LeAudioLtvMap(bis_config.codec_specific_params);
116 auto ltv_raw_sz = ltv.RawPacketSize();
117
118 size_t old_size = data.size();
119 data.resize(old_size + ltv_raw_sz + 2);
120
121 // Set the cursor behind the old data
122 auto* p_value = data.data() + old_size;
123
124 // BIS_index[i[k]]
125 UINT8_TO_STREAM(p_value, bis_config.bis_index);
126
127 // Per BIS Codec Specific Params[i[k]]
128 UINT8_TO_STREAM(p_value, ltv_raw_sz);
129 if (ltv_raw_sz > 0) {
130 p_value = ltv.RawPacket(p_value);
131 }
132 }
133 }
134
EmitSubgroup(const BasicAudioAnnouncementSubgroup & subgroup_config,std::vector<uint8_t> & data)135 static void EmitSubgroup(const BasicAudioAnnouncementSubgroup& subgroup_config,
136 std::vector<uint8_t>& data) {
137 // That's the level 2 data
138
139 // Resize for the num_bis
140 size_t initial_offset = data.size();
141 data.resize(initial_offset + 1);
142
143 // Set the cursor behind the old data and adds the level 2 Num_BIS[i]
144 uint8_t* p_value = data.data() + initial_offset;
145 UINT8_TO_STREAM(p_value, subgroup_config.bis_configs.size());
146
147 EmitCodecConfiguration(subgroup_config.codec_config, data, nullptr);
148 EmitMetadata(subgroup_config.metadata, data);
149
150 // This adds the level 3 data
151 EmitBisConfigs(subgroup_config.bis_configs, data);
152 }
153
ToRawPacket(BasicAudioAnnouncementData const & in,std::vector<uint8_t> & data)154 bool ToRawPacket(BasicAudioAnnouncementData const& in,
155 std::vector<uint8_t>& data) {
156 EmitHeader(in, data);
157
158 // Set the cursor behind the old data and resize
159 size_t old_size = data.size();
160 data.resize(old_size + 1);
161 uint8_t* p_value = data.data() + old_size;
162
163 // Emit the subgroup size and each subgroup
164 // That's the level 1 Num_Subgroups
165 UINT8_TO_STREAM(p_value, in.subgroup_configs.size());
166 for (const auto& subgroup_config : in.subgroup_configs) {
167 // That's the level 2 and higher level data
168 EmitSubgroup(subgroup_config, data);
169 }
170
171 return true;
172 }
173
PrepareAdvertisingData(bool is_public,const std::string & broadcast_name,bluetooth::le_audio::BroadcastId & broadcast_id,const bluetooth::le_audio::PublicBroadcastAnnouncementData & public_announcement,std::vector<uint8_t> & adv_data)174 void PrepareAdvertisingData(
175 bool is_public, const std::string& broadcast_name,
176 bluetooth::le_audio::BroadcastId& broadcast_id,
177 const bluetooth::le_audio::PublicBroadcastAnnouncementData&
178 public_announcement,
179 std::vector<uint8_t>& adv_data) {
180 adv_data.resize(7);
181 uint8_t* data_ptr = adv_data.data();
182 UINT8_TO_STREAM(data_ptr, 6);
183 UINT8_TO_STREAM(data_ptr, BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE);
184 UINT16_TO_STREAM(data_ptr, kBroadcastAudioAnnouncementServiceUuid);
185 UINT24_TO_STREAM(data_ptr, broadcast_id);
186
187 // Prepare public broadcast announcement data
188 if (is_public) {
189 size_t old_size = adv_data.size();
190 // 5: datalen(1) + adtype(1) + serviceuuid(2) + features(1)
191 adv_data.resize(old_size + 5);
192 // Skip the data length field until the full content is generated
193 data_ptr = adv_data.data() + old_size + 1;
194 UINT8_TO_STREAM(data_ptr, BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE);
195 UINT16_TO_STREAM(data_ptr, kPublicBroadcastAnnouncementServiceUuid);
196 UINT8_TO_STREAM(data_ptr, public_announcement.features);
197 // Set metadata length to 0 if no meta data present
198 EmitMetadata(public_announcement.metadata, adv_data);
199
200 // Update the length field accordingly
201 data_ptr = adv_data.data() + old_size;
202 UINT8_TO_STREAM(data_ptr, adv_data.size() - old_size - 1);
203
204 // Prepare broadcast name
205 if (!broadcast_name.empty()) {
206 EmitBroadcastName(broadcast_name, adv_data);
207 }
208 }
209 }
210
PreparePeriodicData(const BasicAudioAnnouncementData & announcement,std::vector<uint8_t> & periodic_data)211 void PreparePeriodicData(const BasicAudioAnnouncementData& announcement,
212 std::vector<uint8_t>& periodic_data) {
213 /* Account for AD Type + Service UUID */
214 periodic_data.resize(4);
215 /* Skip the data length field until the full content is generated */
216 uint8_t* data_ptr = periodic_data.data() + 1;
217 UINT8_TO_STREAM(data_ptr, BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE);
218 UINT16_TO_STREAM(data_ptr, kBasicAudioAnnouncementServiceUuid);
219
220 /* Append the announcement */
221 ToRawPacket(announcement, periodic_data);
222
223 /* Update the length field accordingly */
224 data_ptr = periodic_data.data();
225 UINT8_TO_STREAM(data_ptr, periodic_data.size() - 1);
226 }
227
228 constexpr types::LeAudioCodecId kLeAudioCodecIdLc3 = {
229 .coding_format = types::kLeAudioCodingFormatLC3,
230 .vendor_company_id = types::kLeAudioVendorCompanyIdUndefined,
231 .vendor_codec_id = types::kLeAudioVendorCodecIdUndefined};
232
233 static const BroadcastCodecWrapper lc3_mono_16_2 = BroadcastCodecWrapper(
234 kLeAudioCodecIdLc3,
235 // LeAudioCodecConfiguration
236 {.num_channels = LeAudioCodecConfiguration::kChannelNumberMono,
237 .sample_rate = LeAudioCodecConfiguration::kSampleRate16000,
238 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
239 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
240 // Bitrate
241 32000,
242 // Frame len.
243 40);
244
245 static const BroadcastCodecWrapper lc3_stereo_16_2 = BroadcastCodecWrapper(
246 kLeAudioCodecIdLc3,
247 // LeAudioCodecConfiguration
248 {.num_channels = LeAudioCodecConfiguration::kChannelNumberStereo,
249 .sample_rate = LeAudioCodecConfiguration::kSampleRate16000,
250 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
251 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
252 // Bitrate
253 32000,
254 // Frame len.
255 40);
256
257 static const BroadcastCodecWrapper lc3_stereo_24_2 = BroadcastCodecWrapper(
258 kLeAudioCodecIdLc3,
259 // LeAudioCodecConfiguration
260 {.num_channels = LeAudioCodecConfiguration::kChannelNumberStereo,
261 .sample_rate = LeAudioCodecConfiguration::kSampleRate24000,
262 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
263 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
264 // Bitrate
265 48000,
266 // Frame len.
267 60);
268
269 static const BroadcastCodecWrapper lc3_stereo_48_1 = BroadcastCodecWrapper(
270 kLeAudioCodecIdLc3,
271 // LeAudioCodecConfiguration
272 {.num_channels = LeAudioCodecConfiguration::kChannelNumberStereo,
273 .sample_rate = LeAudioCodecConfiguration::kSampleRate48000,
274 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
275 .data_interval_us = LeAudioCodecConfiguration::kInterval7500Us},
276 // Bitrate
277 80000,
278 // Frame len.
279 75);
280
281 static const BroadcastCodecWrapper lc3_stereo_48_2 = BroadcastCodecWrapper(
282 kLeAudioCodecIdLc3,
283 // LeAudioCodecConfiguration
284 {.num_channels = LeAudioCodecConfiguration::kChannelNumberStereo,
285 .sample_rate = LeAudioCodecConfiguration::kSampleRate48000,
286 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
287 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
288 // Bitrate
289 80000,
290 // Frame len.
291 100);
292
293 static const BroadcastCodecWrapper lc3_stereo_48_3 = BroadcastCodecWrapper(
294 kLeAudioCodecIdLc3,
295 // LeAudioCodecConfiguration
296 {.num_channels = LeAudioCodecConfiguration::kChannelNumberStereo,
297 .sample_rate = LeAudioCodecConfiguration::kSampleRate48000,
298 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
299 .data_interval_us = LeAudioCodecConfiguration::kInterval7500Us},
300 // Bitrate
301 96000,
302 // Frame len.
303 90);
304
305 static const BroadcastCodecWrapper lc3_stereo_48_4 = BroadcastCodecWrapper(
306 kLeAudioCodecIdLc3,
307 // LeAudioCodecConfiguration
308 {.num_channels = LeAudioCodecConfiguration::kChannelNumberStereo,
309 .sample_rate = LeAudioCodecConfiguration::kSampleRate48000,
310 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
311 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
312 // Bitrate
313 96000,
314 // Frame len.
315 120);
316
317 const std::map<uint32_t, uint8_t> sample_rate_to_sampling_freq_map = {
318 {LeAudioCodecConfiguration::kSampleRate8000,
319 codec_spec_conf::kLeAudioSamplingFreq8000Hz},
320 {LeAudioCodecConfiguration::kSampleRate16000,
321 codec_spec_conf::kLeAudioSamplingFreq16000Hz},
322 {LeAudioCodecConfiguration::kSampleRate24000,
323 codec_spec_conf::kLeAudioSamplingFreq24000Hz},
324 {LeAudioCodecConfiguration::kSampleRate32000,
325 codec_spec_conf::kLeAudioSamplingFreq32000Hz},
326 {LeAudioCodecConfiguration::kSampleRate44100,
327 codec_spec_conf::kLeAudioSamplingFreq44100Hz},
328 {LeAudioCodecConfiguration::kSampleRate48000,
329 codec_spec_conf::kLeAudioSamplingFreq48000Hz},
330 };
331
332 const std::map<uint32_t, uint8_t> data_interval_ms_to_frame_duration = {
333 {LeAudioCodecConfiguration::kInterval7500Us,
334 codec_spec_conf::kLeAudioCodecLC3FrameDur7500us},
335 {LeAudioCodecConfiguration::kInterval10000Us,
336 codec_spec_conf::kLeAudioCodecLC3FrameDur10000us},
337 };
338
GetBisCodecSpecData(uint8_t bis_idx) const339 types::LeAudioLtvMap BroadcastCodecWrapper::GetBisCodecSpecData(
340 uint8_t bis_idx) const {
341 /* For a single channel this will be set at the subgroup lvl. */
342 if (source_codec_config.num_channels == 1) return {};
343
344 switch (bis_idx) {
345 case 1:
346 return types::LeAudioLtvMap(
347 {{codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation,
348 UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontLeft)}});
349 case 2:
350 return types::LeAudioLtvMap(
351 {{codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation,
352 UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontRight)}});
353 break;
354 default:
355 return {};
356 }
357 }
358
GetSubgroupCodecSpecData() const359 types::LeAudioLtvMap BroadcastCodecWrapper::GetSubgroupCodecSpecData() const {
360 LOG_ASSERT(
361 sample_rate_to_sampling_freq_map.count(source_codec_config.sample_rate))
362 << "Invalid sample_rate";
363 LOG_ASSERT(data_interval_ms_to_frame_duration.count(
364 source_codec_config.data_interval_us))
365 << "Invalid data_interval";
366
367 std::map<uint8_t, std::vector<uint8_t>> codec_spec_ltvs = {
368 {codec_spec_conf::kLeAudioCodecLC3TypeSamplingFreq,
369 UINT8_TO_VEC_UINT8(sample_rate_to_sampling_freq_map.at(
370 source_codec_config.sample_rate))},
371 {codec_spec_conf::kLeAudioCodecLC3TypeFrameDuration,
372 UINT8_TO_VEC_UINT8(data_interval_ms_to_frame_duration.at(
373 source_codec_config.data_interval_us))},
374 };
375
376 if (codec_id.coding_format == kLeAudioCodecIdLc3.coding_format) {
377 uint16_t bc =
378 lc3_frame_bytes(source_codec_config.data_interval_us, codec_bitrate);
379 codec_spec_ltvs[codec_spec_conf::kLeAudioCodecLC3TypeOctetPerFrame] =
380 UINT16_TO_VEC_UINT8(bc);
381 }
382
383 if (source_codec_config.num_channels == 1) {
384 codec_spec_ltvs
385 [codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation] =
386 UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontCenter);
387 }
388
389 return types::LeAudioLtvMap(codec_spec_ltvs);
390 }
391
operator <<(std::ostream & os,const le_audio::broadcaster::BroadcastCodecWrapper & config)392 std::ostream& operator<<(
393 std::ostream& os,
394 const le_audio::broadcaster::BroadcastCodecWrapper& config) {
395 os << " BroadcastCodecWrapper=[";
396 os << "CodecID="
397 << "{" << +config.GetLeAudioCodecId().coding_format << ":"
398 << +config.GetLeAudioCodecId().vendor_company_id << ":"
399 << +config.GetLeAudioCodecId().vendor_codec_id << "}";
400 os << ", LeAudioCodecConfiguration="
401 << "{NumChannels=" << +config.GetNumChannels()
402 << ", SampleRate=" << +config.GetSampleRate()
403 << ", BitsPerSample=" << +config.GetBitsPerSample()
404 << ", DataIntervalUs=" << +config.GetDataIntervalUs() << "}";
405 os << ", Bitrate=" << +config.GetBitrate();
406 os << "]";
407 return os;
408 }
409
operator <<(std::ostream & os,const le_audio::broadcaster::BroadcastQosConfig & config)410 std::ostream& operator<<(
411 std::ostream& os, const le_audio::broadcaster::BroadcastQosConfig& config) {
412 os << " BroadcastQosConfig=[";
413 os << "RTN=" << +config.getRetransmissionNumber();
414 os << ", MaxTransportLatency=" << config.getMaxTransportLatency();
415 os << "]";
416 return os;
417 }
418
419 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
420 lc3_mono_16_2_1 = {lc3_mono_16_2, qos_config_2_10};
421
422 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
423 lc3_mono_16_2_2 = {lc3_mono_16_2, qos_config_4_60};
424
425 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
426 lc3_stereo_16_2_2 = {lc3_stereo_16_2, qos_config_4_60};
427
428 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
429 lc3_stereo_24_2_1 = {lc3_stereo_24_2, qos_config_2_10};
430
431 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
432 lc3_stereo_24_2_2 = {lc3_stereo_24_2, qos_config_4_60};
433
434 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
435 lc3_stereo_48_1_2 = {lc3_stereo_48_1, qos_config_4_50};
436
437 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
438 lc3_stereo_48_2_2 = {lc3_stereo_48_2, qos_config_4_65};
439
440 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
441 lc3_stereo_48_3_2 = {lc3_stereo_48_3, qos_config_4_50};
442
443 static const std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
444 lc3_stereo_48_4_2 = {lc3_stereo_48_4, qos_config_4_65};
445
446 std::pair<const BroadcastCodecWrapper&, const BroadcastQosConfig&>
getStreamConfigForContext(types::AudioContexts context)447 getStreamConfigForContext(types::AudioContexts context) {
448 const std::string* options =
449 stack_config_get_interface()->get_pts_broadcast_audio_config_options();
450 if (options) {
451 if (!options->compare("lc3_stereo_48_1_2")) return lc3_stereo_48_1_2;
452 if (!options->compare("lc3_stereo_48_2_2")) return lc3_stereo_48_2_2;
453 if (!options->compare("lc3_stereo_48_3_2")) return lc3_stereo_48_3_2;
454 if (!options->compare("lc3_stereo_48_4_2")) return lc3_stereo_48_4_2;
455 }
456 // High quality, Low Latency
457 if (context.test_any(LeAudioContextType::GAME | LeAudioContextType::LIVE))
458 return lc3_stereo_24_2_1;
459
460 // Low quality, Low Latency
461 if (context.test(LeAudioContextType::INSTRUCTIONAL)) return lc3_mono_16_2_1;
462
463 // Low quality, High Reliability
464 if (context.test_any(LeAudioContextType::SOUNDEFFECTS |
465 LeAudioContextType::UNSPECIFIED))
466 return lc3_stereo_16_2_2;
467
468 if (context.test_any(LeAudioContextType::ALERTS |
469 LeAudioContextType::NOTIFICATIONS |
470 LeAudioContextType::EMERGENCYALARM))
471 return lc3_mono_16_2_2;
472
473 // High quality, High Reliability
474 if (context.test(LeAudioContextType::MEDIA)) return lc3_stereo_24_2_2;
475
476 // Defaults: Low quality, High Reliability
477 return lc3_mono_16_2_2;
478 }
479
480 } /* namespace broadcaster */
481 } /* namespace le_audio */
482
483 /* Helper functions for comparing BroadcastAnnouncements */
484 namespace bluetooth {
485 namespace le_audio {
486
isMetadataSame(std::map<uint8_t,std::vector<uint8_t>> m1,std::map<uint8_t,std::vector<uint8_t>> m2)487 static bool isMetadataSame(std::map<uint8_t, std::vector<uint8_t>> m1,
488 std::map<uint8_t, std::vector<uint8_t>> m2) {
489 if (m1.size() != m2.size()) return false;
490
491 for (auto& m1pair : m1) {
492 if (m2.count(m1pair.first) == 0) return false;
493
494 auto& m2val = m2.at(m1pair.first);
495 if (m1pair.second.size() != m2val.size()) return false;
496
497 if (m1pair.second.size() != 0) {
498 if (memcmp(m1pair.second.data(), m2val.data(), m2val.size()) != 0)
499 return false;
500 }
501 }
502 return true;
503 }
504
operator ==(const BasicAudioAnnouncementData & lhs,const BasicAudioAnnouncementData & rhs)505 bool operator==(const BasicAudioAnnouncementData& lhs,
506 const BasicAudioAnnouncementData& rhs) {
507 if (lhs.presentation_delay != rhs.presentation_delay) return false;
508
509 if (lhs.subgroup_configs.size() != rhs.subgroup_configs.size()) return false;
510
511 for (auto i = 0lu; i < lhs.subgroup_configs.size(); ++i) {
512 auto& lhs_subgroup = lhs.subgroup_configs[i];
513 auto& rhs_subgroup = rhs.subgroup_configs[i];
514
515 if (lhs_subgroup.codec_config.codec_id !=
516 rhs_subgroup.codec_config.codec_id)
517 return false;
518
519 if (lhs_subgroup.codec_config.vendor_company_id !=
520 rhs_subgroup.codec_config.vendor_company_id)
521 return false;
522
523 if (lhs_subgroup.codec_config.vendor_codec_id !=
524 rhs_subgroup.codec_config.vendor_codec_id)
525 return false;
526
527 if (!isMetadataSame(lhs_subgroup.codec_config.codec_specific_params,
528 rhs_subgroup.codec_config.codec_specific_params))
529 return false;
530
531 if (!isMetadataSame(lhs_subgroup.metadata, rhs_subgroup.metadata))
532 return false;
533
534 for (auto j = 0lu; j < lhs_subgroup.bis_configs.size(); ++j) {
535 auto& lhs_bis_config = lhs_subgroup.bis_configs[i];
536 auto& rhs_bis_config = rhs_subgroup.bis_configs[i];
537 if (lhs_bis_config.bis_index != rhs_bis_config.bis_index) return false;
538
539 if (!isMetadataSame(lhs_bis_config.codec_specific_params,
540 rhs_bis_config.codec_specific_params))
541 return false;
542 }
543 }
544
545 return true;
546 }
547
operator ==(const PublicBroadcastAnnouncementData & lhs,const PublicBroadcastAnnouncementData & rhs)548 bool operator==(const PublicBroadcastAnnouncementData& lhs,
549 const PublicBroadcastAnnouncementData& rhs) {
550 if (lhs.features != rhs.features) return false;
551 if (!isMetadataSame(lhs.metadata, rhs.metadata)) return false;
552
553 return true;
554 }
555 } // namespace le_audio
556 } // namespace bluetooth
557