1 /* 2 * Copyright (C) 2018 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.icu.util.ULocale; 22 23 import java.lang.annotation.Retention; 24 import java.lang.annotation.RetentionPolicy; 25 import java.util.HashMap; 26 import java.util.Locale; 27 import java.util.Map; 28 import java.util.Objects; 29 30 31 /** 32 * The AudioPresentation class encapsulates the information that describes an audio presentation 33 * which is available in next generation audio content. 34 * 35 * Used by {@link MediaExtractor} {@link MediaExtractor#getAudioPresentations(int)} and 36 * {@link AudioTrack} {@link AudioTrack#setPresentation(AudioPresentation)} to query available 37 * presentations and to select one, respectively. 38 * 39 * A list of available audio presentations in a media source can be queried using 40 * {@link MediaExtractor#getAudioPresentations(int)}. This list can be presented to a user for 41 * selection. 42 * An AudioPresentation can be passed to an offloaded audio decoder via 43 * {@link AudioTrack#setPresentation(AudioPresentation)} to request decoding of the selected 44 * presentation. An audio stream may contain multiple presentations that differ by language, 45 * accessibility, end point mastering and dialogue enhancement. An audio presentation may also have 46 * a set of description labels in different languages to help the user to make an informed 47 * selection. 48 * 49 * Applications that parse media streams and extract presentation information on their own 50 * can create instances of AudioPresentation by using {@link AudioPresentation.Builder} class. 51 */ 52 public final class AudioPresentation { 53 private final int mPresentationId; 54 private final int mProgramId; 55 private final ULocale mLanguage; 56 57 /** @hide */ 58 @IntDef( 59 value = { 60 MASTERING_NOT_INDICATED, 61 MASTERED_FOR_STEREO, 62 MASTERED_FOR_SURROUND, 63 MASTERED_FOR_3D, 64 MASTERED_FOR_HEADPHONE, 65 }) 66 @Retention(RetentionPolicy.SOURCE) 67 public @interface MasteringIndicationType {} 68 private final @MasteringIndicationType int mMasteringIndication; 69 private final boolean mAudioDescriptionAvailable; 70 private final boolean mSpokenSubtitlesAvailable; 71 private final boolean mDialogueEnhancementAvailable; 72 private final Map<ULocale, CharSequence> mLabels; 73 74 /** 75 * No preferred reproduction channel layout. 76 * 77 * @see Builder#setMasteringIndication(int) 78 */ 79 public static final int MASTERING_NOT_INDICATED = 0; 80 /** 81 * Stereo speaker layout. 82 * 83 * @see Builder#setMasteringIndication(int) 84 */ 85 public static final int MASTERED_FOR_STEREO = 1; 86 /** 87 * Two-dimensional (e.g. 5.1) speaker layout. 88 * 89 * @see Builder#setMasteringIndication(int) 90 */ 91 public static final int MASTERED_FOR_SURROUND = 2; 92 /** 93 * Three-dimensional (e.g. 5.1.2) speaker layout. 94 * 95 * @see Builder#setMasteringIndication(int) 96 */ 97 public static final int MASTERED_FOR_3D = 3; 98 /** 99 * Prerendered for headphone playback. 100 * 101 * @see Builder#setMasteringIndication(int) 102 */ 103 public static final int MASTERED_FOR_HEADPHONE = 4; 104 105 /** 106 * This ID is reserved. No items can be explicitly assigned this ID. 107 */ 108 private static final int UNKNOWN_ID = -1; 109 110 /** 111 * This allows an application developer to construct an AudioPresentation object with all the 112 * parameters. 113 * The IDs are all that is required for an 114 * {@link AudioTrack#setPresentation(AudioPresentation)} to be successful. 115 * The rest of the metadata is informative only so as to distinguish features 116 * of different presentations. 117 * @param presentationId Presentation ID to be decoded by a next generation audio decoder. 118 * @param programId Program ID to be decoded by a next generation audio decoder. 119 * @param language Locale corresponding to ISO 639-1/639-2 language code. 120 * @param masteringIndication One of {@link AudioPresentation#MASTERING_NOT_INDICATED}, 121 * {@link AudioPresentation#MASTERED_FOR_STEREO}, 122 * {@link AudioPresentation#MASTERED_FOR_SURROUND}, 123 * {@link AudioPresentation#MASTERED_FOR_3D}, 124 * {@link AudioPresentation#MASTERED_FOR_HEADPHONE}. 125 * @param audioDescriptionAvailable Audio description for the visually impaired. 126 * @param spokenSubtitlesAvailable Spoken subtitles for the visually impaired. 127 * @param dialogueEnhancementAvailable Dialogue enhancement. 128 * @param labels Text label indexed by its locale corresponding to the language code. 129 */ AudioPresentation(int presentationId, int programId, @NonNull ULocale language, @MasteringIndicationType int masteringIndication, boolean audioDescriptionAvailable, boolean spokenSubtitlesAvailable, boolean dialogueEnhancementAvailable, @NonNull Map<ULocale, CharSequence> labels)130 private AudioPresentation(int presentationId, 131 int programId, 132 @NonNull ULocale language, 133 @MasteringIndicationType int masteringIndication, 134 boolean audioDescriptionAvailable, 135 boolean spokenSubtitlesAvailable, 136 boolean dialogueEnhancementAvailable, 137 @NonNull Map<ULocale, CharSequence> labels) { 138 mPresentationId = presentationId; 139 mProgramId = programId; 140 mLanguage = language; 141 mMasteringIndication = masteringIndication; 142 mAudioDescriptionAvailable = audioDescriptionAvailable; 143 mSpokenSubtitlesAvailable = spokenSubtitlesAvailable; 144 mDialogueEnhancementAvailable = dialogueEnhancementAvailable; 145 mLabels = new HashMap<ULocale, CharSequence>(labels); 146 } 147 148 /** 149 * Returns presentation ID used by the framework to select an audio presentation rendered by a 150 * decoder. Presentation ID is typically sequential, but does not have to be. 151 */ getPresentationId()152 public int getPresentationId() { 153 return mPresentationId; 154 } 155 156 /** 157 * Returns program ID used by the framework to select an audio presentation rendered by a 158 * decoder. Program ID can be used to further uniquely identify the presentation to a decoder. 159 */ getProgramId()160 public int getProgramId() { 161 return mProgramId; 162 } 163 164 /** 165 * @return a map of available text labels for this presentation. Each label is indexed by its 166 * locale corresponding to the language code as specified by ISO 639-2. Either ISO 639-2/B 167 * or ISO 639-2/T could be used. 168 */ getLabels()169 public Map<Locale, String> getLabels() { 170 Map<Locale, String> localeLabels = new HashMap<Locale, String>(mLabels.size()); 171 for (Map.Entry<ULocale, CharSequence> entry : mLabels.entrySet()) { 172 localeLabels.put(entry.getKey().toLocale(), entry.getValue().toString()); 173 } 174 return localeLabels; 175 } 176 getULabels()177 private Map<ULocale, CharSequence> getULabels() { 178 return mLabels; 179 } 180 181 /** 182 * @return the locale corresponding to audio presentation's ISO 639-1/639-2 language code. 183 */ getLocale()184 public Locale getLocale() { 185 return mLanguage.toLocale(); 186 } 187 getULocale()188 private ULocale getULocale() { 189 return mLanguage; 190 } 191 192 /** 193 * @return the mastering indication of the audio presentation. 194 * See {@link AudioPresentation#MASTERING_NOT_INDICATED}, 195 * {@link AudioPresentation#MASTERED_FOR_STEREO}, 196 * {@link AudioPresentation#MASTERED_FOR_SURROUND}, 197 * {@link AudioPresentation#MASTERED_FOR_3D}, 198 * {@link AudioPresentation#MASTERED_FOR_HEADPHONE} 199 */ 200 @MasteringIndicationType getMasteringIndication()201 public int getMasteringIndication() { 202 return mMasteringIndication; 203 } 204 205 /** 206 * Indicates whether an audio description for the visually impaired is available. 207 * @return {@code true} if audio description is available. 208 */ hasAudioDescription()209 public boolean hasAudioDescription() { 210 return mAudioDescriptionAvailable; 211 } 212 213 /** 214 * Indicates whether spoken subtitles for the visually impaired are available. 215 * @return {@code true} if spoken subtitles are available. 216 */ hasSpokenSubtitles()217 public boolean hasSpokenSubtitles() { 218 return mSpokenSubtitlesAvailable; 219 } 220 221 /** 222 * Indicates whether dialogue enhancement is available. 223 * @return {@code true} if dialogue enhancement is available. 224 */ hasDialogueEnhancement()225 public boolean hasDialogueEnhancement() { 226 return mDialogueEnhancementAvailable; 227 } 228 229 @Override equals(Object o)230 public boolean equals(Object o) { 231 if (this == o) { 232 return true; 233 } 234 if (!(o instanceof AudioPresentation)) { 235 return false; 236 } 237 AudioPresentation obj = (AudioPresentation) o; 238 return mPresentationId == obj.getPresentationId() 239 && mProgramId == obj.getProgramId() 240 && mLanguage.equals(obj.getULocale()) 241 && mMasteringIndication == obj.getMasteringIndication() 242 && mAudioDescriptionAvailable == obj.hasAudioDescription() 243 && mSpokenSubtitlesAvailable == obj.hasSpokenSubtitles() 244 && mDialogueEnhancementAvailable == obj.hasDialogueEnhancement() 245 && mLabels.equals(obj.getULabels()); 246 } 247 248 @Override hashCode()249 public int hashCode() { 250 return Objects.hash(mPresentationId, 251 mProgramId, 252 mLanguage.hashCode(), 253 mMasteringIndication, 254 mAudioDescriptionAvailable, 255 mSpokenSubtitlesAvailable, 256 mDialogueEnhancementAvailable, 257 mLabels.hashCode()); 258 } 259 260 @Override toString()261 public String toString() { 262 StringBuilder sb = new StringBuilder(); 263 sb.append(getClass().getSimpleName() + " "); 264 sb.append("{ presentation id=" + mPresentationId); 265 sb.append(", program id=" + mProgramId); 266 sb.append(", language=" + mLanguage); 267 sb.append(", labels=" + mLabels); 268 sb.append(", mastering indication=" + mMasteringIndication); 269 sb.append(", audio description=" + mAudioDescriptionAvailable); 270 sb.append(", spoken subtitles=" + mSpokenSubtitlesAvailable); 271 sb.append(", dialogue enhancement=" + mDialogueEnhancementAvailable); 272 sb.append(" }"); 273 return sb.toString(); 274 } 275 276 /** 277 * A builder class for creating {@link AudioPresentation} objects. 278 */ 279 public static final class Builder { 280 private final int mPresentationId; 281 private int mProgramId = UNKNOWN_ID; 282 private ULocale mLanguage = new ULocale(""); 283 private int mMasteringIndication = MASTERING_NOT_INDICATED; 284 private boolean mAudioDescriptionAvailable = false; 285 private boolean mSpokenSubtitlesAvailable = false; 286 private boolean mDialogueEnhancementAvailable = false; 287 private Map<ULocale, CharSequence> mLabels = new HashMap<ULocale, CharSequence>(); 288 289 /** 290 * Create a {@link Builder}. Any field that should be included in the 291 * {@link AudioPresentation} must be added. 292 * 293 * @param presentationId The presentation ID of this audio presentation. 294 */ Builder(int presentationId)295 public Builder(int presentationId) { 296 mPresentationId = presentationId; 297 } 298 /** 299 * Sets the ProgramId to which this audio presentation refers. 300 * 301 * @param programId The program ID to be decoded. 302 */ setProgramId(int programId)303 public @NonNull Builder setProgramId(int programId) { 304 mProgramId = programId; 305 return this; 306 } 307 /** 308 * Sets the language information of the audio presentation. 309 * 310 * @param language Locale corresponding to ISO 639-1/639-2 language code. 311 */ setLocale(@onNull ULocale language)312 public @NonNull Builder setLocale(@NonNull ULocale language) { 313 mLanguage = language; 314 return this; 315 } 316 317 /** 318 * Sets the mastering indication. 319 * 320 * @param masteringIndication Input to set mastering indication. 321 * @throws IllegalArgumentException if the mastering indication is not any of 322 * {@link AudioPresentation#MASTERING_NOT_INDICATED}, 323 * {@link AudioPresentation#MASTERED_FOR_STEREO}, 324 * {@link AudioPresentation#MASTERED_FOR_SURROUND}, 325 * {@link AudioPresentation#MASTERED_FOR_3D}, 326 * and {@link AudioPresentation#MASTERED_FOR_HEADPHONE} 327 */ setMasteringIndication( @asteringIndicationType int masteringIndication)328 public @NonNull Builder setMasteringIndication( 329 @MasteringIndicationType int masteringIndication) { 330 if (masteringIndication != MASTERING_NOT_INDICATED 331 && masteringIndication != MASTERED_FOR_STEREO 332 && masteringIndication != MASTERED_FOR_SURROUND 333 && masteringIndication != MASTERED_FOR_3D 334 && masteringIndication != MASTERED_FOR_HEADPHONE) { 335 throw new IllegalArgumentException("Unknown mastering indication: " 336 + masteringIndication); 337 } 338 mMasteringIndication = masteringIndication; 339 return this; 340 } 341 342 /** 343 * Sets locale / text label pairs describing the presentation. 344 * 345 * @param labels Text label indexed by its locale corresponding to the language code. 346 */ setLabels(@onNull Map<ULocale, CharSequence> labels)347 public @NonNull Builder setLabels(@NonNull Map<ULocale, CharSequence> labels) { 348 mLabels = new HashMap<ULocale, CharSequence>(labels); 349 return this; 350 } 351 352 /** 353 * Indicate whether the presentation contains audio description for the visually impaired. 354 * 355 * @param audioDescriptionAvailable Audio description for the visually impaired. 356 */ setHasAudioDescription(boolean audioDescriptionAvailable)357 public @NonNull Builder setHasAudioDescription(boolean audioDescriptionAvailable) { 358 mAudioDescriptionAvailable = audioDescriptionAvailable; 359 return this; 360 } 361 362 /** 363 * Indicate whether the presentation contains spoken subtitles for the visually impaired. 364 * 365 * @param spokenSubtitlesAvailable Spoken subtitles for the visually impaired. 366 */ setHasSpokenSubtitles(boolean spokenSubtitlesAvailable)367 public @NonNull Builder setHasSpokenSubtitles(boolean spokenSubtitlesAvailable) { 368 mSpokenSubtitlesAvailable = spokenSubtitlesAvailable; 369 return this; 370 } 371 372 /** 373 * Indicate whether the presentation supports dialogue enhancement. 374 * 375 * @param dialogueEnhancementAvailable Dialogue enhancement. 376 */ setHasDialogueEnhancement(boolean dialogueEnhancementAvailable)377 public @NonNull Builder setHasDialogueEnhancement(boolean dialogueEnhancementAvailable) { 378 mDialogueEnhancementAvailable = dialogueEnhancementAvailable; 379 return this; 380 } 381 382 /** 383 * Creates a {@link AudioPresentation} instance with the specified fields. 384 * 385 * @return The new {@link AudioPresentation} instance 386 */ build()387 public @NonNull AudioPresentation build() { 388 return new AudioPresentation(mPresentationId, mProgramId, 389 mLanguage, mMasteringIndication, 390 mAudioDescriptionAvailable, mSpokenSubtitlesAvailable, 391 mDialogueEnhancementAvailable, mLabels); 392 } 393 } 394 } 395