1 /*
2  * Copyright (C) 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 package android.media;
18 
19 import android.annotation.IntRange;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.util.Log;
23 import android.util.Pair;
24 
25 import java.lang.reflect.ParameterizedType;
26 import java.nio.BufferUnderflowException;
27 import java.nio.ByteBuffer;
28 import java.nio.ByteOrder;
29 import java.nio.charset.Charset;
30 import java.nio.charset.StandardCharsets;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Map;
34 import java.util.Objects;
35 import java.util.Set;
36 
37 /**
38  * AudioMetadata class is used to manage typed key-value pairs for
39  * configuration and capability requests within the Audio Framework.
40  */
41 public final class AudioMetadata {
42     private static final String TAG = "AudioMetadata";
43 
44     /**
45      * Key interface for the {@code AudioMetadata} map.
46      *
47      * <p>The presence of this {@code Key} interface on an object allows
48      * it to reference metadata in the Audio Framework.</p>
49      *
50      * <p>Vendors are allowed to implement this {@code Key} interface for their debugging or
51      * private application use. To avoid name conflicts, vendor key names should be qualified by
52      * the vendor company name followed by a dot; for example, "vendorCompany.someVolume".</p>
53      *
54      * @param <T> type of value associated with {@code Key}.
55      */
56     /*
57      * Internal details:
58      * Conceivably metadata keys exposing multiple interfaces
59      * could be eligible to work in multiple framework domains.
60      */
61     public interface Key<T> {
62         /**
63          * Returns the internal name of the key.  The name should be unique in the
64          * {@code AudioMetadata} namespace.  Vendors should prefix their keys with
65          * the company name followed by a dot.
66          */
67         @NonNull
getName()68         String getName();
69 
70         /**
71          * Returns the class type {@code T} of the associated value.  Valid class types for
72          * {@link android.os.Build.VERSION_CODES#R} are
73          * {@code Integer.class}, {@code Long.class}, {@code Float.class}, {@code Double.class},
74          * {@code String.class}.
75          */
76         @NonNull
getValueClass()77         Class<T> getValueClass();
78 
79         // TODO: consider adding bool isValid(@NonNull T value)
80     }
81 
82     /**
83      * Creates a {@link AudioMetadataMap} suitable for adding keys.
84      * @return an empty {@link AudioMetadataMap} instance.
85      */
86     @NonNull
createMap()87     public static AudioMetadataMap createMap() {
88         return new BaseMap();
89     }
90 
91     /**
92      * A container class for AudioMetadata Format keys.
93      *
94      * @see AudioTrack.OnCodecFormatChangedListener
95      */
96     public static class Format {
97         // The key name strings used here must match that of the native framework, but are
98         // allowed to change between API releases.  This due to the Java specification
99         // on what is a compile time constant.
100         //
101         // Key<?> are final variables but not constant variables (per Java spec 4.12.4) because
102         // the keys are not a primitive type nor a String initialized by a constant expression.
103         // Hence (per Java spec 13.1.3), they are not resolved at compile time,
104         // rather are picked up by applications at run time.
105         //
106         // So the contractual API behavior of AudioMetadata.Key<> are different than Strings
107         // initialized by a constant expression (for example MediaFormat.KEY_*).
108 
109         // See MediaFormat
110         /**
111          * A key representing the bitrate of the encoded stream used in
112          *
113          * If the stream is variable bitrate, this is the average bitrate of the stream.
114          * The unit is bits per second.
115          *
116          * An Integer value.
117          *
118          * @see MediaFormat#KEY_BIT_RATE
119          */
120         @NonNull public static final Key<Integer> KEY_BIT_RATE =
121                 createKey("bitrate", Integer.class);
122 
123         /**
124          * A key representing the audio channel mask of the stream.
125          *
126          * An Integer value.
127          *
128          * @see AudioTrack#getChannelConfiguration()
129          * @see MediaFormat#KEY_CHANNEL_MASK
130          */
131         @NonNull public static final Key<Integer> KEY_CHANNEL_MASK =
132                 createKey("channel-mask", Integer.class);
133 
134 
135         /**
136          * A key representing the codec mime string.
137          *
138          * A String value.
139          *
140          * @see MediaFormat#KEY_MIME
141          */
142         @NonNull public static final Key<String> KEY_MIME = createKey("mime", String.class);
143 
144         /**
145          * A key representing the audio sample rate in Hz of the stream.
146          *
147          * An Integer value.
148          *
149          * @see AudioFormat#getSampleRate()
150          * @see MediaFormat#KEY_SAMPLE_RATE
151          */
152         @NonNull public static final Key<Integer> KEY_SAMPLE_RATE =
153                 createKey("sample-rate", Integer.class);
154 
155         // Unique to Audio
156 
157         /**
158          * A key representing the bit width of an element of decoded data.
159          *
160          * An Integer value.
161          */
162         @NonNull public static final Key<Integer> KEY_BIT_WIDTH =
163                 createKey("bit-width", Integer.class);
164 
165         /**
166          * A key representing the presence of Atmos in an E-AC3 stream.
167          *
168          * A Boolean value which is true if Atmos is present in an E-AC3 stream.
169          */
170 
171         // Since Boolean isn't handled by Parceling, we translate
172         // internally to KEY_HAS_ATMOS when sending through JNI.
173         // Consider deprecating this key for KEY_HAS_ATMOS in the future.
174         //
175         @NonNull public static final Key<Boolean> KEY_ATMOS_PRESENT =
176                 createKey("atmos-present", Boolean.class);
177 
178         /**
179          * A key representing the presence of Atmos in an E-AC3 stream.
180          *
181          * An Integer value which is nonzero if Atmos is present in an E-AC3 stream.
182          * The integer representation is used for communication to the native side.
183          * @hide
184          */
185         @NonNull public static final Key<Integer> KEY_HAS_ATMOS =
186                 createKey("has-atmos", Integer.class);
187 
188         /**
189          * A key representing the audio encoding used for the stream.
190          * This is the same encoding used in {@link AudioFormat#getEncoding()}.
191          *
192          * An Integer value.
193          *
194          * @see AudioFormat#getEncoding()
195          */
196         @NonNull public static final Key<Integer> KEY_AUDIO_ENCODING =
197                 createKey("audio-encoding", Integer.class);
198 
199 
200         /**
201          * A key representing the audio presentation id being decoded by a next generation
202          * audio decoder.
203          *
204          * An Integer value representing presentation id.
205          *
206          * @see AudioPresentation#getPresentationId()
207          */
208         @NonNull public static final Key<Integer> KEY_PRESENTATION_ID =
209                 createKey("presentation-id", Integer.class);
210 
211          /**
212          * A key representing the audio program id being decoded by a next generation
213          * audio decoder.
214          *
215          * An Integer value representing program id.
216          *
217          * @see AudioPresentation#getProgramId()
218          */
219         @NonNull public static final Key<Integer> KEY_PROGRAM_ID =
220                 createKey("program-id", Integer.class);
221 
222 
223          /**
224          * A key representing the audio presentation content classifier being rendered
225          * by a next generation audio decoder.
226          *
227          * An Integer value representing presentation content classifier.
228          *
229          * @see AudioPresentation#CONTENT_UNKNOWN
230          * @see AudioPresentation#CONTENT_MAIN
231          * @see AudioPresentation#CONTENT_MUSIC_AND_EFFECTS
232          * @see AudioPresentation#CONTENT_VISUALLY_IMPAIRED
233          * @see AudioPresentation#CONTENT_HEARING_IMPAIRED
234          * @see AudioPresentation#CONTENT_DIALOG
235          * @see AudioPresentation#CONTENT_COMMENTARY
236          * @see AudioPresentation#CONTENT_EMERGENCY
237          * @see AudioPresentation#CONTENT_VOICEOVER
238          */
239         @NonNull public static final Key<Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER =
240                 createKey("presentation-content-classifier", Integer.class);
241 
242         /**
243          * A key representing the audio presentation language being rendered by a next
244          * generation audio decoder.
245          *
246          * A String value representing ISO 639-2 (three letter code).
247          *
248          * @see AudioPresentation#getLocale()
249          */
250         @NonNull public static final Key<String> KEY_PRESENTATION_LANGUAGE =
251                 createKey("presentation-language", String.class);
252 
Format()253         private Format() {} // delete constructor
254     }
255 
256     /////////////////////////////////////////////////////////////////////////
257     // Hidden methods and functions.
258 
259     /**
260      * Returns a Key object with the correct interface for the AudioMetadata.
261      *
262      * An interface with the same name and type will be treated as
263      * identical for the purposes of value storage, even though
264      * other methods or hidden parameters may return different values.
265      *
266      * @param name The name of the key.
267      * @param type The class type of the value represented by the key.
268      * @param <T> The type of value.
269      * @return a new key interface.
270      *
271      * Creating keys is currently only allowed by the Framework.
272      * @hide
273      */
274     @NonNull
createKey(@onNull String name, @NonNull Class<T> type)275     public static <T> Key<T> createKey(@NonNull String name, @NonNull Class<T> type) {
276         // Implementation specific.
277         return new Key<T>() {
278             private final String mName = name;
279             private final Class<T> mType = type;
280 
281             @Override
282             @NonNull
283             public String getName() {
284                 return mName;
285             }
286 
287             @Override
288             @NonNull
289             public Class<T> getValueClass() {
290                 return mType;
291             }
292 
293             /**
294              * Return true if the name and the type of two objects are the same.
295              */
296             @Override
297             public boolean equals(Object obj) {
298                 if (obj == this) {
299                     return true;
300                 }
301                 if (!(obj instanceof Key)) {
302                     return false;
303                 }
304                 Key<?> other = (Key<?>) obj;
305                 return mName.equals(other.getName()) && mType.equals(other.getValueClass());
306             }
307 
308             @Override
309             public int hashCode() {
310                 return Objects.hash(mName, mType);
311             }
312         };
313     }
314 
315     /**
316      * @hide
317      *
318      * AudioMetadata is based on interfaces in order to allow multiple inheritance
319      * and maximum flexibility in implementation.
320      *
321      * Here, we provide a simple implementation of {@link Map} interface;
322      * Note that the Keys are not specific to this Map implementation.
323      *
324      * It is possible to require the keys to be of a certain class
325      * before allowing a set or get operation.
326      */
327     public static class BaseMap implements AudioMetadataMap {
328         @Override
containsKey(@onNull Key<T> key)329         public <T> boolean containsKey(@NonNull Key<T> key) {
330             Pair<Key<?>, Object> valuePair = mHashMap.get(pairFromKey(key));
331             return valuePair != null;
332         }
333 
334         @Override
335         @NonNull
dup()336         public AudioMetadataMap dup() {
337             BaseMap map = new BaseMap();
338             map.mHashMap.putAll(this.mHashMap);
339             return map;
340         }
341 
342         @Override
343         @Nullable
get(@onNull Key<T> key)344         public <T> T get(@NonNull Key<T> key) {
345             Pair<Key<?>, Object> valuePair = mHashMap.get(pairFromKey(key));
346             return (T) getValueFromValuePair(valuePair);
347         }
348 
349         @Override
350         @NonNull
keySet()351         public Set<Key<?>> keySet() {
352             HashSet<Key<?>> set = new HashSet();
353             for (Pair<Key<?>, Object> pair : mHashMap.values()) {
354                 set.add(pair.first);
355             }
356             return set;
357         }
358 
359         @Override
360         @Nullable
remove(@onNull Key<T> key)361         public <T> T remove(@NonNull Key<T> key) {
362             Pair<Key<?>, Object> valuePair = mHashMap.remove(pairFromKey(key));
363             return (T) getValueFromValuePair(valuePair);
364         }
365 
366         @Override
367         @Nullable
set(@onNull Key<T> key, @NonNull T value)368         public <T> T set(@NonNull Key<T> key, @NonNull T value) {
369             Objects.requireNonNull(value);
370             Pair<Key<?>, Object> valuePair = mHashMap
371                     .put(pairFromKey(key), new Pair<Key<?>, Object>(key, value));
372             return (T) getValueFromValuePair(valuePair);
373         }
374 
375         @Override
size()376         public int size() {
377             return mHashMap.size();
378         }
379 
380         /**
381          * Return true if the object is a BaseMap and the content from two BaseMap are the same.
382          * Note: Need to override the equals functions of Key<T> for HashMap comparison.
383          */
384         @Override
equals(Object obj)385         public boolean equals(Object obj) {
386             if (obj == this) {
387                 return true;
388             }
389             if (!(obj instanceof BaseMap)) {
390                 return false;
391             }
392             BaseMap other = (BaseMap) obj;
393             return mHashMap.equals(other.mHashMap);
394         }
395 
396         @Override
hashCode()397         public int hashCode() {
398             return Objects.hash(mHashMap);
399         }
400 
401         /*
402          * Implementation specific.
403          *
404          * To store the value in the HashMap we need to convert the Key interface
405          * to a hashcode() / equals() compliant Pair.
406          */
407         @NonNull
pairFromKey(@onNull Key<T> key)408         private static <T> Pair<String, Class<?>> pairFromKey(@NonNull Key<T> key) {
409             Objects.requireNonNull(key);
410             return new Pair<String, Class<?>>(key.getName(), key.getValueClass());
411         }
412 
413         /*
414          * Implementation specific.
415          *
416          * We store in a Pair (valuePair) the key along with the Object value.
417          * This helper returns the Object value from the value pair.
418          */
419         @Nullable
getValueFromValuePair(@ullable Pair<Key<?>, Object> valuePair)420         private static Object getValueFromValuePair(@Nullable Pair<Key<?>, Object> valuePair) {
421             if (valuePair == null) {
422                 return null;
423             }
424             return valuePair.second;
425         }
426 
427         /*
428          * Implementation specific.
429          *
430          * We use a HashMap to back the AudioMetadata BaseMap object.
431          * This is not locked, so concurrent reads are permitted if all threads
432          * have a ReadMap; this is risky with a Map.
433          */
434         private final HashMap<Pair<String, Class<?>>, Pair<Key<?>, Object>> mHashMap =
435                 new HashMap();
436     }
437 
438     // The audio metadata object type index should be kept the same as
439     // the ones in audio_utils::metadata::metadata_types
440     private static final int AUDIO_METADATA_OBJ_TYPE_NONE = 0;
441     private static final int AUDIO_METADATA_OBJ_TYPE_INT = 1;
442     private static final int AUDIO_METADATA_OBJ_TYPE_LONG = 2;
443     private static final int AUDIO_METADATA_OBJ_TYPE_FLOAT = 3;
444     private static final int AUDIO_METADATA_OBJ_TYPE_DOUBLE = 4;
445     private static final int AUDIO_METADATA_OBJ_TYPE_STRING = 5;
446     // BaseMap is corresponding to audio_utils::metadata::Data
447     private static final int AUDIO_METADATA_OBJ_TYPE_BASEMAP = 6;
448 
449     private static final Map<Class, Integer> AUDIO_METADATA_OBJ_TYPES = Map.of(
450             Integer.class, AUDIO_METADATA_OBJ_TYPE_INT,
451             Long.class, AUDIO_METADATA_OBJ_TYPE_LONG,
452             Float.class, AUDIO_METADATA_OBJ_TYPE_FLOAT,
453             Double.class, AUDIO_METADATA_OBJ_TYPE_DOUBLE,
454             String.class, AUDIO_METADATA_OBJ_TYPE_STRING,
455             BaseMap.class, AUDIO_METADATA_OBJ_TYPE_BASEMAP);
456 
457     private static final Charset AUDIO_METADATA_CHARSET = StandardCharsets.UTF_8;
458 
459     /**
460      * An auto growing byte buffer
461      */
462     private static class AutoGrowByteBuffer {
463         private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
464         private static final int LONG_BYTE_COUNT = Long.SIZE / Byte.SIZE;
465         private static final int FLOAT_BYTE_COUNT = Float.SIZE / Byte.SIZE;
466         private static final int DOUBLE_BYTE_COUNT = Double.SIZE / Byte.SIZE;
467 
468         private ByteBuffer mBuffer;
469 
AutoGrowByteBuffer()470         AutoGrowByteBuffer() {
471             this(1024);
472         }
473 
AutoGrowByteBuffer(@ntRangefrom = 0) int initialCapacity)474         AutoGrowByteBuffer(@IntRange(from = 0) int initialCapacity) {
475             mBuffer = ByteBuffer.allocateDirect(initialCapacity);
476         }
477 
getRawByteBuffer()478         public ByteBuffer getRawByteBuffer() {
479             // Slice the buffer from 0 to position.
480             int limit = mBuffer.limit();
481             int position = mBuffer.position();
482             mBuffer.limit(position);
483             mBuffer.position(0);
484             ByteBuffer buffer = mBuffer.slice();
485 
486             // Restore position and limit.
487             mBuffer.limit(limit);
488             mBuffer.position(position);
489             return buffer;
490         }
491 
order()492         public ByteOrder order() {
493             return mBuffer.order();
494         }
495 
position()496         public int position() {
497             return mBuffer.position();
498         }
499 
position(int newPosition)500         public AutoGrowByteBuffer position(int newPosition) {
501             mBuffer.position(newPosition);
502             return this;
503         }
504 
order(ByteOrder order)505         public AutoGrowByteBuffer order(ByteOrder order) {
506             mBuffer.order(order);
507             return this;
508         }
509 
putInt(int value)510         public AutoGrowByteBuffer putInt(int value) {
511             ensureCapacity(INTEGER_BYTE_COUNT);
512             mBuffer.putInt(value);
513             return this;
514         }
515 
putLong(long value)516         public AutoGrowByteBuffer putLong(long value) {
517             ensureCapacity(LONG_BYTE_COUNT);
518             mBuffer.putLong(value);
519             return this;
520         }
521 
putFloat(float value)522         public AutoGrowByteBuffer putFloat(float value) {
523             ensureCapacity(FLOAT_BYTE_COUNT);
524             mBuffer.putFloat(value);
525             return this;
526         }
527 
putDouble(double value)528         public AutoGrowByteBuffer putDouble(double value) {
529             ensureCapacity(DOUBLE_BYTE_COUNT);
530             mBuffer.putDouble(value);
531             return this;
532         }
533 
put(byte[] src)534         public AutoGrowByteBuffer put(byte[] src) {
535             ensureCapacity(src.length);
536             mBuffer.put(src);
537             return this;
538         }
539 
540         /**
541          * Ensures capacity to append at least <code>count</code> values.
542          */
ensureCapacity(@ntRange int count)543         private void ensureCapacity(@IntRange int count) {
544             if (mBuffer.remaining() < count) {
545                 int newCapacity = mBuffer.position() + count;
546                 if (newCapacity > Integer.MAX_VALUE >> 1) {
547                     throw new IllegalStateException(
548                             "Item memory requirements too large: " + newCapacity);
549                 }
550                 newCapacity <<= 1;
551                 ByteBuffer buffer = ByteBuffer.allocateDirect(newCapacity);
552                 buffer.order(mBuffer.order());
553 
554                 // Copy data from old buffer to new buffer
555                 mBuffer.flip();
556                 buffer.put(mBuffer);
557 
558                 // Set buffer to new buffer
559                 mBuffer = buffer;
560             }
561         }
562     }
563 
564     /**
565      * @hide
566      * Describes a unpacking/packing contract of type {@code T} out of a {@link ByteBuffer}
567      *
568      * @param <T> the type being unpack
569      */
570     private interface DataPackage<T> {
571         /**
572          * Read an item from a {@link ByteBuffer}.
573          *
574          * The parceling format is assumed the same as the one described in
575          * audio_utils::Metadata.h. Copied here as a reference.
576          * All values are native endian order.
577          *
578          * Datum = { (type_size_t)  Type (the type index from type_as_value<T>.)
579          *           (datum_size_t) Size (size of datum, including the size field)
580          *           (byte string)  Payload<Type>
581          *         }
582          *
583          * Primitive types:
584          * Payload<Type> = { bytes in native endian order }
585          *
586          * Vector, Map, Container types:
587          * Payload<Type> = { (index_size_t) number of elements
588          *                   (byte string)  Payload<Element_Type> * number
589          *                 }
590          *
591          * Pair container types:
592          * Payload<Type> = { (byte string) Payload<first>,
593          *                   (byte string) Payload<second>
594          *                 }
595          *
596          * @param buffer the byte buffer to read from
597          * @return an object, which types is given type for {@link DataPackage}
598          * @throws BufferUnderflowException when there is no enough data remaining
599          *      in the buffer for unpacking.
600          */
601         @Nullable
unpack(ByteBuffer buffer)602         T unpack(ByteBuffer buffer);
603 
604         /**
605          * Pack the item into a byte array. This is the reversed way of unpacking.
606          *
607          * @param output is the stream to which to write the data
608          * @param obj the item to pack
609          * @return true if packing successfully. Otherwise, return false.
610          */
pack(AutoGrowByteBuffer output, T obj)611         boolean pack(AutoGrowByteBuffer output, T obj);
612 
613         /**
614          * Return what kind of data is contained in the package.
615          */
getMyType()616         default Class getMyType() {
617             return (Class) ((ParameterizedType) getClass().getGenericInterfaces()[0])
618                     .getActualTypeArguments()[0];
619         }
620     }
621 
622     /*****************************************************************************************
623      * Following class are common {@link DataPackage} implementations, which include types
624      * that are defined in audio_utils::metadata::metadata_types
625      *
626      * For Java
627      *     int32_t corresponds to Integer
628      *     int64_t corresponds to Long
629      *     float corresponds to Float
630      *     double corresponds to Double
631      *     std::string corresponds to String
632      *     Data corresponds to BaseMap
633      *     Datum corresponds to Object
634      ****************************************************************************************/
635 
636     private static final Map<Integer, DataPackage<?>> DATA_PACKAGES = Map.of(
637             AUDIO_METADATA_OBJ_TYPE_INT, new DataPackage<Integer>() {
638                 @Override
639                 @Nullable
640                 public Integer unpack(ByteBuffer buffer) {
641                     return buffer.getInt();
642                 }
643 
644                 @Override
645                 public boolean pack(AutoGrowByteBuffer output, Integer obj) {
646                     output.putInt(obj);
647                     return true;
648                 }
649             },
650             AUDIO_METADATA_OBJ_TYPE_LONG, new DataPackage<Long>() {
651                 @Override
652                 @Nullable
653                 public Long unpack(ByteBuffer buffer) {
654                     return buffer.getLong();
655                 }
656 
657                 @Override
658                 public boolean pack(AutoGrowByteBuffer output, Long obj) {
659                     output.putLong(obj);
660                     return true;
661                 }
662             },
663             AUDIO_METADATA_OBJ_TYPE_FLOAT, new DataPackage<Float>() {
664                 @Override
665                 @Nullable
666                 public Float unpack(ByteBuffer buffer) {
667                     return buffer.getFloat();
668                 }
669 
670                 @Override
671                 public boolean pack(AutoGrowByteBuffer output, Float obj) {
672                     output.putFloat(obj);
673                     return true;
674                 }
675             },
676             AUDIO_METADATA_OBJ_TYPE_DOUBLE, new DataPackage<Double>() {
677                 @Override
678                 @Nullable
679                 public Double unpack(ByteBuffer buffer) {
680                     return buffer.getDouble();
681                 }
682 
683                 @Override
684                 public boolean pack(AutoGrowByteBuffer output, Double obj) {
685                     output.putDouble(obj);
686                     return true;
687                 }
688             },
689             AUDIO_METADATA_OBJ_TYPE_STRING, new DataPackage<String>() {
690                 @Override
691                 @Nullable
692                 public String unpack(ByteBuffer buffer) {
693                     int dataSize = buffer.getInt();
694                     if (buffer.position() + dataSize > buffer.limit()) {
695                         return null;
696                     }
697                     byte[] valueArr = new byte[dataSize];
698                     buffer.get(valueArr);
699                     String value = new String(valueArr, AUDIO_METADATA_CHARSET);
700                     return value;
701                 }
702 
703                 /**
704                  * This is a reversed operation of unpack. It is needed to write the String
705                  * at bytes encoded with AUDIO_METADATA_CHARSET. There should be an integer
706                  * value representing the length of the bytes written before the bytes.
707                  */
708                 @Override
709                 public boolean pack(AutoGrowByteBuffer output, String obj) {
710                     byte[] valueArr = obj.getBytes(AUDIO_METADATA_CHARSET);
711                     output.putInt(valueArr.length);
712                     output.put(valueArr);
713                     return true;
714                 }
715             },
716             AUDIO_METADATA_OBJ_TYPE_BASEMAP, new BaseMapPackage());
717 
718     // ObjectPackage is a special case that it is expected to unpack audio_utils::metadata::Datum,
719     // which contains data type and data size besides the payload for the data.
720     private static final ObjectPackage OBJECT_PACKAGE = new ObjectPackage();
721 
722     private static class ObjectPackage implements DataPackage<Pair<Class, Object>> {
723         /**
724          * The {@link ObjectPackage} will unpack byte string for audio_utils::metadata::Datum.
725          * Since the Datum is a std::any, {@link Object} is used to carrying the data. The
726          * data type is stored in the data package header. In that case, a {@link Class}
727          * will also be returned to indicate the actual type for the object.
728          */
729         @Override
730         @Nullable
unpack(ByteBuffer buffer)731         public Pair<Class, Object> unpack(ByteBuffer buffer) {
732             int dataType = buffer.getInt();
733             DataPackage dataPackage = DATA_PACKAGES.get(dataType);
734             if (dataPackage == null) {
735                 Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
736                 return null;
737             }
738             int dataSize = buffer.getInt();
739             int position = buffer.position();
740             Object obj = dataPackage.unpack(buffer);
741             if (buffer.position() - position != dataSize) {
742                 Log.e(TAG, "Broken data package");
743                 return null;
744             }
745             return new Pair<Class, Object>(dataPackage.getMyType(), obj);
746         }
747 
748         @Override
pack(AutoGrowByteBuffer output, Pair<Class, Object> obj)749         public boolean pack(AutoGrowByteBuffer output, Pair<Class, Object> obj) {
750             final Integer dataType = AUDIO_METADATA_OBJ_TYPES.get(obj.first);
751             if (dataType == null) {
752                 Log.e(TAG, "Cannot find data type for " + obj.first);
753                 return false;
754             }
755             DataPackage dataPackage = DATA_PACKAGES.get(dataType);
756             if (dataPackage == null) {
757                 Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
758                 return false;
759             }
760             output.putInt(dataType);
761             int position = output.position(); // Keep current position.
762             output.putInt(0); // Keep a place for the size of payload.
763             int payloadIdx = output.position();
764             if (!dataPackage.pack(output, obj.second)) {
765                 Log.i(TAG, "Failed to pack object: " + obj.second);
766                 return false;
767             }
768             // Put the actual payload size.
769             int currentPosition = output.position();
770             output.position(position);
771             output.putInt(currentPosition - payloadIdx);
772             output.position(currentPosition);
773             return true;
774         }
775     }
776 
777     /**
778      * BaseMap will be corresponding to audio_utils::metadata::Data.
779      */
780     private static class BaseMapPackage implements DataPackage<BaseMap> {
781         @Override
782         @Nullable
unpack(ByteBuffer buffer)783         public BaseMap unpack(ByteBuffer buffer) {
784             BaseMap ret = new BaseMap();
785             int mapSize = buffer.getInt();
786             DataPackage<String> strDataPackage =
787                     (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
788             if (strDataPackage == null) {
789                 Log.e(TAG, "Cannot find DataPackage for String");
790                 return null;
791             }
792             for (int i = 0; i < mapSize; i++) {
793                 String key = strDataPackage.unpack(buffer);
794                 if (key == null) {
795                     Log.e(TAG, "Failed to unpack key for map");
796                     return null;
797                 }
798                 Pair<Class, Object> value = OBJECT_PACKAGE.unpack(buffer);
799                 if (value == null) {
800                     Log.e(TAG, "Failed to unpack value for map");
801                     return null;
802                 }
803 
804                 // Special handling of KEY_ATMOS_PRESENT.
805                 if (key.equals(Format.KEY_HAS_ATMOS.getName())
806                         && value.first == Format.KEY_HAS_ATMOS.getValueClass()) {
807                     ret.set(Format.KEY_ATMOS_PRESENT,
808                             (Boolean) ((int) value.second != 0));  // Translate Integer to Boolean
809                     continue; // Should we store both keys in the java table?
810                 }
811 
812                 ret.set(createKey(key, value.first), value.first.cast(value.second));
813             }
814             return ret;
815         }
816 
817         @Override
pack(AutoGrowByteBuffer output, BaseMap obj)818         public boolean pack(AutoGrowByteBuffer output, BaseMap obj) {
819             output.putInt(obj.size());
820             DataPackage<String> strDataPackage =
821                     (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
822             if (strDataPackage == null) {
823                 Log.e(TAG, "Cannot find DataPackage for String");
824                 return false;
825             }
826             for (Key<?> key : obj.keySet()) {
827                 Object value = obj.get(key);
828 
829                 // Special handling of KEY_ATMOS_PRESENT.
830                 if (key == Format.KEY_ATMOS_PRESENT) {
831                     key = Format.KEY_HAS_ATMOS;
832                     value = (Integer) ((boolean) value ? 1 : 0); // Translate Boolean to Integer
833                 }
834 
835                 if (!strDataPackage.pack(output, key.getName())) {
836                     Log.i(TAG, "Failed to pack key: " + key.getName());
837                     return false;
838                 }
839                 if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), value))) {
840                     Log.i(TAG, "Failed to pack value: " + obj.get(key));
841                     return false;
842                 }
843             }
844             return true;
845         }
846     }
847 
848     /**
849      * @hide
850      * Extract a {@link BaseMap} from a given {@link ByteBuffer}
851      * @param buffer is a byte string that contains information to unpack.
852      * @return a {@link BaseMap} object if extracting successfully from given byte buffer.
853      *     Otherwise, returns {@code null}.
854      */
855     @Nullable
fromByteBuffer(ByteBuffer buffer)856     public static BaseMap fromByteBuffer(ByteBuffer buffer) {
857         DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
858         if (dataPackage == null) {
859             Log.e(TAG, "Cannot find DataPackage for BaseMap");
860             return null;
861         }
862         try {
863             return (BaseMap) dataPackage.unpack(buffer);
864         } catch (BufferUnderflowException e) {
865             Log.e(TAG, "No enough data to unpack");
866         }
867         return null;
868     }
869 
870     /**
871      * @hide
872      * Pack a {link BaseMap} to a {@link ByteBuffer}
873      * @param data is the object for packing
874      * @param order is the byte order
875      * @return a {@link ByteBuffer} if successfully packing the data.
876      *     Otherwise, returns {@code null};
877      */
878     @Nullable
toByteBuffer(BaseMap data, ByteOrder order)879     public static ByteBuffer toByteBuffer(BaseMap data, ByteOrder order) {
880         DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
881         if (dataPackage == null) {
882             Log.e(TAG, "Cannot find DataPackage for BaseMap");
883             return null;
884         }
885         AutoGrowByteBuffer output = new AutoGrowByteBuffer();
886         output.order(order);
887         if (dataPackage.pack(output, data)) {
888             return output.getRawByteBuffer();
889         }
890         return null;
891     }
892 
893     // Delete the constructor as there is nothing to implement here.
AudioMetadata()894     private AudioMetadata() {}
895 }
896