1 /*
2 * Copyright 2019 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 module contains API of the audio stream control protocol.
20 */
21
22 #include "client_parser.h"
23
24 #include <base/strings/string_number_conversions.h>
25 #include <bluetooth/log.h>
26 #include <hardware/bt_gatt_types.h>
27
28 #include <bitset>
29 #include <cstddef>
30 #include <cstdint>
31 #include <map>
32 #include <numeric>
33 #include <sstream>
34 #include <string>
35 #include <utility>
36 #include <vector>
37
38 #include "le_audio_types.h"
39 #include "le_audio_utils.h"
40 #include "stack/include/bt_types.h"
41
42 using bluetooth::le_audio::types::acs_ac_record;
43
44 namespace bluetooth::le_audio {
45 namespace client_parser {
46 namespace ascs {
47 static std::map<uint8_t, std::string> ase_state_map_string = {
48 {kAseStateIdle, "Idle"},
49 {kAseStateCodecConfigured, "Codec Configured"},
50 {kAseStateQosConfigured, "QoS Configured"},
51 {kAseStateEnabling, "Enabling"},
52 {kAseStateStreaming, "Streaming"},
53 {kAseStateDisabling, "Disabling"},
54 {kAseStateReleasing, "Releasing"},
55 };
56
57 static std::map<uint8_t, std::string> ctp_opcode_map_string = {
58 {kCtpOpcodeCodecConfiguration, "Config Codec"},
59 {kCtpOpcodeQosConfiguration, "Config QoS"},
60 {kCtpOpcodeEnable, "Enable"},
61 {kCtpOpcodeReceiverStartReady, "Receiver Start Ready"},
62 {kCtpOpcodeDisable, "Disable"},
63 {kCtpOpcodeReceiverStopReady, "Receiver Stop Ready"},
64 {kCtpOpcodeUpdateMetadata, "Update Metadata"},
65 {kCtpOpcodeRelease, "Release"},
66 };
67
68 static std::map<uint8_t, std::string> ctp_configuration_reason_map_string = {
69 {kCtpResponseNoReason, ""},
70 {kCtpResponseCodecId, "Codec ID"},
71 {kCtpResponseCodecSpecificConfiguration, "Codec specific configuration"},
72 {kCtpResponseSduInterval, "SDU interval"},
73 {kCtpResponseFraming, "Framing"},
74 {kCtpResponsePhy, "PHY"},
75 {kCtpResponseMaximumSduSize, "Maximum SDU size"},
76 {kCtpResponseRetransmissionNumber, "Retransmission number"},
77 {kCtpResponseMaxTransportLatency, "Max Transport latency"},
78 {kCtpResponsePresentationDelay, "Presentation delay"},
79 {kCtpResponseInvalidAseCisMapping, "Invalid ASE CIS mapping"},
80 };
81
82 static std::map<uint8_t, std::string> ctp_response_code_map_string = {
83 {kCtpResponseCodeSuccess, "Success"},
84 {kCtpResponseCodeUnsupportedOpcode, "Unsupported Opcode"},
85 {kCtpResponseCodeInvalidLength, "Invalid Length"},
86 {kCtpResponseCodeInvalidAseId, "Invalid ASE ID"},
87 {kCtpResponseCodeInvalidAseStateMachineTransition, "Invalid ASE State Machine Transition"},
88 {kCtpResponseCodeInvalidAseDirection, "Invalid ASE Direction"},
89 {kCtpResponseCodeUnsupportedAudioCapabilities, "Unsupported Audio Capabilities"},
90 {kCtpResponseCodeUnsupportedConfigurationParameterValue,
91 "Unsupported Configuration Parameter Value"},
92 {kCtpResponseCodeRejectedConfigurationParameterValue,
93 "Rejected Configuration Parameter Value"},
94 {kCtpResponseCodeInvalidConfigurationParameterValue,
95 "Invalid Configuration Parameter Value"},
96 {kCtpResponseCodeUnsupportedMetadata, "Unsupported Metadata"},
97 {kCtpResponseCodeRejectedMetadata, "Rejected Metadata"},
98 {kCtpResponseCodeInvalidMetadata, "Invalid Metadata"},
99 {kCtpResponseCodeInsufficientResources, "Insufficient Resources"},
100 {kCtpResponseCodeUnspecifiedError, "Unspecified Error"},
101 };
102
103 static std::map<uint8_t, std::string> ctp_metadata_reason_map_string = {
104 {kCtpMetadataResponsePreferredAudioContexts, "Preferred Audio Contexts"},
105 {kCtpMetadataResponseStreamingAudioContexts, "Streaming Audio Contexts"},
106 {kCtpMetadataResponseProgramInfo, "Program Info"},
107 {kCtpMetadataResponseLanguage, "Language"},
108 {kCtpMetadataResponseCcidList, "CCID List"},
109 {kCtpMetadataResponseParentalRating, "Parental Rating"},
110 {kCtpMetadataResponseProgramInfoUri, "Program Info URI"},
111 {kCtpMetadataResponseExtendedMetadata, "Extended Metadata"},
112 {kCtpMetadataResponseVendorSpecific, "Vendor Specific"},
113 };
114
115 static std::map<uint8_t, std::map<uint8_t, std::string>*> ctp_response_code_map = {
116 {kCtpResponseCodeUnsupportedConfigurationParameterValue,
117 &ctp_configuration_reason_map_string},
118 {kCtpResponseCodeRejectedConfigurationParameterValue, &ctp_configuration_reason_map_string},
119 {kCtpResponseCodeInvalidConfigurationParameterValue, &ctp_configuration_reason_map_string},
120 {kCtpResponseCodeUnsupportedMetadata, &ctp_metadata_reason_map_string},
121 {kCtpResponseCodeRejectedMetadata, &ctp_metadata_reason_map_string},
122 {kCtpResponseCodeInvalidMetadata, &ctp_metadata_reason_map_string},
123 };
124
ParseAseStatusHeader(ase_rsp_hdr & arh,uint16_t len,const uint8_t * value)125 bool ParseAseStatusHeader(ase_rsp_hdr& arh, uint16_t len, const uint8_t* value) {
126 if (len < kAseRspHdrMinLen) {
127 log::error("wrong len of ASE char (header): {}", static_cast<int>(len));
128
129 return false;
130 }
131
132 STREAM_TO_UINT8(arh.id, value);
133 STREAM_TO_UINT8(arh.state, value);
134
135 log::info("ASE status: \tASE id: 0x{:x}\tASE state: {} (0x{:x})", arh.id,
136 ase_state_map_string[arh.state], arh.state);
137
138 return true;
139 }
140
ParseAseStatusCodecConfiguredStateParams(struct ase_codec_configured_state_params & rsp,uint16_t len,const uint8_t * value)141 bool ParseAseStatusCodecConfiguredStateParams(struct ase_codec_configured_state_params& rsp,
142 uint16_t len, const uint8_t* value) {
143 uint8_t codec_spec_conf_len;
144
145 if (len < kAseStatusCodecConfMinLen) {
146 log::error("Wrong len of codec conf status (Codec conf header)");
147 return false;
148 }
149
150 STREAM_TO_UINT8(rsp.framing, value);
151 STREAM_TO_UINT8(rsp.preferred_phy, value);
152 STREAM_TO_UINT8(rsp.preferred_retrans_nb, value);
153 STREAM_TO_UINT16(rsp.max_transport_latency, value);
154 STREAM_TO_UINT24(rsp.pres_delay_min, value);
155 STREAM_TO_UINT24(rsp.pres_delay_max, value);
156 STREAM_TO_UINT24(rsp.preferred_pres_delay_min, value);
157 STREAM_TO_UINT24(rsp.preferred_pres_delay_max, value);
158 STREAM_TO_UINT8(rsp.codec_id.coding_format, value);
159 STREAM_TO_UINT16(rsp.codec_id.vendor_company_id, value);
160 STREAM_TO_UINT16(rsp.codec_id.vendor_codec_id, value);
161 STREAM_TO_UINT8(codec_spec_conf_len, value);
162
163 len -= kAseStatusCodecConfMinLen;
164
165 if (len != codec_spec_conf_len) {
166 log::error("Wrong len of codec conf status (Codec spec conf)");
167 return false;
168 }
169 if (codec_spec_conf_len) {
170 rsp.codec_spec_conf = std::vector<uint8_t>(value, value + codec_spec_conf_len);
171 }
172
173 log::info(
174 "Codec configuration\n\tFraming: 0x{:x}\n\tPreferred PHY: "
175 "0x{:x}\n\tPreferred retransmission number: 0x{:x}\n\tMax transport "
176 "latency: 0x{:x}\n\tPresence delay min: 0x{:x}\n\tPresence delay max: "
177 "0x{:x}\n\tPreferredPresentationDelayMin: "
178 "0x{:x}\n\tPreferredPresentationDelayMax: 0x{:x}\n\tCoding format: "
179 "0x{:x}\n\tVendor codec company ID: 0x{:x}\n\tVendor codec ID: "
180 "0x{:x}\n\tCodec specific conf len: {}\n\tCodec specific conf: {}",
181 rsp.framing, rsp.preferred_phy, rsp.preferred_retrans_nb, rsp.max_transport_latency,
182 rsp.pres_delay_min, rsp.pres_delay_max, rsp.preferred_pres_delay_min,
183 rsp.preferred_pres_delay_max, rsp.codec_id.coding_format, rsp.codec_id.vendor_company_id,
184 rsp.codec_id.vendor_codec_id, (int)codec_spec_conf_len,
185 base::HexEncode(rsp.codec_spec_conf.data(), rsp.codec_spec_conf.size()));
186
187 return true;
188 }
189
ParseAseStatusQosConfiguredStateParams(struct ase_qos_configured_state_params & rsp,uint16_t len,const uint8_t * value)190 bool ParseAseStatusQosConfiguredStateParams(struct ase_qos_configured_state_params& rsp,
191 uint16_t len, const uint8_t* value) {
192 if (len != kAseStatusCodecQosConfMinLen) {
193 log::error("Wrong len of ASE characteristic (QOS conf header)");
194 return false;
195 }
196
197 STREAM_TO_UINT8(rsp.cig_id, value);
198 STREAM_TO_UINT8(rsp.cis_id, value);
199 STREAM_TO_UINT24(rsp.sdu_interval, value);
200 STREAM_TO_UINT8(rsp.framing, value);
201 STREAM_TO_UINT8(rsp.phy, value);
202 STREAM_TO_UINT16(rsp.max_sdu, value);
203 STREAM_TO_UINT8(rsp.retrans_nb, value);
204 STREAM_TO_UINT16(rsp.max_transport_latency, value);
205 STREAM_TO_UINT24(rsp.pres_delay, value);
206
207 log::info(
208 "Codec QoS Configured\n\tCIG: 0x{:x}\n\tCIS: 0x{:x}\n\tSDU interval: "
209 "0x{:x}\n\tFraming: 0x{:x}\n\tPHY: 0x{:x}\n\tMax SDU: "
210 "0x{:x}\n\tRetransmission number: 0x{:x}\n\tMax transport latency: "
211 "0x{:x}\n\tPresentation delay: 0x{:x}",
212 rsp.cig_id, rsp.cis_id, rsp.sdu_interval, rsp.framing, rsp.phy, rsp.max_sdu,
213 rsp.retrans_nb, rsp.max_transport_latency, rsp.pres_delay);
214
215 return true;
216 }
217
ParseAseStatusTransientStateParams(struct ase_transient_state_params & rsp,uint16_t len,const uint8_t * value)218 bool ParseAseStatusTransientStateParams(struct ase_transient_state_params& rsp, uint16_t len,
219 const uint8_t* value) {
220 uint8_t metadata_len;
221
222 if (len < kAseStatusTransMinLen) {
223 log::error("Wrong len of ASE characteristic (metadata)");
224 return false;
225 }
226
227 STREAM_TO_UINT8(rsp.cig_id, value);
228 STREAM_TO_UINT8(rsp.cis_id, value);
229 STREAM_TO_UINT8(metadata_len, value);
230 len -= kAseStatusTransMinLen;
231
232 if (len != metadata_len) {
233 log::error("Wrong len of ASE characteristic (metadata)");
234 return false;
235 }
236
237 if (metadata_len > 0) {
238 rsp.metadata = std::vector<uint8_t>(value, value + metadata_len);
239 }
240
241 log::info(
242 "Status enabling/streaming/disabling\n\tCIG: 0x{:x}\n\tCIS: "
243 "0x{:x}\n\tMetadata: {}",
244 rsp.cig_id, rsp.cis_id, base::HexEncode(rsp.metadata.data(), rsp.metadata.size()));
245
246 return true;
247 }
248
ParseAseCtpNotification(struct ctp_ntf & ntf,uint16_t len,const uint8_t * value)249 bool ParseAseCtpNotification(struct ctp_ntf& ntf, uint16_t len, const uint8_t* value) {
250 uint8_t num_entries;
251
252 if (len < kCtpNtfMinLen) {
253 log::error("Wrong len of ASE control point notification: {}", (int)len);
254 return false;
255 }
256
257 STREAM_TO_UINT8(ntf.op, value);
258 STREAM_TO_UINT8(num_entries, value);
259
260 if (len != kCtpNtfMinLen + (num_entries * kCtpAseEntryMinLen)) {
261 log::error("Wrong len of ASE control point notification (ASE IDs)");
262 return false;
263 }
264
265 for (int i = 0; i < num_entries; i++) {
266 struct ctp_ase_entry entry;
267
268 STREAM_TO_UINT8(entry.ase_id, value);
269 STREAM_TO_UINT8(entry.response_code, value);
270 STREAM_TO_UINT8(entry.reason, value);
271
272 ntf.entries.push_back(std::move(entry));
273 }
274
275 log::info("Control point notification\n\tOpcode: {} (0x{:x})\n\tNum ASE IDs: {}",
276 ctp_opcode_map_string[ntf.op], ntf.op, (int)num_entries);
277 for (size_t i = 0; i < num_entries; i++) {
278 log::info(
279 "\n\tASE ID[0x{:x}] response: {} (0x{:x}) reason: {} (0x{:x})", ntf.entries[i].ase_id,
280 ctp_response_code_map_string[ntf.entries[i].response_code],
281 ntf.entries[i].response_code,
282 ((ctp_response_code_map.count(ntf.entries[i].response_code) != 0)
283 ? (*ctp_response_code_map[ntf.entries[i].response_code])[ntf.entries[i].reason]
284 : ""),
285 ntf.entries[i].reason);
286 }
287
288 return true;
289 }
290
PrepareAseCtpCodecConfig(const std::vector<struct ctp_codec_conf> & confs,std::vector<uint8_t> & value)291 bool PrepareAseCtpCodecConfig(const std::vector<struct ctp_codec_conf>& confs,
292 std::vector<uint8_t>& value) {
293 if (confs.size() == 0) {
294 log::error("Configuration set is empty!");
295 return false;
296 }
297
298 std::stringstream conf_ents_str;
299 size_t msg_len = std::accumulate(
300 confs.begin(), confs.end(), confs.size() * kCtpCodecConfMinLen + kAseNumSize + kCtpOpSize,
301 [&conf_ents_str](size_t cur_len, auto const& conf) {
302 if (utils::IsCodecUsingLtvFormat(conf.codec_id)) {
303 types::LeAudioLtvMap ltv;
304 if (ltv.Parse(conf.codec_config.data(), conf.codec_config.size())) {
305 for (const auto& [type, value] : ltv.Values()) {
306 conf_ents_str << "\ttype: " << std::to_string(type)
307 << "\tlen: " << std::to_string(value.size())
308 << "\tdata: " << base::HexEncode(value.data(), value.size())
309 << "\n";
310 }
311 return cur_len + conf.codec_config.size();
312 }
313 log::error("Error parsing codec configuration LTV data.");
314 }
315
316 conf_ents_str << "\t"
317 << base::HexEncode(conf.codec_config.data(), conf.codec_config.size());
318 return cur_len + conf.codec_config.size();
319 });
320
321 value.resize(msg_len);
322 uint8_t* msg = value.data();
323 UINT8_TO_STREAM(msg, kCtpOpcodeCodecConfiguration);
324
325 UINT8_TO_STREAM(msg, confs.size());
326 for (const struct ctp_codec_conf& conf : confs) {
327 UINT8_TO_STREAM(msg, conf.ase_id);
328 UINT8_TO_STREAM(msg, conf.target_latency);
329 UINT8_TO_STREAM(msg, conf.target_phy);
330 UINT8_TO_STREAM(msg, conf.codec_id.coding_format);
331 UINT16_TO_STREAM(msg, conf.codec_id.vendor_company_id);
332 UINT16_TO_STREAM(msg, conf.codec_id.vendor_codec_id);
333
334 UINT8_TO_STREAM(msg, conf.codec_config.size());
335 ARRAY_TO_STREAM(msg, conf.codec_config.data(), static_cast<int>(conf.codec_config.size()));
336
337 log::info(
338 "Codec configuration\n\tAse id: 0x{:x}\n\tTarget latency: "
339 "0x{:x}\n\tTarget PHY: 0x{:x}\n\tCoding format: 0x{:x}\n\tVendor codec "
340 "company ID: 0x{:x}\n\tVendor codec ID: 0x{:x}\n\tCodec config len: "
341 "{}\n\tCodec spec conf: \n{}",
342 conf.ase_id, conf.target_latency, conf.target_phy, conf.codec_id.coding_format,
343 conf.codec_id.vendor_company_id, conf.codec_id.vendor_codec_id,
344 static_cast<int>(conf.codec_config.size()), conf_ents_str.str());
345 }
346
347 return true;
348 }
349
PrepareAseCtpConfigQos(const std::vector<struct ctp_qos_conf> & confs,std::vector<uint8_t> & value)350 bool PrepareAseCtpConfigQos(const std::vector<struct ctp_qos_conf>& confs,
351 std::vector<uint8_t>& value) {
352 if (confs.size() == 0) {
353 log::error("Configuration set is empty!");
354 return false;
355 }
356 value.resize(confs.size() * kCtpQosConfMinLen + kAseNumSize + kCtpOpSize);
357
358 uint8_t* msg = value.data();
359 UINT8_TO_STREAM(msg, kCtpOpcodeQosConfiguration);
360 UINT8_TO_STREAM(msg, confs.size());
361
362 for (const struct ctp_qos_conf& conf : confs) {
363 UINT8_TO_STREAM(msg, conf.ase_id);
364 UINT8_TO_STREAM(msg, conf.cig);
365 UINT8_TO_STREAM(msg, conf.cis);
366 UINT24_TO_STREAM(msg, conf.sdu_interval);
367 UINT8_TO_STREAM(msg, conf.framing);
368 UINT8_TO_STREAM(msg, conf.phy);
369 UINT16_TO_STREAM(msg, conf.max_sdu);
370 UINT8_TO_STREAM(msg, conf.retrans_nb);
371 UINT16_TO_STREAM(msg, conf.max_transport_latency);
372 UINT24_TO_STREAM(msg, conf.pres_delay);
373
374 log::info(
375 "QoS configuration\n\tAse id: 0x{:x}\n\tcig: 0x{:x}\n\tCis: "
376 "0x{:x}\n\tSDU interval: 0x{:x}\n\tFraming: 0x{:x}\n\tPhy: "
377 "0x{:x}\n\tMax sdu size: 0x{:x}\n\tRetrans nb: 0x{:x}\n\tMax Transport "
378 "latency: 0x{:x}\n\tPres delay: 0x{:x}",
379 conf.ase_id, conf.cig, conf.cis, conf.sdu_interval, conf.framing, conf.phy,
380 conf.max_sdu, conf.retrans_nb, conf.max_transport_latency, conf.pres_delay);
381 }
382
383 return true;
384 }
385
PrepareAseCtpEnable(const std::vector<struct ctp_enable> & confs,std::vector<uint8_t> & value)386 bool PrepareAseCtpEnable(const std::vector<struct ctp_enable>& confs, std::vector<uint8_t>& value) {
387 if (confs.size() == 0) {
388 log::error("Configuration set is empty!");
389 return false;
390 }
391
392 if (confs.size() > UINT8_MAX) {
393 log::error("To many ASEs to update metadata");
394 return false;
395 }
396
397 uint16_t msg_len = confs.size() * kCtpEnableMinLen + kAseNumSize + kCtpOpSize;
398 for (auto& conf : confs) {
399 if (msg_len > GATT_MAX_ATTR_LEN) {
400 log::error("Message length above GATT maximum");
401 return false;
402 }
403 if (conf.metadata.size() > UINT8_MAX) {
404 log::error("ase[{}] metadata length is invalid", conf.ase_id);
405 return false;
406 }
407
408 msg_len += conf.metadata.size();
409 }
410 value.resize(msg_len);
411
412 uint8_t* msg = value.data();
413 UINT8_TO_STREAM(msg, kCtpOpcodeEnable);
414 UINT8_TO_STREAM(msg, confs.size());
415
416 for (const struct ctp_enable& conf : confs) {
417 UINT8_TO_STREAM(msg, conf.ase_id);
418 UINT8_TO_STREAM(msg, conf.metadata.size());
419 ARRAY_TO_STREAM(msg, conf.metadata.data(), static_cast<int>(conf.metadata.size()));
420
421 log::info("Enable\n\tAse id: 0x{:x}\n\tMetadata: {}", conf.ase_id,
422 base::HexEncode(conf.metadata.data(), conf.metadata.size()));
423 }
424
425 return true;
426 }
427
PrepareAseCtpAudioReceiverStartReady(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)428 bool PrepareAseCtpAudioReceiverStartReady(const std::vector<uint8_t>& ase_ids,
429 std::vector<uint8_t>& value) {
430 if (ase_ids.size() == 0) {
431 log::error("ASEs ID set is empty!");
432 return false;
433 }
434 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
435
436 uint8_t* msg = value.data();
437 UINT8_TO_STREAM(msg, kCtpOpcodeReceiverStartReady);
438 UINT8_TO_STREAM(msg, ase_ids.size());
439
440 for (const uint8_t& id : ase_ids) {
441 UINT8_TO_STREAM(msg, id);
442
443 log::info("ReceiverStartReady\n\tAse id: 0x{:x}", id);
444 }
445
446 return true;
447 }
448
PrepareAseCtpDisable(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)449 bool PrepareAseCtpDisable(const std::vector<uint8_t>& ase_ids, std::vector<uint8_t>& value) {
450 if (ase_ids.size() == 0) {
451 log::error("ASEs ID set is empty!");
452 return false;
453 }
454 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
455
456 uint8_t* msg = value.data();
457 UINT8_TO_STREAM(msg, kCtpOpcodeDisable);
458 UINT8_TO_STREAM(msg, ase_ids.size());
459
460 for (const uint8_t& id : ase_ids) {
461 UINT8_TO_STREAM(msg, id);
462
463 log::info("Disable\n\tAse id: 0x{:x}", id);
464 }
465
466 return true;
467 }
468
PrepareAseCtpAudioReceiverStopReady(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)469 bool PrepareAseCtpAudioReceiverStopReady(const std::vector<uint8_t>& ase_ids,
470 std::vector<uint8_t>& value) {
471 if (ase_ids.size() == 0) {
472 log::error("ASEs ID set is empty!");
473 return false;
474 }
475 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
476
477 uint8_t* msg = value.data();
478 UINT8_TO_STREAM(msg, kCtpOpcodeReceiverStopReady);
479 UINT8_TO_STREAM(msg, ase_ids.size());
480
481 for (const uint8_t& ase_id : ase_ids) {
482 UINT8_TO_STREAM(msg, ase_id);
483
484 log::info("ReceiverStopReady\n\tAse id: 0x{:x}", ase_id);
485 }
486
487 return true;
488 }
489
PrepareAseCtpUpdateMetadata(const std::vector<struct ctp_update_metadata> & confs,std::vector<uint8_t> & value)490 bool PrepareAseCtpUpdateMetadata(const std::vector<struct ctp_update_metadata>& confs,
491 std::vector<uint8_t>& value) {
492 if (confs.size() == 0) {
493 log::error("Configuration set is empty!");
494 return false;
495 }
496
497 if (confs.size() > UINT8_MAX) {
498 log::error("To many ASEs to update metadata");
499 return false;
500 }
501
502 uint16_t msg_len = confs.size() * kCtpUpdateMetadataMinLen + kAseNumSize + kCtpOpSize;
503 for (auto& conf : confs) {
504 if (msg_len > GATT_MAX_ATTR_LEN) {
505 log::error("Message length above GATT maximum");
506 return false;
507 }
508 if (conf.metadata.size() > UINT8_MAX) {
509 log::error("ase[{}] metadata length is invalid", conf.ase_id);
510 return false;
511 }
512
513 msg_len += conf.metadata.size();
514 }
515 value.resize(msg_len);
516
517 uint8_t* msg = value.data();
518 UINT8_TO_STREAM(msg, kCtpOpcodeUpdateMetadata);
519 UINT8_TO_STREAM(msg, confs.size());
520
521 for (const struct ctp_update_metadata& conf : confs) {
522 UINT8_TO_STREAM(msg, conf.ase_id);
523 UINT8_TO_STREAM(msg, conf.metadata.size());
524 ARRAY_TO_STREAM(msg, conf.metadata.data(), static_cast<int>(conf.metadata.size()));
525
526 log::info("Update Metadata\n\tAse id: 0x{:x}\n\tMetadata: {}", conf.ase_id,
527 base::HexEncode(conf.metadata.data(), conf.metadata.size()));
528 }
529
530 return true;
531 }
532
PrepareAseCtpRelease(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)533 bool PrepareAseCtpRelease(const std::vector<uint8_t>& ase_ids, std::vector<uint8_t>& value) {
534 if (ase_ids.size() == 0) {
535 return true;
536 }
537 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
538
539 uint8_t* msg = value.data();
540 UINT8_TO_STREAM(msg, kCtpOpcodeRelease);
541 UINT8_TO_STREAM(msg, ase_ids.size());
542
543 for (const uint8_t& ase_id : ase_ids) {
544 UINT8_TO_STREAM(msg, ase_id);
545
546 log::info("Release\n\tAse id: 0x{:x}", ase_id);
547 }
548
549 return true;
550 }
551 } // namespace ascs
552
553 namespace pacs {
554
ParseSinglePac(std::vector<struct acs_ac_record> & pac_recs,uint16_t len,const uint8_t * value)555 int ParseSinglePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
556 const uint8_t* value) {
557 struct acs_ac_record rec;
558 uint8_t codec_spec_cap_len, metadata_len;
559
560 if (len < kAcsPacRecordMinLen) {
561 log::error("Wrong len of PAC record ({}!={})", len, kAcsPacRecordMinLen);
562 pac_recs.clear();
563 return -1;
564 }
565
566 STREAM_TO_UINT8(rec.codec_id.coding_format, value);
567 STREAM_TO_UINT16(rec.codec_id.vendor_company_id, value);
568 STREAM_TO_UINT16(rec.codec_id.vendor_codec_id, value);
569 STREAM_TO_UINT8(codec_spec_cap_len, value);
570 len -= kAcsPacRecordMinLen - kAcsPacMetadataLenLen;
571
572 if (len < codec_spec_cap_len + kAcsPacMetadataLenLen) {
573 log::error("Wrong len of PAC record (codec specific capabilities) ({}!={})", len,
574 codec_spec_cap_len + kAcsPacMetadataLenLen);
575 pac_recs.clear();
576 return -1;
577 }
578
579 rec.codec_spec_caps_raw.assign(value, value + codec_spec_cap_len);
580
581 if (utils::IsCodecUsingLtvFormat(rec.codec_id)) {
582 if (!rec.codec_spec_caps.Parse(value, codec_spec_cap_len)) {
583 log::error("Unable to parse codec specific parameters LTV: {}",
584 base::HexEncode(value, codec_spec_cap_len));
585 return -1;
586 }
587 }
588
589 value += codec_spec_cap_len;
590 len -= codec_spec_cap_len;
591
592 STREAM_TO_UINT8(metadata_len, value);
593 len -= kAcsPacMetadataLenLen;
594
595 if (len < metadata_len) {
596 log::error("Wrong len of PAC record (metadata) ({}!={})", len, metadata_len);
597 pac_recs.clear();
598 return -1;
599 }
600
601 if (!rec.metadata.Parse(value, metadata_len)) {
602 log::error("PAC record contains corrupted LTV formatted metadata: {}",
603 base::HexEncode(value, metadata_len));
604 return -1;
605 }
606 value += metadata_len;
607 len -= metadata_len;
608
609 pac_recs.push_back(std::move(rec));
610
611 return len;
612 }
613
ParsePacs(std::vector<struct acs_ac_record> & pac_recs,uint16_t len,const uint8_t * value)614 bool ParsePacs(std::vector<struct acs_ac_record>& pac_recs, uint16_t len, const uint8_t* value) {
615 if (len < kAcsPacDiscoverRspMinLen) {
616 log::error("Wrong len of PAC characteristic ({}!={})", len, kAcsPacDiscoverRspMinLen);
617 return false;
618 }
619
620 uint8_t pac_rec_nb;
621 STREAM_TO_UINT8(pac_rec_nb, value);
622 len -= kAcsPacDiscoverRspMinLen;
623
624 pac_recs.reserve(pac_rec_nb);
625 for (int i = 0; i < pac_rec_nb; i++) {
626 int remaining_len = ParseSinglePac(pac_recs, len, value);
627 if (remaining_len < 0) {
628 log::error("Error parsing PAC records.");
629 return false;
630 }
631
632 value += (len - remaining_len);
633 len = remaining_len;
634 }
635
636 return true;
637 }
638
ParseAudioLocations(types::AudioLocations & audio_locations,uint16_t len,const uint8_t * value)639 bool ParseAudioLocations(types::AudioLocations& audio_locations, uint16_t len,
640 const uint8_t* value) {
641 if (len != kAudioLocationsRspMinLen) {
642 log::error("Wrong len of Audio Location characteristic");
643 return false;
644 }
645
646 STREAM_TO_UINT32(audio_locations, value);
647
648 log::info("Audio locations: {}", audio_locations.to_string());
649
650 return true;
651 }
652
ParseSupportedAudioContexts(types::BidirectionalPair<types::AudioContexts> & contexts,uint16_t len,const uint8_t * value)653 bool ParseSupportedAudioContexts(types::BidirectionalPair<types::AudioContexts>& contexts,
654 uint16_t len, const uint8_t* value) {
655 if (len != kAseAudioSuppContRspMinLen) {
656 log::error("Wrong len of Audio Supported Context characteristic");
657 return false;
658 }
659
660 STREAM_TO_UINT16(contexts.sink.value_ref(), value);
661 STREAM_TO_UINT16(contexts.source.value_ref(), value);
662
663 log::info(
664 "Supported Audio Contexts: \n\tSupported Sink Contexts: {}\n\tSupported "
665 "Source Contexts: {}",
666 contexts.sink.to_string(), contexts.source.to_string());
667
668 return true;
669 }
670
ParseAvailableAudioContexts(types::BidirectionalPair<types::AudioContexts> & contexts,uint16_t len,const uint8_t * value)671 bool ParseAvailableAudioContexts(types::BidirectionalPair<types::AudioContexts>& contexts,
672 uint16_t len, const uint8_t* value) {
673 if (len != kAseAudioAvailRspMinLen) {
674 log::error("Wrong len of Audio Availability characteristic");
675 return false;
676 }
677
678 STREAM_TO_UINT16(contexts.sink.value_ref(), value);
679 STREAM_TO_UINT16(contexts.source.value_ref(), value);
680
681 log::info(
682 "Available Audio Contexts: \n\tAvailable Sink Contexts: {}\n\tAvailable "
683 "Source Contexts: {}",
684 contexts.sink.to_string(), contexts.source.to_string());
685
686 return true;
687 }
688 } // namespace pacs
689
690 namespace tmap {
691
ParseTmapRole(std::bitset<16> & role,uint16_t len,const uint8_t * value)692 bool ParseTmapRole(std::bitset<16>& role, uint16_t len, const uint8_t* value) {
693 if (len != kTmapRoleLen) {
694 log::error(", Wrong len of Telephony Media Audio Profile Role, characteristic");
695 return false;
696 }
697
698 STREAM_TO_UINT16(role, value);
699
700 log::info(", Telephony Media Audio Profile Role:\n\tRole: {}", role.to_string());
701
702 return true;
703 }
704 } // namespace tmap
705
706 } // namespace client_parser
707 } // namespace bluetooth::le_audio
708