Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2014 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.IntDef;
     20 import android.annotation.SystemApi;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 import android.text.TextUtils;
     24 import android.util.Log;
     25 
     26 import java.lang.annotation.Retention;
     27 import java.lang.annotation.RetentionPolicy;
     28 import java.util.Collections;
     29 import java.util.HashSet;
     30 import java.util.Iterator;
     31 import java.util.Objects;
     32 import java.util.Set;
     33 
     34 /**
     35  * A class to encapsulate a collection of attributes describing information about an audio
     36  * stream.
     37  * <p><code>AudioAttributes</code> supersede the notion of stream types (see for instance
     38  * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}) for defining the
     39  * behavior of audio playback. Attributes allow an application to specify more information than is
     40  * conveyed in a stream type by allowing the application to define:
     41  * <ul>
     42  * <li>usage: "why" you are playing a sound, what is this sound used for. This is achieved with
     43  *     the "usage" information. Examples of usage are {@link #USAGE_MEDIA} and {@link #USAGE_ALARM}.
     44  *     These two examples are the closest to stream types, but more detailed use cases are
     45  *     available. Usage information is more expressive than a stream type, and allows certain
     46  *     platforms or routing policies to use this information for more refined volume or routing
     47  *     decisions. Usage is the most important information to supply in <code>AudioAttributes</code>
     48  *     and it is recommended to build any instance with this information supplied, see
     49  *     {@link AudioAttributes.Builder} for exceptions.</li>
     50  * <li>content type: "what" you are playing. The content type expresses the general category of
     51  *     the content. This information is optional. But in case it is known (for instance
     52  *     {@link #CONTENT_TYPE_MOVIE} for a movie streaming service or {@link #CONTENT_TYPE_MUSIC} for
     53  *     a music playback application) this information might be used by the audio framework to
     54  *     selectively configure some audio post-processing blocks.</li>
     55  * <li>flags: "how" is playback to be affected, see the flag definitions for the specific playback
     56  *     behaviors they control. </li>
     57  * </ul>
     58  * <p><code>AudioAttributes</code> are used for example in one of the {@link AudioTrack}
     59  * constructors (see {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}),
     60  * to configure a {@link MediaPlayer}
     61  * (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)} or a
     62  * {@link android.app.Notification} (see {@link android.app.Notification#audioAttributes}). An
     63  * <code>AudioAttributes</code> instance is built through its builder,
     64  * {@link AudioAttributes.Builder}.
     65  */
     66 public final class AudioAttributes implements Parcelable {
     67     private final static String TAG = "AudioAttributes";
     68 
     69     /**
     70      * Content type value to use when the content type is unknown, or other than the ones defined.
     71      */
     72     public final static int CONTENT_TYPE_UNKNOWN = 0;
     73     /**
     74      * Content type value to use when the content type is speech.
     75      */
     76     public final static int CONTENT_TYPE_SPEECH = 1;
     77     /**
     78      * Content type value to use when the content type is music.
     79      */
     80     public final static int CONTENT_TYPE_MUSIC = 2;
     81     /**
     82      * Content type value to use when the content type is a soundtrack, typically accompanying
     83      * a movie or TV program.
     84      */
     85     public final static int CONTENT_TYPE_MOVIE = 3;
     86     /**
     87      * Content type value to use when the content type is a sound used to accompany a user
     88      * action, such as a beep or sound effect expressing a key click, or event, such as the
     89      * type of a sound for a bonus being received in a game. These sounds are mostly synthesized
     90      * or short Foley sounds.
     91      */
     92     public final static int CONTENT_TYPE_SONIFICATION = 4;
     93 
     94     /**
     95      * Usage value to use when the usage is unknown.
     96      */
     97     public final static int USAGE_UNKNOWN = 0;
     98     /**
     99      * Usage value to use when the usage is media, such as music, or movie
    100      * soundtracks.
    101      */
    102     public final static int USAGE_MEDIA = 1;
    103     /**
    104      * Usage value to use when the usage is voice communications, such as telephony
    105      * or VoIP.
    106      */
    107     public final static int USAGE_VOICE_COMMUNICATION = 2;
    108     /**
    109      * Usage value to use when the usage is in-call signalling, such as with
    110      * a "busy" beep, or DTMF tones.
    111      */
    112     public final static int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3;
    113     /**
    114      * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
    115      */
    116     public final static int USAGE_ALARM = 4;
    117     /**
    118      * Usage value to use when the usage is notification. See other
    119      * notification usages for more specialized uses.
    120      */
    121     public final static int USAGE_NOTIFICATION = 5;
    122     /**
    123      * Usage value to use when the usage is telephony ringtone.
    124      */
    125     public final static int USAGE_NOTIFICATION_RINGTONE = 6;
    126     /**
    127      * Usage value to use when the usage is a request to enter/end a
    128      * communication, such as a VoIP communication or video-conference.
    129      */
    130     public final static int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7;
    131     /**
    132      * Usage value to use when the usage is notification for an "instant"
    133      * communication such as a chat, or SMS.
    134      */
    135     public final static int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8;
    136     /**
    137      * Usage value to use when the usage is notification for a
    138      * non-immediate type of communication such as e-mail.
    139      */
    140     public final static int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9;
    141     /**
    142      * Usage value to use when the usage is to attract the user's attention,
    143      * such as a reminder or low battery warning.
    144      */
    145     public final static int USAGE_NOTIFICATION_EVENT = 10;
    146     /**
    147      * Usage value to use when the usage is for accessibility, such as with
    148      * a screen reader.
    149      */
    150     public final static int USAGE_ASSISTANCE_ACCESSIBILITY = 11;
    151     /**
    152      * Usage value to use when the usage is driving or navigation directions.
    153      */
    154     public final static int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12;
    155     /**
    156      * Usage value to use when the usage is sonification, such as  with user
    157      * interface sounds.
    158      */
    159     public final static int USAGE_ASSISTANCE_SONIFICATION = 13;
    160     /**
    161      * Usage value to use when the usage is for game audio.
    162      */
    163     public final static int USAGE_GAME = 14;
    164     /**
    165      * @hide
    166      * Usage value to use when feeding audio to the platform and replacing "traditional" audio
    167      * source, such as audio capture devices.
    168      */
    169     public final static int USAGE_VIRTUAL_SOURCE = 15;
    170 
    171     /**
    172      * Flag defining a behavior where the audibility of the sound will be ensured by the system.
    173      */
    174     public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
    175     /**
    176      * @hide
    177      * Flag defining a behavior where the playback of the sound is ensured without
    178      * degradation only when going to a secure sink.
    179      */
    180     // FIXME not guaranteed yet
    181     // TODO  add in FLAG_ALL_PUBLIC when supported and in public API
    182     public final static int FLAG_SECURE = 0x1 << 1;
    183     /**
    184      * @hide
    185      * Flag to enable when the stream is associated with SCO usage.
    186      * Internal use only for dealing with legacy STREAM_BLUETOOTH_SCO
    187      */
    188     public final static int FLAG_SCO = 0x1 << 2;
    189     /**
    190      * @hide
    191      * Flag defining a behavior where the system ensures that the playback of the sound will
    192      * be compatible with its use as a broadcast for surrounding people and/or devices.
    193      * Ensures audibility with no or minimal post-processing applied.
    194      */
    195     @SystemApi
    196     public final static int FLAG_BEACON = 0x1 << 3;
    197 
    198     /**
    199      * Flag requesting the use of an output stream supporting hardware A/V synchronization.
    200      */
    201     public final static int FLAG_HW_AV_SYNC = 0x1 << 4;
    202 
    203     /**
    204      * @hide
    205      * Flag requesting capture from the source used for hardware hotword detection.
    206      * To be used with capture preset MediaRecorder.AudioSource.HOTWORD or
    207      * MediaRecorder.AudioSource.VOICE_RECOGNITION.
    208      */
    209     @SystemApi
    210     public final static int FLAG_HW_HOTWORD = 0x1 << 5;
    211 
    212     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
    213             FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD;
    214     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
    215 
    216     private int mUsage = USAGE_UNKNOWN;
    217     private int mContentType = CONTENT_TYPE_UNKNOWN;
    218     private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
    219     private int mFlags = 0x0;
    220     private HashSet<String> mTags;
    221     private String mFormattedTags;
    222 
    223     private AudioAttributes() {
    224     }
    225 
    226     /**
    227      * Return the content type.
    228      * @return one of the values that can be set in {@link Builder#setContentType(int)}
    229      */
    230     public int getContentType() {
    231         return mContentType;
    232     }
    233 
    234     /**
    235      * Return the usage.
    236      * @return one of the values that can be set in {@link Builder#setUsage(int)}
    237      */
    238     public int getUsage() {
    239         return mUsage;
    240     }
    241 
    242     /**
    243      * @hide
    244      * Return the capture preset.
    245      * @return one of the values that can be set in {@link Builder#setCapturePreset(int)} or a
    246      *    negative value if none has been set.
    247      */
    248     @SystemApi
    249     public int getCapturePreset() {
    250         return mSource;
    251     }
    252 
    253     /**
    254      * Return the flags.
    255      * @return a combined mask of all flags
    256      */
    257     public int getFlags() {
    258         // only return the flags that are public
    259         return (mFlags & (FLAG_ALL_PUBLIC));
    260     }
    261 
    262     /**
    263      * @hide
    264      * Return all the flags, even the non-public ones.
    265      * Internal use only
    266      * @return a combined mask of all flags
    267      */
    268     public int getAllFlags() {
    269         return (mFlags & FLAG_ALL);
    270     }
    271 
    272     /**
    273      * @hide
    274      * Return the set of tags.
    275      * @return a read-only set of all tags stored as strings.
    276      */
    277     public Set<String> getTags() {
    278         return Collections.unmodifiableSet(mTags);
    279     }
    280 
    281     /**
    282      * Builder class for {@link AudioAttributes} objects.
    283      * <p> Here is an example where <code>Builder</code> is used to define the
    284      * {@link AudioAttributes} to be used by a new <code>AudioTrack</code> instance:
    285      *
    286      * <pre class="prettyprint">
    287      * AudioTrack myTrack = new AudioTrack(
    288      *         new AudioAttributes.Builder()
    289      *             .setUsage(AudioAttributes.USAGE_MEDIA)
    290      *             .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
    291      *             .build(),
    292      *         myFormat, myBuffSize, AudioTrack.MODE_STREAM, mySession);
    293      * </pre>
    294      *
    295      * <p>By default all types of information (usage, content type, flags) conveyed by an
    296      * <code>AudioAttributes</code> instance are set to "unknown". Unknown information will be
    297      * interpreted as a default value that is dependent on the context of use, for instance a
    298      * {@link MediaPlayer} will use a default usage of {@link AudioAttributes#USAGE_MEDIA}.
    299      */
    300     public static class Builder {
    301         private int mUsage = USAGE_UNKNOWN;
    302         private int mContentType = CONTENT_TYPE_UNKNOWN;
    303         private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
    304         private int mFlags = 0x0;
    305         private HashSet<String> mTags = new HashSet<String>();
    306 
    307         /**
    308          * Constructs a new Builder with the defaults.
    309          * By default, usage and content type are respectively {@link AudioAttributes#USAGE_UNKNOWN}
    310          * and {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}, and flags are 0. It is recommended to
    311          * configure the usage (with {@link #setUsage(int)}) or deriving attributes from a legacy
    312          * stream type (with {@link #setLegacyStreamType(int)}) before calling {@link #build()}
    313          * to override any default playback behavior in terms of routing and volume management.
    314          */
    315         public Builder() {
    316         }
    317 
    318         /**
    319          * Constructs a new Builder from a given AudioAttributes
    320          * @param aa the AudioAttributes object whose data will be reused in the new Builder.
    321          */
    322         @SuppressWarnings("unchecked") // for cloning of mTags
    323         public Builder(AudioAttributes aa) {
    324             mUsage = aa.mUsage;
    325             mContentType = aa.mContentType;
    326             mFlags = aa.mFlags;
    327             mTags = (HashSet<String>) aa.mTags.clone();
    328         }
    329 
    330         /**
    331          * Combines all of the attributes that have been set and return a new
    332          * {@link AudioAttributes} object.
    333          * @return a new {@link AudioAttributes} object
    334          */
    335         @SuppressWarnings("unchecked") // for cloning of mTags
    336         public AudioAttributes build() {
    337             AudioAttributes aa = new AudioAttributes();
    338             aa.mContentType = mContentType;
    339             aa.mUsage = mUsage;
    340             aa.mSource = mSource;
    341             aa.mFlags = mFlags;
    342             aa.mTags = (HashSet<String>) mTags.clone();
    343             aa.mFormattedTags = TextUtils.join(";", mTags);
    344             return aa;
    345         }
    346 
    347         /**
    348          * Sets the attribute describing what is the intended use of the the audio signal,
    349          * such as alarm or ringtone.
    350          * @param usage one of {@link AudioAttributes#USAGE_UNKNOWN},
    351          *     {@link AudioAttributes#USAGE_MEDIA},
    352          *     {@link AudioAttributes#USAGE_VOICE_COMMUNICATION},
    353          *     {@link AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING},
    354          *     {@link AudioAttributes#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
    355          *     {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE},
    356          *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST},
    357          *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT},
    358          *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED},
    359          *     {@link AudioAttributes#USAGE_NOTIFICATION_EVENT},
    360          *     {@link AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY},
    361          *     {@link AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE},
    362          *     {@link AudioAttributes#USAGE_ASSISTANCE_SONIFICATION},
    363          *     {@link AudioAttributes#USAGE_GAME}.
    364          * @return the same Builder instance.
    365          */
    366         public Builder setUsage(@AttributeUsage int usage) {
    367             switch (usage) {
    368                 case USAGE_UNKNOWN:
    369                 case USAGE_MEDIA:
    370                 case USAGE_VOICE_COMMUNICATION:
    371                 case USAGE_VOICE_COMMUNICATION_SIGNALLING:
    372                 case USAGE_ALARM:
    373                 case USAGE_NOTIFICATION:
    374                 case USAGE_NOTIFICATION_RINGTONE:
    375                 case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
    376                 case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
    377                 case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
    378                 case USAGE_NOTIFICATION_EVENT:
    379                 case USAGE_ASSISTANCE_ACCESSIBILITY:
    380                 case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
    381                 case USAGE_ASSISTANCE_SONIFICATION:
    382                 case USAGE_GAME:
    383                 case USAGE_VIRTUAL_SOURCE:
    384                      mUsage = usage;
    385                      break;
    386                 default:
    387                      mUsage = USAGE_UNKNOWN;
    388             }
    389             return this;
    390         }
    391 
    392         /**
    393          * Sets the attribute describing the content type of the audio signal, such as speech,
    394          * or music.
    395          * @param contentType the content type values, one of
    396          *     {@link AudioAttributes#CONTENT_TYPE_MOVIE},
    397          *     {@link AudioAttributes#CONTENT_TYPE_MUSIC},
    398          *     {@link AudioAttributes#CONTENT_TYPE_SONIFICATION},
    399          *     {@link AudioAttributes#CONTENT_TYPE_SPEECH},
    400          *     {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}.
    401          * @return the same Builder instance.
    402          */
    403         public Builder setContentType(@AttributeContentType int contentType) {
    404             switch (contentType) {
    405                 case CONTENT_TYPE_UNKNOWN:
    406                 case CONTENT_TYPE_MOVIE:
    407                 case CONTENT_TYPE_MUSIC:
    408                 case CONTENT_TYPE_SONIFICATION:
    409                 case CONTENT_TYPE_SPEECH:
    410                      mContentType = contentType;
    411                      break;
    412                 default:
    413                      mUsage = CONTENT_TYPE_UNKNOWN;
    414             }
    415             return this;
    416         }
    417 
    418         /**
    419          * Sets the combination of flags.
    420          * @param flags the {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED} flag.
    421          * @return the same Builder instance.
    422          */
    423         public Builder setFlags(int flags) {
    424             flags &= AudioAttributes.FLAG_ALL;
    425             mFlags |= flags;
    426             return this;
    427         }
    428 
    429         /**
    430          * @hide
    431          * Add a custom tag stored as a string
    432          * @param tag
    433          * @return the same Builder instance.
    434          */
    435         public Builder addTag(String tag) {
    436             mTags.add(tag);
    437             return this;
    438         }
    439 
    440         /**
    441          * Sets attributes as inferred from the legacy stream types.
    442          * Use this method when building an {@link AudioAttributes} instance to initialize some of
    443          * the attributes by information derived from a legacy stream type.
    444          * @param streamType one of {@link AudioManager#STREAM_VOICE_CALL},
    445          *   {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
    446          *   {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM},
    447          *    or {@link AudioManager#STREAM_NOTIFICATION}.
    448          * @return the same Builder instance.
    449          */
    450         public Builder setLegacyStreamType(int streamType) {
    451             return setInternalLegacyStreamType(streamType);
    452         }
    453 
    454         /**
    455          * @hide
    456          * For internal framework use only, enables building from hidden stream types.
    457          * @param streamType
    458          * @return the same Builder instance.
    459          */
    460         public Builder setInternalLegacyStreamType(int streamType) {
    461             switch(streamType) {
    462                 case AudioSystem.STREAM_VOICE_CALL:
    463                     mContentType = CONTENT_TYPE_SPEECH;
    464                     break;
    465                 case AudioSystem.STREAM_SYSTEM_ENFORCED:
    466                     mFlags |= FLAG_AUDIBILITY_ENFORCED;
    467                     // intended fall through, attributes in common with STREAM_SYSTEM
    468                 case AudioSystem.STREAM_SYSTEM:
    469                     mContentType = CONTENT_TYPE_SONIFICATION;
    470                     break;
    471                 case AudioSystem.STREAM_RING:
    472                     mContentType = CONTENT_TYPE_SONIFICATION;
    473                     break;
    474                 case AudioSystem.STREAM_MUSIC:
    475                     mContentType = CONTENT_TYPE_MUSIC;
    476                     break;
    477                 case AudioSystem.STREAM_ALARM:
    478                     mContentType = CONTENT_TYPE_SONIFICATION;
    479                     break;
    480                 case AudioSystem.STREAM_NOTIFICATION:
    481                     mContentType = CONTENT_TYPE_SONIFICATION;
    482                     break;
    483                 case AudioSystem.STREAM_BLUETOOTH_SCO:
    484                     mContentType = CONTENT_TYPE_SPEECH;
    485                     mFlags |= FLAG_SCO;
    486                     break;
    487                 case AudioSystem.STREAM_DTMF:
    488                     mContentType = CONTENT_TYPE_SONIFICATION;
    489                     break;
    490                 case AudioSystem.STREAM_TTS:
    491                     mContentType = CONTENT_TYPE_SPEECH;
    492                     break;
    493                 default:
    494                     Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
    495             }
    496             mUsage = usageForLegacyStreamType(streamType);
    497             return this;
    498         }
    499 
    500         /**
    501          * @hide
    502          * Sets the capture preset.
    503          * Use this audio attributes configuration method when building an {@link AudioRecord}
    504          * instance with {@link AudioRecord#AudioRecord(AudioAttributes, AudioFormat, int)}.
    505          * @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
    506          *     {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
    507          *     {@link MediaRecorder.AudioSource#VOICE_RECOGNITION} or
    508          *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
    509          * @return the same Builder instance.
    510          */
    511         @SystemApi
    512         public Builder setCapturePreset(int preset) {
    513             switch (preset) {
    514                 case MediaRecorder.AudioSource.DEFAULT:
    515                 case MediaRecorder.AudioSource.MIC:
    516                 case MediaRecorder.AudioSource.CAMCORDER:
    517                 case MediaRecorder.AudioSource.VOICE_RECOGNITION:
    518                 case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
    519                     mSource = preset;
    520                     break;
    521                 default:
    522                     Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes");
    523             }
    524             return this;
    525         }
    526 
    527         /**
    528          * @hide
    529          * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
    530          * REMOTE_SUBMIX and FM_TUNER.
    531          * @param preset
    532          * @return the same Builder instance.
    533          */
    534         public Builder setInternalCapturePreset(int preset) {
    535             if ((preset == MediaRecorder.AudioSource.HOTWORD)
    536                     || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)
    537                     || (preset == MediaRecorder.AudioSource.FM_TUNER)) {
    538                 mSource = preset;
    539             } else {
    540                 setCapturePreset(preset);
    541             }
    542             return this;
    543         }
    544     };
    545 
    546     @Override
    547     public int describeContents() {
    548         return 0;
    549     }
    550 
    551     /**
    552      * @hide
    553      * Used to indicate that when parcelling, the tags should be parcelled through the flattened
    554      * formatted string, not through the array of strings.
    555      * Keep in sync with frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
    556      * see definition of kAudioAttributesMarshallTagFlattenTags
    557      */
    558     public final static int FLATTEN_TAGS = 0x1;
    559     /**
    560      * When adding tags for writeToParcel(Parcel, int), add them in the list of flags (| NEW_FLAG)
    561      */
    562     private final static int ALL_PARCEL_FLAGS = FLATTEN_TAGS;
    563     @Override
    564     public void writeToParcel(Parcel dest, int flags) {
    565         dest.writeInt(mUsage);
    566         dest.writeInt(mContentType);
    567         dest.writeInt(mSource);
    568         dest.writeInt(mFlags);
    569         dest.writeInt(flags & ALL_PARCEL_FLAGS);
    570         if ((flags & FLATTEN_TAGS) == 0) {
    571             String[] tagsArray = new String[mTags.size()];
    572             mTags.toArray(tagsArray);
    573             dest.writeStringArray(tagsArray);
    574         } else if ((flags & FLATTEN_TAGS) == FLATTEN_TAGS) {
    575             dest.writeString(mFormattedTags);
    576         }
    577     }
    578 
    579     private AudioAttributes(Parcel in) {
    580         mUsage = in.readInt();
    581         mContentType = in.readInt();
    582         mSource = in.readInt();
    583         mFlags = in.readInt();
    584         boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS);
    585         mTags = new HashSet<String>();
    586         if (hasFlattenedTags) {
    587             mFormattedTags = new String(in.readString());
    588             mTags.add(mFormattedTags);
    589         } else {
    590             String[] tagsArray = in.readStringArray();
    591             for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
    592                 mTags.add(tagsArray[i]);
    593             }
    594             mFormattedTags = TextUtils.join(";", mTags);
    595         }
    596     }
    597 
    598     public static final Parcelable.Creator<AudioAttributes> CREATOR
    599             = new Parcelable.Creator<AudioAttributes>() {
    600         /**
    601          * Rebuilds an AudioAttributes previously stored with writeToParcel().
    602          * @param p Parcel object to read the AudioAttributes from
    603          * @return a new AudioAttributes created from the data in the parcel
    604          */
    605         public AudioAttributes createFromParcel(Parcel p) {
    606             return new AudioAttributes(p);
    607         }
    608         public AudioAttributes[] newArray(int size) {
    609             return new AudioAttributes[size];
    610         }
    611     };
    612 
    613     @Override
    614     public boolean equals(Object o) {
    615         if (this == o) return true;
    616         if (o == null || getClass() != o.getClass()) return false;
    617 
    618         AudioAttributes that = (AudioAttributes) o;
    619 
    620         return ((mContentType == that.mContentType)
    621                 && (mFlags == that.mFlags)
    622                 && (mSource == that.mSource)
    623                 && (mUsage == that.mUsage)
    624                 //mFormattedTags is never null due to assignment in Builder or unmarshalling
    625                 && (mFormattedTags.equals(that.mFormattedTags)));
    626     }
    627 
    628     @Override
    629     public int hashCode() {
    630         return Objects.hash(mContentType, mFlags, mSource, mUsage, mFormattedTags);
    631     }
    632 
    633     @Override
    634     public String toString () {
    635         return new String("AudioAttributes:"
    636                 + " usage=" + mUsage
    637                 + " content=" + mContentType
    638                 + " flags=0x" + Integer.toHexString(mFlags).toUpperCase()
    639                 + " tags=" + mFormattedTags);
    640     }
    641 
    642     /** @hide */
    643     public String usageToString() {
    644         return usageToString(mUsage);
    645     }
    646 
    647     /** @hide */
    648     public static String usageToString(int usage) {
    649         switch(usage) {
    650             case USAGE_UNKNOWN:
    651                 return new String("USAGE_UNKNOWN");
    652             case USAGE_MEDIA:
    653                 return new String("USAGE_MEDIA");
    654             case USAGE_VOICE_COMMUNICATION:
    655                 return new String("USAGE_VOICE_COMMUNICATION");
    656             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
    657                 return new String("USAGE_VOICE_COMMUNICATION");
    658             case USAGE_ALARM:
    659                 return new String("USAGE_ALARM");
    660             case USAGE_NOTIFICATION:
    661                 return new String("USAGE_NOTIFICATION");
    662             case USAGE_NOTIFICATION_RINGTONE:
    663                 return new String("USAGE_NOTIFICATION");
    664             case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
    665                 return new String("USAGE_NOTIFICATION");
    666             case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
    667                 return new String("USAGE_NOTIFICATION_COMMUNICATION_INSTANT");
    668             case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
    669                 return new String("USAGE_NOTIFICATION_COMMUNICATION_DELAYED");
    670             case USAGE_NOTIFICATION_EVENT:
    671                 return new String("USAGE_NOTIFICATION_EVENT");
    672             case USAGE_ASSISTANCE_ACCESSIBILITY:
    673                 return new String("USAGE_ASSISTANCE_ACCESSIBILITY");
    674             case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
    675                 return new String("USAGE_ASSISTANCE_NAVIGATION_GUIDANCE");
    676             case USAGE_ASSISTANCE_SONIFICATION:
    677                 return new String("USAGE_ASSISTANCE_SONIFICATION");
    678             case USAGE_GAME:
    679                 return new String("USAGE_GAME");
    680             default:
    681                 return new String("unknown usage " + usage);
    682         }
    683     }
    684 
    685     /** @hide */
    686     public static int usageForLegacyStreamType(int streamType) {
    687         switch(streamType) {
    688             case AudioSystem.STREAM_VOICE_CALL:
    689                 return USAGE_VOICE_COMMUNICATION;
    690             case AudioSystem.STREAM_SYSTEM_ENFORCED:
    691             case AudioSystem.STREAM_SYSTEM:
    692                 return USAGE_ASSISTANCE_SONIFICATION;
    693             case AudioSystem.STREAM_RING:
    694                 return USAGE_NOTIFICATION_RINGTONE;
    695             case AudioSystem.STREAM_MUSIC:
    696                 return USAGE_MEDIA;
    697             case AudioSystem.STREAM_ALARM:
    698                 return USAGE_ALARM;
    699             case AudioSystem.STREAM_NOTIFICATION:
    700                 return USAGE_NOTIFICATION;
    701             case AudioSystem.STREAM_BLUETOOTH_SCO:
    702                 return USAGE_VOICE_COMMUNICATION;
    703             case AudioSystem.STREAM_DTMF:
    704                 return USAGE_VOICE_COMMUNICATION_SIGNALLING;
    705             case AudioSystem.STREAM_TTS:
    706                 return USAGE_ASSISTANCE_ACCESSIBILITY;
    707             default:
    708                 return USAGE_UNKNOWN;
    709         }
    710     }
    711 
    712     /** @hide */
    713     public static int toLegacyStreamType(AudioAttributes aa) {
    714         // flags to stream type mapping
    715         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
    716             return AudioSystem.STREAM_SYSTEM_ENFORCED;
    717         }
    718         if ((aa.getFlags() & FLAG_SCO) == FLAG_SCO) {
    719             return AudioSystem.STREAM_BLUETOOTH_SCO;
    720         }
    721 
    722         // usage to stream type mapping
    723         switch (aa.getUsage()) {
    724             case USAGE_MEDIA:
    725             case USAGE_GAME:
    726             case USAGE_ASSISTANCE_ACCESSIBILITY:
    727             case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
    728                 return AudioSystem.STREAM_MUSIC;
    729             case USAGE_ASSISTANCE_SONIFICATION:
    730                 return AudioSystem.STREAM_SYSTEM;
    731             case USAGE_VOICE_COMMUNICATION:
    732                 return AudioSystem.STREAM_VOICE_CALL;
    733             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
    734                 return AudioSystem.STREAM_DTMF;
    735             case USAGE_ALARM:
    736                 return AudioSystem.STREAM_ALARM;
    737             case USAGE_NOTIFICATION_RINGTONE:
    738                 return AudioSystem.STREAM_RING;
    739             case USAGE_NOTIFICATION:
    740             case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
    741             case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
    742             case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
    743             case USAGE_NOTIFICATION_EVENT:
    744                 return AudioSystem.STREAM_NOTIFICATION;
    745             case USAGE_UNKNOWN:
    746             default:
    747                 return AudioSystem.STREAM_MUSIC;
    748         }
    749     }
    750 
    751     /** @hide */
    752     @IntDef({
    753         USAGE_UNKNOWN,
    754         USAGE_MEDIA,
    755         USAGE_VOICE_COMMUNICATION,
    756         USAGE_VOICE_COMMUNICATION_SIGNALLING,
    757         USAGE_ALARM,
    758         USAGE_NOTIFICATION,
    759         USAGE_NOTIFICATION_RINGTONE,
    760         USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
    761         USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
    762         USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
    763         USAGE_NOTIFICATION_EVENT,
    764         USAGE_ASSISTANCE_ACCESSIBILITY,
    765         USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
    766         USAGE_ASSISTANCE_SONIFICATION,
    767         USAGE_GAME
    768     })
    769     @Retention(RetentionPolicy.SOURCE)
    770     public @interface AttributeUsage {}
    771 
    772     /** @hide */
    773     @IntDef({
    774         CONTENT_TYPE_UNKNOWN,
    775         CONTENT_TYPE_SPEECH,
    776         CONTENT_TYPE_MUSIC,
    777         CONTENT_TYPE_MOVIE,
    778         CONTENT_TYPE_SONIFICATION
    779     })
    780     @Retention(RetentionPolicy.SOURCE)
    781     public @interface AttributeContentType {}
    782 }
    783