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