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