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.NonNull;
     21 import android.annotation.SystemApi;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.text.TextUtils;
     25 import android.util.Log;
     26 
     27 import java.lang.annotation.Retention;
     28 import java.lang.annotation.RetentionPolicy;
     29 import java.util.Collections;
     30 import java.util.HashSet;
     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     /**
    213      * @hide
    214      * Flag requesting audible playback even under limited interruptions.
    215      */
    216     @SystemApi
    217     public final static int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1 << 6;
    218 
    219     /**
    220      * @hide
    221      * Flag requesting audible playback even when the underlying stream is muted.
    222      */
    223     @SystemApi
    224     public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
    225 
    226     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
    227             FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
    228             FLAG_BYPASS_MUTE;
    229     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
    230 
    231     private int mUsage = USAGE_UNKNOWN;
    232     private int mContentType = CONTENT_TYPE_UNKNOWN;
    233     private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
    234     private int mFlags = 0x0;
    235     private HashSet<String> mTags;
    236     private String mFormattedTags;
    237 
    238     private AudioAttributes() {
    239     }
    240 
    241     /**
    242      * Return the content type.
    243      * @return one of the values that can be set in {@link Builder#setContentType(int)}
    244      */
    245     public int getContentType() {
    246         return mContentType;
    247     }
    248 
    249     /**
    250      * Return the usage.
    251      * @return one of the values that can be set in {@link Builder#setUsage(int)}
    252      */
    253     public int getUsage() {
    254         return mUsage;
    255     }
    256 
    257     /**
    258      * @hide
    259      * Return the capture preset.
    260      * @return one of the values that can be set in {@link Builder#setCapturePreset(int)} or a
    261      *    negative value if none has been set.
    262      */
    263     @SystemApi
    264     public int getCapturePreset() {
    265         return mSource;
    266     }
    267 
    268     /**
    269      * Return the flags.
    270      * @return a combined mask of all flags
    271      */
    272     public int getFlags() {
    273         // only return the flags that are public
    274         return (mFlags & (FLAG_ALL_PUBLIC));
    275     }
    276 
    277     /**
    278      * @hide
    279      * Return all the flags, even the non-public ones.
    280      * Internal use only
    281      * @return a combined mask of all flags
    282      */
    283     @SystemApi
    284     public int getAllFlags() {
    285         return (mFlags & FLAG_ALL);
    286     }
    287 
    288     /**
    289      * @hide
    290      * Return the set of tags.
    291      * @return a read-only set of all tags stored as strings.
    292      */
    293     public Set<String> getTags() {
    294         return Collections.unmodifiableSet(mTags);
    295     }
    296 
    297     /**
    298      * Builder class for {@link AudioAttributes} objects.
    299      * <p> Here is an example where <code>Builder</code> is used to define the
    300      * {@link AudioAttributes} to be used by a new <code>AudioTrack</code> instance:
    301      *
    302      * <pre class="prettyprint">
    303      * AudioTrack myTrack = new AudioTrack(
    304      *         new AudioAttributes.Builder()
    305      *             .setUsage(AudioAttributes.USAGE_MEDIA)
    306      *             .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
    307      *             .build(),
    308      *         myFormat, myBuffSize, AudioTrack.MODE_STREAM, mySession);
    309      * </pre>
    310      *
    311      * <p>By default all types of information (usage, content type, flags) conveyed by an
    312      * <code>AudioAttributes</code> instance are set to "unknown". Unknown information will be
    313      * interpreted as a default value that is dependent on the context of use, for instance a
    314      * {@link MediaPlayer} will use a default usage of {@link AudioAttributes#USAGE_MEDIA}.
    315      */
    316     public static class Builder {
    317         private int mUsage = USAGE_UNKNOWN;
    318         private int mContentType = CONTENT_TYPE_UNKNOWN;
    319         private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
    320         private int mFlags = 0x0;
    321         private HashSet<String> mTags = new HashSet<String>();
    322 
    323         /**
    324          * Constructs a new Builder with the defaults.
    325          * By default, usage and content type are respectively {@link AudioAttributes#USAGE_UNKNOWN}
    326          * and {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}, and flags are 0. It is recommended to
    327          * configure the usage (with {@link #setUsage(int)}) or deriving attributes from a legacy
    328          * stream type (with {@link #setLegacyStreamType(int)}) before calling {@link #build()}
    329          * to override any default playback behavior in terms of routing and volume management.
    330          */
    331         public Builder() {
    332         }
    333 
    334         /**
    335          * Constructs a new Builder from a given AudioAttributes
    336          * @param aa the AudioAttributes object whose data will be reused in the new Builder.
    337          */
    338         @SuppressWarnings("unchecked") // for cloning of mTags
    339         public Builder(AudioAttributes aa) {
    340             mUsage = aa.mUsage;
    341             mContentType = aa.mContentType;
    342             mFlags = aa.mFlags;
    343             mTags = (HashSet<String>) aa.mTags.clone();
    344         }
    345 
    346         /**
    347          * Combines all of the attributes that have been set and return a new
    348          * {@link AudioAttributes} object.
    349          * @return a new {@link AudioAttributes} object
    350          */
    351         @SuppressWarnings("unchecked") // for cloning of mTags
    352         public AudioAttributes build() {
    353             AudioAttributes aa = new AudioAttributes();
    354             aa.mContentType = mContentType;
    355             aa.mUsage = mUsage;
    356             aa.mSource = mSource;
    357             aa.mFlags = mFlags;
    358             aa.mTags = (HashSet<String>) mTags.clone();
    359             aa.mFormattedTags = TextUtils.join(";", mTags);
    360             return aa;
    361         }
    362 
    363         /**
    364          * Sets the attribute describing what is the intended use of the the audio signal,
    365          * such as alarm or ringtone.
    366          * @param usage one of {@link AudioAttributes#USAGE_UNKNOWN},
    367          *     {@link AudioAttributes#USAGE_MEDIA},
    368          *     {@link AudioAttributes#USAGE_VOICE_COMMUNICATION},
    369          *     {@link AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING},
    370          *     {@link AudioAttributes#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
    371          *     {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE},
    372          *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST},
    373          *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT},
    374          *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED},
    375          *     {@link AudioAttributes#USAGE_NOTIFICATION_EVENT},
    376          *     {@link AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY},
    377          *     {@link AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE},
    378          *     {@link AudioAttributes#USAGE_ASSISTANCE_SONIFICATION},
    379          *     {@link AudioAttributes#USAGE_GAME}.
    380          * @return the same Builder instance.
    381          */
    382         public Builder setUsage(@AttributeUsage int usage) {
    383             switch (usage) {
    384                 case USAGE_UNKNOWN:
    385                 case USAGE_MEDIA:
    386                 case USAGE_VOICE_COMMUNICATION:
    387                 case USAGE_VOICE_COMMUNICATION_SIGNALLING:
    388                 case USAGE_ALARM:
    389                 case USAGE_NOTIFICATION:
    390                 case USAGE_NOTIFICATION_RINGTONE:
    391                 case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
    392                 case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
    393                 case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
    394                 case USAGE_NOTIFICATION_EVENT:
    395                 case USAGE_ASSISTANCE_ACCESSIBILITY:
    396                 case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
    397                 case USAGE_ASSISTANCE_SONIFICATION:
    398                 case USAGE_GAME:
    399                 case USAGE_VIRTUAL_SOURCE:
    400                      mUsage = usage;
    401                      break;
    402                 default:
    403                      mUsage = USAGE_UNKNOWN;
    404             }
    405             return this;
    406         }
    407 
    408         /**
    409          * Sets the attribute describing the content type of the audio signal, such as speech,
    410          * or music.
    411          * @param contentType the content type values, one of
    412          *     {@link AudioAttributes#CONTENT_TYPE_MOVIE},
    413          *     {@link AudioAttributes#CONTENT_TYPE_MUSIC},
    414          *     {@link AudioAttributes#CONTENT_TYPE_SONIFICATION},
    415          *     {@link AudioAttributes#CONTENT_TYPE_SPEECH},
    416          *     {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}.
    417          * @return the same Builder instance.
    418          */
    419         public Builder setContentType(@AttributeContentType int contentType) {
    420             switch (contentType) {
    421                 case CONTENT_TYPE_UNKNOWN:
    422                 case CONTENT_TYPE_MOVIE:
    423                 case CONTENT_TYPE_MUSIC:
    424                 case CONTENT_TYPE_SONIFICATION:
    425                 case CONTENT_TYPE_SPEECH:
    426                      mContentType = contentType;
    427                      break;
    428                 default:
    429                      mUsage = CONTENT_TYPE_UNKNOWN;
    430             }
    431             return this;
    432         }
    433 
    434         /**
    435          * Sets the combination of flags.
    436          * @param flags the {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED} flag.
    437          * @return the same Builder instance.
    438          */
    439         public Builder setFlags(int flags) {
    440             flags &= AudioAttributes.FLAG_ALL;
    441             mFlags |= flags;
    442             return this;
    443         }
    444 
    445         /**
    446          * @hide
    447          * Add a custom tag stored as a string
    448          * @param tag
    449          * @return the same Builder instance.
    450          */
    451         public Builder addTag(String tag) {
    452             mTags.add(tag);
    453             return this;
    454         }
    455 
    456         /**
    457          * Sets attributes as inferred from the legacy stream types.
    458          * Use this method when building an {@link AudioAttributes} instance to initialize some of
    459          * the attributes by information derived from a legacy stream type.
    460          * @param streamType one of {@link AudioManager#STREAM_VOICE_CALL},
    461          *   {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
    462          *   {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM},
    463          *    or {@link AudioManager#STREAM_NOTIFICATION}.
    464          * @return the same Builder instance.
    465          */
    466         public Builder setLegacyStreamType(int streamType) {
    467             return setInternalLegacyStreamType(streamType);
    468         }
    469 
    470         /**
    471          * @hide
    472          * For internal framework use only, enables building from hidden stream types.
    473          * @param streamType
    474          * @return the same Builder instance.
    475          */
    476         public Builder setInternalLegacyStreamType(int streamType) {
    477             switch(streamType) {
    478                 case AudioSystem.STREAM_VOICE_CALL:
    479                     mContentType = CONTENT_TYPE_SPEECH;
    480                     break;
    481                 case AudioSystem.STREAM_SYSTEM_ENFORCED:
    482                     mFlags |= FLAG_AUDIBILITY_ENFORCED;
    483                     // intended fall through, attributes in common with STREAM_SYSTEM
    484                 case AudioSystem.STREAM_SYSTEM:
    485                     mContentType = CONTENT_TYPE_SONIFICATION;
    486                     break;
    487                 case AudioSystem.STREAM_RING:
    488                     mContentType = CONTENT_TYPE_SONIFICATION;
    489                     break;
    490                 case AudioSystem.STREAM_MUSIC:
    491                     mContentType = CONTENT_TYPE_MUSIC;
    492                     break;
    493                 case AudioSystem.STREAM_ALARM:
    494                     mContentType = CONTENT_TYPE_SONIFICATION;
    495                     break;
    496                 case AudioSystem.STREAM_NOTIFICATION:
    497                     mContentType = CONTENT_TYPE_SONIFICATION;
    498                     break;
    499                 case AudioSystem.STREAM_BLUETOOTH_SCO:
    500                     mContentType = CONTENT_TYPE_SPEECH;
    501                     mFlags |= FLAG_SCO;
    502                     break;
    503                 case AudioSystem.STREAM_DTMF:
    504                     mContentType = CONTENT_TYPE_SONIFICATION;
    505                     break;
    506                 case AudioSystem.STREAM_TTS:
    507                     mContentType = CONTENT_TYPE_SPEECH;
    508                     break;
    509                 default:
    510                     Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
    511             }
    512             mUsage = usageForLegacyStreamType(streamType);
    513             return this;
    514         }
    515 
    516         /**
    517          * @hide
    518          * Sets the capture preset.
    519          * Use this audio attributes configuration method when building an {@link AudioRecord}
    520          * instance with {@link AudioRecord#AudioRecord(AudioAttributes, AudioFormat, int)}.
    521          * @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
    522          *     {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
    523          *     {@link MediaRecorder.AudioSource#VOICE_RECOGNITION} or
    524          *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
    525          * @return the same Builder instance.
    526          */
    527         @SystemApi
    528         public Builder setCapturePreset(int preset) {
    529             switch (preset) {
    530                 case MediaRecorder.AudioSource.DEFAULT:
    531                 case MediaRecorder.AudioSource.MIC:
    532                 case MediaRecorder.AudioSource.CAMCORDER:
    533                 case MediaRecorder.AudioSource.VOICE_RECOGNITION:
    534                 case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
    535                     mSource = preset;
    536                     break;
    537                 default:
    538                     Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes");
    539             }
    540             return this;
    541         }
    542 
    543         /**
    544          * @hide
    545          * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
    546          * REMOTE_SUBMIX and RADIO_TUNER.
    547          * @param preset
    548          * @return the same Builder instance.
    549          */
    550         @SystemApi
    551         public Builder setInternalCapturePreset(int preset) {
    552             if ((preset == MediaRecorder.AudioSource.HOTWORD)
    553                     || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)
    554                     || (preset == MediaRecorder.AudioSource.RADIO_TUNER)) {
    555                 mSource = preset;
    556             } else {
    557                 setCapturePreset(preset);
    558             }
    559             return this;
    560         }
    561     };
    562 
    563     @Override
    564     public int describeContents() {
    565         return 0;
    566     }
    567 
    568     /**
    569      * @hide
    570      * Used to indicate that when parcelling, the tags should be parcelled through the flattened
    571      * formatted string, not through the array of strings.
    572      * Keep in sync with frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
    573      * see definition of kAudioAttributesMarshallTagFlattenTags
    574      */
    575     public final static int FLATTEN_TAGS = 0x1;
    576     /**
    577      * When adding tags for writeToParcel(Parcel, int), add them in the list of flags (| NEW_FLAG)
    578      */
    579     private final static int ALL_PARCEL_FLAGS = FLATTEN_TAGS;
    580     @Override
    581     public void writeToParcel(Parcel dest, int flags) {
    582         dest.writeInt(mUsage);
    583         dest.writeInt(mContentType);
    584         dest.writeInt(mSource);
    585         dest.writeInt(mFlags);
    586         dest.writeInt(flags & ALL_PARCEL_FLAGS);
    587         if ((flags & FLATTEN_TAGS) == 0) {
    588             String[] tagsArray = new String[mTags.size()];
    589             mTags.toArray(tagsArray);
    590             dest.writeStringArray(tagsArray);
    591         } else if ((flags & FLATTEN_TAGS) == FLATTEN_TAGS) {
    592             dest.writeString(mFormattedTags);
    593         }
    594     }
    595 
    596     private AudioAttributes(Parcel in) {
    597         mUsage = in.readInt();
    598         mContentType = in.readInt();
    599         mSource = in.readInt();
    600         mFlags = in.readInt();
    601         boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS);
    602         mTags = new HashSet<String>();
    603         if (hasFlattenedTags) {
    604             mFormattedTags = new String(in.readString());
    605             mTags.add(mFormattedTags);
    606         } else {
    607             String[] tagsArray = in.readStringArray();
    608             for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
    609                 mTags.add(tagsArray[i]);
    610             }
    611             mFormattedTags = TextUtils.join(";", mTags);
    612         }
    613     }
    614 
    615     public static final Parcelable.Creator<AudioAttributes> CREATOR
    616             = new Parcelable.Creator<AudioAttributes>() {
    617         /**
    618          * Rebuilds an AudioAttributes previously stored with writeToParcel().
    619          * @param p Parcel object to read the AudioAttributes from
    620          * @return a new AudioAttributes created from the data in the parcel
    621          */
    622         public AudioAttributes createFromParcel(Parcel p) {
    623             return new AudioAttributes(p);
    624         }
    625         public AudioAttributes[] newArray(int size) {
    626             return new AudioAttributes[size];
    627         }
    628     };
    629 
    630     @Override
    631     public boolean equals(Object o) {
    632         if (this == o) return true;
    633         if (o == null || getClass() != o.getClass()) return false;
    634 
    635         AudioAttributes that = (AudioAttributes) o;
    636 
    637         return ((mContentType == that.mContentType)
    638                 && (mFlags == that.mFlags)
    639                 && (mSource == that.mSource)
    640                 && (mUsage == that.mUsage)
    641                 //mFormattedTags is never null due to assignment in Builder or unmarshalling
    642                 && (mFormattedTags.equals(that.mFormattedTags)));
    643     }
    644 
    645     @Override
    646     public int hashCode() {
    647         return Objects.hash(mContentType, mFlags, mSource, mUsage, mFormattedTags);
    648     }
    649 
    650     @Override
    651     public String toString () {
    652         return new String("AudioAttributes:"
    653                 + " usage=" + mUsage
    654                 + " content=" + mContentType
    655                 + " flags=0x" + Integer.toHexString(mFlags).toUpperCase()
    656                 + " tags=" + mFormattedTags);
    657     }
    658 
    659     /** @hide */
    660     public String usageToString() {
    661         return usageToString(mUsage);
    662     }
    663 
    664     /** @hide */
    665     public static String usageToString(int usage) {
    666         switch(usage) {
    667             case USAGE_UNKNOWN:
    668                 return new String("USAGE_UNKNOWN");
    669             case USAGE_MEDIA:
    670                 return new String("USAGE_MEDIA");
    671             case USAGE_VOICE_COMMUNICATION:
    672                 return new String("USAGE_VOICE_COMMUNICATION");
    673             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
    674                 return new String("USAGE_VOICE_COMMUNICATION");
    675             case USAGE_ALARM:
    676                 return new String("USAGE_ALARM");
    677             case USAGE_NOTIFICATION:
    678                 return new String("USAGE_NOTIFICATION");
    679             case USAGE_NOTIFICATION_RINGTONE:
    680                 return new String("USAGE_NOTIFICATION");
    681             case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
    682                 return new String("USAGE_NOTIFICATION");
    683             case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
    684                 return new String("USAGE_NOTIFICATION_COMMUNICATION_INSTANT");
    685             case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
    686                 return new String("USAGE_NOTIFICATION_COMMUNICATION_DELAYED");
    687             case USAGE_NOTIFICATION_EVENT:
    688                 return new String("USAGE_NOTIFICATION_EVENT");
    689             case USAGE_ASSISTANCE_ACCESSIBILITY:
    690                 return new String("USAGE_ASSISTANCE_ACCESSIBILITY");
    691             case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
    692                 return new String("USAGE_ASSISTANCE_NAVIGATION_GUIDANCE");
    693             case USAGE_ASSISTANCE_SONIFICATION:
    694                 return new String("USAGE_ASSISTANCE_SONIFICATION");
    695             case USAGE_GAME:
    696                 return new String("USAGE_GAME");
    697             default:
    698                 return new String("unknown usage " + usage);
    699         }
    700     }
    701 
    702     /** @hide */
    703     public static int usageForLegacyStreamType(int streamType) {
    704         switch(streamType) {
    705             case AudioSystem.STREAM_VOICE_CALL:
    706                 return USAGE_VOICE_COMMUNICATION;
    707             case AudioSystem.STREAM_SYSTEM_ENFORCED:
    708             case AudioSystem.STREAM_SYSTEM:
    709                 return USAGE_ASSISTANCE_SONIFICATION;
    710             case AudioSystem.STREAM_RING:
    711                 return USAGE_NOTIFICATION_RINGTONE;
    712             case AudioSystem.STREAM_MUSIC:
    713                 return USAGE_MEDIA;
    714             case AudioSystem.STREAM_ALARM:
    715                 return USAGE_ALARM;
    716             case AudioSystem.STREAM_NOTIFICATION:
    717                 return USAGE_NOTIFICATION;
    718             case AudioSystem.STREAM_BLUETOOTH_SCO:
    719                 return USAGE_VOICE_COMMUNICATION;
    720             case AudioSystem.STREAM_DTMF:
    721                 return USAGE_VOICE_COMMUNICATION_SIGNALLING;
    722             case AudioSystem.STREAM_TTS:
    723                 return USAGE_ASSISTANCE_ACCESSIBILITY;
    724             default:
    725                 return USAGE_UNKNOWN;
    726         }
    727     }
    728     /**
    729      * @hide
    730      * CANDIDATE FOR PUBLIC (or at least SYSTEM) API
    731      * Returns the stream type matching the given attributes for volume control.
    732      * Use this method to derive the stream type needed to configure the volume
    733      * control slider in an {@link Activity} with {@link Activity#setVolumeControlStream(int)}.
    734      * <BR>Do not use this method to set the stream type on an audio player object
    735      * (e.g. {@link AudioTrack}, {@link MediaPlayer}), use <code>AudioAttributes</code> instead.
    736      * @param aa non-null AudioAttributes.
    737      * @return a valid stream type for <code>Activity</code> or stream volume control that matches
    738      *     the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
    739      *     match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value
    740      *     for {@link AudioManager#setStreamVolume(int, int, int)}.
    741      */
    742     public static int getVolumeControlStream(@NonNull AudioAttributes aa) {
    743         if (aa == null) {
    744             throw new IllegalArgumentException("Invalid null audio attributes");
    745         }
    746         return toVolumeStreamType(true /*fromGetVolumeControlStream*/, aa);
    747     }
    748 
    749     /**
    750      * @hide
    751      * Only use to get which stream type should be used for volume control, NOT for audio playback
    752      * (all audio playback APIs are supposed to take AudioAttributes as input parameters)
    753      * @param aa non-null AudioAttributes.
    754      * @return a valid stream type for volume control that matches the attributes.
    755      */
    756     public static int toLegacyStreamType(@NonNull AudioAttributes aa) {
    757         return toVolumeStreamType(false /*fromGetVolumeControlStream*/, aa);
    758     }
    759 
    760     private static int toVolumeStreamType(boolean fromGetVolumeControlStream, AudioAttributes aa) {
    761         // flags to stream type mapping
    762         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
    763             return fromGetVolumeControlStream ?
    764                     AudioSystem.STREAM_SYSTEM : AudioSystem.STREAM_SYSTEM_ENFORCED;
    765         }
    766         if ((aa.getFlags() & FLAG_SCO) == FLAG_SCO) {
    767             return fromGetVolumeControlStream ?
    768                     AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_BLUETOOTH_SCO;
    769         }
    770 
    771         // usage to stream type mapping
    772         switch (aa.getUsage()) {
    773             case USAGE_MEDIA:
    774             case USAGE_GAME:
    775             case USAGE_ASSISTANCE_ACCESSIBILITY:
    776             case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
    777                 return AudioSystem.STREAM_MUSIC;
    778             case USAGE_ASSISTANCE_SONIFICATION:
    779                 return AudioSystem.STREAM_SYSTEM;
    780             case USAGE_VOICE_COMMUNICATION:
    781                 return AudioSystem.STREAM_VOICE_CALL;
    782             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
    783                 return fromGetVolumeControlStream ?
    784                         AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_DTMF;
    785             case USAGE_ALARM:
    786                 return AudioSystem.STREAM_ALARM;
    787             case USAGE_NOTIFICATION_RINGTONE:
    788                 return AudioSystem.STREAM_RING;
    789             case USAGE_NOTIFICATION:
    790             case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
    791             case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
    792             case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
    793             case USAGE_NOTIFICATION_EVENT:
    794                 return AudioSystem.STREAM_NOTIFICATION;
    795             case USAGE_UNKNOWN:
    796                 return fromGetVolumeControlStream ?
    797                         AudioManager.USE_DEFAULT_STREAM_TYPE : AudioSystem.STREAM_MUSIC;
    798             default:
    799                 if (fromGetVolumeControlStream) {
    800                     throw new IllegalArgumentException("Unknown usage value " + aa.getUsage() +
    801                             " in audio attributes");
    802                 } else {
    803                     return AudioSystem.STREAM_MUSIC;
    804                 }
    805         }
    806     }
    807 
    808     /** @hide */
    809     @IntDef({
    810         USAGE_UNKNOWN,
    811         USAGE_MEDIA,
    812         USAGE_VOICE_COMMUNICATION,
    813         USAGE_VOICE_COMMUNICATION_SIGNALLING,
    814         USAGE_ALARM,
    815         USAGE_NOTIFICATION,
    816         USAGE_NOTIFICATION_RINGTONE,
    817         USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
    818         USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
    819         USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
    820         USAGE_NOTIFICATION_EVENT,
    821         USAGE_ASSISTANCE_ACCESSIBILITY,
    822         USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
    823         USAGE_ASSISTANCE_SONIFICATION,
    824         USAGE_GAME
    825     })
    826     @Retention(RetentionPolicy.SOURCE)
    827     public @interface AttributeUsage {}
    828 
    829     /** @hide */
    830     @IntDef({
    831         CONTENT_TYPE_UNKNOWN,
    832         CONTENT_TYPE_SPEECH,
    833         CONTENT_TYPE_MUSIC,
    834         CONTENT_TYPE_MOVIE,
    835         CONTENT_TYPE_SONIFICATION
    836     })
    837     @Retention(RetentionPolicy.SOURCE)
    838     public @interface AttributeContentType {}
    839 }
    840