From 68fd23a96756e275f25312e469fd81d06dfccdfa Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 15 Jan 2021 14:48:30 +0000 Subject: [PATCH] Add option to set preferred audio role flags in DefaultTrackSelector We already have the eequivalent option for text tracks. PiperOrigin-RevId: 351999287 --- RELEASENOTES.md | 1 + .../trackselection/DefaultTrackSelector.java | 13 ++++ .../TrackSelectionParameters.java | 26 +++++++ .../DefaultTrackSelectorTest.java | 70 +++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6e602e4c09..5fe3577574 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -141,6 +141,7 @@ * Add option to specify multiple preferred audio or text languages. * Add option to specify preferred MIME type(s) for video and audio ([#8320](https://github.com/google/ExoPlayer/issues/8320)). + * Add option to specify preferred audio role flags. * Forward `Timeline` and `MediaPeriodId` to `TrackSelection.Factory`. * DASH: * Support low-latency DASH playback (`availabilityTimeOffset` and diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 85be24aafa..05988b4748 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -489,6 +489,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { return this; } + @Override + public ParametersBuilder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAudioRoleFlags) { + super.setPreferredAudioRoleFlags(preferredAudioRoleFlags); + return this; + } + /** * Sets the maximum allowed audio channel count. * @@ -843,6 +849,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { preferredVideoMimeTypes, // Audio preferredAudioLanguages, + preferredAudioRoleFlags, maxAudioChannelCount, maxAudioBitrate, exceedAudioConstraintsIfNecessary, @@ -1112,6 +1119,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ImmutableList preferredVideoMimeTypes, // Audio ImmutableList preferredAudioLanguages, + @C.RoleFlags int preferredAudioRoleFlags, int maxAudioChannelCount, int maxAudioBitrate, boolean exceedAudioConstraintsIfNecessary, @@ -1135,6 +1143,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { SparseBooleanArray rendererDisabledFlags) { super( preferredAudioLanguages, + preferredAudioRoleFlags, preferredTextLanguages, preferredTextRoleFlags, selectUndeterminedTextLanguage, @@ -2724,6 +2733,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { private final boolean isWithinRendererCapabilities; private final int preferredLanguageScore; private final int preferredLanguageIndex; + private final int preferredRoleFlagsScore; private final int localeLanguageMatchIndex; private final int localeLanguageScore; private final boolean isDefaultSelectionFlag; @@ -2753,6 +2763,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { } preferredLanguageIndex = bestLanguageIndex; preferredLanguageScore = bestLanguageScore; + preferredRoleFlagsScore = + Integer.bitCount(format.roleFlags & parameters.preferredAudioRoleFlags); isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; channelCount = format.channelCount; sampleRate = format.sampleRate; @@ -2809,6 +2821,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { other.preferredLanguageIndex, Ordering.natural().reverse()) .compare(this.preferredLanguageScore, other.preferredLanguageScore) + .compare(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore) .compareFalseFirst(this.isWithinConstraints, other.isWithinConstraints) .compare( this.preferredMimeTypeMatchIndex, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java index be1f8f6733..88719bc0ab 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java @@ -40,6 +40,7 @@ public class TrackSelectionParameters implements Parcelable { public static class Builder { /* package */ ImmutableList preferredAudioLanguages; + @C.RoleFlags /* package */ int preferredAudioRoleFlags; /* package */ ImmutableList preferredTextLanguages; @C.RoleFlags /* package */ int preferredTextRoleFlags; /* package */ boolean selectUndeterminedTextLanguage; @@ -63,6 +64,7 @@ public class TrackSelectionParameters implements Parcelable { @Deprecated public Builder() { preferredAudioLanguages = ImmutableList.of(); + preferredAudioRoleFlags = 0; preferredTextLanguages = ImmutableList.of(); preferredTextRoleFlags = 0; selectUndeterminedTextLanguage = false; @@ -75,6 +77,7 @@ public class TrackSelectionParameters implements Parcelable { */ /* package */ Builder(TrackSelectionParameters initialValues) { preferredAudioLanguages = initialValues.preferredAudioLanguages; + preferredAudioRoleFlags = initialValues.preferredAudioRoleFlags; preferredTextLanguages = initialValues.preferredTextLanguages; preferredTextRoleFlags = initialValues.preferredTextRoleFlags; selectUndeterminedTextLanguage = initialValues.selectUndeterminedTextLanguage; @@ -111,6 +114,17 @@ public class TrackSelectionParameters implements Parcelable { return this; } + /** + * Sets the preferred {@link C.RoleFlags} for audio tracks. + * + * @param preferredAudioRoleFlags Preferred audio role flags. + * @return This builder. + */ + public Builder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAudioRoleFlags) { + this.preferredAudioRoleFlags = preferredAudioRoleFlags; + return this; + } + /** * Sets the preferred language and role flags for text tracks based on the accessibility * settings of {@link CaptioningManager}. @@ -201,6 +215,7 @@ public class TrackSelectionParameters implements Parcelable { return new TrackSelectionParameters( // Audio preferredAudioLanguages, + preferredAudioRoleFlags, // Text preferredTextLanguages, preferredTextRoleFlags, @@ -262,6 +277,11 @@ public class TrackSelectionParameters implements Parcelable { * default. The default value is an empty list. */ public final ImmutableList preferredAudioLanguages; + /** + * The preferred {@link C.RoleFlags} for audio tracks. {@code 0} selects the default track if + * there is one, or the first track if there's no default. The default value is {@code 0}. + */ + @C.RoleFlags public final int preferredAudioRoleFlags; /** * The preferred languages for text tracks as IETF BCP 47 conformant tags in order of preference. * An empty list selects the default track if there is one, or no track otherwise. The default @@ -290,12 +310,14 @@ public class TrackSelectionParameters implements Parcelable { /* package */ TrackSelectionParameters( ImmutableList preferredAudioLanguages, + @C.RoleFlags int preferredAudioRoleFlags, ImmutableList preferredTextLanguages, @C.RoleFlags int preferredTextRoleFlags, boolean selectUndeterminedTextLanguage, @C.SelectionFlags int disabledTextTrackSelectionFlags) { // Audio this.preferredAudioLanguages = preferredAudioLanguages; + this.preferredAudioRoleFlags = preferredAudioRoleFlags; // Text this.preferredTextLanguages = preferredTextLanguages; this.preferredTextRoleFlags = preferredTextRoleFlags; @@ -307,6 +329,7 @@ public class TrackSelectionParameters implements Parcelable { ArrayList preferredAudioLanguages = new ArrayList<>(); in.readList(preferredAudioLanguages, /* loader= */ null); this.preferredAudioLanguages = ImmutableList.copyOf(preferredAudioLanguages); + this.preferredAudioRoleFlags = in.readInt(); ArrayList preferredTextLanguages = new ArrayList<>(); in.readList(preferredTextLanguages, /* loader= */ null); this.preferredTextLanguages = ImmutableList.copyOf(preferredTextLanguages); @@ -331,6 +354,7 @@ public class TrackSelectionParameters implements Parcelable { } TrackSelectionParameters other = (TrackSelectionParameters) obj; return preferredAudioLanguages.equals(other.preferredAudioLanguages) + && preferredAudioRoleFlags == other.preferredAudioRoleFlags && preferredTextLanguages.equals(other.preferredTextLanguages) && preferredTextRoleFlags == other.preferredTextRoleFlags && selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage @@ -341,6 +365,7 @@ public class TrackSelectionParameters implements Parcelable { public int hashCode() { int result = 1; result = 31 * result + preferredAudioLanguages.hashCode(); + result = 31 * result + preferredAudioRoleFlags; result = 31 * result + preferredTextLanguages.hashCode(); result = 31 * result + preferredTextRoleFlags; result = 31 * result + (selectUndeterminedTextLanguage ? 1 : 0); @@ -358,6 +383,7 @@ public class TrackSelectionParameters implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeList(preferredAudioLanguages); + dest.writeInt(preferredAudioRoleFlags); dest.writeList(preferredTextLanguages); dest.writeInt(preferredTextRoleFlags); Util.writeBoolean(dest, selectUndeterminedTextLanguage); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java index 0762eee9fb..e1ff3002eb 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java @@ -383,6 +383,75 @@ public final class DefaultTrackSelectorTest { assertFixedSelection(result.selections.get(0), trackGroups, enAudioFormat); } + /** + * Tests that track selector will select audio track with the highest number of matching role + * flags given by {@link Parameters}. + */ + @Test + public void selectTracks_withPreferredAudioRoleFlags_selectPreferredTrack() throws Exception { + Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon(); + Format noRoleFlags = formatBuilder.build(); + Format lessRoleFlags = formatBuilder.setRoleFlags(C.ROLE_FLAG_CAPTION).build(); + Format moreRoleFlags = + formatBuilder + .setRoleFlags(C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_COMMENTARY | C.ROLE_FLAG_DUB) + .build(); + TrackGroupArray trackGroups = wrapFormats(noRoleFlags, moreRoleFlags, lessRoleFlags); + + trackSelector.setParameters( + defaultParameters + .buildUpon() + .setPreferredAudioRoleFlags(C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_COMMENTARY)); + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES}, + trackGroups, + periodId, + TIMELINE); + assertFixedSelection(result.selections.get(0), trackGroups, moreRoleFlags); + } + + /** + * Tests that track selector with select default audio track if no role flag preference is + * specified by {@link Parameters}. + */ + @Test + public void selectTracks_withoutPreferredAudioRoleFlags_selectsDefaultTrack() throws Exception { + Format firstFormat = AUDIO_FORMAT; + Format defaultFormat = + AUDIO_FORMAT.buildUpon().setSelectionFlags(C.SELECTION_FLAG_DEFAULT).build(); + Format roleFlagFormat = AUDIO_FORMAT.buildUpon().setRoleFlags(C.ROLE_FLAG_CAPTION).build(); + TrackGroupArray trackGroups = wrapFormats(firstFormat, defaultFormat, roleFlagFormat); + + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES}, + trackGroups, + periodId, + TIMELINE); + assertFixedSelection(result.selections.get(0), trackGroups, defaultFormat); + } + + /** + * Tests that track selector with select the first audio track if no role flag preference is + * specified by {@link Parameters} and no default track exists. + */ + @Test + public void selectTracks_withoutPreferredAudioRoleFlagsOrDefaultTrack_selectsFirstTrack() + throws Exception { + Format firstFormat = AUDIO_FORMAT; + Format roleFlagFormat = AUDIO_FORMAT.buildUpon().setRoleFlags(C.ROLE_FLAG_CAPTION).build(); + TrackGroupArray trackGroups = wrapFormats(firstFormat, roleFlagFormat); + + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES}, + trackGroups, + periodId, + TIMELINE); + assertFixedSelection(result.selections.get(0), trackGroups, firstFormat); + } + /** * Tests that track selector will prefer selecting audio track with language that match preferred * language given by {@link Parameters} over track with {@link C#SELECTION_FLAG_DEFAULT}. @@ -1667,6 +1736,7 @@ public final class DefaultTrackSelectorTest { /* preferredVideoMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_AV1, MimeTypes.VIDEO_H264), // Audio /* preferredAudioLanguages= */ ImmutableList.of("zh", "jp"), + /* preferredAudioRoleFlags= */ C.ROLE_FLAG_COMMENTARY, /* maxAudioChannelCount= */ 10, /* maxAudioBitrate= */ 11, /* exceedAudioConstraintsIfNecessary= */ false,