diff options
| author | 2023-11-29 07:42:16 +0000 | |
|---|---|---|
| committer | 2023-11-29 07:42:16 +0000 | |
| commit | 31e84d0a7d2eec35d08a29cca7c68d2690cae5cd (patch) | |
| tree | e229be23b777831b8b19cea4acc99051ba6264c5 | |
| parent | 7fd1bda9069d8293911e29fef0e98ed2068245e9 (diff) | |
| parent | 2f3da6158f55864b420a07411d149cc5c98ae540 (diff) | |
Merge "CTA2075: Finalize the loudness configurator API" into main
| -rw-r--r-- | core/api/current.txt | 13 | ||||
| -rw-r--r-- | media/java/android/media/LoudnessCodecConfigurator.java | 183 | ||||
| -rw-r--r-- | media/java/android/media/LoudnessCodecDispatcher.java | 3 |
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()); |