Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public static class Builder {
private ImmutableList<String> preferredAudioLabels;
private @C.RoleFlags int preferredAudioRoleFlags;
private int maxAudioChannelCount;
private int preferredAudioChannelCount;
private int maxAudioBitrate;
private ImmutableList<String> preferredAudioMimeTypes;
private AudioOffloadPreferences audioOffloadPreferences;
Expand Down Expand Up @@ -135,6 +136,7 @@ public Builder() {
preferredAudioLabels = ImmutableList.of();
preferredAudioRoleFlags = 0;
maxAudioChannelCount = Integer.MAX_VALUE;
preferredAudioChannelCount = 0;
maxAudioBitrate = Integer.MAX_VALUE;
preferredAudioMimeTypes = ImmutableList.of();
audioOffloadPreferences = AudioOffloadPreferences.DEFAULT;
Expand Down Expand Up @@ -215,6 +217,8 @@ protected Builder(Bundle bundle) {
bundle.getInt(FIELD_PREFERRED_AUDIO_ROLE_FLAGS, DEFAULT.preferredAudioRoleFlags);
maxAudioChannelCount =
bundle.getInt(FIELD_MAX_AUDIO_CHANNEL_COUNT, DEFAULT.maxAudioChannelCount);
preferredAudioChannelCount =
bundle.getInt(FIELD_PREFERRED_AUDIO_CHANNEL_COUNT, DEFAULT.preferredAudioChannelCount);
maxAudioBitrate = bundle.getInt(FIELD_MAX_AUDIO_BITRATE, DEFAULT.maxAudioBitrate);
preferredAudioMimeTypes =
ImmutableList.copyOf(
Expand Down Expand Up @@ -331,6 +335,7 @@ private void init(@UnknownInitialization Builder this, TrackSelectionParameters
preferredAudioRoleFlags = parameters.preferredAudioRoleFlags;
preferredAudioLabels = parameters.preferredAudioLabels;
maxAudioChannelCount = parameters.maxAudioChannelCount;
preferredAudioChannelCount = parameters.preferredAudioChannelCount;
maxAudioBitrate = parameters.maxAudioBitrate;
preferredAudioMimeTypes = parameters.preferredAudioMimeTypes;
audioOffloadPreferences = parameters.audioOffloadPreferences;
Expand Down Expand Up @@ -664,6 +669,23 @@ public Builder setMaxAudioChannelCount(int maxAudioChannelCount) {
return this;
}

/**
* Sets the preferred audio channel count. When set to a value greater than 0, audio tracks
* with channel count >= this value will be preferred over tracks with lower channel count,
* regardless of role flags (main vs alt). This allows selecting 5.1 surround tracks over
* stereo tracks even when the stereo track has a main role.
*
* <p>Set to 0 to disable this preference (default behavior based on role flags).
*
* @param preferredAudioChannelCount Preferred audio channel count, or 0 to disable.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder setPreferredAudioChannelCount(int preferredAudioChannelCount) {
this.preferredAudioChannelCount = preferredAudioChannelCount;
return this;
}

/**
* Sets the maximum allowed audio bitrate.
*
Expand Down Expand Up @@ -1305,6 +1327,13 @@ public static TrackSelectionParameters getDefaults(Context context) {
*/
public final int maxAudioChannelCount;

/**
* Preferred audio channel count. When set to a value greater than 0, audio tracks with channel
* count >= this value will be preferred over tracks with lower channel count, regardless of role
* flags. The default value is {@code 0} (disabled).
*/
public final int preferredAudioChannelCount;

/**
* Maximum allowed audio bitrate in bits per second. The default value is {@link
* Integer#MAX_VALUE} (i.e. no constraint).
Expand Down Expand Up @@ -1428,6 +1457,7 @@ protected TrackSelectionParameters(Builder builder) {
this.preferredAudioLanguages = builder.preferredAudioLanguages;
this.preferredAudioRoleFlags = builder.preferredAudioRoleFlags;
this.maxAudioChannelCount = builder.maxAudioChannelCount;
this.preferredAudioChannelCount = builder.preferredAudioChannelCount;
this.preferredAudioLabels = builder.preferredAudioLabels;
this.maxAudioBitrate = builder.maxAudioBitrate;
this.preferredAudioMimeTypes = builder.preferredAudioMimeTypes;
Expand Down Expand Up @@ -1487,6 +1517,7 @@ public boolean equals(@Nullable Object obj) {
&& preferredAudioLanguages.equals(other.preferredAudioLanguages)
&& preferredAudioRoleFlags == other.preferredAudioRoleFlags
&& maxAudioChannelCount == other.maxAudioChannelCount
&& preferredAudioChannelCount == other.preferredAudioChannelCount
&& preferredAudioLabels.equals(other.preferredAudioLabels)
&& maxAudioBitrate == other.maxAudioBitrate
&& preferredAudioMimeTypes.equals(other.preferredAudioMimeTypes)
Expand Down Expand Up @@ -1533,6 +1564,7 @@ public int hashCode() {
result = 31 * result + preferredAudioLanguages.hashCode();
result = 31 * result + preferredAudioRoleFlags;
result = 31 * result + maxAudioChannelCount;
result = 31 * result + preferredAudioChannelCount;
result = 31 * result + preferredAudioLabels.hashCode();
result = 31 * result + maxAudioBitrate;
result = 31 * result + preferredAudioMimeTypes.hashCode();
Expand Down Expand Up @@ -1597,6 +1629,7 @@ public int hashCode() {
private static final String FIELD_PREFERRED_VIDEO_LABELS = Util.intToStringMaxRadix(36);
private static final String FIELD_PREFERRED_AUDIO_LABELS = Util.intToStringMaxRadix(37);
private static final String FIELD_PREFERRED_TEXT_LABELS = Util.intToStringMaxRadix(38);
private static final String FIELD_PREFERRED_AUDIO_CHANNEL_COUNT = Util.intToStringMaxRadix(39);

/**
* Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()}
Expand Down Expand Up @@ -1639,6 +1672,7 @@ public Bundle toBundle() {
FIELD_PREFERRED_AUDIO_LANGUAGES, preferredAudioLanguages.toArray(new String[0]));
bundle.putInt(FIELD_PREFERRED_AUDIO_ROLE_FLAGS, preferredAudioRoleFlags);
bundle.putInt(FIELD_MAX_AUDIO_CHANNEL_COUNT, maxAudioChannelCount);
bundle.putInt(FIELD_PREFERRED_AUDIO_CHANNEL_COUNT, preferredAudioChannelCount);
bundle.putInt(FIELD_MAX_AUDIO_BITRATE, maxAudioBitrate);
bundle.putStringArray(
FIELD_PREFERRED_AUDIO_LABELS, preferredAudioLabels.toArray(new String[0]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,14 @@ public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) {
return this;
}

@SuppressWarnings("deprecation") // Intentionally returning deprecated type
@CanIgnoreReturnValue
@Override
public ParametersBuilder setPreferredAudioChannelCount(int preferredAudioChannelCount) {
delegate.setPreferredAudioChannelCount(preferredAudioChannelCount);
return this;
}

@SuppressWarnings("deprecation") // Intentionally returning deprecated type
@CanIgnoreReturnValue
@Override
Expand Down Expand Up @@ -1277,6 +1285,13 @@ public Builder setMaxAudioChannelCount(int maxAudioChannelCount) {
return this;
}

@CanIgnoreReturnValue
@Override
public Builder setPreferredAudioChannelCount(int preferredAudioChannelCount) {
super.setPreferredAudioChannelCount(preferredAudioChannelCount);
return this;
}

@CanIgnoreReturnValue
@Override
public Builder setMaxAudioBitrate(int maxAudioBitrate) {
Expand Down Expand Up @@ -4074,7 +4089,12 @@ public int compareTo(AudioTrackInfo other) {
this.preferredLanguageIndex,
other.preferredLanguageIndex,
Ordering.natural().reverse())
.compare(this.preferredLanguageScore, other.preferredLanguageScore)
.compare(this.preferredLanguageScore, other.preferredLanguageScore);
// Compare preferred channel count (when set, higher channel count wins over role)
if (this.parameters.preferredAudioChannelCount > 0) {
comparisonChain = comparisonChain.compare(this.channelCount, other.channelCount);
}
comparisonChain = comparisonChain
.compare(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore)
.compare(
this.preferredLabelMatchIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,121 @@ public void selectTracks_withPreferredAudioRoleFlags_selectPreferredTrack() thro
assertFixedSelection(result.selections[0], trackGroups, lessRoleFlags);
}

/**
* Tests that track selector will select the audio track with higher channel count when {@link
* Parameters#preferredAudioChannelCount} is set, even if the track has an alternate role flag.
*/
@Test
public void selectTracks_withPreferredAudioChannelCount_selectsHigherChannelCountTrack()
throws Exception {
Format stereoMainFormat =
AUDIO_FORMAT.buildUpon()
.setId("stereo_main")
.setChannelCount(2)
.setRoleFlags(C.ROLE_FLAG_MAIN)
.build();
Format surroundAltFormat =
AUDIO_FORMAT.buildUpon()
.setId("surround_alt")
.setChannelCount(6)
.setRoleFlags(C.ROLE_FLAG_ALTERNATE)
.build();
TrackGroupArray trackGroups = wrapFormats(stereoMainFormat, surroundAltFormat);

// Without preferredAudioChannelCount, main role stereo track should be selected
trackSelector.setParameters(defaultParameters);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, stereoMainFormat);

// With preferredAudioChannelCount=6, 5.1 surround track should be selected over stereo main
trackSelector.setParameters(
defaultParameters.buildUpon().setPreferredAudioChannelCount(6).build());
result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, surroundAltFormat);
}

/**
* Tests that track selector falls back to lower channel count track when preferred channel count
* track is not supported by renderer.
*/
@Test
public void selectTracks_withPreferredAudioChannelCountNotSupported_fallsBackToSupportedTrack()
throws Exception {
Format stereoFormat =
AUDIO_FORMAT.buildUpon()
.setId("stereo")
.setChannelCount(2)
.setRoleFlags(C.ROLE_FLAG_MAIN)
.build();
Format surroundFormat =
AUDIO_FORMAT.buildUpon()
.setId("surround")
.setChannelCount(6)
.setRoleFlags(C.ROLE_FLAG_ALTERNATE)
.build();
TrackGroupArray trackGroups = wrapFormats(stereoFormat, surroundFormat);

// Renderer only supports stereo (2 channels), surround exceeds capabilities
Map<String, Integer> mappedCapabilities = new HashMap<>();
mappedCapabilities.put(stereoFormat.id, FORMAT_HANDLED);
mappedCapabilities.put(surroundFormat.id, FORMAT_EXCEEDS_CAPABILITIES);
RendererCapabilities stereoOnlyCapabilities =
new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, mappedCapabilities);

// With preferredAudioChannelCount=6, but renderer doesn't support 6 channels,
// should fall back to stereo
trackSelector.setParameters(
defaultParameters.buildUpon().setPreferredAudioChannelCount(6).build());
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {stereoOnlyCapabilities}, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, stereoFormat);
}

/**
* Tests that track selector selects the track with highest channel count among supported tracks
* when preferredAudioChannelCount is set, even if no track meets the threshold.
*/
@Test
public void selectTracks_withPreferredAudioChannelCount_selectsHighestSupportedChannelCount()
throws Exception {
Format stereoFormat =
AUDIO_FORMAT.buildUpon()
.setId("stereo")
.setChannelCount(2)
.setRoleFlags(C.ROLE_FLAG_MAIN)
.build();
Format surroundFormat =
AUDIO_FORMAT.buildUpon()
.setId("surround")
.setChannelCount(6)
.setRoleFlags(C.ROLE_FLAG_ALTERNATE)
.build();
TrackGroupArray trackGroups = wrapFormats(stereoFormat, surroundFormat);

// With preferredAudioChannelCount=8, but only 2ch and 6ch available,
// should select 6ch (highest available) even though it doesn't meet the threshold
trackSelector.setParameters(
defaultParameters.buildUpon().setPreferredAudioChannelCount(8).build());
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(result.selections[0], trackGroups, surroundFormat);
}

@Test
public void
selectTracks_withPreferredTextLanguagesAndRoleFlagsFromCaptioningManager_selectsCaptioningTrack()
Expand Down