• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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