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 CONTENT_UNKNOWN, 61 CONTENT_MAIN, 62 CONTENT_MUSIC_AND_EFFECTS, 63 CONTENT_VISUALLY_IMPAIRED, 64 CONTENT_HEARING_IMPAIRED, 65 CONTENT_DIALOG, 66 CONTENT_COMMENTARY, 67 CONTENT_EMERGENCY, 68 CONTENT_VOICEOVER, 69 }) 70 71 /** 72 * The ContentClassifier int definitions represent the AudioPresentation content 73 * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1) 74 */ 75 @Retention(RetentionPolicy.SOURCE) 76 public @interface ContentClassifier {} 77 78 /** 79 * Audio presentation classifier: Unknown. 80 */ 81 public static final int CONTENT_UNKNOWN = -1; 82 /** 83 * Audio presentation classifier: Complete main. 84 */ 85 public static final int CONTENT_MAIN = 0; 86 /** 87 * Audio presentation content classifier: Music and effects. 88 */ 89 public static final int CONTENT_MUSIC_AND_EFFECTS = 1; 90 /** 91 * Audio presentation content classifier: Visually impaired. 92 */ 93 public static final int CONTENT_VISUALLY_IMPAIRED = 2; 94 /** 95 * Audio presentation content classifier: Hearing impaired. 96 */ 97 public static final int CONTENT_HEARING_IMPAIRED = 3; 98 /** 99 * Audio presentation content classifier: Dialog. 100 */ 101 public static final int CONTENT_DIALOG = 4; 102 /** 103 * Audio presentation content classifier: Commentary. 104 */ 105 public static final int CONTENT_COMMENTARY = 5; 106 /** 107 * Audio presentation content classifier: Emergency. 108 */ 109 public static final int CONTENT_EMERGENCY = 6; 110 /** 111 * Audio presentation content classifier: Voice over. 112 */ 113 public static final int CONTENT_VOICEOVER = 7; 114 115 /** @hide */ 116 @IntDef( 117 value = { 118 MASTERING_NOT_INDICATED, 119 MASTERED_FOR_STEREO, 120 MASTERED_FOR_SURROUND, 121 MASTERED_FOR_3D, 122 MASTERED_FOR_HEADPHONE, 123 }) 124 @Retention(RetentionPolicy.SOURCE) 125 public @interface MasteringIndicationType {} 126 private final @MasteringIndicationType int mMasteringIndication; 127 private final boolean mAudioDescriptionAvailable; 128 private final boolean mSpokenSubtitlesAvailable; 129 private final boolean mDialogueEnhancementAvailable; 130 private final Map<ULocale, CharSequence> mLabels; 131 132 /** 133 * No preferred reproduction channel layout. 134 * 135 * @see Builder#setMasteringIndication(int) 136 */ 137 public static final int MASTERING_NOT_INDICATED = 0; 138 /** 139 * Stereo speaker layout. 140 * 141 * @see Builder#setMasteringIndication(int) 142 */ 143 public static final int MASTERED_FOR_STEREO = 1; 144 /** 145 * Two-dimensional (e.g. 5.1) speaker layout. 146 * 147 * @see Builder#setMasteringIndication(int) 148 */ 149 public static final int MASTERED_FOR_SURROUND = 2; 150 /** 151 * Three-dimensional (e.g. 5.1.2) speaker layout. 152 * 153 * @see Builder#setMasteringIndication(int) 154 */ 155 public static final int MASTERED_FOR_3D = 3; 156 /** 157 * Prerendered for headphone playback. 158 * 159 * @see Builder#setMasteringIndication(int) 160 */ 161 public static final int MASTERED_FOR_HEADPHONE = 4; 162 163 /** 164 * This ID is reserved. No items can be explicitly assigned this ID. 165 */ 166 private static final int UNKNOWN_ID = -1; 167 168 /** 169 * This allows an application developer to construct an AudioPresentation object with all the 170 * parameters. 171 * The IDs are all that is required for an 172 * {@link AudioTrack#setPresentation(AudioPresentation)} to be successful. 173 * The rest of the metadata is informative only so as to distinguish features 174 * of different presentations. 175 * @param presentationId Presentation ID to be decoded by a next generation audio decoder. 176 * @param programId Program ID to be decoded by a next generation audio decoder. 177 * @param language Locale corresponding to ISO 639-1/639-2 language code. 178 * @param masteringIndication One of {@link AudioPresentation#MASTERING_NOT_INDICATED}, 179 * {@link AudioPresentation#MASTERED_FOR_STEREO}, 180 * {@link AudioPresentation#MASTERED_FOR_SURROUND}, 181 * {@link AudioPresentation#MASTERED_FOR_3D}, 182 * {@link AudioPresentation#MASTERED_FOR_HEADPHONE}. 183 * @param audioDescriptionAvailable Audio description for the visually impaired. 184 * @param spokenSubtitlesAvailable Spoken subtitles for the visually impaired. 185 * @param dialogueEnhancementAvailable Dialogue enhancement. 186 * @param labels Text label indexed by its locale corresponding to the language code. 187 */ AudioPresentation(int presentationId, int programId, @NonNull ULocale language, @MasteringIndicationType int masteringIndication, boolean audioDescriptionAvailable, boolean spokenSubtitlesAvailable, boolean dialogueEnhancementAvailable, @NonNull Map<ULocale, CharSequence> labels)188 private AudioPresentation(int presentationId, 189 int programId, 190 @NonNull ULocale language, 191 @MasteringIndicationType int masteringIndication, 192 boolean audioDescriptionAvailable, 193 boolean spokenSubtitlesAvailable, 194 boolean dialogueEnhancementAvailable, 195 @NonNull Map<ULocale, CharSequence> labels) { 196 mPresentationId = presentationId; 197 mProgramId = programId; 198 mLanguage = language; 199 mMasteringIndication = masteringIndication; 200 mAudioDescriptionAvailable = audioDescriptionAvailable; 201 mSpokenSubtitlesAvailable = spokenSubtitlesAvailable; 202 mDialogueEnhancementAvailable = dialogueEnhancementAvailable; 203 mLabels = new HashMap<ULocale, CharSequence>(labels); 204 } 205 206 /** 207 * Returns presentation ID used by the framework to select an audio presentation rendered by a 208 * decoder. Presentation ID is typically sequential, but does not have to be. 209 */ getPresentationId()210 public int getPresentationId() { 211 return mPresentationId; 212 } 213 214 /** 215 * Returns program ID used by the framework to select an audio presentation rendered by a 216 * decoder. Program ID can be used to further uniquely identify the presentation to a decoder. 217 */ getProgramId()218 public int getProgramId() { 219 return mProgramId; 220 } 221 222 /** 223 * @return a map of available text labels for this presentation. Each label is indexed by its 224 * locale corresponding to the language code as specified by ISO 639-2. Either ISO 639-2/B 225 * or ISO 639-2/T could be used. 226 */ getLabels()227 public Map<Locale, String> getLabels() { 228 Map<Locale, String> localeLabels = new HashMap<Locale, String>(mLabels.size()); 229 for (Map.Entry<ULocale, CharSequence> entry : mLabels.entrySet()) { 230 localeLabels.put(entry.getKey().toLocale(), entry.getValue().toString()); 231 } 232 return localeLabels; 233 } 234 getULabels()235 private Map<ULocale, CharSequence> getULabels() { 236 return mLabels; 237 } 238 239 /** 240 * @return the locale corresponding to audio presentation's ISO 639-1/639-2 language code. 241 */ getLocale()242 public Locale getLocale() { 243 return mLanguage.toLocale(); 244 } 245 getULocale()246 private ULocale getULocale() { 247 return mLanguage; 248 } 249 250 /** 251 * @return the mastering indication of the audio presentation. 252 * See {@link AudioPresentation#MASTERING_NOT_INDICATED}, 253 * {@link AudioPresentation#MASTERED_FOR_STEREO}, 254 * {@link AudioPresentation#MASTERED_FOR_SURROUND}, 255 * {@link AudioPresentation#MASTERED_FOR_3D}, 256 * {@link AudioPresentation#MASTERED_FOR_HEADPHONE} 257 */ 258 @MasteringIndicationType getMasteringIndication()259 public int getMasteringIndication() { 260 return mMasteringIndication; 261 } 262 263 /** 264 * Indicates whether an audio description for the visually impaired is available. 265 * @return {@code true} if audio description is available. 266 */ hasAudioDescription()267 public boolean hasAudioDescription() { 268 return mAudioDescriptionAvailable; 269 } 270 271 /** 272 * Indicates whether spoken subtitles for the visually impaired are available. 273 * @return {@code true} if spoken subtitles are available. 274 */ hasSpokenSubtitles()275 public boolean hasSpokenSubtitles() { 276 return mSpokenSubtitlesAvailable; 277 } 278 279 /** 280 * Indicates whether dialogue enhancement is available. 281 * @return {@code true} if dialogue enhancement is available. 282 */ hasDialogueEnhancement()283 public boolean hasDialogueEnhancement() { 284 return mDialogueEnhancementAvailable; 285 } 286 287 @Override equals(Object o)288 public boolean equals(Object o) { 289 if (this == o) { 290 return true; 291 } 292 if (!(o instanceof AudioPresentation)) { 293 return false; 294 } 295 AudioPresentation obj = (AudioPresentation) o; 296 return mPresentationId == obj.getPresentationId() 297 && mProgramId == obj.getProgramId() 298 && mLanguage.equals(obj.getULocale()) 299 && mMasteringIndication == obj.getMasteringIndication() 300 && mAudioDescriptionAvailable == obj.hasAudioDescription() 301 && mSpokenSubtitlesAvailable == obj.hasSpokenSubtitles() 302 && mDialogueEnhancementAvailable == obj.hasDialogueEnhancement() 303 && mLabels.equals(obj.getULabels()); 304 } 305 306 @Override hashCode()307 public int hashCode() { 308 return Objects.hash(mPresentationId, 309 mProgramId, 310 mLanguage.hashCode(), 311 mMasteringIndication, 312 mAudioDescriptionAvailable, 313 mSpokenSubtitlesAvailable, 314 mDialogueEnhancementAvailable, 315 mLabels.hashCode()); 316 } 317 318 @Override toString()319 public String toString() { 320 StringBuilder sb = new StringBuilder(); 321 sb.append(getClass().getSimpleName() + " "); 322 sb.append("{ presentation id=" + mPresentationId); 323 sb.append(", program id=" + mProgramId); 324 sb.append(", language=" + mLanguage); 325 sb.append(", labels=" + mLabels); 326 sb.append(", mastering indication=" + mMasteringIndication); 327 sb.append(", audio description=" + mAudioDescriptionAvailable); 328 sb.append(", spoken subtitles=" + mSpokenSubtitlesAvailable); 329 sb.append(", dialogue enhancement=" + mDialogueEnhancementAvailable); 330 sb.append(" }"); 331 return sb.toString(); 332 } 333 334 /** 335 * A builder class for creating {@link AudioPresentation} objects. 336 */ 337 public static final class Builder { 338 private final int mPresentationId; 339 private int mProgramId = UNKNOWN_ID; 340 private ULocale mLanguage = new ULocale(""); 341 private int mMasteringIndication = MASTERING_NOT_INDICATED; 342 private boolean mAudioDescriptionAvailable = false; 343 private boolean mSpokenSubtitlesAvailable = false; 344 private boolean mDialogueEnhancementAvailable = false; 345 private Map<ULocale, CharSequence> mLabels = new HashMap<ULocale, CharSequence>(); 346 347 /** 348 * Create a {@link Builder}. Any field that should be included in the 349 * {@link AudioPresentation} must be added. 350 * 351 * @param presentationId The presentation ID of this audio presentation. 352 */ Builder(int presentationId)353 public Builder(int presentationId) { 354 mPresentationId = presentationId; 355 } 356 /** 357 * Sets the ProgramId to which this audio presentation refers. 358 * 359 * @param programId The program ID to be decoded. 360 */ setProgramId(int programId)361 public @NonNull Builder setProgramId(int programId) { 362 mProgramId = programId; 363 return this; 364 } 365 /** 366 * Sets the language information of the audio presentation. 367 * 368 * @param language Locale corresponding to ISO 639-1/639-2 language code. 369 */ setLocale(@onNull ULocale language)370 public @NonNull Builder setLocale(@NonNull ULocale language) { 371 mLanguage = language; 372 return this; 373 } 374 375 /** 376 * Sets the mastering indication. 377 * 378 * @param masteringIndication Input to set mastering indication. 379 * @throws IllegalArgumentException if the mastering indication is not any of 380 * {@link AudioPresentation#MASTERING_NOT_INDICATED}, 381 * {@link AudioPresentation#MASTERED_FOR_STEREO}, 382 * {@link AudioPresentation#MASTERED_FOR_SURROUND}, 383 * {@link AudioPresentation#MASTERED_FOR_3D}, 384 * and {@link AudioPresentation#MASTERED_FOR_HEADPHONE} 385 */ setMasteringIndication( @asteringIndicationType int masteringIndication)386 public @NonNull Builder setMasteringIndication( 387 @MasteringIndicationType int masteringIndication) { 388 if (masteringIndication != MASTERING_NOT_INDICATED 389 && masteringIndication != MASTERED_FOR_STEREO 390 && masteringIndication != MASTERED_FOR_SURROUND 391 && masteringIndication != MASTERED_FOR_3D 392 && masteringIndication != MASTERED_FOR_HEADPHONE) { 393 throw new IllegalArgumentException("Unknown mastering indication: " 394 + masteringIndication); 395 } 396 mMasteringIndication = masteringIndication; 397 return this; 398 } 399 400 /** 401 * Sets locale / text label pairs describing the presentation. 402 * 403 * @param labels Text label indexed by its locale corresponding to the language code. 404 */ setLabels(@onNull Map<ULocale, CharSequence> labels)405 public @NonNull Builder setLabels(@NonNull Map<ULocale, CharSequence> labels) { 406 mLabels = new HashMap<ULocale, CharSequence>(labels); 407 return this; 408 } 409 410 /** 411 * Indicate whether the presentation contains audio description for the visually impaired. 412 * 413 * @param audioDescriptionAvailable Audio description for the visually impaired. 414 */ setHasAudioDescription(boolean audioDescriptionAvailable)415 public @NonNull Builder setHasAudioDescription(boolean audioDescriptionAvailable) { 416 mAudioDescriptionAvailable = audioDescriptionAvailable; 417 return this; 418 } 419 420 /** 421 * Indicate whether the presentation contains spoken subtitles for the visually impaired. 422 * 423 * @param spokenSubtitlesAvailable Spoken subtitles for the visually impaired. 424 */ setHasSpokenSubtitles(boolean spokenSubtitlesAvailable)425 public @NonNull Builder setHasSpokenSubtitles(boolean spokenSubtitlesAvailable) { 426 mSpokenSubtitlesAvailable = spokenSubtitlesAvailable; 427 return this; 428 } 429 430 /** 431 * Indicate whether the presentation supports dialogue enhancement. 432 * 433 * @param dialogueEnhancementAvailable Dialogue enhancement. 434 */ setHasDialogueEnhancement(boolean dialogueEnhancementAvailable)435 public @NonNull Builder setHasDialogueEnhancement(boolean dialogueEnhancementAvailable) { 436 mDialogueEnhancementAvailable = dialogueEnhancementAvailable; 437 return this; 438 } 439 440 /** 441 * Creates a {@link AudioPresentation} instance with the specified fields. 442 * 443 * @return The new {@link AudioPresentation} instance 444 */ build()445 public @NonNull AudioPresentation build() { 446 return new AudioPresentation(mPresentationId, mProgramId, 447 mLanguage, mMasteringIndication, 448 mAudioDescriptionAvailable, mSpokenSubtitlesAvailable, 449 mDialogueEnhancementAvailable, mLabels); 450 } 451 } 452 } 453