summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vlad Popa <pvlad@google.com> 2023-11-29 07:42:16 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-11-29 07:42:16 +0000
commit31e84d0a7d2eec35d08a29cca7c68d2690cae5cd (patch)
treee229be23b777831b8b19cea4acc99051ba6264c5
parent7fd1bda9069d8293911e29fef0e98ed2068245e9 (diff)
parent2f3da6158f55864b420a07411d149cc5c98ae540 (diff)
Merge "CTA2075: Finalize the loudness configurator API" into main
-rw-r--r--core/api/current.txt13
-rw-r--r--media/java/android/media/LoudnessCodecConfigurator.java183
-rw-r--r--media/java/android/media/LoudnessCodecDispatcher.java3
3 files changed, 103 insertions, 96 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index e8894a81e65b..0c5b606ac7aa 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -22036,6 +22036,19 @@ package android.media {
method public void onJetUserIdUpdate(android.media.JetPlayer, int, int);
}
+ @FlaggedApi("android.media.audio.loudness_configurator_api") public class LoudnessCodecConfigurator {
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") public void addMediaCodec(@NonNull android.media.MediaCodec);
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") @NonNull public static android.media.LoudnessCodecConfigurator create();
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") @NonNull public static android.media.LoudnessCodecConfigurator create(@NonNull java.util.concurrent.Executor, @NonNull android.media.LoudnessCodecConfigurator.OnLoudnessCodecUpdateListener);
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") @NonNull public android.os.Bundle getLoudnessCodecParams(@NonNull android.media.AudioTrack, @NonNull android.media.MediaCodec);
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") public void removeMediaCodec(@NonNull android.media.MediaCodec);
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") public void setAudioTrack(@Nullable android.media.AudioTrack);
+ }
+
+ @FlaggedApi("android.media.audio.loudness_configurator_api") public static interface LoudnessCodecConfigurator.OnLoudnessCodecUpdateListener {
+ method @FlaggedApi("android.media.audio.loudness_configurator_api") @NonNull public default android.os.Bundle onLoudnessCodecUpdate(@NonNull android.media.MediaCodec, @NonNull android.os.Bundle);
+ }
+
public class MediaActionSound {
ctor public MediaActionSound();
method public void load(int);
diff --git a/media/java/android/media/LoudnessCodecConfigurator.java b/media/java/android/media/LoudnessCodecConfigurator.java
index c879179f7082..de9d87c0b28c 100644
--- a/media/java/android/media/LoudnessCodecConfigurator.java
+++ b/media/java/android/media/LoudnessCodecConfigurator.java
@@ -33,6 +33,7 @@ import androidx.annotation.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -46,9 +47,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
* parameter updates are defined by the CTA-2075 standard.
* <p>A new object should be instantiated for each {@link AudioTrack} with the help
* of {@link #create()} or {@link #create(Executor, OnLoudnessCodecUpdateListener)}.
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
public class LoudnessCodecConfigurator {
@@ -56,9 +54,6 @@ public class LoudnessCodecConfigurator {
/**
* Listener used for receiving asynchronous loudness metadata updates.
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
public interface OnLoudnessCodecUpdateListener {
@@ -75,9 +70,6 @@ public class LoudnessCodecConfigurator {
* @return a Bundle which contains the original computed codecValues
* aggregated with user edits. The platform will configure the associated
* MediaCodecs with the returned Bundle params.
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
@NonNull
@@ -111,9 +103,6 @@ public class LoudnessCodecConfigurator {
* Otherwise, use {@link #create(Executor, OnLoudnessCodecUpdateListener)}.
*
* @return the {@link LoudnessCodecConfigurator} instance
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
public static @NonNull LoudnessCodecConfigurator create() {
@@ -132,9 +121,6 @@ public class LoudnessCodecConfigurator {
* @param listener used for receiving updates
*
* @return the {@link LoudnessCodecConfigurator} instance
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
public static @NonNull LoudnessCodecConfigurator create(
@@ -199,12 +185,9 @@ public class LoudnessCodecConfigurator {
* method will have the effect of clearing the existing set
* {@link AudioTrack} and will stop receiving asynchronous
* loudness updates
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
- public void setAudioTrack(AudioTrack audioTrack) {
+ public void setAudioTrack(@Nullable AudioTrack audioTrack) {
List<LoudnessCodecInfo> codecInfos;
int piid = PLAYER_PIID_INVALID;
int oldPiid = PLAYER_PIID_INVALID;
@@ -249,10 +232,11 @@ public class LoudnessCodecConfigurator {
* previously added.
*
* @param mediaCodec the codec to start receiving asynchronous loudness
- * updates
- *
- * TODO: remove hide once API is final
- * @hide
+ * updates. The codec has to be in a configured or started
+ * state in order to add it for loudness updates.
+ * @throws IllegalArgumentException if the {@code mediaCodec} was not configured,
+ * does not contain loudness metadata or if it
+ * was already added before
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
public void addMediaCodec(@NonNull MediaCodec mediaCodec) {
@@ -261,31 +245,32 @@ public class LoudnessCodecConfigurator {
int piid = PLAYER_PIID_INVALID;
final LoudnessCodecInfo mcInfo = getCodecInfo(mc);
- if (mcInfo != null) {
- synchronized (mConfiguratorLock) {
- final AtomicBoolean containsCodec = new AtomicBoolean(false);
- Set<MediaCodec> newSet = mMediaCodecs.computeIfPresent(mcInfo, (info, codecSet) -> {
- containsCodec.set(!codecSet.add(mc));
- return codecSet;
- });
- if (newSet == null) {
- newSet = new HashSet<>();
- newSet.add(mc);
- mMediaCodecs.put(mcInfo, newSet);
- }
- if (containsCodec.get()) {
- Log.v(TAG, "Loudness configurator already added media codec " + mediaCodec);
- return;
- }
- if (mAudioTrack != null) {
- piid = mAudioTrack.getPlayerIId();
- }
+ if (mcInfo == null) {
+ throw new IllegalArgumentException("Could not extract codec loudness information");
+ }
+ synchronized (mConfiguratorLock) {
+ final AtomicBoolean containsCodec = new AtomicBoolean(false);
+ Set<MediaCodec> newSet = mMediaCodecs.computeIfPresent(mcInfo, (info, codecSet) -> {
+ containsCodec.set(!codecSet.add(mc));
+ return codecSet;
+ });
+ if (newSet == null) {
+ newSet = new HashSet<>();
+ newSet.add(mc);
+ mMediaCodecs.put(mcInfo, newSet);
}
-
- if (piid != PLAYER_PIID_INVALID) {
- mLcDispatcher.addLoudnessCodecInfo(piid, mediaCodec.hashCode(), mcInfo);
+ if (containsCodec.get()) {
+ throw new IllegalArgumentException(
+ "Loudness configurator already added " + mediaCodec);
+ }
+ if (mAudioTrack != null) {
+ piid = mAudioTrack.getPlayerIId();
}
}
+
+ if (piid != PLAYER_PIID_INVALID) {
+ mLcDispatcher.addLoudnessCodecInfo(piid, mediaCodec.hashCode(), mcInfo);
+ }
}
/**
@@ -296,38 +281,44 @@ public class LoudnessCodecConfigurator {
* <p>No elements will be removed if the passed mediaCodec was not added before.
*
* @param mediaCodec the element to remove for receiving asynchronous updates
- *
- * TODO: remove hide once API is final
- * @hide
+ * @throws IllegalArgumentException if the {@code mediaCodec} was not configured,
+ * does not contain loudness metadata or if it
+ * was not added before
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
public void removeMediaCodec(@NonNull MediaCodec mediaCodec) {
int piid = PLAYER_PIID_INVALID;
LoudnessCodecInfo mcInfo;
+ AtomicBoolean removedMc = new AtomicBoolean(false);
AtomicBoolean removeInfo = new AtomicBoolean(false);
mcInfo = getCodecInfo(Objects.requireNonNull(mediaCodec,
"MediaCodec for removeMediaCodec cannot be null"));
- if (mcInfo != null) {
- synchronized (mConfiguratorLock) {
- if (mAudioTrack != null) {
- piid = mAudioTrack.getPlayerIId();
+ if (mcInfo == null) {
+ throw new IllegalArgumentException("Could not extract codec loudness information");
+ }
+ synchronized (mConfiguratorLock) {
+ if (mAudioTrack != null) {
+ piid = mAudioTrack.getPlayerIId();
+ }
+ mMediaCodecs.computeIfPresent(mcInfo, (format, mcs) -> {
+ removedMc.set(mcs.remove(mediaCodec));
+ if (mcs.isEmpty()) {
+ // remove the entry
+ removeInfo.set(true);
+ return null;
}
- mMediaCodecs.computeIfPresent(mcInfo, (format, mcs) -> {
- mcs.remove(mediaCodec);
- if (mcs.isEmpty()) {
- // remove the entry
- removeInfo.set(true);
- return null;
- }
- return mcs;
- });
+ return mcs;
+ });
+ if (!removedMc.get()) {
+ throw new IllegalArgumentException(
+ "Loudness configurator does not contain " + mediaCodec);
}
+ }
- if (piid != PLAYER_PIID_INVALID && removeInfo.get()) {
- mLcDispatcher.removeLoudnessCodecInfo(piid, mcInfo);
- }
+ if (piid != PLAYER_PIID_INVALID && removeInfo.get()) {
+ mLcDispatcher.removeLoudnessCodecInfo(piid, mcInfo);
}
}
@@ -342,9 +333,6 @@ public class LoudnessCodecConfigurator {
*
* @return the {@link Bundle} containing the current loudness parameters. Caller is
* responsible to update the {@link MediaCodec}
- *
- * TODO: remove hide once API is final
- * @hide
*/
@FlaggedApi(FLAG_LOUDNESS_CONFIGURATOR_API)
@NonNull
@@ -375,7 +363,7 @@ public class LoudnessCodecConfigurator {
}
/** @hide */
- /*package*/ HashMap<LoudnessCodecInfo, Set<MediaCodec>> getRegisteredMediaCodecs() {
+ /*package*/ Map<LoudnessCodecInfo, Set<MediaCodec>> getRegisteredMediaCodecs() {
synchronized (mConfiguratorLock) {
return mMediaCodecs;
}
@@ -397,38 +385,43 @@ public class LoudnessCodecConfigurator {
return null;
}
- final MediaFormat inputFormat = mediaCodec.getInputFormat();
- final String mimeType = inputFormat.getString(MediaFormat.KEY_MIME);
- if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mimeType)) {
- // check both KEY_AAC_PROFILE and KEY_PROFILE as some codecs may only recognize one of
- // these two keys
- int aacProfile = -1;
- int profile = -1;
- try {
- aacProfile = inputFormat.getInteger(MediaFormat.KEY_AAC_PROFILE);
- } catch (NullPointerException e) {
- // does not contain KEY_AAC_PROFILE. do nothing
- }
- try {
- profile = inputFormat.getInteger(MediaFormat.KEY_PROFILE);
- } catch (NullPointerException e) {
- // does not contain KEY_PROFILE. do nothing
- }
- if (aacProfile == MediaCodecInfo.CodecProfileLevel.AACObjectXHE
- || profile == MediaCodecInfo.CodecProfileLevel.AACObjectXHE) {
- lci.metadataType = CODEC_METADATA_TYPE_MPEG_D;
+ try {
+ final MediaFormat inputFormat = mediaCodec.getInputFormat();
+ final String mimeType = inputFormat.getString(MediaFormat.KEY_MIME);
+ if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mimeType)) {
+ // check both KEY_AAC_PROFILE and KEY_PROFILE as some codecs may only recognize
+ // one of these two keys
+ int aacProfile = -1;
+ int profile = -1;
+ try {
+ aacProfile = inputFormat.getInteger(MediaFormat.KEY_AAC_PROFILE);
+ } catch (NullPointerException e) {
+ // does not contain KEY_AAC_PROFILE. do nothing
+ }
+ try {
+ profile = inputFormat.getInteger(MediaFormat.KEY_PROFILE);
+ } catch (NullPointerException e) {
+ // does not contain KEY_PROFILE. do nothing
+ }
+ if (aacProfile == MediaCodecInfo.CodecProfileLevel.AACObjectXHE
+ || profile == MediaCodecInfo.CodecProfileLevel.AACObjectXHE) {
+ lci.metadataType = CODEC_METADATA_TYPE_MPEG_D;
+ } else {
+ lci.metadataType = CODEC_METADATA_TYPE_MPEG_4;
+ }
} else {
- lci.metadataType = CODEC_METADATA_TYPE_MPEG_4;
+ Log.w(TAG, "MediaCodec mime type not supported for loudness annotation");
+ return null;
}
- } else {
- Log.w(TAG, "MediaCodec mime type not supported for loudness annotation");
+
+ final MediaFormat outputFormat = mediaCodec.getOutputFormat();
+ lci.isDownmixing = outputFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
+ < inputFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "MediaCodec is not configured", e);
return null;
}
- final MediaFormat outputFormat = mediaCodec.getOutputFormat();
- lci.isDownmixing = outputFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
- < inputFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
-
return lci;
}
}
diff --git a/media/java/android/media/LoudnessCodecDispatcher.java b/media/java/android/media/LoudnessCodecDispatcher.java
index 0da1a497a8fd..b546a81b0498 100644
--- a/media/java/android/media/LoudnessCodecDispatcher.java
+++ b/media/java/android/media/LoudnessCodecDispatcher.java
@@ -33,6 +33,7 @@ import androidx.annotation.NonNull;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
@@ -81,7 +82,7 @@ public class LoudnessCodecDispatcher implements CallbackUtil.DispatcherStub {
mConfiguratorListener.computeIfPresent(listener, (l, lcConfig) -> {
// send the appropriate bundle for the user to update
if (lcConfig.getAssignedTrackPiid() == piid) {
- final HashMap<LoudnessCodecInfo, Set<MediaCodec>> mediaCodecsMap =
+ final Map<LoudnessCodecInfo, Set<MediaCodec>> mediaCodecsMap =
lcConfig.getRegisteredMediaCodecs();
for (LoudnessCodecInfo codecInfo : mediaCodecsMap.keySet()) {
final String infoKey = Integer.toString(codecInfo.hashCode());