1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ANDROID_AUDIO_METADATA_H
18 #define ANDROID_AUDIO_METADATA_H
19
20 #include <stdint.h>
21 #include <sys/cdefs.h>
22 #include <unistd.h>
23
24 #ifdef __cplusplus
25
26 #include "template_utils.h"
27
28 #include <algorithm>
29 #include <any>
30 #include <map>
31 #include <string>
32 #include <tuple>
33 #include <vector>
34
35 /**
36 * Audio Metadata: a C++ Object based map.
37 *
38 * Data is a map of strings to Datum Objects.
39 *
40 * Datum is a C++ "Object", a direct instance of std::any, but limited
41 * to only the following allowed types:
42 *
43 * Native Java equivalent
44 * int32 (int)
45 * int64 (long)
46 * float (float)
47 * double (double)
48 * std::string (String)
49 * Data (std::map<std::string, Datum>) (Map<String, Object>)
50 *
51 * Metadata code supports advanced automatic parceling.
52 * TEST ONLY:
53 * std::vector<Datum> (Object[]) --> vector of Objects
54 * std::pair<Datum, Datum> (Pair<Object, Object>) --> pair of Objects
55 * std::vector<std::vector<std::pair<std::string, short>>> --> recursive containers
56 * struct { int i0; std::vector<int> v1; std::pair<int, int> p2; } --> struct parceling
57 *
58 * The Data map accepts typed Keys, which designate the type T of the
59 * value associated with the Key<T> in the template parameter.
60 *
61 * CKey<T> is the constexpr version suitable for fixed compile-time constants.
62 * Key<T> is the non-constexpr version.
63 *
64 * Notes: for future extensibility:
65 *
66 * In order to add a new type in.
67 *
68 * 1) Add the new type to the END of the metadata_types lists below.
69 *
70 * 2) The new type can be a primitive, or make use of containers std::map, std::vector,
71 * std::pair, or be simple structs (see below).
72 *
73 * 3) Simple structs contain no pointers and all public data. The members can be based
74 * on existing types.
75 * a) If trivially copyable (packed) primitive data,
76 * add to primitive_metadata_types.
77 * b) If the struct requires member-wise parceling, add to structural_metadata_types
78 * (current limit is 4 members).
79 *
80 * 4) The type system is recursive.
81 *
82 * Design notes:
83 * 1) Tuple is intentionally not implemented as it isn't that readable. This can
84 * be revisited if the need comes up. If you have more than a couple of elements,
85 * we suggest embedding in a Data typed map or a Simple struct.
86 *
87 * 2) Each custom type e.g. vector<int>, pair<short, char> takes one
88 * slot in the type index. A full type description language is not implemented
89 * here for brevity and clarity.
90 */
91
92 namespace android::audio_utils::metadata {
93
94 using android::audio_utils::is_specialization_v;
95 using android::audio_utils::is_braces_constructible;
96
97 // Set up type comparison system
98 // see std::variant for the how the type_index() may be used.
99
100 /*
101 * returns the index of type T in the type parameter list Ts.
102 */
103 template <typename T, typename... Ts>
type_index()104 inline constexpr ssize_t type_index() {
105 constexpr bool checks[] = {std::is_same_v<std::decay_t<T>, std::decay_t<Ts>>...};
106 for (size_t i = 0; i < sizeof...(Ts); ++i) {
107 if (checks[i]) return i; // the index in Ts.
108 }
109 return -1; // none found.
110 }
111
112 // compound_type is a holder of types. There are concatenation tricks of type lists
113 // but we don't need them here.
114 template <typename... Ts>
115 struct compound_type {
116 inline static constexpr size_t size_v = sizeof...(Ts);
117 template <typename T>
118 inline static constexpr bool contains_v = type_index<T, Ts...>() >= 0;
119 template <typename T>
index_ofcompound_type120 inline static constexpr ssize_t index_of() { return type_index<T, Ts...>(); }
121
122 // create a tupe equivalent of the compound type. This is useful for
123 // finding the nth type by std::tuple_element
124 using tuple_t = std::tuple<Ts...>;
125
126 /**
127 * Applies function f to a datum pointer a.
128 *
129 * \param f is the function to apply. It should take one argument,
130 * which is a (typed) pointer to the value stored in a.
131 * \param a is the Datum object (derived from std::any).
132 * \param result if non-null stores the return value of f (if f has a return value).
133 * result may be nullptr if one does not care about the return value of f.
134 * \return true on success, false if there is no applicable data stored in a.
135 */
136 template <typename F, typename A>
137 static bool apply(F f, A *a, std::any *result = nullptr) {
138 return apply_impl<F, A, Ts...>(f, a, result);
139 }
140
141 // helper
142 // Linear search in the number of types because of non-cached std:any_cast
143 // lookup. See std::visit for std::variant for constant time implementation.
144 template <typename F, typename A, typename T, typename... Ts2>
apply_implcompound_type145 static bool apply_impl(F f, A *a, std::any *result) {
146 auto t = std::any_cast<T>(a); // may be const ptr or not.
147 if (t == nullptr) {
148 return apply_impl<F, A, Ts2...>(f, a, result);
149 }
150
151 // only save result if the function has a non-void return type.
152 // and result is not nullptr.
153 using result_type = std::invoke_result_t<F, T*>;
154 if constexpr (!std::is_same_v<result_type, void>) {
155 if (result != nullptr) {
156 *result = (result_type)f(t);
157 return true;
158 }
159 }
160
161 f(t); // discard the result
162 return true;
163 }
164
165 // helper base class
166 template <typename F, typename A>
apply_implcompound_type167 static bool apply_impl(F f __attribute__((unused)), A *a __attribute__((unused)),
168 std::any *result __attribute__((unused))) {
169 return false;
170 }
171 };
172
173 #ifdef METADATA_TESTING
174
175 // This is a helper struct to verify that we are moving Datums instead
176 // of copying them.
177 struct MoveCount {
178 int32_t mMoveCount = 0;
179 int32_t mCopyCount = 0;
180
181 MoveCount() = default;
MoveCountMoveCount182 MoveCount(MoveCount&& other) {
183 mMoveCount = other.mMoveCount + 1;
184 mCopyCount = other.mCopyCount;
185 }
MoveCountMoveCount186 MoveCount(const MoveCount& other) {
187 mMoveCount = other.mMoveCount;
188 mCopyCount = other.mCopyCount + 1;
189 }
190 MoveCount &operator=(MoveCount&& other) {
191 mMoveCount = other.mMoveCount + 1;
192 mCopyCount = other.mCopyCount;
193 return *this;
194 }
195 MoveCount &operator=(const MoveCount& other) {
196 mMoveCount = other.mMoveCount;
197 mCopyCount = other.mCopyCount + 1;
198 return *this;
199 }
200 };
201
202 // We can automatically parcel this "Arbitrary" struct
203 // since it has no pointers and all public members.
204 struct Arbitrary {
205 int i0;
206 std::vector<int> v1;
207 std::pair<int, int> p2;
208 };
209
210 #endif
211
212 class Data;
213 class Datum;
214
215 // The order of this list must be maintained for binary compatibility
216 using metadata_types = compound_type<
217 int32_t,
218 int64_t,
219 float,
220 double,
221 std::string,
222 Data /* std::map<std::string, Datum> */
223 // OK to add at end.
224 #ifdef METADATA_TESTING
225 , std::vector<Datum> // another complex object for testing
226 , std::pair<Datum, Datum> // another complex object for testing
227 , std::vector<std::vector<std::pair<std::string, short>>> // complex object
228 , MoveCount
229 , Arbitrary
230 #endif
231 >;
232
233 // A subset of the metadata types may be directly copied as bytes
234 using primitive_metadata_types = compound_type<int32_t, int64_t, float, double
235 #ifdef METADATA_TESTING
236 , MoveCount
237 #endif
238 >;
239
240 // A subset of metadata types which are a struct-based.
241 using structural_metadata_types = compound_type<
242 #ifdef METADATA_TESTING
243 Arbitrary
244 #endif
245 >;
246
247 template <typename T>
248 inline constexpr bool is_primitive_metadata_type_v =
249 primitive_metadata_types::contains_v<T>;
250
251 template <typename T>
252 inline constexpr bool is_structural_metadata_type_v =
253 structural_metadata_types::contains_v<T>;
254
255 template <typename T>
256 inline constexpr bool is_metadata_type_v =
257 metadata_types::contains_v<T>;
258
259 /**
260 * Datum is the C++ version of Object, based on std::any
261 * to be portable to other Data Object systems on std::any. For C++, there
262 * are two forms of generalized Objects, std::variant and std::any.
263 *
264 * What is a variant?
265 * std::variant is like a std::pair<type_index, union>, where the types
266 * are kept in the template parameter list, and you only need to store
267 * the type_index of the current value's type in the template parameter
268 * list to find the value's type (to access data in the union).
269 *
270 * What is an any?
271 * std::any is a std::pair<type_func, pointer> (though the standard encourages
272 * small buffer optimization of the pointer for small data types,
273 * so the pointer might actually be data). The type_func is cleverly
274 * implemented templated, so that one type_func exists per type.
275 *
276 * For datum, we use std::any, which is different than mediametrics::Item
277 * (which uses std::variant).
278 *
279 * std::any is the C++ version of Java's Object. One benefit of std::any
280 * over std::variant is that it is portable outside of this package as a
281 * std::any, to another C++ Object system based on std::any
282 * (as we any_cast to discover the type). std::variant does not have this
283 * portability (without copy conversion) because it requires an explicit
284 * type list to be known in the template, so you can't exchange them freely
285 * as the union size and the type/type ordering will be different in general
286 * between two variant-based Object systems.
287 *
288 * std::any may work better with some recursive types than variants,
289 * as it uses pointers so that physical size need not be known for type
290 * definition.
291 *
292 * This is a design choice: mediametrics::Item as a closed system,
293 * metadata::Datum as an open system.
294 *
295 * CAUTION:
296 * For efficiency, prefer the use of std::any_cast<T>(std::any *)
297 * which returns a pointer to T (no extra copies.)
298 *
299 * std::any_cast<T>(std::any) returns an instance of T (copy constructor).
300 * std::get<N>(std::variant) returns a reference (no extra copies).
301 *
302 * The Data map operations are optimized to return references to
303 * avoid unnecessary copies.
304 */
305
306 class Datum : public std::any {
307 public:
308 // Don't add any virtual functions or non-static member variables.
309
310 Datum() = default;
311
312 // Do not make these explicit
313 // Force type of std::any to exactly the values we permit to be parceled.
314 template <typename T, typename = std::enable_if_t<is_metadata_type_v<T>>>
Datum(T && t)315 Datum(T && t) : std::any(std::forward<T>(t)) {};
316
317 template <typename T, typename = std::enable_if_t<is_metadata_type_v<T>>>
318 Datum& operator=(T&& t) {
319 static_cast<std::any *>(this)->operator=(std::forward<T>(t));
320 return *this;
321 }
322
Datum(const char * t)323 Datum(const char *t) : std::any(std::string(t)) {}; // special string handling
324 };
325
326 // PREVENT INCORRECT MODIFICATIONS
327 // Datum is a helping wrapper on std::any
328 // Don't add any non-static members
329 static_assert(sizeof(Datum) == sizeof(std::any));
330 // Nothing is virtual
331 static_assert(!std::is_polymorphic_v<Datum>);
332
333 /**
334 * Keys
335 *
336 * Audio Metadata keys are typed. Similar to variant's template typenames,
337 * which directly indicate possible types in the union, the Audio Metadata
338 * Keys contain the Value's Type in the Key's template type parameter.
339 *
340 * Example:
341 *
342 * inline constexpr CKey<int64_t> MY_BIGINT("bigint_is_mine");
343 * inline constexpr CKey<Data> TABLE("table");
344 *
345 * Thus if we have a Data object d:
346 *
347 * decltype(d[TABLE]) is Data
348 * decltype(d[MY_BIGINT) is int64_t
349 */
350
351 /**
352 * Key is a non-constexpr key which has local storage in a string.
353 */
354 template <typename T, typename = std::enable_if_t<is_metadata_type_v<T>>>
355 class Key : private std::string {
356 public:
357 using std::string::string; // base constructor
getName()358 const char *getName() const { return c_str(); }
359 };
360
361 /**
362 * CKey is a constexpr key, which is preferred.
363 *
364 * inline constexpr CKey<int64_t> MY_BIGINT("bigint_is_mine");
365 */
366 template <typename T, typename = std::enable_if_t<is_metadata_type_v<T>>>
367 class CKey {
368 const char * const mName;
369 public:
CKey(const char * name)370 explicit constexpr CKey(const char *name) : mName(name) {}
CKey(const Key<T> & key)371 CKey(const Key<T> &key) : mName(key.getName()) {}
getName()372 const char *getName() const { return mName; }
373 };
374
375 /**
376 * Data is the storage for our Datums.
377 *
378 * It is implemented on top of std::map<std::string, Datum>
379 * but we augment it with typed Key
380 * getters and setters, as well as operator[] overloads.
381 */
382 class Data : public std::map<std::string, Datum> {
383 public:
384 // Don't add any virtual functions or non-static member variables.
385
386 // We supplement the raw form of map with
387 // the following typed form using Key.
388
389 // Intentionally there is no get(), we suggest *get_ptr()
390 template <template <typename /* T */, typename... /* enable-ifs */> class K, typename T>
391 T* get_ptr(const K<T>& key, bool allocate = false) {
392 auto it = find(key.getName());
393 if (it == this->end()) {
394 if (!allocate) return nullptr;
395 it = emplace(key.getName(), T{}).first;
396 }
397 return std::any_cast<T>(&it->second);
398 }
399
400 template <template <typename, typename...> class K, typename T>
get_ptr(const K<T> & key)401 const T* get_ptr(const K<T>& key) const {
402 auto it = find(key.getName());
403 if (it == this->end()) return nullptr;
404 return std::any_cast<T>(&it->second);
405 }
406
407 template <template <typename, typename...> class K, typename T>
put(const K<T> & key,T && t)408 void put(const K<T>& key, T && t) {
409 (*this)[key.getName()] = std::forward<T>(t);
410 }
411
412 template <template <typename, typename...> class K>
put(const K<std::string> & key,const char * value)413 void put(const K<std::string>& key, const char *value) {
414 (*this)[key.getName()] = value;
415 }
416
417 // We overload our operator[] so we unhide the one in the base class.
418 using std::map<std::string, Datum>::operator[];
419
420 template <template <typename, typename...> class K, typename T>
421 T& operator[](const K<T> &key) {
422 return *get_ptr(key, /* allocate */ true);
423 }
424
425 template <template <typename, typename...> class K, typename T>
426 const T& operator[](const K<T> &key) const {
427 return *get_ptr(key);
428 }
429 };
430
431 // PREVENT INCORRECT MODIFICATIONS
432 // Data is a helping wrapper on std::map
433 // Don't add any non-static members
434 static_assert(sizeof(Data) == sizeof(std::map<std::string, Datum>));
435 // Nothing is virtual
436 static_assert(!std::is_polymorphic_v<Data>);
437
438 /**
439 * Parceling of Datum by recursive descent to a ByteString
440 *
441 * Parceling Format:
442 * All values are native endian order.
443 *
444 * Datum = {
445 * (type_size_t) Type (the type index from type_as_value<T>.)
446 * (datum_size_t) Size (size of Payload)
447 * (byte string) Payload<Type>
448 * }
449 *
450 * Payload<Primitive_Type> = { bytes in native endian order }
451 *
452 * Payload<String> = { (index_size_t) number of elements (not including zero termination)
453 * bytes of string data.
454 * }
455 *
456 * Vector, Map, Container types:
457 * Payload<Type> = { (index_size_t) number of elements
458 * (byte string) Payload<Element_Type> * number
459 * }
460 *
461 * Pair container types:
462 * Payload<Type> = { (byte string) Payload<first>,
463 * (byte string) Payload<second>
464 * }
465 *
466 * Note: Data is a std::map<std::string, Datum>
467 *
468 * Design notes:
469 *
470 * 1) The size of each datum allows skipping of unknown types for compatibility
471 * of older code with newer Datums.
472 *
473 * Examples:
474 * Payload<Int32> of 123
475 * [ value of 123 ] = 0x7b 0x00 0x00 0x00 123
476 *
477 * Example of Payload<String> of std::string("hi"):
478 * [ (index_size_t) length ] = 0x02 0x00 0x00 0x00 2 strlen("hi")
479 * [ raw bytes "hi" ] = 0x68 0x69 "hi"
480 *
481 * Payload<Data>
482 * [ (index_size_t) entries ]
483 * [ raw bytes (entry 1) Key (Payload<String>)
484 * Value (Datum)
485 * ... (until #entries) ]
486 *
487 * Example of Payload<Data> of {{"hello", "world"},
488 * {"value", (int32_t)1000}};
489 * [ (index_size_t) #entries ] = 0x02 0x00 0x00 0x00 2 entries
490 * Key (Payload<String>)
491 * [ index_size_t length ] = 0x05 0x00 0x00 0x00 5 strlen("hello")
492 * [ raw bytes "hello" ] = 0x68 0x65 0x6c 0x6c 0x6f "hello"
493 * Value (Datum)
494 * [ (type_size_t) type ] = 0x05 0x00 0x00 0x00 5 (TYPE_STRING)
495 * [ (datum_size_t) size ] = 0x09 0x00 0x00 0x00 sizeof(index_size_t) +
496 * strlen("world")
497 * Payload<String>
498 * [ (index_size_t) length ] = 0x05 0x00 0x00 0x00 5 strlen("world")
499 * [ raw bytes "world" ] = 0x77 0x6f 0x72 0x6c 0x64 "world"
500 * Key (Payload<String>)
501 * [ index_size_t length ] = 0x05 0x00 0x00 0x00 5 strlen("value")
502 * [ raw bytes "value" ] = 0x76 0x61 0x6c 0x75 0x65 "value"
503 * Value (Datum)
504 * [ (type_size_t) type ] = 0x01 0x00 0x00 0x00 1 (TYPE_INT32)
505 * [ (datum_size_t) size ] = 0x04 0x00 0x00 0x00 4 sizeof(int32_t)
506 * Payload<Int32>
507 * [ raw bytes 1000 ] = 0xe8 0x03 0x00 0x00 1000
508 *
509 * Metadata is passed as a Payload<Data>.
510 * An implementation dependent detail is that the Keys are always
511 * stored sorted, so the byte string representation generated is unique.
512 */
513
514 // Platform Apex compatibility note:
515 // type_size_t may not change.
516 using type_size_t = uint32_t;
517
518 // Platform Apex compatibility note:
519 // index_size_t must not change.
520 using index_size_t = uint32_t;
521
522 // Platform Apex compatibility note:
523 // datum_size_t must not change.
524 using datum_size_t = uint32_t;
525
526 // The particular implementation of ByteString may change
527 // without affecting compatibility.
528 using ByteString = std::vector<uint8_t>;
529
530 /*
531 These should correspond to the Java AudioMetadata.java
532
533 Permitted type indexes:
534
535 TYPE_NONE = 0,
536 TYPE_INT32 = 1,
537 TYPE_INT64 = 2,
538 TYPE_FLOAT = 3,
539 TYPE_DOUBLE = 4,
540 TYPE_STRING = 5,
541 TYPE_DATA = 6,
542 */
543
544 template <typename T>
get_type_as_value()545 inline constexpr type_size_t get_type_as_value() {
546 return (type_size_t)(metadata_types::index_of<T>() + 1);
547 }
548
549 template <typename T>
550 inline constexpr type_size_t type_as_value = get_type_as_value<T>();
551
552 // forward decl for recursion - do not remove.
553 bool copyToByteString(const Datum& datum, ByteString &bs);
554
555 template <template <typename ...> class V, typename... Args>
556 bool copyToByteString(const V<Args...>& v, ByteString&bs);
557 // end forward decl
558
559 // primitives handled here
560 template <typename T>
561 std::enable_if_t<
562 is_primitive_metadata_type_v<T> || std::is_arithmetic_v<std::decay_t<T>>,
563 bool
564 >
copyToByteString(const T & t,ByteString & bs)565 copyToByteString(const T& t, ByteString& bs) {
566 bs.insert(bs.end(), (uint8_t*)&t, (uint8_t*)&t + sizeof(t));
567 return true;
568 }
569
570 // pairs handled here
571 template <typename A, typename B>
copyToByteString(const std::pair<A,B> & p,ByteString & bs)572 bool copyToByteString(const std::pair<A, B>& p, ByteString& bs) {
573 return copyToByteString(p.first, bs) && copyToByteString(p.second, bs);
574 }
575
576 // containers
577 template <template <typename ...> class V, typename... Args>
copyToByteString(const V<Args...> & v,ByteString & bs)578 bool copyToByteString(const V<Args...>& v, ByteString& bs) {
579 if (v.size() > std::numeric_limits<index_size_t>::max()) return false;
580 index_size_t size = v.size();
581 if (!copyToByteString(size, bs)) return false;
582 if constexpr (std::is_same_v<std::decay_t<V<Args...>>, std::string>) {
583 bs.insert(bs.end(), (uint8_t*)v.c_str(), (uint8_t*)v.c_str() + v.size());
584 } else /* constexpr */ {
585 for (const auto &d : v) { // handles std::vector and std::map
586 if (!copyToByteString(d, bs)) return false;
587 }
588 }
589 return true;
590 }
591
592 // simple struct data (use structured binding to extract members)
593 template <typename T>
594 std::enable_if_t<
595 is_structural_metadata_type_v<T>,
596 bool
597 >
copyToByteString(const T & t,ByteString & bs)598 copyToByteString(const T& t, ByteString& bs) {
599 using type = std::decay_t<T>;
600 if constexpr (is_braces_constructible<type, any_type, any_type, any_type, any_type>{}) {
601 const auto& [e1, e2, e3, e4] = t;
602 return copyToByteString(e1, bs)
603 && copyToByteString(e2, bs)
604 && copyToByteString(e3, bs)
605 && copyToByteString(e4, bs);
606 } else if constexpr (is_braces_constructible<type, any_type, any_type, any_type>{}) {
607 const auto& [e1, e2, e3] = t;
608 return copyToByteString(e1, bs)
609 && copyToByteString(e2, bs)
610 && copyToByteString(e3, bs);
611 } else if constexpr (is_braces_constructible<type, any_type, any_type>{}) {
612 const auto& [e1, e2] = t;
613 return copyToByteString(e1, bs)
614 && copyToByteString(e2, bs);
615 } else if constexpr(is_braces_constructible<type, any_type>{}) {
616 const auto& [e1] = t;
617 return copyToByteString(e1, bs);
618 } else if constexpr (is_braces_constructible<type>{}) {
619 return true; // like std::monostate - no members
620 } else /* constexpr */ {
621 static_assert(dependent_false_v<T>);
622 }
623 }
624
625 // TODO Consider moving to .cpp, but one advantage of keeping in the header
626 // is that C++ invocations don't need to link with the shared library.
627
628 // Datum
629 inline
copyToByteString(const Datum & datum,ByteString & bs)630 bool copyToByteString(const Datum& datum, ByteString &bs) {
631 bool success = false;
632 return metadata_types::apply([&bs, &success](auto ptr) {
633 // save type
634 const type_size_t type = type_as_value<decltype(*ptr)>;
635 if (!copyToByteString(type, bs)) return;
636
637 // get current location
638 const size_t idx = bs.size();
639
640 // save size (replaced later)
641 datum_size_t datum_size = 0;
642 if (!copyToByteString(datum_size, bs)) return;
643
644 // copy data
645 if (!copyToByteString(*ptr, bs)) return;
646
647 // save correct size
648 const size_t diff = bs.size() - idx - sizeof(datum_size);
649 if (diff > std::numeric_limits<datum_size_t>::max()) return;
650 datum_size = diff;
651 std::copy((uint8_t*)&datum_size, (uint8_t*)&datum_size + sizeof(datum_size),
652 bs.begin() + idx);
653 success = true;
654 }, &datum) && success;
655 }
656
657 /**
658 * Obtaining the Datum back from ByteString
659 */
660
661 // A container that lists all the unknown types found during parsing.
662 using ByteStringUnknowns = std::vector<type_size_t>;
663
664 // forward decl for recursion - do not remove.
665 bool copyFromByteString(Datum *datum, const ByteString &bs, size_t& idx,
666 ByteStringUnknowns *unknowns);
667
668 template <template <typename ...> class V, typename... Args>
669 bool copyFromByteString(V<Args...> *v, const ByteString& bs, size_t& idx,
670 ByteStringUnknowns *unknowns);
671
672 // primitive
673 template <typename T>
674 std::enable_if_t<
675 is_primitive_metadata_type_v<T> ||
676 std::is_arithmetic_v<std::decay_t<T>>,
677 bool
678 >
copyFromByteString(T * dest,const ByteString & bs,size_t & idx,ByteStringUnknowns * unknowns)679 copyFromByteString(T *dest, const ByteString& bs, size_t& idx,
680 ByteStringUnknowns *unknowns __attribute__((unused))) {
681 if (idx + sizeof(T) > bs.size()) return false;
682 std::copy(bs.begin() + idx, bs.begin() + idx + sizeof(T), (uint8_t*)dest);
683 idx += sizeof(T);
684 return true;
685 }
686
687 // pairs
688 template <typename A, typename B>
copyFromByteString(std::pair<A,B> * p,const ByteString & bs,size_t & idx,ByteStringUnknowns * unknowns)689 bool copyFromByteString(std::pair<A, B>* p, const ByteString& bs, size_t& idx,
690 ByteStringUnknowns *unknowns) {
691 return copyFromByteString(&p->first, bs, idx, unknowns)
692 && copyFromByteString(&p->second, bs, idx, unknowns);
693 }
694
695 // containers
696 template <template <typename ...> class V, typename... Args>
copyFromByteString(V<Args...> * v,const ByteString & bs,size_t & idx,ByteStringUnknowns * unknowns)697 bool copyFromByteString(V<Args...> *v, const ByteString& bs, size_t& idx,
698 ByteStringUnknowns *unknowns) {
699 index_size_t size;
700 if (!copyFromByteString(&size, bs, idx, unknowns)) return false;
701
702 if constexpr (std::is_same_v<std::decay_t<V<Args...>>, std::string>) {
703 if (size > bs.size() - idx) return false;
704 v->resize(size);
705 for (index_size_t i = 0; i < size; ++i) {
706 (*v)[i] = bs[idx++];
707 }
708 } else if constexpr (is_specialization_v<std::decay_t<V<Args...>>, std::vector>) {
709 for (index_size_t i = 0; i < size; ++i) {
710 std::decay_t<decltype(*v->begin())> value{};
711 if (!copyFromByteString(&value, bs, idx, unknowns)) {
712 return false;
713 }
714 if constexpr (std::is_same_v<std::decay_t<decltype(value)>, Datum>) {
715 if (!value.has_value()) {
716 continue; // ignore empty datum values in a vector.
717 }
718 }
719 v->emplace_back(std::move(value));
720 }
721 } else if constexpr (is_specialization_v<std::decay_t<V<Args...>>, std::map>) {
722 for (index_size_t i = 0; i < size; ++i) {
723 // we can't directly use pair because there may be internal const decls.
724 std::decay_t<decltype(v->begin()->first)> key{};
725 std::decay_t<decltype(v->begin()->second)> value{};
726 if (!copyFromByteString(&key, bs, idx, unknowns) ||
727 !copyFromByteString(&value, bs, idx, unknowns)) {
728 return false;
729 }
730 if constexpr (std::is_same_v<std::decay_t<decltype(value)>, Datum>) {
731 if (!value.has_value()) {
732 continue; // ignore empty datum values in a map.
733 }
734 }
735 v->emplace(std::move(key), std::move(value));
736 }
737 } else /* constexpr */ {
738 for (index_size_t i = 0; i < size; ++i) {
739 std::decay_t<decltype(*v->begin())> value{};
740 if (!copyFromByteString(&value, bs, idx, unknowns)) {
741 return false;
742 }
743 v->emplace(std::move(value));
744 }
745 }
746 return true;
747 }
748
749 // simple structs (use structured binding to extract members)
750 template <typename T>
751 typename std::enable_if_t<is_structural_metadata_type_v<T>, bool>
copyFromByteString(T * t,const ByteString & bs,size_t & idx,ByteStringUnknowns * unknowns)752 copyFromByteString(T *t, const ByteString& bs, size_t& idx,
753 ByteStringUnknowns *unknowns) {
754 using type = std::decay_t<T>;
755 if constexpr (is_braces_constructible<type, any_type, any_type, any_type, any_type>{}) {
756 auto& [e1, e2, e3, e4] = *t;
757 return copyFromByteString(&e1, bs, idx, unknowns)
758 && copyFromByteString(&e2, bs, idx, unknowns)
759 && copyFromByteString(&e3, bs, idx, unknowns)
760 && copyFromByteString(&e4, bs, idx, unknowns);
761 } else if constexpr (is_braces_constructible<type, any_type, any_type, any_type>{}) {
762 auto& [e1, e2, e3] = *t;
763 return copyFromByteString(&e1, bs, idx, unknowns)
764 && copyFromByteString(&e2, bs, idx, unknowns)
765 && copyFromByteString(&e3, bs, idx, unknowns);
766 } else if constexpr (is_braces_constructible<type, any_type, any_type>{}) {
767 auto& [e1, e2] = *t;
768 return copyFromByteString(&e1, bs, idx, unknowns)
769 && copyFromByteString(&e2, bs, idx, unknowns);
770 } else if constexpr (is_braces_constructible<type, any_type>{}) {
771 auto& [e1] = *t;
772 return copyFromByteString(&e1, bs, idx, unknowns);
773 } else if constexpr (is_braces_constructible<type>{}) {
774 return true; // like std::monostate - no members
775 } else /* constexpr */ {
776 static_assert(dependent_false_v<T>);
777 }
778 }
779
780 namespace tedious_details {
781 //
782 // We build a function table at compile time to lookup the proper copyFromByteString method.
783 // See:
784 // https://stackoverflow.com/questions/36785345/void-to-the-nth-element-of-stdtuple-at-runtime
785 // Constant time implementation of std::visit (variant)
786
787 template <typename CompoundT, size_t Index>
copyFromByteString(Datum * datum,const ByteString & bs,size_t & idx,size_t endIdx,ByteStringUnknowns * unknowns)788 bool copyFromByteString(Datum *datum, const ByteString &bs, size_t &idx, size_t endIdx,
789 ByteStringUnknowns *unknowns) {
790 using T = std::tuple_element_t<Index, typename CompoundT::tuple_t>;
791 T value;
792 if (!android::audio_utils::metadata::copyFromByteString(
793 &value, bs, idx, unknowns)) return false; // have we parsed correctly?
794 if (idx != endIdx) return false; // have we consumed the correct number of bytes?
795 *datum = std::move(value);
796 return true;
797 }
798
799 template <typename CompoundT, size_t... Indexes>
copyFromByteString(Datum * datum,const ByteString & bs,size_t & idx,size_t endIdx,ByteStringUnknowns * unknowns,size_t typeIndex,std::index_sequence<Indexes...>)800 constexpr bool copyFromByteString(Datum *datum, const ByteString &bs,
801 size_t &idx, size_t endIdx, ByteStringUnknowns *unknowns,
802 size_t typeIndex, std::index_sequence<Indexes...>)
803 {
804 using function_type =
805 bool (*)(Datum*, const ByteString&, size_t&, size_t, ByteStringUnknowns*);
806 function_type constexpr ptrs[] = {
807 ©FromByteString<CompoundT, Indexes>...
808 };
809 return ptrs[typeIndex](datum, bs, idx, endIdx, unknowns);
810 }
811
812 template <typename CompoundT>
813 __attribute__((noinline))
copyFromByteString(Datum * datum,const ByteString & bs,size_t & idx,size_t endIdx,ByteStringUnknowns * unknowns,size_t typeIndex)814 constexpr bool copyFromByteString(Datum *datum, const ByteString &bs,
815 size_t &idx, size_t endIdx, ByteStringUnknowns *unknowns, size_t typeIndex) {
816 return copyFromByteString<CompoundT>(
817 datum, bs, idx, endIdx, unknowns,
818 typeIndex, std::make_index_sequence<CompoundT::size_v>());
819 }
820
821 } // namespace tedious_details
822
823 // TODO Ditto about moving to .cpp.
824
825 inline
copyFromByteString(Datum * datum,const ByteString & bs,size_t & idx,ByteStringUnknowns * unknowns)826 bool copyFromByteString(Datum *datum, const ByteString &bs, size_t& idx,
827 ByteStringUnknowns *unknowns) {
828 type_size_t type;
829 if (!copyFromByteString(&type, bs, idx, unknowns)) return false;
830
831 datum_size_t datum_size;
832 if (!copyFromByteString(&datum_size, bs, idx, unknowns)) return false;
833 if (datum_size > bs.size() - idx) return false;
834 const size_t endIdx = idx + datum_size;
835
836 if (type == 0 || type > metadata_types::size_v) {
837 idx = endIdx; // skip unrecognized type.
838 if (unknowns != nullptr) {
839 unknowns->push_back(type);
840 return true; // allow further recursion.
841 }
842 return false;
843 }
844
845 // use special trick to instantiate all the types for copyFromByteString
846 // in a table and find the right method from table lookup.
847 return tedious_details::copyFromByteString<metadata_types>(
848 datum, bs, idx, endIdx, unknowns, type - 1);
849 }
850
851 // Handy helpers - these are the most efficient ways to parcel Data.
852 /**
853 * Returns the Data map from a byte string.
854 *
855 * If unknowns is nullptr, then any unknown entries during parsing will cause
856 * an empty map to be returned.
857 *
858 * If unknowns is non-null, then it contains all of the unknown types
859 * encountered during parsing, and a partial map will be returned excluding all
860 * unknown types encountered.
861 */
862 inline
863 Data dataFromByteString(const ByteString &bs,
864 ByteStringUnknowns *unknowns = nullptr) {
865 Data d;
866 size_t idx = 0;
867 if (!copyFromByteString(&d, bs, idx, unknowns)) {
868 return {};
869 }
870 return d; // copy elision
871 }
872
873 inline
byteStringFromData(const Data & data)874 ByteString byteStringFromData(const Data &data) {
875 ByteString bs;
876 copyToByteString(data, bs);
877 return bs; // copy elision
878 }
879
880 /**
881 * \brief Returns the length of the byte string buffer from the raw pointer.
882 *
883 * The raw pointer comes from the Data object's ByteString.data()
884 * or from the C API byte_string_from_audio_metadata().
885 * This is a helper method for C implementations which may pass the raw
886 * byte string buffer pointer (which does not directly contain the length).
887 * C++ methods should always use the ByteString object.
888 *
889 * \param byteString byte string buffer raw pointer.
890 * \return size in bytes of metadata in the buffer or 0 if something went wrong.
891 */
892
dataByteStringLen(const uint8_t * ptr)893 inline size_t dataByteStringLen(const uint8_t *ptr) {
894 index_size_t elements;
895 const uint8_t * const origPtr = ptr;
896 memcpy(&elements, ptr, sizeof(elements));
897 ptr += sizeof(elements);
898 for (index_size_t i = 0; i < elements; ++i) {
899 // get key (string)
900 index_size_t keyLen;
901 memcpy(&keyLen, ptr, sizeof(keyLen));
902 ptr += keyLen + sizeof(keyLen);
903 // get type
904 type_size_t type;
905 memcpy(&type, ptr, sizeof(type));
906 ptr += sizeof(type_size_t);
907 // Note: could check type validity.
908 // payload size
909 datum_size_t datumSize;
910 memcpy(&datumSize, ptr, sizeof(datumSize));
911 ptr += datumSize + sizeof(datumSize);
912 }
913 const ptrdiff_t size = ptr - origPtr;
914 return size < 0 ? 0 : size;
915 }
916
917 } // namespace android::audio_utils::metadata
918
919 #endif // __cplusplus
920
921 // C API (see C++ API above for details)
922
923 /** \cond */
924 __BEGIN_DECLS
925 /** \endcond */
926
927 typedef struct audio_metadata_t audio_metadata_t;
928
929 // Used by audio_metadata_put_unknown() and audio_metadata_get_unknown(), but not part of public API
930 // The name and data structure representation discourage accidental use.
931 typedef struct { char c; } audio_metadata_unknown_t;
932
933 /**
934 * \brief Creates a metadata object
935 *
936 * \return the metadata object or NULL on failure. Caller must call
937 * audio_metadata_destroy to free memory.
938 */
939 audio_metadata_t *audio_metadata_create();
940
941 /**
942 * \brief Put key value pair where the value type is int32_t to audio metadata.
943 *
944 * \param metadata the audio metadata object.
945 * \param key the key of the element to be put.
946 * \param value the value of the element to be put.
947 * \return 0 if the key value pair is put successfully into the audio metadata.
948 * -EINVAL if metadata or key is null.
949 */
950 int audio_metadata_put_int32(audio_metadata_t *metadata, const char *key, int32_t value);
951
952 /**
953 * \brief Put key value pair where the value type is int64_t to audio metadata.
954 *
955 * \param metadata the audio metadata object.
956 * \param key the key of the element to be put.
957 * \param value the value of the element to be put.
958 * \return 0 if the key value pair is put successfully into the audio metadata.
959 * -EINVAL if metadata or key is null.
960 */
961 int audio_metadata_put_int64(audio_metadata_t *metadata, const char *key, int64_t value);
962
963 /**
964 * \brief Put key value pair where the value type is float to audio metadata.
965 *
966 * \param metadata the audio metadata object.
967 * \param key the key of the element to be put.
968 * \param value the value of the element to be put.
969 * \return 0 if the key value pair is put successfully into the audio metadata.
970 * -EINVAL if metadata or key is null.
971 */
972 int audio_metadata_put_float(audio_metadata_t *metadata, const char *key, float value);
973
974 /**
975 * \brief Put key value pair where the value type is double to audio metadata.
976 *
977 * \param metadata the audio metadata object.
978 * \param key the key of the element to be put.
979 * \param value the value of the element to be put.
980 * \return 0 if the key value pair is put successfully into the audio metadata.
981 * -EINVAL if metadata or key is null.
982 */
983 int audio_metadata_put_double(audio_metadata_t *metadata, const char *key, double value);
984
985 /**
986 * \brief Put key value pair where the value type is `const char *` to audio metadata.
987 *
988 * \param metadata the audio metadata object.
989 * \param key the key of the element to be put.
990 * \param value the value of the element to be put.
991 * \return 0 if the key value pair is put successfully into the audio metadata.
992 * -EINVAL if metadata, key or value is null.
993 */
994 int audio_metadata_put_string(audio_metadata_t *metadata, const char *key, const char *value);
995
996 /**
997 * \brief Put key value pair where the value type is audio_metadata_t to audio metadata.
998 *
999 * \param metadata the audio metadata object.
1000 * \param key the key of the element to be put.
1001 * \param value the value of the element to be put.
1002 * \return 0 if the key value pair is put successfully into the audio metadata.
1003 * -EINVAL if metadata, key or value is null.
1004 */
1005 int audio_metadata_put_data(audio_metadata_t *metadata, const char *key, audio_metadata_t *value);
1006
1007 /**
1008 * \brief Declared but not implemented, as any potential caller won't supply a correct value.
1009 */
1010 int audio_metadata_put_unknown(audio_metadata_t *metadata, const char *key,
1011 audio_metadata_unknown_t value);
1012
1013 #ifndef __cplusplus // Only C11 has _Generic; C++ uses overloaded declarations instead
1014
1015 // use C Generics to provide interfaces for put/get functions
1016 // See: https://en.cppreference.com/w/c/language/generic
1017
1018 /**
1019 * A generic interface to put key value pair into the audio metadata.
1020 * Fails at compile-time if type isn't supported.
1021 */
1022 #define audio_metadata_put(metadata, key, value) _Generic((value), \
1023 int32_t: audio_metadata_put_int32, \
1024 int64_t: audio_metadata_put_int64, \
1025 float: audio_metadata_put_float, \
1026 double: audio_metadata_put_double, \
1027 /* https://stackoverflow.com/questions/18857056/c11-generic-how-to-deal-with-string-literals */ \
1028 const char*: audio_metadata_put_string, \
1029 char*: audio_metadata_put_string, \
1030 audio_metadata_t*: audio_metadata_put_data, \
1031 default: audio_metadata_put_unknown \
1032 )(metadata, key, value)
1033
1034 #endif // !__cplusplus
1035
1036 /**
1037 * \brief Get mapped value whose type is int32_t by a given key from audio metadata.
1038 *
1039 * \param metadata the audio metadata object.
1040 * \param key the key value to get value.
1041 * \param value the mapped value to be written.
1042 * \return -EINVAL when 1) metadata is null, 2) key is null, or 3) value is null.
1043 * -ENOENT when 1) key is found in the audio metadata,
1044 * 2) the type of mapped value is not int32_t.
1045 * 0 if successfully find the mapped value.
1046 */
1047 int audio_metadata_get_int32(audio_metadata_t *metadata, const char *key, int32_t *value);
1048
1049 /**
1050 * \brief Get mapped value whose type is int64_t by a given key from audio metadata.
1051 *
1052 * \param metadata the audio metadata object.
1053 * \param key the key value to get value.
1054 * \param value the mapped value to be written.
1055 * \return -EINVAL when 1) metadata is null, 2) key is null, or 3) value is null.
1056 * -ENOENT when 1) key is found in the audio metadata,
1057 * 2) the type of mapped value is not int32_t.
1058 * 0 if successfully find the mapped value.
1059 */
1060 int audio_metadata_get_int64(audio_metadata_t *metadata, const char *key, int64_t *value);
1061
1062 /**
1063 * \brief Get mapped value whose type is float by a given key from audio metadata.
1064 *
1065 * \param metadata the audio metadata object.
1066 * \param key the key value to get value.
1067 * \param value the mapped value to be written.
1068 * \return -EINVAL when 1) metadata is null, 2) key is null, or 3) value is null.
1069 * -ENOENT when 1) key is found in the audio metadata,
1070 * 2) the type of mapped value is not float.
1071 * 0 if successfully find the mapped value.
1072 */
1073 int audio_metadata_get_float(audio_metadata_t *metadata, const char *key, float *value);
1074
1075 /**
1076 * \brief Get mapped value whose type is double by a given key from audio metadata.
1077 *
1078 * \param metadata the audio metadata object.
1079 * \param key the key value to get value.
1080 * \param value the mapped value to be written.
1081 * \return -EINVAL when 1) metadata is null, 2) key is null, or 3) value is null.
1082 * -ENOENT when 1) key is found in the audio metadata,
1083 * 2) the type of mapped value is not double.
1084 * 0 if successfully find the mapped value.
1085 */
1086 int audio_metadata_get_double(audio_metadata_t *metadata, const char *key, double *value);
1087
1088 /**
1089 * \brief Get mapped value whose type is std::string by a given key from audio metadata.
1090 *
1091 * \param metadata the audio metadata object.
1092 * \param key the key value to get value.
1093 * \param value the mapped value to be written. The memory will be allocated in the
1094 * function, which must be freed by caller.
1095 * \return -EINVAL when 1) metadata is null, 2) key is null, or 3) value is null.
1096 * -ENOENT when 1) key is found in the audio metadata,
1097 * 2) the type of mapped value is not std::string.
1098 * -ENOMEM when fails allocating memory for value.
1099 * 0 if successfully find the mapped value.
1100 */
1101 int audio_metadata_get_string(audio_metadata_t *metadata, const char *key, char **value);
1102
1103 /**
1104 * \brief Get mapped value whose type is audio_metadata_t by a given key from audio metadata.
1105 *
1106 * \param metadata the audio metadata object.
1107 * \param key the key value to get value.
1108 * \param value the mapped value to be written. The memory will be allocated in the
1109 * function, which should be free by caller via audio_metadata_destroy.
1110 * \return -EINVAL when 1) metadata is null, 2) key is null, or 3) value is null.
1111 * -ENOENT when 1) key is found in the audio metadata,
1112 * 2) the type of mapped value is not audio_utils::metadata::Data.
1113 * -ENOMEM when fails allocating memory for value.
1114 * 0 if successfully find the mapped value.
1115 */
1116 int audio_metadata_get_data(audio_metadata_t *metadata, const char *key, audio_metadata_t **value);
1117
1118 /**
1119 * \brief Declared but not implemented, as any potential caller won't supply a correct value.
1120 */
1121 int audio_metadata_get_unknown(audio_metadata_t *metadata, const char *key,
1122 audio_metadata_unknown_t *value);
1123
1124 #ifndef __cplusplus // Only C11 has _Generic; C++ uses overloaded declarations instead
1125
1126 /**
1127 * A generic interface to get mapped value by a given key from audio metadata. The value object
1128 * will remain the same if the key is not found in the audio metadata.
1129 * Fails at compile-time if type isn't supported.
1130 */
1131 #define audio_metadata_get(metadata, key, value) _Generic((value), \
1132 int32_t*: audio_metadata_get_int32, \
1133 int64_t*: audio_metadata_get_int64, \
1134 float*: audio_metadata_get_float, \
1135 double*: audio_metadata_get_double, \
1136 char**: audio_metadata_get_string, \
1137 audio_metadata_t**: audio_metadata_get_data, \
1138 default: audio_metadata_get_unknown \
1139 )(metadata, key, value)
1140
1141 #endif // !__cplusplus
1142
1143 /**
1144 * \brief Remove item from audio metadata.
1145 *
1146 * \param metadata the audio metadata object.
1147 * \param key the key of the item that is going to be removed.
1148 * \return -EINVAL if metadata or key is null. Otherwise, return the number of elements erased.
1149 */
1150 ssize_t audio_metadata_erase(audio_metadata_t *metadata, const char *key);
1151
1152 /**
1153 * \brief Destroys the metadata object
1154 *
1155 * \param metadata object returned by create, if NULL nothing happens.
1156 */
1157 void audio_metadata_destroy(audio_metadata_t *metadata);
1158
1159 /**
1160 * \brief Unpack byte string into a given audio metadata
1161 *
1162 * \param byteString a byte string that contains data to convert to audio metadata.
1163 * \param length the length of the byte string
1164 * \return the audio metadata object that contains the converted data. Caller must call
1165 * audio_metadata_destroy to free the memory.
1166 */
1167 audio_metadata_t *audio_metadata_from_byte_string(const uint8_t *byteString, size_t length);
1168
1169 /**
1170 * \brief Pack the audio metadata into a byte string
1171 *
1172 * \param metadata the audio metadata object to be converted.
1173 * \param byteString the buffer to write data to. The memory will be allocated
1174 * in the function, which must be freed by caller via free().
1175 * \return -EINVAL if metadata or byteString is null.
1176 * -ENOMEM if fails to allocate memory for byte string.
1177 * The length of the byte string.
1178 */
1179 ssize_t byte_string_from_audio_metadata(audio_metadata_t *metadata, uint8_t **byteString);
1180
1181 /**
1182 * \brief Return the size in bytes of the metadata byte string
1183 *
1184 * Note: strlen() cannot be used as there are embedded 0's in the byte string.
1185 *
1186 * \param byteString a valid byte string buffer from byte_string_from_audio_metadata().
1187 * \return size in bytes of metadata in the buffer or 0 if something went wrong.
1188 */
1189 size_t audio_metadata_byte_string_len(const uint8_t *byteString);
1190
1191 /** \cond */
1192 __END_DECLS
1193 /** \endcond */
1194
1195 #ifdef __cplusplus
1196
1197 inline
audio_metadata_put(audio_metadata_t * metadata,const char * key,int32_t value)1198 int audio_metadata_put(audio_metadata_t *metadata, const char *key, int32_t value)
1199 {
1200 return audio_metadata_put_int32(metadata, key, value);
1201 }
1202
1203 inline
audio_metadata_put(audio_metadata_t * metadata,const char * key,int64_t value)1204 int audio_metadata_put(audio_metadata_t *metadata, const char *key, int64_t value)
1205 {
1206 return audio_metadata_put_int64(metadata, key, value);
1207 }
1208
1209 inline
audio_metadata_put(audio_metadata_t * metadata,const char * key,float value)1210 int audio_metadata_put(audio_metadata_t *metadata, const char *key, float value)
1211 {
1212 return audio_metadata_put_float(metadata, key, value);
1213 }
1214
1215 inline
audio_metadata_put(audio_metadata_t * metadata,const char * key,double value)1216 int audio_metadata_put(audio_metadata_t *metadata, const char *key, double value)
1217 {
1218 return audio_metadata_put_double(metadata, key, value);
1219 }
1220
1221 inline
audio_metadata_put(audio_metadata_t * metadata,const char * key,const char * value)1222 int audio_metadata_put(audio_metadata_t *metadata, const char *key, const char *value)
1223 {
1224 return audio_metadata_put_string(metadata, key, value);
1225 }
1226
1227 inline
audio_metadata_put(audio_metadata_t * metadata,const char * key,audio_metadata_t * value)1228 int audio_metadata_put(audio_metadata_t *metadata, const char *key, audio_metadata_t *value)
1229 {
1230 return audio_metadata_put_data(metadata, key, value);
1231 }
1232
1233 // No overload for default type
1234
1235 inline
audio_metadata_get(audio_metadata_t * metadata,const char * key,int32_t * value)1236 int audio_metadata_get(audio_metadata_t *metadata, const char *key, int32_t *value)
1237 {
1238 return audio_metadata_get_int32(metadata, key, value);
1239 }
1240
1241 inline
audio_metadata_get(audio_metadata_t * metadata,const char * key,int64_t * value)1242 int audio_metadata_get(audio_metadata_t *metadata, const char *key, int64_t *value)
1243 {
1244 return audio_metadata_get_int64(metadata, key, value);
1245 }
1246
1247 inline
audio_metadata_get(audio_metadata_t * metadata,const char * key,float * value)1248 int audio_metadata_get(audio_metadata_t *metadata, const char *key, float *value)
1249 {
1250 return audio_metadata_get_float(metadata, key, value);
1251 }
1252
1253 inline
audio_metadata_get(audio_metadata_t * metadata,const char * key,double * value)1254 int audio_metadata_get(audio_metadata_t *metadata, const char *key, double *value)
1255 {
1256 return audio_metadata_get_double(metadata, key, value);
1257 }
1258
1259 inline
audio_metadata_get(audio_metadata_t * metadata,const char * key,char ** value)1260 int audio_metadata_get(audio_metadata_t *metadata, const char *key, char **value)
1261 {
1262 return audio_metadata_get_string(metadata, key, value);
1263 }
1264
1265 inline
audio_metadata_get(audio_metadata_t * metadata,const char * key,audio_metadata_t ** value)1266 int audio_metadata_get(audio_metadata_t *metadata, const char *key, audio_metadata_t **value)
1267 {
1268 return audio_metadata_get_data(metadata, key, value);
1269 }
1270
1271 // No overload for default type
1272
1273 #endif // __cplusplus
1274
1275 #endif // !ANDROID_AUDIO_METADATA_H
1276