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 
AudioAttributes()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      */
getContentType()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      */
getUsage()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
getCapturePreset()249     public int getCapturePreset() {
250         return mSource;
251     }
252 
253     /**
254      * Return the flags.
255      * @return a combined mask of all flags
256      */
getFlags()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      */
getAllFlags()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      */
getTags()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          */
Builder()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
Builder(AudioAttributes aa)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
build()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          */
setUsage(@ttributeUsage int usage)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          */
setContentType(@ttributeContentType int contentType)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          */
setFlags(int flags)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          */
addTag(String tag)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          */
setLegacyStreamType(int streamType)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          */
setInternalLegacyStreamType(int streamType)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
setCapturePreset(int preset)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          */
setInternalCapturePreset(int preset)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
describeContents()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
writeToParcel(Parcel dest, int flags)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 
AudioAttributes(Parcel in)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
equals(Object o)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
hashCode()629     public int hashCode() {
630         return Objects.hash(mContentType, mFlags, mSource, mUsage, mFormattedTags);
631     }
632 
633     @Override
toString()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 */
usageToString()643     public String usageToString() {
644         return usageToString(mUsage);
645     }
646 
647     /** @hide */
usageToString(int usage)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 */
usageForLegacyStreamType(int streamType)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 */
toLegacyStreamType(AudioAttributes aa)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