summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/current.txt14
-rw-r--r--api/test-current.txt6
-rw-r--r--media/java/android/media/AudioPresentation.java254
-rw-r--r--media/jni/android_media_AudioPresentation.h45
4 files changed, 259 insertions, 60 deletions
diff --git a/api/current.txt b/api/current.txt
index 80ee52577ac9..b98ef685ecaf 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -22927,6 +22927,8 @@ package android.media {
method public java.util.Map<java.util.Locale, java.lang.String> getLabels();
method public java.util.Locale getLocale();
method public int getMasteringIndication();
+ method public int getPresentationId();
+ method public int getProgramId();
method public boolean hasAudioDescription();
method public boolean hasDialogueEnhancement();
method public boolean hasSpokenSubtitles();
@@ -22937,6 +22939,18 @@ package android.media {
field public static final int MASTERING_NOT_INDICATED = 0; // 0x0
}
+ public static class AudioPresentation.Builder {
+ ctor public AudioPresentation.Builder(int);
+ method public android.media.AudioPresentation build();
+ method public android.media.AudioPresentation.Builder setHasAudioDescription(boolean);
+ method public android.media.AudioPresentation.Builder setHasDialogueEnhancement(boolean);
+ method public android.media.AudioPresentation.Builder setHasSpokenSubtitles(boolean);
+ method public android.media.AudioPresentation.Builder setLabels(java.util.Map<android.icu.util.ULocale, java.lang.String>);
+ method public android.media.AudioPresentation.Builder setLocale(android.icu.util.ULocale);
+ method public android.media.AudioPresentation.Builder setMasteringIndication(int);
+ method public android.media.AudioPresentation.Builder setProgramId(int);
+ }
+
public class AudioRecord implements android.media.AudioRouting {
ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
diff --git a/api/test-current.txt b/api/test-current.txt
index d453395fe9cd..3f26ab094ce9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -578,12 +578,6 @@ package android.media {
method public static boolean isEncodingLinearPcm(int);
}
- public final class AudioPresentation {
- ctor public AudioPresentation(int, int, java.util.Map<java.lang.String, java.lang.String>, java.lang.String, int, boolean, boolean, boolean);
- method public int getPresentationId();
- method public int getProgramId();
- }
-
public final class BufferingParams implements android.os.Parcelable {
method public int describeContents();
method public int getInitialMarkMs();
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index ce71436b9bb3..1cc650bf2702 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -19,13 +19,14 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.icu.util.ULocale;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
/**
@@ -34,7 +35,7 @@ import java.util.Map;
*
* Used by {@link MediaExtractor} {@link MediaExtractor#getAudioPresentations(int)} and
* {@link AudioTrack} {@link AudioTrack#setPresentation(AudioPresentation)} to query available
- * presentations and to select one.
+ * presentations and to select one, respectively.
*
* A list of available audio presentations in a media source can be queried using
* {@link MediaExtractor#getAudioPresentations(int)}. This list can be presented to a user for
@@ -49,8 +50,7 @@ import java.util.Map;
public final class AudioPresentation {
private final int mPresentationId;
private final int mProgramId;
- private final Map<String, String> mLabels;
- private final String mLanguage;
+ private final ULocale mLanguage;
/** @hide */
@IntDef(
@@ -63,72 +63,98 @@ public final class AudioPresentation {
})
@Retention(RetentionPolicy.SOURCE)
public @interface MasteringIndicationType {}
-
private final @MasteringIndicationType int mMasteringIndication;
private final boolean mAudioDescriptionAvailable;
private final boolean mSpokenSubtitlesAvailable;
private final boolean mDialogueEnhancementAvailable;
+ private final Map<ULocale, String> mLabels;
/**
* No preferred reproduction channel layout.
+ *
+ * @see Builder#setMasteringIndication(int)
*/
public static final int MASTERING_NOT_INDICATED = 0;
/**
* Stereo speaker layout.
+ *
+ * @see Builder#setMasteringIndication(int)
*/
public static final int MASTERED_FOR_STEREO = 1;
/**
* Two-dimensional (e.g. 5.1) speaker layout.
+ *
+ * @see Builder#setMasteringIndication(int)
*/
public static final int MASTERED_FOR_SURROUND = 2;
/**
* Three-dimensional (e.g. 5.1.2) speaker layout.
+ *
+ * @see Builder#setMasteringIndication(int)
*/
public static final int MASTERED_FOR_3D = 3;
/**
* Prerendered for headphone playback.
+ *
+ * @see Builder#setMasteringIndication(int)
*/
public static final int MASTERED_FOR_HEADPHONE = 4;
/**
- * @hide
- */
- @TestApi
- public AudioPresentation(int presentationId,
- int programId,
- @NonNull Map<String, String> labels,
- @NonNull String language,
- @MasteringIndicationType int masteringIndication,
- boolean audioDescriptionAvailable,
- boolean spokenSubtitlesAvailable,
- boolean dialogueEnhancementAvailable) {
- this.mPresentationId = presentationId;
- this.mProgramId = programId;
- this.mLanguage = language;
- this.mMasteringIndication = masteringIndication;
- this.mAudioDescriptionAvailable = audioDescriptionAvailable;
- this.mSpokenSubtitlesAvailable = spokenSubtitlesAvailable;
- this.mDialogueEnhancementAvailable = dialogueEnhancementAvailable;
-
- this.mLabels = new HashMap<String, String>(labels);
+ * This ID is reserved. No items can be explicitly assigned this ID.
+ */
+ private static final int UNKNOWN_ID = -1;
+
+ /**
+ * This allows an application developer to construct an AudioPresentation object with all the
+ * parameters.
+ * The IDs are all that is required for an
+ * {@link AudioTrack#setPresentation(AudioPresentation)} to be successful.
+ * The rest of the metadata is informative only so as to distinguish features
+ * of different presentations.
+ * @param presentationId Presentation ID to be decoded by a next generation audio decoder.
+ * @param programId Program ID to be decoded by a next generation audio decoder.
+ * @param language Locale corresponding to ISO 639-1/639-2 language code.
+ * @param masteringIndication One of {@link AudioPresentation#MASTERING_NOT_INDICATED},
+ * {@link AudioPresentation#MASTERED_FOR_STEREO},
+ * {@link AudioPresentation#MASTERED_FOR_SURROUND},
+ * {@link AudioPresentation#MASTERED_FOR_3D},
+ * {@link AudioPresentation#MASTERED_FOR_HEADPHONE}.
+ * @param audioDescriptionAvailable Audio description for the visually impaired.
+ * @param spokenSubtitlesAvailable Spoken subtitles for the visually impaired.
+ * @param dialogueEnhancementAvailable Dialogue enhancement.
+ * @param labels Text label indexed by its locale corresponding to the language code.
+ */
+ private AudioPresentation(int presentationId,
+ int programId,
+ @NonNull ULocale language,
+ @MasteringIndicationType int masteringIndication,
+ boolean audioDescriptionAvailable,
+ boolean spokenSubtitlesAvailable,
+ boolean dialogueEnhancementAvailable,
+ @NonNull Map<ULocale, String> labels) {
+ mPresentationId = presentationId;
+ mProgramId = programId;
+ mLanguage = language;
+ mMasteringIndication = masteringIndication;
+ mAudioDescriptionAvailable = audioDescriptionAvailable;
+ mSpokenSubtitlesAvailable = spokenSubtitlesAvailable;
+ mDialogueEnhancementAvailable = dialogueEnhancementAvailable;
+ mLabels = new HashMap<ULocale, String>(labels);
}
/**
- * The framework uses this presentation id to select an audio presentation rendered by a
- * decoder. Presentation id is typically sequential, but does not have to be.
- * @hide
+ * Returns presentation ID used by the framework to select an audio presentation rendered by a
+ * decoder. Presentation ID is typically sequential, but does not have to be.
*/
- @TestApi
public int getPresentationId() {
return mPresentationId;
}
/**
- * The framework uses this program id to select an audio presentation rendered by a decoder.
- * Program id can be used to further uniquely identify the presentation to a decoder.
- * @hide
+ * Returns program ID used by the framework to select an audio presentation rendered by a
+ * decoder. Program ID can be used to further uniquely identify the presentation to a decoder.
*/
- @TestApi
public int getProgramId() {
return mProgramId;
}
@@ -139,9 +165,9 @@ public final class AudioPresentation {
* or ISO 639-2/T could be used.
*/
public Map<Locale, String> getLabels() {
- Map<Locale, String> localeLabels = new HashMap<>();
- for (Map.Entry<String, String> entry : mLabels.entrySet()) {
- localeLabels.put(new Locale(entry.getKey()), entry.getValue());
+ Map<Locale, String> localeLabels = new HashMap<Locale, String>();
+ for (Map.Entry<ULocale, String> entry : mLabels.entrySet()) {
+ localeLabels.put(entry.getKey().toLocale(), entry.getValue());
}
return localeLabels;
}
@@ -150,13 +176,20 @@ public final class AudioPresentation {
* @return the locale corresponding to audio presentation's ISO 639-1/639-2 language code.
*/
public Locale getLocale() {
- return new Locale(mLanguage);
+ return mLanguage.toLocale();
+ }
+
+ private ULocale getULocale() {
+ return mLanguage;
}
/**
* @return the mastering indication of the audio presentation.
- * See {@link #MASTERING_NOT_INDICATED}, {@link #MASTERED_FOR_STEREO},
- * {@link #MASTERED_FOR_SURROUND}, {@link #MASTERED_FOR_3D}, {@link #MASTERED_FOR_HEADPHONE}
+ * See {@link AudioPresentation#MASTERING_NOT_INDICATED},
+ * {@link AudioPresentation#MASTERED_FOR_STEREO},
+ * {@link AudioPresentation#MASTERED_FOR_SURROUND},
+ * {@link AudioPresentation#MASTERED_FOR_3D},
+ * {@link AudioPresentation#MASTERED_FOR_HEADPHONE}
*/
@MasteringIndicationType
public int getMasteringIndication() {
@@ -186,4 +219,147 @@ public final class AudioPresentation {
public boolean hasDialogueEnhancement() {
return mDialogueEnhancementAvailable;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof AudioPresentation)) {
+ return false;
+ }
+ AudioPresentation obj = (AudioPresentation) o;
+ return mPresentationId == obj.getPresentationId()
+ && mProgramId == obj.getProgramId()
+ && mLanguage == obj.getULocale()
+ && mMasteringIndication == obj.getMasteringIndication()
+ && mAudioDescriptionAvailable == obj.hasAudioDescription()
+ && mSpokenSubtitlesAvailable == obj.hasSpokenSubtitles()
+ && mDialogueEnhancementAvailable == obj.hasDialogueEnhancement()
+ && mLabels.equals(obj.getLabels());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mPresentationId);
+ }
+
+ /**
+ * A builder class for creating {@link AudioPresentation} objects.
+ */
+ public static class Builder {
+ private final int mPresentationId;
+ private int mProgramId = UNKNOWN_ID;
+ private ULocale mLanguage = new ULocale("");
+ private int mMasteringIndication = MASTERING_NOT_INDICATED;
+ private boolean mAudioDescriptionAvailable = false;
+ private boolean mSpokenSubtitlesAvailable = false;
+ private boolean mDialogueEnhancementAvailable = false;
+ private Map<ULocale, String> mLabels = new HashMap<ULocale, String>();
+
+ /**
+ * Create a {@link Builder}. Any field that should be included in the
+ * {@link AudioPresentation} must be added.
+ *
+ * @param presentationId the presentation ID of this audio presentation
+ */
+ public Builder(int presentationId) {
+ mPresentationId = presentationId;
+ }
+ /**
+ * Sets the ProgramId to which this audio presentation refers.
+ *
+ * @param programId
+ */
+ public @NonNull Builder setProgramId(int programId) {
+ mProgramId = programId;
+ return this;
+ }
+ /**
+ * Sets the language information of the audio presentation.
+ *
+ * @param language code
+ */
+ public @NonNull Builder setLocale(ULocale language) {
+ mLanguage = language;
+ return this;
+ }
+
+ /**
+ * Sets the mastering indication.
+ *
+ * @param masteringIndication Input to set mastering indication.
+ * @throws IllegalArgumentException if the mastering indication is not any of
+ * {@link AudioPresentation#MASTERING_NOT_INDICATED},
+ * {@link AudioPresentation#MASTERED_FOR_STEREO},
+ * {@link AudioPresentation#MASTERED_FOR_SURROUND},
+ * {@link AudioPresentation#MASTERED_FOR_3D},
+ * and {@link AudioPresentation#MASTERED_FOR_HEADPHONE}
+ */
+ public @NonNull Builder setMasteringIndication(
+ @MasteringIndicationType int masteringIndication) {
+ if (masteringIndication != MASTERING_NOT_INDICATED
+ && masteringIndication != MASTERED_FOR_STEREO
+ && masteringIndication != MASTERED_FOR_SURROUND
+ && masteringIndication != MASTERED_FOR_3D
+ && masteringIndication != MASTERED_FOR_HEADPHONE) {
+ throw new IllegalArgumentException("Unknown mastering indication: "
+ + masteringIndication);
+ }
+ mMasteringIndication = masteringIndication;
+ return this;
+ }
+
+ /**
+ * Sets locale / text label pairs describing the presentation.
+ *
+ * @param labels
+ */
+ public @NonNull Builder setLabels(@NonNull Map<ULocale, String> labels) {
+ mLabels = new HashMap<ULocale, String>(labels);
+ return this;
+ }
+
+ /**
+ * Indicate whether the presentation contains audio description for the visually impaired.
+ *
+ * @param audioDescriptionAvailable
+ */
+ public @NonNull Builder setHasAudioDescription(boolean audioDescriptionAvailable) {
+ mAudioDescriptionAvailable = audioDescriptionAvailable;
+ return this;
+ }
+
+ /**
+ * Indicate whether the presentation contains spoken subtitles for the visually impaired.
+ *
+ * @param spokenSubtitlesAvailable
+ */
+ public @NonNull Builder setHasSpokenSubtitles(boolean spokenSubtitlesAvailable) {
+ mSpokenSubtitlesAvailable = spokenSubtitlesAvailable;
+ return this;
+ }
+
+ /**
+ * Indicate whether the presentation supports dialogue enhancement.
+ *
+ * @param dialogueEnhancementAvailable
+ */
+ public @NonNull Builder setHasDialogueEnhancement(boolean dialogueEnhancementAvailable) {
+ mDialogueEnhancementAvailable = dialogueEnhancementAvailable;
+ return this;
+ }
+
+ /**
+ * Creates a {@link AudioPresentation} instance with the specified fields.
+ *
+ * @return The new {@link AudioPresentation} instance
+ */
+ public @NonNull AudioPresentation build() {
+ return new AudioPresentation(mPresentationId, mProgramId,
+ mLanguage, mMasteringIndication,
+ mAudioDescriptionAvailable, mSpokenSubtitlesAvailable,
+ mDialogueEnhancementAvailable, mLabels);
+ }
+ }
}
diff --git a/media/jni/android_media_AudioPresentation.h b/media/jni/android_media_AudioPresentation.h
index 71b8dacfbdfa..5306de6f8580 100644
--- a/media/jni/android_media_AudioPresentation.h
+++ b/media/jni/android_media_AudioPresentation.h
@@ -49,7 +49,7 @@ struct JAudioPresentationInfo {
}
constructID = env->GetMethodID(clazz, "<init>",
- "(IILjava/util/Map;Ljava/lang/String;IZZZ)V");
+ "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V");
env->DeleteLocalRef(lclazz);
// list objects
@@ -104,21 +104,26 @@ struct JAudioPresentationInfo {
// don't expose private keys (starting with android._)
continue;
}
-
jobject valueObj = NULL;
-
AString val;
CHECK(msg->findString(key, &val));
-
valueObj = env->NewStringUTF(val.c_str());
-
if (valueObj != NULL) {
- jstring keyObj = env->NewStringUTF(key);
-
- env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj);
-
- env->DeleteLocalRef(keyObj); keyObj = NULL;
+ ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale"));
+ if (localeClazz.get() == NULL) {
+ return -EINVAL;
+ }
+ jmethodID localeConstructID =
+ env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V");
+ if (localeConstructID == NULL) {
+ return -EINVAL;
+ }
+ jstring jLanguage = env->NewStringUTF(key);
+ jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage);
+ env->CallObjectMethod(hashMap, hashMapPutID, jLocale, valueObj);
+ env->DeleteLocalRef(jLocale); jLocale = NULL;
env->DeleteLocalRef(valueObj); valueObj = NULL;
+ env->DeleteLocalRef(jLanguage); jLanguage = NULL;
}
}
@@ -142,26 +147,36 @@ struct JAudioPresentationInfo {
if (ConvertMessageToMap(env, labelMessage, &jLabelObject) != OK) {
return NULL;
}
- jstring jLanguage = env->NewStringUTF(ap->mLanguage.string());
-
+ ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale"));
+ if (localeClazz.get() == NULL) {
+ return NULL;
+ }
+ jmethodID localeConstructID =
+ env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V");
+ if (localeConstructID == NULL) {
+ return NULL;
+ }
+ jstring jLanguage = env->NewStringUTF(ap->mLanguage.c_str());
+ jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage);
jobject jValueObj = env->NewObject(fields.clazz, fields.constructID,
static_cast<jint>(ap->mPresentationId),
static_cast<jint>(ap->mProgramId),
- jLabelObject,
- jLanguage,
+ jLocale,
static_cast<jint>(ap->mMasteringIndication),
static_cast<jboolean>((ap->mAudioDescriptionAvailable == 1) ?
1 : 0),
static_cast<jboolean>((ap->mSpokenSubtitlesAvailable == 1) ?
1 : 0),
static_cast<jboolean>((ap->mDialogueEnhancementAvailable == 1) ?
- 1 : 0));
+ 1 : 0),
+ jLabelObject);
if (jValueObj == NULL) {
env->DeleteLocalRef(jLanguage); jLanguage = NULL;
return NULL;
}
env->CallBooleanMethod(list, fields.listAddId, jValueObj);
+ env->DeleteLocalRef(jLocale); jLocale = NULL;
env->DeleteLocalRef(jValueObj); jValueObj = NULL;
env->DeleteLocalRef(jLanguage); jLanguage = NULL;
}