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