blob: f114c8150065cc042bb5b4921dc1e014f169302f [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.trackselection;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.BundleableUtil.fromNullableBundle;
import static com.google.common.base.MoreObjects.firstNonNull;
import android.content.Context;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Looper;
import android.view.accessibility.CaptioningManager;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
import java.util.Set;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
/**
* Constraint parameters for track selection.
*
* <p>For example the following code modifies the parameters to restrict video track selections to
* SD, and to select a German audio track if there is one:
*
* <pre>{@code
* // Build on the current parameters.
* TrackSelectionParameters currentParameters = player.getTrackSelectionParameters()
* // Build the resulting parameters.
* TrackSelectionParameters newParameters = currentParameters
* .buildUpon()
* .setMaxVideoSizeSd()
* .setPreferredAudioLanguage("deu")
* .build();
* // Set the new parameters.
* player.setTrackSelectionParameters(newParameters);
* }</pre>
*/
public class TrackSelectionParameters implements Bundleable {
/**
* A builder for {@link TrackSelectionParameters}. See the {@link TrackSelectionParameters}
* documentation for explanations of the parameters that can be configured using this builder.
*/
public static class Builder {
// Video
private int maxVideoWidth;
private int maxVideoHeight;
private int maxVideoFrameRate;
private int maxVideoBitrate;
private int minVideoWidth;
private int minVideoHeight;
private int minVideoFrameRate;
private int minVideoBitrate;
private int viewportWidth;
private int viewportHeight;
private boolean viewportOrientationMayChange;
private ImmutableList<String> preferredVideoMimeTypes;
private @C.RoleFlags int preferredVideoRoleFlags;
// Audio
private ImmutableList<String> preferredAudioLanguages;
private @C.RoleFlags int preferredAudioRoleFlags;
private int maxAudioChannelCount;
private int maxAudioBitrate;
private ImmutableList<String> preferredAudioMimeTypes;
// Text
private ImmutableList<String> preferredTextLanguages;
private @C.RoleFlags int preferredTextRoleFlags;
private boolean selectUndeterminedTextLanguage;
// General
private boolean forceLowestBitrate;
private boolean forceHighestSupportedBitrate;
private TrackSelectionOverrides trackSelectionOverrides;
private ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
/**
* @deprecated {@link Context} constraints will not be set using this constructor. Use {@link
* #Builder(Context)} instead.
*/
@Deprecated
public Builder() {
// Video
maxVideoWidth = Integer.MAX_VALUE;
maxVideoHeight = Integer.MAX_VALUE;
maxVideoFrameRate = Integer.MAX_VALUE;
maxVideoBitrate = Integer.MAX_VALUE;
viewportWidth = Integer.MAX_VALUE;
viewportHeight = Integer.MAX_VALUE;
viewportOrientationMayChange = true;
preferredVideoMimeTypes = ImmutableList.of();
preferredVideoRoleFlags = 0;
// Audio
preferredAudioLanguages = ImmutableList.of();
preferredAudioRoleFlags = 0;
maxAudioChannelCount = Integer.MAX_VALUE;
maxAudioBitrate = Integer.MAX_VALUE;
preferredAudioMimeTypes = ImmutableList.of();
// Text
preferredTextLanguages = ImmutableList.of();
preferredTextRoleFlags = 0;
selectUndeterminedTextLanguage = false;
// General
forceLowestBitrate = false;
forceHighestSupportedBitrate = false;
trackSelectionOverrides = TrackSelectionOverrides.EMPTY;
disabledTrackTypes = ImmutableSet.of();
}
/**
* Creates a builder with default initial values.
*
* @param context Any context.
*/
@SuppressWarnings({"deprecation", "method.invocation"}) // Methods invoked are setter only.
public Builder(Context context) {
this();
setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(context);
setViewportSizeToPhysicalDisplaySize(context, /* viewportOrientationMayChange= */ true);
}
/** Creates a builder with the initial values specified in {@code initialValues}. */
protected Builder(TrackSelectionParameters initialValues) {
init(initialValues);
}
/** Creates a builder with the initial values specified in {@code bundle}. */
protected Builder(Bundle bundle) {
// Video
maxVideoWidth =
bundle.getInt(keyForField(FIELD_MAX_VIDEO_WIDTH), DEFAULT_WITHOUT_CONTEXT.maxVideoWidth);
maxVideoHeight =
bundle.getInt(
keyForField(FIELD_MAX_VIDEO_HEIGHT), DEFAULT_WITHOUT_CONTEXT.maxVideoHeight);
maxVideoFrameRate =
bundle.getInt(
keyForField(FIELD_MAX_VIDEO_FRAMERATE), DEFAULT_WITHOUT_CONTEXT.maxVideoFrameRate);
maxVideoBitrate =
bundle.getInt(
keyForField(FIELD_MAX_VIDEO_BITRATE), DEFAULT_WITHOUT_CONTEXT.maxVideoBitrate);
minVideoWidth =
bundle.getInt(keyForField(FIELD_MIN_VIDEO_WIDTH), DEFAULT_WITHOUT_CONTEXT.minVideoWidth);
minVideoHeight =
bundle.getInt(
keyForField(FIELD_MIN_VIDEO_HEIGHT), DEFAULT_WITHOUT_CONTEXT.minVideoHeight);
minVideoFrameRate =
bundle.getInt(
keyForField(FIELD_MIN_VIDEO_FRAMERATE), DEFAULT_WITHOUT_CONTEXT.minVideoFrameRate);
minVideoBitrate =
bundle.getInt(
keyForField(FIELD_MIN_VIDEO_BITRATE), DEFAULT_WITHOUT_CONTEXT.minVideoBitrate);
viewportWidth =
bundle.getInt(keyForField(FIELD_VIEWPORT_WIDTH), DEFAULT_WITHOUT_CONTEXT.viewportWidth);
viewportHeight =
bundle.getInt(keyForField(FIELD_VIEWPORT_HEIGHT), DEFAULT_WITHOUT_CONTEXT.viewportHeight);
viewportOrientationMayChange =
bundle.getBoolean(
keyForField(FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE),
DEFAULT_WITHOUT_CONTEXT.viewportOrientationMayChange);
preferredVideoMimeTypes =
ImmutableList.copyOf(
firstNonNull(
bundle.getStringArray(keyForField(FIELD_PREFERRED_VIDEO_MIMETYPES)),
new String[0]));
preferredVideoRoleFlags =
bundle.getInt(
keyForField(FIELD_PREFERRED_VIDEO_ROLE_FLAGS),
DEFAULT_WITHOUT_CONTEXT.preferredVideoRoleFlags);
// Audio
String[] preferredAudioLanguages1 =
firstNonNull(
bundle.getStringArray(keyForField(FIELD_PREFERRED_AUDIO_LANGUAGES)), new String[0]);
preferredAudioLanguages = normalizeLanguageCodes(preferredAudioLanguages1);
preferredAudioRoleFlags =
bundle.getInt(
keyForField(FIELD_PREFERRED_AUDIO_ROLE_FLAGS),
DEFAULT_WITHOUT_CONTEXT.preferredAudioRoleFlags);
maxAudioChannelCount =
bundle.getInt(
keyForField(FIELD_MAX_AUDIO_CHANNEL_COUNT),
DEFAULT_WITHOUT_CONTEXT.maxAudioChannelCount);
maxAudioBitrate =
bundle.getInt(
keyForField(FIELD_MAX_AUDIO_BITRATE), DEFAULT_WITHOUT_CONTEXT.maxAudioBitrate);
preferredAudioMimeTypes =
ImmutableList.copyOf(
firstNonNull(
bundle.getStringArray(keyForField(FIELD_PREFERRED_AUDIO_MIME_TYPES)),
new String[0]));
// Text
preferredTextLanguages =
normalizeLanguageCodes(
firstNonNull(
bundle.getStringArray(keyForField(FIELD_PREFERRED_TEXT_LANGUAGES)),
new String[0]));
preferredTextRoleFlags =
bundle.getInt(
keyForField(FIELD_PREFERRED_TEXT_ROLE_FLAGS),
DEFAULT_WITHOUT_CONTEXT.preferredTextRoleFlags);
selectUndeterminedTextLanguage =
bundle.getBoolean(
keyForField(FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE),
DEFAULT_WITHOUT_CONTEXT.selectUndeterminedTextLanguage);
// General
forceLowestBitrate =
bundle.getBoolean(
keyForField(FIELD_FORCE_LOWEST_BITRATE), DEFAULT_WITHOUT_CONTEXT.forceLowestBitrate);
forceHighestSupportedBitrate =
bundle.getBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE),
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
trackSelectionOverrides =
fromNullableBundle(
TrackSelectionOverrides.CREATOR,
bundle.getBundle(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)),
TrackSelectionOverrides.EMPTY);
disabledTrackTypes =
ImmutableSet.copyOf(
Ints.asList(
firstNonNull(
bundle.getIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE)), new int[0])));
}
/** Overrides the value of the builder with the value of {@link TrackSelectionParameters}. */
@EnsuresNonNull({
"preferredVideoMimeTypes",
"preferredAudioLanguages",
"preferredAudioMimeTypes",
"preferredTextLanguages",
"trackSelectionOverrides",
"disabledTrackTypes",
})
private void init(@UnknownInitialization Builder this, TrackSelectionParameters parameters) {
// Video
maxVideoWidth = parameters.maxVideoWidth;
maxVideoHeight = parameters.maxVideoHeight;
maxVideoFrameRate = parameters.maxVideoFrameRate;
maxVideoBitrate = parameters.maxVideoBitrate;
minVideoWidth = parameters.minVideoWidth;
minVideoHeight = parameters.minVideoHeight;
minVideoFrameRate = parameters.minVideoFrameRate;
minVideoBitrate = parameters.minVideoBitrate;
viewportWidth = parameters.viewportWidth;
viewportHeight = parameters.viewportHeight;
viewportOrientationMayChange = parameters.viewportOrientationMayChange;
preferredVideoMimeTypes = parameters.preferredVideoMimeTypes;
preferredVideoRoleFlags = parameters.preferredVideoRoleFlags;
// Audio
preferredAudioLanguages = parameters.preferredAudioLanguages;
preferredAudioRoleFlags = parameters.preferredAudioRoleFlags;
maxAudioChannelCount = parameters.maxAudioChannelCount;
maxAudioBitrate = parameters.maxAudioBitrate;
preferredAudioMimeTypes = parameters.preferredAudioMimeTypes;
// Text
preferredTextLanguages = parameters.preferredTextLanguages;
preferredTextRoleFlags = parameters.preferredTextRoleFlags;
selectUndeterminedTextLanguage = parameters.selectUndeterminedTextLanguage;
// General
forceLowestBitrate = parameters.forceLowestBitrate;
forceHighestSupportedBitrate = parameters.forceHighestSupportedBitrate;
trackSelectionOverrides = parameters.trackSelectionOverrides;
disabledTrackTypes = parameters.disabledTrackTypes;
}
/** Overrides the value of the builder with the value of {@link TrackSelectionParameters}. */
protected Builder set(TrackSelectionParameters parameters) {
init(parameters);
return this;
}
// Video
/**
* Equivalent to {@link #setMaxVideoSize setMaxVideoSize(1279, 719)}.
*
* @return This builder.
*/
public Builder setMaxVideoSizeSd() {
return setMaxVideoSize(1279, 719);
}
/**
* Equivalent to {@link #setMaxVideoSize setMaxVideoSize(Integer.MAX_VALUE, Integer.MAX_VALUE)}.
*
* @return This builder.
*/
public Builder clearVideoSizeConstraints() {
return setMaxVideoSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* Sets the maximum allowed video width and height.
*
* @param maxVideoWidth Maximum allowed video width in pixels.
* @param maxVideoHeight Maximum allowed video height in pixels.
* @return This builder.
*/
public Builder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) {
this.maxVideoWidth = maxVideoWidth;
this.maxVideoHeight = maxVideoHeight;
return this;
}
/**
* Sets the maximum allowed video frame rate.
*
* @param maxVideoFrameRate Maximum allowed video frame rate in hertz.
* @return This builder.
*/
public Builder setMaxVideoFrameRate(int maxVideoFrameRate) {
this.maxVideoFrameRate = maxVideoFrameRate;
return this;
}
/**
* Sets the maximum allowed video bitrate.
*
* @param maxVideoBitrate Maximum allowed video bitrate in bits per second.
* @return This builder.
*/
public Builder setMaxVideoBitrate(int maxVideoBitrate) {
this.maxVideoBitrate = maxVideoBitrate;
return this;
}
/**
* Sets the minimum allowed video width and height.
*
* @param minVideoWidth Minimum allowed video width in pixels.
* @param minVideoHeight Minimum allowed video height in pixels.
* @return This builder.
*/
public Builder setMinVideoSize(int minVideoWidth, int minVideoHeight) {
this.minVideoWidth = minVideoWidth;
this.minVideoHeight = minVideoHeight;
return this;
}
/**
* Sets the minimum allowed video frame rate.
*
* @param minVideoFrameRate Minimum allowed video frame rate in hertz.
* @return This builder.
*/
public Builder setMinVideoFrameRate(int minVideoFrameRate) {
this.minVideoFrameRate = minVideoFrameRate;
return this;
}
/**
* Sets the minimum allowed video bitrate.
*
* @param minVideoBitrate Minimum allowed video bitrate in bits per second.
* @return This builder.
*/
public Builder setMinVideoBitrate(int minVideoBitrate) {
this.minVideoBitrate = minVideoBitrate;
return this;
}
/**
* Equivalent to calling {@link #setViewportSize(int, int, boolean)} with the viewport size
* obtained from {@link Util#getCurrentDisplayModeSize(Context)}.
*
* @param context Any context.
* @param viewportOrientationMayChange Whether the viewport orientation may change during
* playback.
* @return This builder.
*/
public Builder setViewportSizeToPhysicalDisplaySize(
Context context, boolean viewportOrientationMayChange) {
// Assume the viewport is fullscreen.
Point viewportSize = Util.getCurrentDisplayModeSize(context);
return setViewportSize(viewportSize.x, viewportSize.y, viewportOrientationMayChange);
}
/**
* Equivalent to {@link #setViewportSize setViewportSize(Integer.MAX_VALUE, Integer.MAX_VALUE,
* true)}.
*
* @return This builder.
*/
public Builder clearViewportSizeConstraints() {
return setViewportSize(Integer.MAX_VALUE, Integer.MAX_VALUE, true);
}
/**
* Sets the viewport size to constrain adaptive video selections so that only tracks suitable
* for the viewport are selected.
*
* @param viewportWidth Viewport width in pixels.
* @param viewportHeight Viewport height in pixels.
* @param viewportOrientationMayChange Whether the viewport orientation may change during
* playback.
* @return This builder.
*/
public Builder setViewportSize(
int viewportWidth, int viewportHeight, boolean viewportOrientationMayChange) {
this.viewportWidth = viewportWidth;
this.viewportHeight = viewportHeight;
this.viewportOrientationMayChange = viewportOrientationMayChange;
return this;
}
/**
* Sets the preferred sample MIME type for video tracks.
*
* @param mimeType The preferred MIME type for video tracks, or {@code null} to clear a
* previously set preference.
* @return This builder.
*/
public Builder setPreferredVideoMimeType(@Nullable String mimeType) {
return mimeType == null ? setPreferredVideoMimeTypes() : setPreferredVideoMimeTypes(mimeType);
}
/**
* Sets the preferred sample MIME types for video tracks.
*
* @param mimeTypes The preferred MIME types for video tracks in order of preference, or an
* empty list for no preference.
* @return This builder.
*/
public Builder setPreferredVideoMimeTypes(String... mimeTypes) {
preferredVideoMimeTypes = ImmutableList.copyOf(mimeTypes);
return this;
}
/**
* Sets the preferred {@link C.RoleFlags} for video tracks.
*
* @param preferredVideoRoleFlags Preferred video role flags.
* @return This builder.
*/
public Builder setPreferredVideoRoleFlags(@C.RoleFlags int preferredVideoRoleFlags) {
this.preferredVideoRoleFlags = preferredVideoRoleFlags;
return this;
}
// Audio
/**
* Sets the preferred language for audio and forced text tracks.
*
* @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag, or
* {@code null} to select the default track, or the first track if there's no default.
* @return This builder.
*/
public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) {
return preferredAudioLanguage == null
? setPreferredAudioLanguages()
: setPreferredAudioLanguages(preferredAudioLanguage);
}
/**
* Sets the preferred languages for audio and forced text tracks.
*
* @param preferredAudioLanguages Preferred audio languages as IETF BCP 47 conformant tags in
* order of preference, or an empty array to select the default track, or the first track if
* there's no default.
* @return This builder.
*/
public Builder setPreferredAudioLanguages(String... preferredAudioLanguages) {
this.preferredAudioLanguages = normalizeLanguageCodes(preferredAudioLanguages);
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 maximum allowed audio channel count.
*
* @param maxAudioChannelCount Maximum allowed audio channel count.
* @return This builder.
*/
public Builder setMaxAudioChannelCount(int maxAudioChannelCount) {
this.maxAudioChannelCount = maxAudioChannelCount;
return this;
}
/**
* Sets the maximum allowed audio bitrate.
*
* @param maxAudioBitrate Maximum allowed audio bitrate in bits per second.
* @return This builder.
*/
public Builder setMaxAudioBitrate(int maxAudioBitrate) {
this.maxAudioBitrate = maxAudioBitrate;
return this;
}
/**
* Sets the preferred sample MIME type for audio tracks.
*
* @param mimeType The preferred MIME type for audio tracks, or {@code null} to clear a
* previously set preference.
* @return This builder.
*/
public Builder setPreferredAudioMimeType(@Nullable String mimeType) {
return mimeType == null ? setPreferredAudioMimeTypes() : setPreferredAudioMimeTypes(mimeType);
}
/**
* Sets the preferred sample MIME types for audio tracks.
*
* @param mimeTypes The preferred MIME types for audio tracks in order of preference, or an
* empty list for no preference.
* @return This builder.
*/
public Builder setPreferredAudioMimeTypes(String... mimeTypes) {
preferredAudioMimeTypes = ImmutableList.copyOf(mimeTypes);
return this;
}
// Text
/**
* Sets the preferred language and role flags for text tracks based on the accessibility
* settings of {@link CaptioningManager}.
*
* <p>Does nothing for API levels &lt; 19 or when the {@link CaptioningManager} is disabled.
*
* @param context A {@link Context}.
* @return This builder.
*/
public Builder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(
Context context) {
if (Util.SDK_INT >= 19) {
setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettingsV19(context);
}
return this;
}
/**
* Sets the preferred language for text tracks.
*
* @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag, or
* {@code null} to select the default track if there is one, or no track otherwise.
* @return This builder.
*/
public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) {
return preferredTextLanguage == null
? setPreferredTextLanguages()
: setPreferredTextLanguages(preferredTextLanguage);
}
/**
* Sets the preferred languages for text tracks.
*
* @param preferredTextLanguages Preferred text languages as IETF BCP 47 conformant tags in
* order of preference, or an empty array to select the default track if there is one, or no
* track otherwise.
* @return This builder.
*/
public Builder setPreferredTextLanguages(String... preferredTextLanguages) {
this.preferredTextLanguages = normalizeLanguageCodes(preferredTextLanguages);
return this;
}
/**
* Sets the preferred {@link C.RoleFlags} for text tracks.
*
* @param preferredTextRoleFlags Preferred text role flags.
* @return This builder.
*/
public Builder setPreferredTextRoleFlags(@C.RoleFlags int preferredTextRoleFlags) {
this.preferredTextRoleFlags = preferredTextRoleFlags;
return this;
}
/**
* Sets whether a text track with undetermined language should be selected if no track with
* {@link #setPreferredTextLanguages(String...) a preferred language} is available, or if the
* preferred language is unset.
*
* @param selectUndeterminedTextLanguage Whether a text track with undetermined language should
* be selected if no preferred language track is available.
* @return This builder.
*/
public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) {
this.selectUndeterminedTextLanguage = selectUndeterminedTextLanguage;
return this;
}
// General
/**
* Sets whether to force selection of the single lowest bitrate audio and video tracks that
* comply with all other constraints.
*
* @param forceLowestBitrate Whether to force selection of the single lowest bitrate audio and
* video tracks.
* @return This builder.
*/
public Builder setForceLowestBitrate(boolean forceLowestBitrate) {
this.forceLowestBitrate = forceLowestBitrate;
return this;
}
/**
* Sets whether to force selection of the highest bitrate audio and video tracks that comply
* with all other constraints.
*
* @param forceHighestSupportedBitrate Whether to force selection of the highest bitrate audio
* and video tracks.
* @return This builder.
*/
public Builder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) {
this.forceHighestSupportedBitrate = forceHighestSupportedBitrate;
return this;
}
/**
* Sets the selection overrides.
*
* @param trackSelectionOverrides The track selection overrides.
* @return This builder.
*/
public Builder setTrackSelectionOverrides(TrackSelectionOverrides trackSelectionOverrides) {
this.trackSelectionOverrides = trackSelectionOverrides;
return this;
}
/**
* Sets the disabled track types, preventing all tracks of those types from being selected for
* playback.
*
* @param disabledTrackTypes The track types to disable.
* @return This builder.
*/
public Builder setDisabledTrackTypes(Set<@C.TrackType Integer> disabledTrackTypes) {
this.disabledTrackTypes = ImmutableSet.copyOf(disabledTrackTypes);
return this;
}
/** Builds a {@link TrackSelectionParameters} instance with the selected values. */
public TrackSelectionParameters build() {
return new TrackSelectionParameters(this);
}
@RequiresApi(19)
private void setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettingsV19(
Context context) {
if (Util.SDK_INT < 23 && Looper.myLooper() == null) {
// Android platform bug (pre-Marshmallow) that causes RuntimeExceptions when
// CaptioningService is instantiated from a non-Looper thread. See [internal: b/143779904].
return;
}
CaptioningManager captioningManager =
(CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
if (captioningManager == null || !captioningManager.isEnabled()) {
return;
}
preferredTextRoleFlags = C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND;
Locale preferredLocale = captioningManager.getLocale();
if (preferredLocale != null) {
preferredTextLanguages = ImmutableList.of(Util.getLocaleLanguageTag(preferredLocale));
}
}
private static ImmutableList<String> normalizeLanguageCodes(String[] preferredTextLanguages) {
ImmutableList.Builder<String> listBuilder = ImmutableList.builder();
for (String language : checkNotNull(preferredTextLanguages)) {
listBuilder.add(Util.normalizeLanguageCode(checkNotNull(language)));
}
return listBuilder.build();
}
}
/**
* An instance with default values, except those obtained from the {@link Context}.
*
* <p>If possible, use {@link #getDefaults(Context)} instead.
*
* <p>This instance will not have the following settings:
*
* <ul>
* <li>{@link Builder#setViewportSizeToPhysicalDisplaySize(Context, boolean) Viewport
* constraints} configured for the primary display.
* <li>{@link Builder#setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(Context)
* Preferred text language and role flags} configured to the accessibility settings of
* {@link CaptioningManager}.
* </ul>
*/
@SuppressWarnings("deprecation")
public static final TrackSelectionParameters DEFAULT_WITHOUT_CONTEXT = new Builder().build();
/**
* @deprecated This instance is not configured using {@link Context} constraints. Use {@link
* #getDefaults(Context)} instead.
*/
@Deprecated public static final TrackSelectionParameters DEFAULT = DEFAULT_WITHOUT_CONTEXT;
/** Returns an instance configured with default values. */
public static TrackSelectionParameters getDefaults(Context context) {
return new Builder(context).build();
}
// Video
/**
* Maximum allowed video width in pixels. The default value is {@link Integer#MAX_VALUE} (i.e. no
* constraint).
*
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the region
* of the display within which video will be played), use ({@link #viewportWidth}, {@link
* #viewportHeight} and {@link #viewportOrientationMayChange}) instead.
*/
public final int maxVideoWidth;
/**
* Maximum allowed video height in pixels. The default value is {@link Integer#MAX_VALUE} (i.e. no
* constraint).
*
* <p>To constrain adaptive video track selections to be suitable for a given viewport (the region
* of the display within which video will be played), use ({@link #viewportWidth}, {@link
* #viewportHeight} and {@link #viewportOrientationMayChange}) instead.
*/
public final int maxVideoHeight;
/**
* Maximum allowed video frame rate in hertz. The default value is {@link Integer#MAX_VALUE} (i.e.
* no constraint).
*/
public final int maxVideoFrameRate;
/**
* Maximum allowed video bitrate in bits per second. The default value is {@link
* Integer#MAX_VALUE} (i.e. no constraint).
*/
public final int maxVideoBitrate;
/** Minimum allowed video width in pixels. The default value is 0 (i.e. no constraint). */
public final int minVideoWidth;
/** Minimum allowed video height in pixels. The default value is 0 (i.e. no constraint). */
public final int minVideoHeight;
/** Minimum allowed video frame rate in hertz. The default value is 0 (i.e. no constraint). */
public final int minVideoFrameRate;
/**
* Minimum allowed video bitrate in bits per second. The default value is 0 (i.e. no constraint).
*/
public final int minVideoBitrate;
/**
* Viewport width in pixels. Constrains video track selections for adaptive content so that only
* tracks suitable for the viewport are selected. The default value is the physical width of the
* primary display, in pixels.
*/
public final int viewportWidth;
/**
* Viewport height in pixels. Constrains video track selections for adaptive content so that only
* tracks suitable for the viewport are selected. The default value is the physical height of the
* primary display, in pixels.
*/
public final int viewportHeight;
/**
* Whether the viewport orientation may change during playback. Constrains video track selections
* for adaptive content so that only tracks suitable for the viewport are selected. The default
* value is {@code true}.
*/
public final boolean viewportOrientationMayChange;
/**
* The preferred sample MIME types for video tracks in order of preference, or an empty list for
* no preference. The default is an empty list.
*/
public final ImmutableList<String> preferredVideoMimeTypes;
/**
* The preferred {@link C.RoleFlags} for video 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}.
*/
public final @C.RoleFlags int preferredVideoRoleFlags;
// Audio
/**
* The preferred languages for audio and forced text tracks as IETF BCP 47 conformant tags in
* order of preference. An empty list selects the default track, or the first track if there's no
* default. The default value is an empty list.
*/
public final ImmutableList<String> 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}.
*/
public final @C.RoleFlags int preferredAudioRoleFlags;
/**
* Maximum allowed audio channel count. The default value is {@link Integer#MAX_VALUE} (i.e. no
* constraint).
*/
public final int maxAudioChannelCount;
/**
* Maximum allowed audio bitrate in bits per second. The default value is {@link
* Integer#MAX_VALUE} (i.e. no constraint).
*/
public final int maxAudioBitrate;
/**
* The preferred sample MIME types for audio tracks in order of preference, or an empty list for
* no preference. The default is an empty list.
*/
public final ImmutableList<String> preferredAudioMimeTypes;
// Text
/**
* 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
* value is an empty list, or the language of the accessibility {@link CaptioningManager} if
* enabled.
*/
public final ImmutableList<String> preferredTextLanguages;
/**
* The preferred {@link C.RoleFlags} for text tracks. {@code 0} selects the default track if there
* is one, or no track otherwise. The default value is {@code 0}, or {@link C#ROLE_FLAG_SUBTITLE}
* | {@link C#ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND} if the accessibility {@link CaptioningManager}
* is enabled.
*/
public final @C.RoleFlags int preferredTextRoleFlags;
/**
* Whether a text track with undetermined language should be selected if no track with {@link
* #preferredTextLanguages} is available, or if {@link #preferredTextLanguages} is unset. The
* default value is {@code false}.
*/
public final boolean selectUndeterminedTextLanguage;
// General
/**
* Whether to force selection of the single lowest bitrate audio and video tracks that comply with
* all other constraints. The default value is {@code false}.
*/
public final boolean forceLowestBitrate;
/**
* Whether to force selection of the highest bitrate audio and video tracks that comply with all
* other constraints. The default value is {@code false}.
*/
public final boolean forceHighestSupportedBitrate;
/** Overrides to force tracks to be selected. */
public final TrackSelectionOverrides trackSelectionOverrides;
/**
* The track types that are disabled. No track of a disabled type will be selected, thus no track
* type contained in the set will be played. The default value is that no track type is disabled
* (empty set).
*/
public final ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
protected TrackSelectionParameters(Builder builder) {
// Video
this.maxVideoWidth = builder.maxVideoWidth;
this.maxVideoHeight = builder.maxVideoHeight;
this.maxVideoFrameRate = builder.maxVideoFrameRate;
this.maxVideoBitrate = builder.maxVideoBitrate;
this.minVideoWidth = builder.minVideoWidth;
this.minVideoHeight = builder.minVideoHeight;
this.minVideoFrameRate = builder.minVideoFrameRate;
this.minVideoBitrate = builder.minVideoBitrate;
this.viewportWidth = builder.viewportWidth;
this.viewportHeight = builder.viewportHeight;
this.viewportOrientationMayChange = builder.viewportOrientationMayChange;
this.preferredVideoMimeTypes = builder.preferredVideoMimeTypes;
this.preferredVideoRoleFlags = builder.preferredVideoRoleFlags;
// Audio
this.preferredAudioLanguages = builder.preferredAudioLanguages;
this.preferredAudioRoleFlags = builder.preferredAudioRoleFlags;
this.maxAudioChannelCount = builder.maxAudioChannelCount;
this.maxAudioBitrate = builder.maxAudioBitrate;
this.preferredAudioMimeTypes = builder.preferredAudioMimeTypes;
// Text
this.preferredTextLanguages = builder.preferredTextLanguages;
this.preferredTextRoleFlags = builder.preferredTextRoleFlags;
this.selectUndeterminedTextLanguage = builder.selectUndeterminedTextLanguage;
// General
this.forceLowestBitrate = builder.forceLowestBitrate;
this.forceHighestSupportedBitrate = builder.forceHighestSupportedBitrate;
this.trackSelectionOverrides = builder.trackSelectionOverrides;
this.disabledTrackTypes = builder.disabledTrackTypes;
}
/** Creates a new {@link Builder}, copying the initial values from this instance. */
public Builder buildUpon() {
return new Builder(this);
}
@Override
@SuppressWarnings("EqualsGetClass")
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TrackSelectionParameters other = (TrackSelectionParameters) obj;
// Video
return maxVideoWidth == other.maxVideoWidth
&& maxVideoHeight == other.maxVideoHeight
&& maxVideoFrameRate == other.maxVideoFrameRate
&& maxVideoBitrate == other.maxVideoBitrate
&& minVideoWidth == other.minVideoWidth
&& minVideoHeight == other.minVideoHeight
&& minVideoFrameRate == other.minVideoFrameRate
&& minVideoBitrate == other.minVideoBitrate
&& viewportOrientationMayChange == other.viewportOrientationMayChange
&& viewportWidth == other.viewportWidth
&& viewportHeight == other.viewportHeight
&& preferredVideoMimeTypes.equals(other.preferredVideoMimeTypes)
&& preferredVideoRoleFlags == other.preferredVideoRoleFlags
// Audio
&& preferredAudioLanguages.equals(other.preferredAudioLanguages)
&& preferredAudioRoleFlags == other.preferredAudioRoleFlags
&& maxAudioChannelCount == other.maxAudioChannelCount
&& maxAudioBitrate == other.maxAudioBitrate
&& preferredAudioMimeTypes.equals(other.preferredAudioMimeTypes)
&& preferredTextLanguages.equals(other.preferredTextLanguages)
&& preferredTextRoleFlags == other.preferredTextRoleFlags
&& selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage
// General
&& forceLowestBitrate == other.forceLowestBitrate
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
&& trackSelectionOverrides.equals(other.trackSelectionOverrides)
&& disabledTrackTypes.equals(other.disabledTrackTypes);
}
@Override
public int hashCode() {
int result = 1;
// Video
result = 31 * result + maxVideoWidth;
result = 31 * result + maxVideoHeight;
result = 31 * result + maxVideoFrameRate;
result = 31 * result + maxVideoBitrate;
result = 31 * result + minVideoWidth;
result = 31 * result + minVideoHeight;
result = 31 * result + minVideoFrameRate;
result = 31 * result + minVideoBitrate;
result = 31 * result + (viewportOrientationMayChange ? 1 : 0);
result = 31 * result + viewportWidth;
result = 31 * result + viewportHeight;
result = 31 * result + preferredVideoMimeTypes.hashCode();
result = 31 * result + preferredVideoRoleFlags;
// Audio
result = 31 * result + preferredAudioLanguages.hashCode();
result = 31 * result + preferredAudioRoleFlags;
result = 31 * result + maxAudioChannelCount;
result = 31 * result + maxAudioBitrate;
result = 31 * result + preferredAudioMimeTypes.hashCode();
// Text
result = 31 * result + preferredTextLanguages.hashCode();
result = 31 * result + preferredTextRoleFlags;
result = 31 * result + (selectUndeterminedTextLanguage ? 1 : 0);
// General
result = 31 * result + (forceLowestBitrate ? 1 : 0);
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
result = 31 * result + trackSelectionOverrides.hashCode();
result = 31 * result + disabledTrackTypes.hashCode();
return result;
}
// Bundleable implementation
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FIELD_PREFERRED_AUDIO_LANGUAGES,
FIELD_PREFERRED_AUDIO_ROLE_FLAGS,
FIELD_PREFERRED_TEXT_LANGUAGES,
FIELD_PREFERRED_TEXT_ROLE_FLAGS,
FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE,
FIELD_MAX_VIDEO_WIDTH,
FIELD_MAX_VIDEO_HEIGHT,
FIELD_MAX_VIDEO_FRAMERATE,
FIELD_MAX_VIDEO_BITRATE,
FIELD_MIN_VIDEO_WIDTH,
FIELD_MIN_VIDEO_HEIGHT,
FIELD_MIN_VIDEO_FRAMERATE,
FIELD_MIN_VIDEO_BITRATE,
FIELD_VIEWPORT_WIDTH,
FIELD_VIEWPORT_HEIGHT,
FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE,
FIELD_PREFERRED_VIDEO_MIMETYPES,
FIELD_MAX_AUDIO_CHANNEL_COUNT,
FIELD_MAX_AUDIO_BITRATE,
FIELD_PREFERRED_AUDIO_MIME_TYPES,
FIELD_FORCE_LOWEST_BITRATE,
FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE,
FIELD_SELECTION_OVERRIDE_KEYS,
FIELD_SELECTION_OVERRIDE_VALUES,
FIELD_DISABLED_TRACK_TYPE,
FIELD_PREFERRED_VIDEO_ROLE_FLAGS
})
private @interface FieldNumber {}
private static final int FIELD_PREFERRED_AUDIO_LANGUAGES = 1;
private static final int FIELD_PREFERRED_AUDIO_ROLE_FLAGS = 2;
private static final int FIELD_PREFERRED_TEXT_LANGUAGES = 3;
private static final int FIELD_PREFERRED_TEXT_ROLE_FLAGS = 4;
private static final int FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE = 5;
private static final int FIELD_MAX_VIDEO_WIDTH = 6;
private static final int FIELD_MAX_VIDEO_HEIGHT = 7;
private static final int FIELD_MAX_VIDEO_FRAMERATE = 8;
private static final int FIELD_MAX_VIDEO_BITRATE = 9;
private static final int FIELD_MIN_VIDEO_WIDTH = 10;
private static final int FIELD_MIN_VIDEO_HEIGHT = 11;
private static final int FIELD_MIN_VIDEO_FRAMERATE = 12;
private static final int FIELD_MIN_VIDEO_BITRATE = 13;
private static final int FIELD_VIEWPORT_WIDTH = 14;
private static final int FIELD_VIEWPORT_HEIGHT = 15;
private static final int FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE = 16;
private static final int FIELD_PREFERRED_VIDEO_MIMETYPES = 17;
private static final int FIELD_MAX_AUDIO_CHANNEL_COUNT = 18;
private static final int FIELD_MAX_AUDIO_BITRATE = 19;
private static final int FIELD_PREFERRED_AUDIO_MIME_TYPES = 20;
private static final int FIELD_FORCE_LOWEST_BITRATE = 21;
private static final int FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE = 22;
private static final int FIELD_SELECTION_OVERRIDE_KEYS = 23;
private static final int FIELD_SELECTION_OVERRIDE_VALUES = 24;
private static final int FIELD_DISABLED_TRACK_TYPE = 25;
private static final int FIELD_PREFERRED_VIDEO_ROLE_FLAGS = 26;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
// Video
bundle.putInt(keyForField(FIELD_MAX_VIDEO_WIDTH), maxVideoWidth);
bundle.putInt(keyForField(FIELD_MAX_VIDEO_HEIGHT), maxVideoHeight);
bundle.putInt(keyForField(FIELD_MAX_VIDEO_FRAMERATE), maxVideoFrameRate);
bundle.putInt(keyForField(FIELD_MAX_VIDEO_BITRATE), maxVideoBitrate);
bundle.putInt(keyForField(FIELD_MIN_VIDEO_WIDTH), minVideoWidth);
bundle.putInt(keyForField(FIELD_MIN_VIDEO_HEIGHT), minVideoHeight);
bundle.putInt(keyForField(FIELD_MIN_VIDEO_FRAMERATE), minVideoFrameRate);
bundle.putInt(keyForField(FIELD_MIN_VIDEO_BITRATE), minVideoBitrate);
bundle.putInt(keyForField(FIELD_VIEWPORT_WIDTH), viewportWidth);
bundle.putInt(keyForField(FIELD_VIEWPORT_HEIGHT), viewportHeight);
bundle.putBoolean(
keyForField(FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE), viewportOrientationMayChange);
bundle.putStringArray(
keyForField(FIELD_PREFERRED_VIDEO_MIMETYPES),
preferredVideoMimeTypes.toArray(new String[0]));
bundle.putInt(keyForField(FIELD_PREFERRED_VIDEO_ROLE_FLAGS), preferredVideoRoleFlags);
// Audio
bundle.putStringArray(
keyForField(FIELD_PREFERRED_AUDIO_LANGUAGES),
preferredAudioLanguages.toArray(new String[0]));
bundle.putInt(keyForField(FIELD_PREFERRED_AUDIO_ROLE_FLAGS), preferredAudioRoleFlags);
bundle.putInt(keyForField(FIELD_MAX_AUDIO_CHANNEL_COUNT), maxAudioChannelCount);
bundle.putInt(keyForField(FIELD_MAX_AUDIO_BITRATE), maxAudioBitrate);
bundle.putStringArray(
keyForField(FIELD_PREFERRED_AUDIO_MIME_TYPES),
preferredAudioMimeTypes.toArray(new String[0]));
// Text
bundle.putStringArray(
keyForField(FIELD_PREFERRED_TEXT_LANGUAGES), preferredTextLanguages.toArray(new String[0]));
bundle.putInt(keyForField(FIELD_PREFERRED_TEXT_ROLE_FLAGS), preferredTextRoleFlags);
bundle.putBoolean(
keyForField(FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE), selectUndeterminedTextLanguage);
// General
bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate);
bundle.putBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate);
bundle.putBundle(
keyForField(FIELD_SELECTION_OVERRIDE_KEYS), trackSelectionOverrides.toBundle());
bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes));
return bundle;
}
/** Object that can restore {@code TrackSelectionParameters} from a {@link Bundle}. */
public static final Creator<TrackSelectionParameters> CREATOR =
bundle -> new Builder(bundle).build();
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}