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