1 /******************************************************************************
2 *
3 * Copyright 2022 The Android Open Source Project
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 #include "storage_helper.h"
20
21 #include <bluetooth/log.h>
22
23 #include <algorithm>
24 #include <cstddef>
25 #include <cstdint>
26 #include <limits>
27 #include <tuple>
28 #include <vector>
29
30 #include "client_parser.h"
31 #include "devices.h"
32 #include "le_audio_types.h"
33 #include "stack/include/bt_types.h"
34
35 using bluetooth::le_audio::types::hdl_pair;
36
37 namespace bluetooth::le_audio {
38 static constexpr uint8_t LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC = 0x00;
39 static constexpr uint8_t LEAUDIO_ASE_STORAGE_CURRENT_LAYOUT_MAGIC = 0x00;
40 static constexpr uint8_t LEAUDIO_HANDLES_STORAGE_CURRENT_LAYOUT_MAGIC = 0x00;
41 static constexpr uint8_t LEAUDIO_CODEC_ID_SZ = 5;
42
43 static constexpr size_t LEAUDIO_STORAGE_MAGIC_SZ = sizeof(uint8_t) /* magic is always uint8_t */;
44
45 static constexpr size_t LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ =
46 LEAUDIO_STORAGE_MAGIC_SZ + sizeof(uint8_t); /* num_of_entries */
47
48 static constexpr size_t LEAUDIO_PACS_ENTRY_HDR_SZ =
49 sizeof(uint16_t) /*handle*/ + sizeof(uint16_t) /*ccc handle*/ +
50 sizeof(uint8_t) /* number of pack records in single characteristic */;
51
52 static constexpr size_t LEAUDIO_PACS_ENTRY_SZ =
53 sizeof(uint8_t) /* size of single pac record */ + LEAUDIO_CODEC_ID_SZ /*codec id*/ +
54 sizeof(uint8_t) /*codec capabilities len*/ + sizeof(uint8_t) /*metadata len*/;
55
56 static constexpr size_t LEAUDIO_ASES_ENTRY_SZ =
57 sizeof(uint16_t) /*handle*/ + sizeof(uint16_t) /*ccc handle*/ +
58 sizeof(uint8_t) /*direction*/ + sizeof(uint8_t) /*ase id*/;
59
60 static constexpr size_t LEAUDIO_STORAGE_HANDLES_ENTRIES_SZ =
61 LEAUDIO_STORAGE_MAGIC_SZ + sizeof(uint16_t) /*control point handle*/ +
62 sizeof(uint16_t) /*ccc handle*/ + sizeof(uint16_t) /*sink audio location handle*/ +
63 sizeof(uint16_t) /*ccc handle*/ + sizeof(uint16_t) /*source audio location handle*/ +
64 sizeof(uint16_t) /*ccc handle*/ + sizeof(uint16_t) /*supported context type handle*/ +
65 sizeof(uint16_t) /*ccc handle*/ + sizeof(uint16_t) /*available context type handle*/ +
66 sizeof(uint16_t) /*ccc handle*/ + sizeof(uint16_t) /* tmas handle */;
67
serializePacs(const bluetooth::le_audio::types::PublishedAudioCapabilities & pacs,std::vector<uint8_t> & out)68 static bool serializePacs(const bluetooth::le_audio::types::PublishedAudioCapabilities& pacs,
69 std::vector<uint8_t>& out) {
70 auto num_of_pacs = pacs.size();
71 if (num_of_pacs == 0 || (num_of_pacs > std::numeric_limits<uint8_t>::max())) {
72 log::warn("No pacs available");
73 return false;
74 }
75
76 /* Calculate the total size */
77 auto pac_bin_size = LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ;
78 for (auto pac_tuple : pacs) {
79 auto& pac_recs = std::get<1>(pac_tuple);
80 pac_bin_size += LEAUDIO_PACS_ENTRY_HDR_SZ;
81 for (const auto& pac : pac_recs) {
82 pac_bin_size += LEAUDIO_PACS_ENTRY_SZ;
83 pac_bin_size += pac.metadata.RawPacketSize();
84 pac_bin_size += pac.codec_spec_caps_raw.size();
85 }
86 }
87
88 out.resize(pac_bin_size);
89 auto* ptr = out.data();
90
91 /* header */
92 UINT8_TO_STREAM(ptr, LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC);
93 UINT8_TO_STREAM(ptr, num_of_pacs);
94
95 /* pacs entries */
96 for (auto pac_tuple : pacs) {
97 auto& pac_recs = std::get<1>(pac_tuple);
98 uint16_t handle = std::get<0>(pac_tuple).val_hdl;
99 uint16_t ccc_handle = std::get<0>(pac_tuple).ccc_hdl;
100
101 UINT16_TO_STREAM(ptr, handle);
102 UINT16_TO_STREAM(ptr, ccc_handle);
103 UINT8_TO_STREAM(ptr, pac_recs.size());
104
105 log::verbose("Handle: 0x{:04x}, ccc handle: 0x{:04x}, pac count: {}", handle, ccc_handle,
106 static_cast<int>(pac_recs.size()));
107
108 for (const auto& pac : pac_recs) {
109 /* Pac len */
110 auto pac_len =
111 LEAUDIO_PACS_ENTRY_SZ + pac.codec_spec_caps_raw.size() + pac.metadata.RawPacketSize();
112 log::verbose("Pac size {}", static_cast<int>(pac_len));
113 UINT8_TO_STREAM(ptr, pac_len - 1 /* Minus size */);
114
115 /* Codec ID*/
116 UINT8_TO_STREAM(ptr, pac.codec_id.coding_format);
117 UINT16_TO_STREAM(ptr, pac.codec_id.vendor_company_id);
118 UINT16_TO_STREAM(ptr, pac.codec_id.vendor_codec_id);
119
120 /* Codec caps */
121 log::verbose("Codec capability size {}", static_cast<int>(pac.codec_spec_caps_raw.size()));
122 UINT8_TO_STREAM(ptr, pac.codec_spec_caps_raw.size());
123 if (pac.codec_spec_caps_raw.size() > 0) {
124 ARRAY_TO_STREAM(ptr, pac.codec_spec_caps_raw.data(),
125 static_cast<int>(pac.codec_spec_caps_raw.size()));
126 }
127
128 /* Metadata */
129 auto raw_metadata = pac.metadata.RawPacket();
130 log::verbose("Metadata size {}", static_cast<int>(raw_metadata.size()));
131 UINT8_TO_STREAM(ptr, raw_metadata.size());
132 if (raw_metadata.size() > 0) {
133 ARRAY_TO_STREAM(ptr, raw_metadata.data(), (int)raw_metadata.size());
134 }
135 }
136 }
137 return true;
138 }
139
SerializeSinkPacs(const bluetooth::le_audio::LeAudioDevice * leAudioDevice,std::vector<uint8_t> & out)140 bool SerializeSinkPacs(const bluetooth::le_audio::LeAudioDevice* leAudioDevice,
141 std::vector<uint8_t>& out) {
142 if (leAudioDevice == nullptr) {
143 log::warn("Skipping unknown device");
144 return false;
145 }
146 log::verbose("Device {}, num of PAC characteristics: {}", leAudioDevice->address_,
147 static_cast<int>(leAudioDevice->snk_pacs_.size()));
148 return serializePacs(leAudioDevice->snk_pacs_, out);
149 }
150
SerializeSourcePacs(const bluetooth::le_audio::LeAudioDevice * leAudioDevice,std::vector<uint8_t> & out)151 bool SerializeSourcePacs(const bluetooth::le_audio::LeAudioDevice* leAudioDevice,
152 std::vector<uint8_t>& out) {
153 if (leAudioDevice == nullptr) {
154 log::warn("Skipping unknown device");
155 return false;
156 }
157 log::verbose("Device {}, num of PAC characteristics: {}", leAudioDevice->address_,
158 static_cast<int>(leAudioDevice->src_pacs_.size()));
159 return serializePacs(leAudioDevice->src_pacs_, out);
160 }
161
deserializePacs(LeAudioDevice * leAudioDevice,types::PublishedAudioCapabilities & pacs_db,const std::vector<uint8_t> & in)162 static bool deserializePacs(LeAudioDevice* leAudioDevice,
163 types::PublishedAudioCapabilities& pacs_db,
164 const std::vector<uint8_t>& in) {
165 if (in.size() < LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + LEAUDIO_PACS_ENTRY_SZ) {
166 log::warn("There is not single PACS stored");
167 return false;
168 }
169
170 auto* ptr = in.data();
171
172 uint8_t magic;
173 STREAM_TO_UINT8(magic, ptr);
174
175 if (magic != LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC) {
176 log::error("Invalid magic ({}!={}) for device {}", magic,
177 LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC, leAudioDevice->address_);
178 return false;
179 }
180
181 uint8_t num_of_pacs_chars;
182 STREAM_TO_UINT8(num_of_pacs_chars, ptr);
183
184 if (in.size() <
185 LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + (num_of_pacs_chars * LEAUDIO_PACS_ENTRY_SZ)) {
186 log::error("Invalid persistent storage data for device {}", leAudioDevice->address_);
187 return false;
188 }
189
190 /* pacs entries */
191 while (num_of_pacs_chars--) {
192 struct hdl_pair hdl_pair;
193 uint8_t pac_count;
194
195 STREAM_TO_UINT16(hdl_pair.val_hdl, ptr);
196 STREAM_TO_UINT16(hdl_pair.ccc_hdl, ptr);
197 STREAM_TO_UINT8(pac_count, ptr);
198
199 log::verbose("Handle: 0x{:04x}, ccc handle: 0x{:04x}, pac_count: {}", hdl_pair.val_hdl,
200 hdl_pair.ccc_hdl, pac_count);
201
202 pacs_db.push_back(std::make_tuple(
203 hdl_pair, std::vector<struct bluetooth::le_audio::types::acs_ac_record>()));
204
205 auto hdl = hdl_pair.val_hdl;
206 auto pac_tuple_iter = std::find_if(pacs_db.begin(), pacs_db.end(), [&hdl](auto& pac_ent) {
207 return std::get<0>(pac_ent).val_hdl == hdl;
208 });
209
210 std::vector<struct bluetooth::le_audio::types::acs_ac_record> pac_recs;
211 while (pac_count--) {
212 uint8_t pac_len;
213 STREAM_TO_UINT8(pac_len, ptr);
214 log::verbose("Pac len {}", pac_len);
215
216 if (client_parser::pacs::ParseSinglePac(pac_recs, pac_len, ptr) < 0) {
217 log::error("Cannot parse stored PACs (impossible)");
218 return false;
219 }
220 ptr += pac_len;
221 }
222 leAudioDevice->RegisterPACs(&std::get<1>(*pac_tuple_iter), &pac_recs);
223 }
224
225 return true;
226 }
227
DeserializeSinkPacs(bluetooth::le_audio::LeAudioDevice * leAudioDevice,const std::vector<uint8_t> & in)228 bool DeserializeSinkPacs(bluetooth::le_audio::LeAudioDevice* leAudioDevice,
229 const std::vector<uint8_t>& in) {
230 log::verbose("");
231 if (leAudioDevice == nullptr) {
232 log::warn("Skipping unknown device");
233 return false;
234 }
235 return deserializePacs(leAudioDevice, leAudioDevice->snk_pacs_, in);
236 }
237
DeserializeSourcePacs(bluetooth::le_audio::LeAudioDevice * leAudioDevice,const std::vector<uint8_t> & in)238 bool DeserializeSourcePacs(bluetooth::le_audio::LeAudioDevice* leAudioDevice,
239 const std::vector<uint8_t>& in) {
240 log::verbose("");
241 if (leAudioDevice == nullptr) {
242 log::warn("Skipping unknown device");
243 return false;
244 }
245 return deserializePacs(leAudioDevice, leAudioDevice->src_pacs_, in);
246 }
247
SerializeAses(const bluetooth::le_audio::LeAudioDevice * leAudioDevice,std::vector<uint8_t> & out)248 bool SerializeAses(const bluetooth::le_audio::LeAudioDevice* leAudioDevice,
249 std::vector<uint8_t>& out) {
250 if (leAudioDevice == nullptr) {
251 log::warn("Skipping unknown device");
252 return false;
253 }
254
255 auto num_of_ases = leAudioDevice->ases_.size();
256 log::debug("device: {}, number of ases {}", leAudioDevice->address_,
257 static_cast<int>(num_of_ases));
258
259 if (num_of_ases == 0 || (num_of_ases > std::numeric_limits<uint8_t>::max())) {
260 log::warn("No ases available for device {}", leAudioDevice->address_);
261 return false;
262 }
263
264 /* Calculate the total size */
265 auto ases_bin_size = LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + num_of_ases * LEAUDIO_ASES_ENTRY_SZ;
266 out.resize(ases_bin_size);
267 auto* ptr = out.data();
268
269 /* header */
270 UINT8_TO_STREAM(ptr, LEAUDIO_ASE_STORAGE_CURRENT_LAYOUT_MAGIC);
271 UINT8_TO_STREAM(ptr, num_of_ases);
272
273 /* pacs entries */
274 for (const auto& ase : leAudioDevice->ases_) {
275 log::verbose(
276 "Storing ASE ID: {}, direction {}, handle 0x{:04x}, ccc_handle 0x{:04x}", ase.id,
277 ase.direction == bluetooth::le_audio::types::kLeAudioDirectionSink ? "sink " : "source",
278 ase.hdls.val_hdl, ase.hdls.ccc_hdl);
279
280 UINT16_TO_STREAM(ptr, ase.hdls.val_hdl);
281 UINT16_TO_STREAM(ptr, ase.hdls.ccc_hdl);
282 UINT8_TO_STREAM(ptr, ase.id);
283 UINT8_TO_STREAM(ptr, ase.direction);
284 }
285
286 return true;
287 }
288
DeserializeAses(bluetooth::le_audio::LeAudioDevice * leAudioDevice,const std::vector<uint8_t> & in)289 bool DeserializeAses(bluetooth::le_audio::LeAudioDevice* leAudioDevice,
290 const std::vector<uint8_t>& in) {
291 if (leAudioDevice == nullptr) {
292 log::warn("Skipping unknown device");
293 return false;
294 }
295
296 if (in.size() < LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + LEAUDIO_ASES_ENTRY_SZ) {
297 log::warn("There is not single ASE stored for device {}", leAudioDevice->address_);
298 return false;
299 }
300
301 auto* ptr = in.data();
302
303 uint8_t magic;
304 STREAM_TO_UINT8(magic, ptr);
305
306 if (magic != LEAUDIO_ASE_STORAGE_CURRENT_LAYOUT_MAGIC) {
307 log::error("Invalid magic ({}!={}", magic, LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC);
308 return false;
309 }
310
311 uint8_t num_of_ases;
312 STREAM_TO_UINT8(num_of_ases, ptr);
313
314 if (in.size() < LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + (num_of_ases * LEAUDIO_ASES_ENTRY_SZ)) {
315 log::error("Invalid persistent storage data for device {}", leAudioDevice->address_);
316 return false;
317 }
318
319 log::debug("Loading {} Ases for device {}", num_of_ases, leAudioDevice->address_);
320 /* sets entries */
321 while (num_of_ases--) {
322 uint16_t handle;
323 uint16_t ccc_handle;
324 uint8_t direction;
325 uint8_t ase_id;
326
327 STREAM_TO_UINT16(handle, ptr);
328 STREAM_TO_UINT16(ccc_handle, ptr);
329 STREAM_TO_UINT8(ase_id, ptr);
330 STREAM_TO_UINT8(direction, ptr);
331
332 leAudioDevice->ases_.emplace_back(handle, ccc_handle, direction, ase_id);
333 log::verbose(
334 "Loading ASE ID: {}, direction {}, handle 0x{:04x}, ccc_handle 0x{:04x}", ase_id,
335 direction == bluetooth::le_audio::types::kLeAudioDirectionSink ? "sink " : "source",
336 handle, ccc_handle);
337 }
338
339 return true;
340 }
341
SerializeHandles(const LeAudioDevice * leAudioDevice,std::vector<uint8_t> & out)342 bool SerializeHandles(const LeAudioDevice* leAudioDevice, std::vector<uint8_t>& out) {
343 if (leAudioDevice == nullptr) {
344 log::warn("Skipping unknown device");
345 return false;
346 }
347
348 /* Calculate the total size */
349 out.resize(LEAUDIO_STORAGE_HANDLES_ENTRIES_SZ);
350 auto* ptr = out.data();
351
352 /* header */
353 UINT8_TO_STREAM(ptr, LEAUDIO_HANDLES_STORAGE_CURRENT_LAYOUT_MAGIC);
354
355 if (leAudioDevice->ctp_hdls_.val_hdl == 0 || leAudioDevice->ctp_hdls_.ccc_hdl == 0) {
356 log::warn("Invalid control point handles for device {}", leAudioDevice->address_);
357 return false;
358 }
359
360 UINT16_TO_STREAM(ptr, leAudioDevice->ctp_hdls_.val_hdl);
361 UINT16_TO_STREAM(ptr, leAudioDevice->ctp_hdls_.ccc_hdl);
362
363 UINT16_TO_STREAM(ptr, leAudioDevice->audio_locations_.sink
364 ? leAudioDevice->audio_locations_.sink->handles.val_hdl
365 : 0);
366 UINT16_TO_STREAM(ptr, leAudioDevice->audio_locations_.sink
367 ? leAudioDevice->audio_locations_.sink->handles.ccc_hdl
368 : 0);
369
370 UINT16_TO_STREAM(ptr, leAudioDevice->audio_locations_.source
371 ? leAudioDevice->audio_locations_.source->handles.val_hdl
372 : 0);
373 UINT16_TO_STREAM(ptr, leAudioDevice->audio_locations_.source
374 ? leAudioDevice->audio_locations_.source->handles.ccc_hdl
375 : 0);
376
377 UINT16_TO_STREAM(ptr, leAudioDevice->audio_supp_cont_hdls_.val_hdl);
378 UINT16_TO_STREAM(ptr, leAudioDevice->audio_supp_cont_hdls_.ccc_hdl);
379
380 UINT16_TO_STREAM(ptr, leAudioDevice->audio_avail_hdls_.val_hdl);
381 UINT16_TO_STREAM(ptr, leAudioDevice->audio_avail_hdls_.ccc_hdl);
382
383 UINT16_TO_STREAM(ptr, leAudioDevice->tmap_role_hdl_);
384
385 return true;
386 }
387
DeserializeHandles(LeAudioDevice * leAudioDevice,const std::vector<uint8_t> & in)388 bool DeserializeHandles(LeAudioDevice* leAudioDevice, const std::vector<uint8_t>& in) {
389 if (leAudioDevice == nullptr) {
390 log::warn("Skipping unknown device");
391 return false;
392 }
393
394 if (in.size() != LEAUDIO_STORAGE_HANDLES_ENTRIES_SZ) {
395 log::warn("There is not single ASE stored for device {}", leAudioDevice->address_);
396 return false;
397 }
398
399 auto* ptr = in.data();
400
401 uint8_t magic;
402 STREAM_TO_UINT8(magic, ptr);
403
404 if (magic != LEAUDIO_HANDLES_STORAGE_CURRENT_LAYOUT_MAGIC) {
405 log::error("Invalid magic ({}!={}) for device {}", magic,
406 LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC, leAudioDevice->address_);
407 return false;
408 }
409
410 STREAM_TO_UINT16(leAudioDevice->ctp_hdls_.val_hdl, ptr);
411 STREAM_TO_UINT16(leAudioDevice->ctp_hdls_.ccc_hdl, ptr);
412 log::verbose("ctp.val_hdl: 0x{:04x}, ctp.ccc_hdl: 0x{:04x}", leAudioDevice->ctp_hdls_.val_hdl,
413 leAudioDevice->ctp_hdls_.ccc_hdl);
414
415 uint16_t val_hdl, ccc_hdl;
416 STREAM_TO_UINT16(val_hdl, ptr);
417 STREAM_TO_UINT16(ccc_hdl, ptr);
418 log::verbose(
419 "snk_audio_locations_hdls_.val_hdl: 0x{:04x},snk_audio_locations_hdls_.ccc_hdl: 0x{:04x}",
420 val_hdl, ccc_hdl);
421 if (val_hdl) {
422 leAudioDevice->audio_locations_.sink.emplace(hdl_pair(val_hdl, ccc_hdl),
423 types::AudioLocations(0));
424 }
425
426 STREAM_TO_UINT16(val_hdl, ptr);
427 STREAM_TO_UINT16(ccc_hdl, ptr);
428 log::verbose(
429 "src_audio_locations_hdls_.val_hdl: 0x{:04x},src_audio_locations_hdls_.ccc_hdl: 0x{:04x}",
430 val_hdl, ccc_hdl);
431 if (val_hdl) {
432 leAudioDevice->audio_locations_.source.emplace(hdl_pair(val_hdl, ccc_hdl),
433 types::AudioLocations(0));
434 }
435
436 STREAM_TO_UINT16(leAudioDevice->audio_supp_cont_hdls_.val_hdl, ptr);
437 STREAM_TO_UINT16(leAudioDevice->audio_supp_cont_hdls_.ccc_hdl, ptr);
438 log::verbose("audio_supp_cont_hdls_.val_hdl: 0x{:04x},audio_supp_cont_hdls_.ccc_hdl: 0x{:04x}",
439 leAudioDevice->audio_supp_cont_hdls_.val_hdl,
440 leAudioDevice->audio_supp_cont_hdls_.ccc_hdl);
441
442 STREAM_TO_UINT16(leAudioDevice->audio_avail_hdls_.val_hdl, ptr);
443 STREAM_TO_UINT16(leAudioDevice->audio_avail_hdls_.ccc_hdl, ptr);
444 log::verbose("audio_avail_hdls_.val_hdl: 0x{:04x},audio_avail_hdls_.ccc_hdl: 0x{:04x}",
445 leAudioDevice->audio_avail_hdls_.val_hdl, leAudioDevice->audio_avail_hdls_.ccc_hdl);
446
447 STREAM_TO_UINT16(leAudioDevice->tmap_role_hdl_, ptr);
448 log::verbose("tmap_role_hdl_: 0x{:04x}", leAudioDevice->tmap_role_hdl_);
449
450 leAudioDevice->known_service_handles_ = true;
451 return true;
452 }
453
454 static constexpr uint8_t LEAUDIO_GMAP_STORAGE_V1_LAYOUT_MAGIC = 0x01;
455 static constexpr uint8_t LEAUDIO_GMAP_STORAGE_V1_LAYOUT_SZ = 7;
456 static constexpr uint8_t LEAUDIO_GMAP_STORAGE_CURRENT_LAYOUT_MAGIC =
457 LEAUDIO_GMAP_STORAGE_V1_LAYOUT_MAGIC;
458
SerializeGmapV1(const GmapClient * gmapClient,std::vector<uint8_t> & out)459 static bool SerializeGmapV1(const GmapClient* gmapClient, std::vector<uint8_t>& out) {
460 if (gmapClient == nullptr) {
461 log::warn("GMAP client not available");
462 return false;
463 }
464
465 /* The total size */
466 out.resize(LEAUDIO_GMAP_STORAGE_V1_LAYOUT_SZ);
467 auto* ptr = out.data();
468
469 /* header */
470 UINT8_TO_STREAM(ptr, LEAUDIO_GMAP_STORAGE_V1_LAYOUT_MAGIC);
471
472 /* handles */
473 UINT16_TO_STREAM(ptr, gmapClient->getRoleHandle());
474 UINT16_TO_STREAM(ptr, gmapClient->getUGTFeatureHandle());
475
476 /* role & features */
477 UINT8_TO_STREAM(ptr, gmapClient->getRole().to_ulong());
478 UINT8_TO_STREAM(ptr, gmapClient->getUGTFeature().to_ulong());
479
480 return true;
481 }
482
SerializeGmap(const GmapClient * gmapClient,std::vector<uint8_t> & out)483 bool SerializeGmap(const GmapClient* gmapClient, std::vector<uint8_t>& out) {
484 if (gmapClient == nullptr) {
485 log::warn("GMAP client not available");
486 return false;
487 }
488
489 if (LEAUDIO_GMAP_STORAGE_CURRENT_LAYOUT_MAGIC == LEAUDIO_GMAP_STORAGE_V1_LAYOUT_MAGIC) {
490 return SerializeGmapV1(gmapClient, out);
491 }
492
493 log::warn("Invalid GMAP storage magic number {}", +LEAUDIO_GMAP_STORAGE_CURRENT_LAYOUT_MAGIC);
494 }
495
DeserializeGmapV1(GmapClient * gmapClient,const std::vector<uint8_t> & in)496 bool DeserializeGmapV1(GmapClient* gmapClient, const std::vector<uint8_t>& in) {
497 if (in.size() != LEAUDIO_GMAP_STORAGE_V1_LAYOUT_SZ) {
498 log::warn("Invalid storage size for GMAP data. Got {}, expected {}", in.size(),
499 +LEAUDIO_GMAP_STORAGE_V1_LAYOUT_SZ);
500 return false;
501 }
502
503 // Skip the magic number
504 auto* ptr = in.data() + 1;
505
506 /* handles */
507 uint16_t role_handle, ugt_feature_handle;
508 STREAM_TO_UINT16(role_handle, ptr);
509 STREAM_TO_UINT16(ugt_feature_handle, ptr);
510
511 uint8_t role, ugt_feature;
512 STREAM_TO_UINT8(role, ptr);
513 STREAM_TO_UINT8(ugt_feature, ptr);
514
515 gmapClient->AddFromStorage(role, role_handle, ugt_feature, ugt_feature_handle);
516 return true;
517 }
518
DeserializeGmap(GmapClient * gmapClient,const std::vector<uint8_t> & in)519 bool DeserializeGmap(GmapClient* gmapClient, const std::vector<uint8_t>& in) {
520 if (gmapClient == nullptr) {
521 log::warn("GMAP client not available");
522 return false;
523 }
524
525 if (in.size() < 1) {
526 log::warn("GMAP storage is not available");
527 return false;
528 }
529
530 auto* ptr = in.data();
531 uint8_t magic;
532 STREAM_TO_UINT8(magic, ptr);
533
534 if (magic == LEAUDIO_GMAP_STORAGE_V1_LAYOUT_MAGIC) {
535 return DeserializeGmapV1(gmapClient, in);
536 }
537
538 log::warn("Invalid GMAP storage magic number. Got {}, current {}", +magic,
539 +LEAUDIO_GMAP_STORAGE_CURRENT_LAYOUT_MAGIC);
540 return false;
541 }
542
543 } // namespace bluetooth::le_audio
544