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