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 return false;
295 }
296
297 std::stringstream conf_ents_str;
298 size_t msg_len = std::accumulate(
299 confs.begin(), confs.end(), confs.size() * kCtpCodecConfMinLen + kAseNumSize + kCtpOpSize,
300 [&conf_ents_str](size_t cur_len, auto const& conf) {
301 if (utils::IsCodecUsingLtvFormat(conf.codec_id)) {
302 types::LeAudioLtvMap ltv;
303 if (ltv.Parse(conf.codec_config.data(), conf.codec_config.size())) {
304 for (const auto& [type, value] : ltv.Values()) {
305 conf_ents_str << "\ttype: " << std::to_string(type)
306 << "\tlen: " << std::to_string(value.size())
307 << "\tdata: " << base::HexEncode(value.data(), value.size())
308 << "\n";
309 }
310 return cur_len + conf.codec_config.size();
311 }
312 log::error("Error parsing codec configuration LTV data.");
313 }
314
315 conf_ents_str << "\t"
316 << base::HexEncode(conf.codec_config.data(), conf.codec_config.size());
317 return cur_len + conf.codec_config.size();
318 });
319
320 value.resize(msg_len);
321 uint8_t* msg = value.data();
322 UINT8_TO_STREAM(msg, kCtpOpcodeCodecConfiguration);
323
324 UINT8_TO_STREAM(msg, confs.size());
325 for (const struct ctp_codec_conf& conf : confs) {
326 UINT8_TO_STREAM(msg, conf.ase_id);
327 UINT8_TO_STREAM(msg, conf.target_latency);
328 UINT8_TO_STREAM(msg, conf.target_phy);
329 UINT8_TO_STREAM(msg, conf.codec_id.coding_format);
330 UINT16_TO_STREAM(msg, conf.codec_id.vendor_company_id);
331 UINT16_TO_STREAM(msg, conf.codec_id.vendor_codec_id);
332
333 UINT8_TO_STREAM(msg, conf.codec_config.size());
334 ARRAY_TO_STREAM(msg, conf.codec_config.data(), static_cast<int>(conf.codec_config.size()));
335
336 log::info(
337 "Codec configuration\n\tAse id: 0x{:x}\n\tTarget latency: "
338 "0x{:x}\n\tTarget PHY: 0x{:x}\n\tCoding format: 0x{:x}\n\tVendor codec "
339 "company ID: 0x{:x}\n\tVendor codec ID: 0x{:x}\n\tCodec config len: "
340 "{}\n\tCodec spec conf: \n{}",
341 conf.ase_id, conf.target_latency, conf.target_phy, conf.codec_id.coding_format,
342 conf.codec_id.vendor_company_id, conf.codec_id.vendor_codec_id,
343 static_cast<int>(conf.codec_config.size()), conf_ents_str.str());
344 }
345
346 return true;
347 }
348
PrepareAseCtpConfigQos(const std::vector<struct ctp_qos_conf> & confs,std::vector<uint8_t> & value)349 bool PrepareAseCtpConfigQos(const std::vector<struct ctp_qos_conf>& confs,
350 std::vector<uint8_t>& value) {
351 if (confs.size() == 0) {
352 return false;
353 }
354 value.resize(confs.size() * kCtpQosConfMinLen + kAseNumSize + kCtpOpSize);
355
356 uint8_t* msg = value.data();
357 UINT8_TO_STREAM(msg, kCtpOpcodeQosConfiguration);
358 UINT8_TO_STREAM(msg, confs.size());
359
360 for (const struct ctp_qos_conf& conf : confs) {
361 UINT8_TO_STREAM(msg, conf.ase_id);
362 UINT8_TO_STREAM(msg, conf.cig);
363 UINT8_TO_STREAM(msg, conf.cis);
364 UINT24_TO_STREAM(msg, conf.sdu_interval);
365 UINT8_TO_STREAM(msg, conf.framing);
366 UINT8_TO_STREAM(msg, conf.phy);
367 UINT16_TO_STREAM(msg, conf.max_sdu);
368 UINT8_TO_STREAM(msg, conf.retrans_nb);
369 UINT16_TO_STREAM(msg, conf.max_transport_latency);
370 UINT24_TO_STREAM(msg, conf.pres_delay);
371
372 log::info(
373 "QoS configuration\n\tAse id: 0x{:x}\n\tcig: 0x{:x}\n\tCis: "
374 "0x{:x}\n\tSDU interval: 0x{:x}\n\tFraming: 0x{:x}\n\tPhy: "
375 "0x{:x}\n\tMax sdu size: 0x{:x}\n\tRetrans nb: 0x{:x}\n\tMax Transport "
376 "latency: 0x{:x}\n\tPres delay: 0x{:x}",
377 conf.ase_id, conf.cig, conf.cis, conf.sdu_interval, conf.framing, conf.phy,
378 conf.max_sdu, conf.retrans_nb, conf.max_transport_latency, conf.pres_delay);
379 }
380
381 return true;
382 }
383
PrepareAseCtpEnable(const std::vector<struct ctp_enable> & confs,std::vector<uint8_t> & value)384 bool PrepareAseCtpEnable(const std::vector<struct ctp_enable>& confs, std::vector<uint8_t>& value) {
385 if (confs.size() == 0) {
386 return false;
387 }
388
389 if (confs.size() > UINT8_MAX) {
390 log::error("To many ASEs to update metadata");
391 return false;
392 }
393
394 uint16_t msg_len = confs.size() * kCtpEnableMinLen + kAseNumSize + kCtpOpSize;
395 for (auto& conf : confs) {
396 if (msg_len > GATT_MAX_ATTR_LEN) {
397 log::error("Message length above GATT maximum");
398 return false;
399 }
400 if (conf.metadata.size() > UINT8_MAX) {
401 log::error("ase[{}] metadata length is invalid", conf.ase_id);
402 return false;
403 }
404
405 msg_len += conf.metadata.size();
406 }
407 value.resize(msg_len);
408
409 uint8_t* msg = value.data();
410 UINT8_TO_STREAM(msg, kCtpOpcodeEnable);
411 UINT8_TO_STREAM(msg, confs.size());
412
413 for (const struct ctp_enable& conf : confs) {
414 UINT8_TO_STREAM(msg, conf.ase_id);
415 UINT8_TO_STREAM(msg, conf.metadata.size());
416 ARRAY_TO_STREAM(msg, conf.metadata.data(), static_cast<int>(conf.metadata.size()));
417
418 log::info("Enable\n\tAse id: 0x{:x}\n\tMetadata: {}", conf.ase_id,
419 base::HexEncode(conf.metadata.data(), conf.metadata.size()));
420 }
421
422 return true;
423 }
424
PrepareAseCtpAudioReceiverStartReady(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)425 bool PrepareAseCtpAudioReceiverStartReady(const std::vector<uint8_t>& ase_ids,
426 std::vector<uint8_t>& value) {
427 if (ase_ids.size() == 0) {
428 return false;
429 }
430 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
431
432 uint8_t* msg = value.data();
433 UINT8_TO_STREAM(msg, kCtpOpcodeReceiverStartReady);
434 UINT8_TO_STREAM(msg, ase_ids.size());
435
436 for (const uint8_t& id : ase_ids) {
437 UINT8_TO_STREAM(msg, id);
438
439 log::info("ReceiverStartReady\n\tAse id: 0x{:x}", id);
440 }
441
442 return true;
443 }
444
PrepareAseCtpDisable(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)445 bool PrepareAseCtpDisable(const std::vector<uint8_t>& ase_ids, std::vector<uint8_t>& value) {
446 if (ase_ids.size() == 0) {
447 return false;
448 }
449 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
450
451 uint8_t* msg = value.data();
452 UINT8_TO_STREAM(msg, kCtpOpcodeDisable);
453 UINT8_TO_STREAM(msg, ase_ids.size());
454
455 for (const uint8_t& id : ase_ids) {
456 UINT8_TO_STREAM(msg, id);
457
458 log::info("Disable\n\tAse id: 0x{:x}", id);
459 }
460
461 return true;
462 }
463
PrepareAseCtpAudioReceiverStopReady(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)464 bool PrepareAseCtpAudioReceiverStopReady(const std::vector<uint8_t>& ase_ids,
465 std::vector<uint8_t>& value) {
466 if (ase_ids.size() == 0) {
467 return false;
468 }
469 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
470
471 uint8_t* msg = value.data();
472 UINT8_TO_STREAM(msg, kCtpOpcodeReceiverStopReady);
473 UINT8_TO_STREAM(msg, ase_ids.size());
474
475 for (const uint8_t& ase_id : ase_ids) {
476 UINT8_TO_STREAM(msg, ase_id);
477
478 log::info("ReceiverStopReady\n\tAse id: 0x{:x}", ase_id);
479 }
480
481 return true;
482 }
483
PrepareAseCtpUpdateMetadata(const std::vector<struct ctp_update_metadata> & confs,std::vector<uint8_t> & value)484 bool PrepareAseCtpUpdateMetadata(const std::vector<struct ctp_update_metadata>& confs,
485 std::vector<uint8_t>& value) {
486 if (confs.size() == 0) {
487 return false;
488 }
489
490 if (confs.size() > UINT8_MAX) {
491 log::error("To many ASEs to update metadata");
492 return false;
493 }
494
495 uint16_t msg_len = confs.size() * kCtpUpdateMetadataMinLen + kAseNumSize + kCtpOpSize;
496 for (auto& conf : confs) {
497 if (msg_len > GATT_MAX_ATTR_LEN) {
498 log::error("Message length above GATT maximum");
499 return false;
500 }
501 if (conf.metadata.size() > UINT8_MAX) {
502 log::error("ase[{}] metadata length is invalid", conf.ase_id);
503 return false;
504 }
505
506 msg_len += conf.metadata.size();
507 }
508 value.resize(msg_len);
509
510 uint8_t* msg = value.data();
511 UINT8_TO_STREAM(msg, kCtpOpcodeUpdateMetadata);
512 UINT8_TO_STREAM(msg, confs.size());
513
514 for (const struct ctp_update_metadata& conf : confs) {
515 UINT8_TO_STREAM(msg, conf.ase_id);
516 UINT8_TO_STREAM(msg, conf.metadata.size());
517 ARRAY_TO_STREAM(msg, conf.metadata.data(), static_cast<int>(conf.metadata.size()));
518
519 log::info("Update Metadata\n\tAse id: 0x{:x}\n\tMetadata: {}", conf.ase_id,
520 base::HexEncode(conf.metadata.data(), conf.metadata.size()));
521 }
522
523 return true;
524 }
525
PrepareAseCtpRelease(const std::vector<uint8_t> & ase_ids,std::vector<uint8_t> & value)526 bool PrepareAseCtpRelease(const std::vector<uint8_t>& ase_ids, std::vector<uint8_t>& value) {
527 if (ase_ids.size() == 0) {
528 return true;
529 }
530 value.resize(ase_ids.size() * kAseIdSize + kAseNumSize + kCtpOpSize);
531
532 uint8_t* msg = value.data();
533 UINT8_TO_STREAM(msg, kCtpOpcodeRelease);
534 UINT8_TO_STREAM(msg, ase_ids.size());
535
536 for (const uint8_t& ase_id : ase_ids) {
537 UINT8_TO_STREAM(msg, ase_id);
538
539 log::info("Release\n\tAse id: 0x{:x}", ase_id);
540 }
541
542 return true;
543 }
544 } // namespace ascs
545
546 namespace pacs {
547
ParseSinglePac(std::vector<struct acs_ac_record> & pac_recs,uint16_t len,const uint8_t * value)548 int ParseSinglePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
549 const uint8_t* value) {
550 struct acs_ac_record rec;
551 uint8_t codec_spec_cap_len, metadata_len;
552
553 if (len < kAcsPacRecordMinLen) {
554 log::error("Wrong len of PAC record ({}!={})", len, kAcsPacRecordMinLen);
555 pac_recs.clear();
556 return -1;
557 }
558
559 STREAM_TO_UINT8(rec.codec_id.coding_format, value);
560 STREAM_TO_UINT16(rec.codec_id.vendor_company_id, value);
561 STREAM_TO_UINT16(rec.codec_id.vendor_codec_id, value);
562 STREAM_TO_UINT8(codec_spec_cap_len, value);
563 len -= kAcsPacRecordMinLen - kAcsPacMetadataLenLen;
564
565 if (len < codec_spec_cap_len + kAcsPacMetadataLenLen) {
566 log::error("Wrong len of PAC record (codec specific capabilities) ({}!={})", len,
567 codec_spec_cap_len + kAcsPacMetadataLenLen);
568 pac_recs.clear();
569 return -1;
570 }
571
572 rec.codec_spec_caps_raw.assign(value, value + codec_spec_cap_len);
573
574 if (utils::IsCodecUsingLtvFormat(rec.codec_id)) {
575 bool parsed;
576 rec.codec_spec_caps = types::LeAudioLtvMap::Parse(value, codec_spec_cap_len, parsed);
577 if (!parsed) {
578 return -1;
579 }
580 }
581
582 value += codec_spec_cap_len;
583 len -= codec_spec_cap_len;
584
585 STREAM_TO_UINT8(metadata_len, value);
586 len -= kAcsPacMetadataLenLen;
587
588 if (len < metadata_len) {
589 log::error("Wrong len of PAC record (metadata) ({}!={})", len, metadata_len);
590 pac_recs.clear();
591 return -1;
592 }
593
594 rec.metadata = std::vector<uint8_t>(value, value + metadata_len);
595 value += metadata_len;
596 len -= metadata_len;
597
598 pac_recs.push_back(std::move(rec));
599
600 return len;
601 }
602
ParsePacs(std::vector<struct acs_ac_record> & pac_recs,uint16_t len,const uint8_t * value)603 bool ParsePacs(std::vector<struct acs_ac_record>& pac_recs, uint16_t len, const uint8_t* value) {
604 if (len < kAcsPacDiscoverRspMinLen) {
605 log::error("Wrong len of PAC characteristic ({}!={})", len, kAcsPacDiscoverRspMinLen);
606 return false;
607 }
608
609 uint8_t pac_rec_nb;
610 STREAM_TO_UINT8(pac_rec_nb, value);
611 len -= kAcsPacDiscoverRspMinLen;
612
613 pac_recs.reserve(pac_rec_nb);
614 for (int i = 0; i < pac_rec_nb; i++) {
615 int remaining_len = ParseSinglePac(pac_recs, len, value);
616 if (remaining_len < 0) {
617 return false;
618 }
619
620 value += (len - remaining_len);
621 len = remaining_len;
622 }
623
624 return true;
625 }
626
ParseAudioLocations(types::AudioLocations & audio_locations,uint16_t len,const uint8_t * value)627 bool ParseAudioLocations(types::AudioLocations& audio_locations, uint16_t len,
628 const uint8_t* value) {
629 if (len != kAudioLocationsRspMinLen) {
630 log::error("Wrong len of Audio Location characteristic");
631 return false;
632 }
633
634 STREAM_TO_UINT32(audio_locations, value);
635
636 log::info("Audio locations: {}", audio_locations.to_string());
637
638 return true;
639 }
640
ParseSupportedAudioContexts(types::BidirectionalPair<types::AudioContexts> & contexts,uint16_t len,const uint8_t * value)641 bool ParseSupportedAudioContexts(types::BidirectionalPair<types::AudioContexts>& contexts,
642 uint16_t len, const uint8_t* value) {
643 if (len != kAseAudioSuppContRspMinLen) {
644 log::error("Wrong len of Audio Supported Context characteristic");
645 return false;
646 }
647
648 STREAM_TO_UINT16(contexts.sink.value_ref(), value);
649 STREAM_TO_UINT16(contexts.source.value_ref(), value);
650
651 log::info(
652 "Supported Audio Contexts: \n\tSupported Sink Contexts: {}\n\tSupported "
653 "Source Contexts: {}",
654 contexts.sink.to_string(), contexts.source.to_string());
655
656 return true;
657 }
658
ParseAvailableAudioContexts(types::BidirectionalPair<types::AudioContexts> & contexts,uint16_t len,const uint8_t * value)659 bool ParseAvailableAudioContexts(types::BidirectionalPair<types::AudioContexts>& contexts,
660 uint16_t len, const uint8_t* value) {
661 if (len != kAseAudioAvailRspMinLen) {
662 log::error("Wrong len of Audio Availability characteristic");
663 return false;
664 }
665
666 STREAM_TO_UINT16(contexts.sink.value_ref(), value);
667 STREAM_TO_UINT16(contexts.source.value_ref(), value);
668
669 log::info(
670 "Available Audio Contexts: \n\tAvailable Sink Contexts: {}\n\tAvailable "
671 "Source Contexts: {}",
672 contexts.sink.to_string(), contexts.source.to_string());
673
674 return true;
675 }
676 } // namespace pacs
677
678 namespace tmap {
679
ParseTmapRole(std::bitset<16> & role,uint16_t len,const uint8_t * value)680 bool ParseTmapRole(std::bitset<16>& role, uint16_t len, const uint8_t* value) {
681 if (len != kTmapRoleLen) {
682 log::error(", Wrong len of Telephony Media Audio Profile Role, characteristic");
683 return false;
684 }
685
686 STREAM_TO_UINT16(role, value);
687
688 log::info(", Telephony Media Audio Profile Role:\n\tRole: {}", role.to_string());
689
690 return true;
691 }
692 } // namespace tmap
693
694 } // namespace client_parser
695 } // namespace bluetooth::le_audio
696