mirror of
https://github.com/samsonjs/media.git
synced 2026-04-14 12:45:47 +00:00
Move renderer flags, overrides and tunneling ID into Parameters
- This is needed to make DefaultTrackSelector properly thread safe, and enable atomic changes to the selector that, for example, disable a renderer and enable another one at the same time. - This change also saves/restores parameters and the start position in PlayerActivity, resolving the ref'd issue. Issue: #3915 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=193913350
This commit is contained in:
parent
5926e20105
commit
7d6b0e1fda
7 changed files with 552 additions and 246 deletions
|
|
@ -116,6 +116,12 @@ public class PlayerActivity extends Activity
|
|||
// For backwards compatibility only.
|
||||
private static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
|
||||
|
||||
// Saved instance state keys.
|
||||
private static final String KEY_TRACK_SELECTOR_PARAMETERS = "track_selector_parameters";
|
||||
private static final String KEY_WINDOW = "window";
|
||||
private static final String KEY_POSITION = "position";
|
||||
private static final String KEY_AUTO_PLAY = "auto_play";
|
||||
|
||||
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
|
||||
private static final CookieManager DEFAULT_COOKIE_MANAGER;
|
||||
static {
|
||||
|
|
@ -132,14 +138,15 @@ public class PlayerActivity extends Activity
|
|||
private SimpleExoPlayer player;
|
||||
private MediaSource mediaSource;
|
||||
private DefaultTrackSelector trackSelector;
|
||||
private DefaultTrackSelector.Parameters trackSelectorParameters;
|
||||
private TrackSelectionHelper trackSelectionHelper;
|
||||
private DebugTextViewHelper debugViewHelper;
|
||||
private boolean inErrorState;
|
||||
private TrackGroupArray lastSeenTrackGroupArray;
|
||||
|
||||
private boolean shouldAutoPlay;
|
||||
private int resumeWindow;
|
||||
private long resumePosition;
|
||||
private boolean startAutoPlay;
|
||||
private int startWindow;
|
||||
private long startPosition;
|
||||
|
||||
// Fields used only for ad playback. The ads loader is loaded via reflection.
|
||||
|
||||
|
|
@ -152,8 +159,6 @@ public class PlayerActivity extends Activity
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
shouldAutoPlay = true;
|
||||
clearResumePosition();
|
||||
mediaDataSourceFactory = buildDataSourceFactory(true);
|
||||
mainHandler = new Handler();
|
||||
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
|
||||
|
|
@ -169,13 +174,22 @@ public class PlayerActivity extends Activity
|
|||
playerView = findViewById(R.id.player_view);
|
||||
playerView.setControllerVisibilityListener(this);
|
||||
playerView.requestFocus();
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
trackSelectorParameters = savedInstanceState.getParcelable(KEY_TRACK_SELECTOR_PARAMETERS);
|
||||
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
|
||||
startWindow = savedInstanceState.getInt(KEY_WINDOW);
|
||||
startPosition = savedInstanceState.getLong(KEY_POSITION);
|
||||
} else {
|
||||
trackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
|
||||
clearStartPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
releasePlayer();
|
||||
shouldAutoPlay = true;
|
||||
clearResumePosition();
|
||||
clearStartPosition();
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +247,16 @@ public class PlayerActivity extends Activity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
updateTrackSelectorParameters();
|
||||
updateStartPosition();
|
||||
outState.putParcelable(KEY_TRACK_SELECTOR_PARAMETERS, trackSelectorParameters);
|
||||
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
|
||||
outState.putInt(KEY_WINDOW, startWindow);
|
||||
outState.putLong(KEY_POSITION, startPosition);
|
||||
}
|
||||
|
||||
// Activity input
|
||||
|
||||
@Override
|
||||
|
|
@ -365,6 +389,7 @@ public class PlayerActivity extends Activity
|
|||
new DefaultRenderersFactory(this, extensionRendererMode);
|
||||
|
||||
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
|
||||
trackSelector.setParameters(trackSelectorParameters);
|
||||
trackSelectionHelper = new TrackSelectionHelper(trackSelector);
|
||||
lastSeenTrackGroupArray = null;
|
||||
|
||||
|
|
@ -381,7 +406,7 @@ public class PlayerActivity extends Activity
|
|||
drmSessionManager.addListener(mainHandler, eventLogger);
|
||||
}
|
||||
|
||||
player.setPlayWhenReady(shouldAutoPlay);
|
||||
player.setPlayWhenReady(startAutoPlay);
|
||||
playerView.setPlayer(player);
|
||||
playerView.setPlaybackPreparer(this);
|
||||
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
||||
|
|
@ -421,11 +446,11 @@ public class PlayerActivity extends Activity
|
|||
}
|
||||
mediaSource.addEventListener(mainHandler, eventLogger);
|
||||
}
|
||||
boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
|
||||
if (haveResumePosition) {
|
||||
player.seekTo(resumeWindow, resumePosition);
|
||||
boolean haveStartPosition = startWindow != C.INDEX_UNSET;
|
||||
if (haveStartPosition) {
|
||||
player.seekTo(startWindow, startPosition);
|
||||
}
|
||||
player.prepare(mediaSource, !haveResumePosition, false);
|
||||
player.prepare(mediaSource, !haveStartPosition, false);
|
||||
inErrorState = false;
|
||||
updateButtonVisibilities();
|
||||
}
|
||||
|
|
@ -483,10 +508,10 @@ public class PlayerActivity extends Activity
|
|||
|
||||
private void releasePlayer() {
|
||||
if (player != null) {
|
||||
updateTrackSelectorParameters();
|
||||
updateStartPosition();
|
||||
debugViewHelper.stop();
|
||||
debugViewHelper = null;
|
||||
shouldAutoPlay = player.getPlayWhenReady();
|
||||
updateResumePosition();
|
||||
player.release();
|
||||
player = null;
|
||||
mediaSource = null;
|
||||
|
|
@ -495,14 +520,24 @@ public class PlayerActivity extends Activity
|
|||
}
|
||||
}
|
||||
|
||||
private void updateResumePosition() {
|
||||
resumeWindow = player.getCurrentWindowIndex();
|
||||
resumePosition = Math.max(0, player.getContentPosition());
|
||||
private void updateTrackSelectorParameters() {
|
||||
if (trackSelector != null) {
|
||||
trackSelectorParameters = trackSelector.getParameters();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearResumePosition() {
|
||||
resumeWindow = C.INDEX_UNSET;
|
||||
resumePosition = C.TIME_UNSET;
|
||||
private void updateStartPosition() {
|
||||
if (player != null) {
|
||||
startAutoPlay = player.getPlayWhenReady();
|
||||
startWindow = player.getCurrentWindowIndex();
|
||||
startPosition = Math.max(0, player.getContentPosition());
|
||||
}
|
||||
}
|
||||
|
||||
private void clearStartPosition() {
|
||||
startAutoPlay = true;
|
||||
startWindow = C.INDEX_UNSET;
|
||||
startPosition = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -661,7 +696,7 @@ public class PlayerActivity extends Activity
|
|||
// This will only occur if the user has performed a seek whilst in the error state. Update
|
||||
// the resume position so that if the user then retries, playback will resume from the
|
||||
// position to which they seeked.
|
||||
updateResumePosition();
|
||||
updateStartPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -695,10 +730,10 @@ public class PlayerActivity extends Activity
|
|||
}
|
||||
inErrorState = true;
|
||||
if (isBehindLiveWindow(e)) {
|
||||
clearResumePosition();
|
||||
clearStartPosition();
|
||||
initializePlayer();
|
||||
} else {
|
||||
updateResumePosition();
|
||||
updateStartPosition();
|
||||
updateButtonVisibilities();
|
||||
showControls();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import com.google.android.exoplayer2.RendererCapabilities;
|
|||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -79,8 +81,9 @@ import java.util.Arrays;
|
|||
!= RendererCapabilities.ADAPTIVE_NOT_SUPPORTED
|
||||
&& trackGroups.get(i).length > 1;
|
||||
}
|
||||
isDisabled = selector.getRendererDisabled(rendererIndex);
|
||||
override = selector.getSelectionOverride(rendererIndex, trackGroups);
|
||||
Parameters parameters = selector.getParameters();
|
||||
isDisabled = parameters.getRendererDisabled(rendererIndex);
|
||||
override = parameters.getSelectionOverride(rendererIndex, trackGroups);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(title)
|
||||
|
|
@ -170,12 +173,14 @@ import java.util.Arrays;
|
|||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
selector.setRendererDisabled(rendererIndex, isDisabled);
|
||||
ParametersBuilder parametersBuilder = selector.buildUponParameters();
|
||||
parametersBuilder.setRendererDisabled(rendererIndex, isDisabled);
|
||||
if (override != null) {
|
||||
selector.setSelectionOverride(rendererIndex, trackGroups, override);
|
||||
parametersBuilder.setSelectionOverride(rendererIndex, trackGroups, override);
|
||||
} else {
|
||||
selector.clearSelectionOverrides(rendererIndex);
|
||||
parametersBuilder.clearSelectionOverrides(rendererIndex);
|
||||
}
|
||||
selector.setParameters(parametersBuilder);
|
||||
}
|
||||
|
||||
// View.OnClickListener
|
||||
|
|
|
|||
|
|
@ -45,24 +45,91 @@ import java.util.Map;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* A default {@link TrackSelector} suitable for most use cases.
|
||||
* A default {@link TrackSelector} suitable for most use cases. Track selections are made according
|
||||
* to configurable {@link Parameters}, which can be set by calling {@link
|
||||
* #setParameters(Parameters)}.
|
||||
*
|
||||
* <h3>Modifying parameters</h3>
|
||||
*
|
||||
* To modify only some aspects of the parameters currently used by a selector, it's possible to
|
||||
* obtain a {@link ParametersBuilder} initialized with the current {@link Parameters}. The desired
|
||||
* modifications can be made on the builder, and the resulting {@link Parameters} can then be built
|
||||
* and set on the selector. For example the following code modifies the parameters to restrict video
|
||||
* track selections to SD, and to prefer German audio tracks:
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Build on the current parameters.
|
||||
* Parameters currentParameters = trackSelector.getParameters();
|
||||
* // Build the resulting parameters.
|
||||
* Parameters newParameters = currentParameters
|
||||
* .buildUpon()
|
||||
* .setMaxVideoSizeSd()
|
||||
* .setPreferredAudioLanguage("deu")
|
||||
* .build();
|
||||
* // Set the new parameters.
|
||||
* trackSelector.setParameters(newParameters);
|
||||
* }</pre>
|
||||
*
|
||||
* Convenience methods and chaining allow this to be written more concisely as:
|
||||
*
|
||||
* <pre>{@code
|
||||
* trackSelector.setParameters(
|
||||
* trackSelector
|
||||
* .buildUponParameters()
|
||||
* .setMaxVideoSizeSd()
|
||||
* .setPreferredAudioLanguage("deu"));
|
||||
* }</pre>
|
||||
*
|
||||
* Selection {@link Parameters} support many different options, some of which are described below.
|
||||
*
|
||||
* <h3>Track selection overrides</h3>
|
||||
*
|
||||
* Track selection overrides can be used to select specific tracks. To specify an override for a
|
||||
* renderer, it's first necessary to obtain the tracks that have been mapped to it:
|
||||
*
|
||||
* <pre>{@code
|
||||
* MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
||||
* TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
|
||||
* : mappedTrackInfo.getTrackGroups(rendererIndex);
|
||||
* }</pre>
|
||||
*
|
||||
* If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so
|
||||
* setting an override isn't possible. Note that a {@link Player.EventListener} registered on the
|
||||
* player can be used to determine when the current tracks (and therefore the mapping) changes. If
|
||||
* {@code rendererTrackGroups} is non-null then an override can be set. The next step is to query
|
||||
* the properties of the available tracks to determine the {@code groupIndex} and the {@code
|
||||
* trackIndices} within the group it that should be selected. The override can then be specified
|
||||
* using {@link ParametersBuilder#setSelectionOverride}:
|
||||
*
|
||||
* <pre>{@code
|
||||
* SelectionOverride selectionOverride = new SelectionOverride(groupIndex, trackIndices);
|
||||
* trackSelector.setParameters(
|
||||
* trackSelector
|
||||
* .buildUponParameters()
|
||||
* .setSelectionOverride(rendererIndex, rendererTrackGroups, selectionOverride));
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Disabling renderers</h3>
|
||||
*
|
||||
* Renderers can be disabled using {@link ParametersBuilder#setRendererDisabled}. Disabling a
|
||||
* renderer differs from setting a {@code null} override because the renderer is disabled
|
||||
* unconditionally, whereas a {@code null} override is applied only when the track groups available
|
||||
* to the renderer match the {@link TrackGroupArray} for which it was specified.
|
||||
*
|
||||
* <h3>Constraint based track selection</h3>
|
||||
*
|
||||
* Whilst this selector supports setting specific track overrides, the recommended way of changing
|
||||
* which tracks are selected is by setting {@link Parameters} that constrain the track selection
|
||||
* process. For example an instance can specify a preferred language for the audio track, and impose
|
||||
* constraints on the maximum video resolution that should be selected for adaptive playbacks.
|
||||
* Modifying the parameters is simple:
|
||||
* Whilst track selection overrides make it possible to select specific tracks, the recommended way
|
||||
* of controlling which tracks are selected is by specifying constraints. For example consider the
|
||||
* case of wanting to restrict video track selections to SD, and preferring German audio tracks.
|
||||
* Track selection overrides could be used to select specific tracks meeting these criteria, however
|
||||
* a simpler and more flexible approach is to specify these constraints directly:
|
||||
*
|
||||
* <pre>{@code
|
||||
* Parameters currentParameters = trackSelector.getParameters();
|
||||
* // Generate new parameters to prefer German audio and impose a maximum video size constraint.
|
||||
* Parameters newParameters = currentParameters
|
||||
* .withPreferredAudioLanguage("deu")
|
||||
* .withMaxVideoSize(1024, 768);
|
||||
* // Set the new parameters on the selector.
|
||||
* trackSelector.setParameters(newParameters);
|
||||
* trackSelector.setParameters(
|
||||
* trackSelector
|
||||
* .buildUponParameters()
|
||||
* .setMaxVideoSizeSd()
|
||||
* .setPreferredAudioLanguage("deu"));
|
||||
* }</pre>
|
||||
*
|
||||
* There are several benefits to using constraint based track selection instead of specific track
|
||||
|
|
@ -77,46 +144,11 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
* only applied to periods whose tracks match those for which the override was set.
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Track overrides</h3>
|
||||
*
|
||||
* This selector supports overriding of track selections for each renderer. To specify an override
|
||||
* for a renderer it's first necessary to obtain the tracks that have been mapped to it:
|
||||
*
|
||||
* <pre>{@code
|
||||
* MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
||||
* TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
|
||||
* : mappedTrackInfo.getTrackGroups(rendererIndex);
|
||||
* }</pre>
|
||||
*
|
||||
* If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so
|
||||
* setting an override isn't possible. Note that a {@link Player.EventListener} registered on the
|
||||
* player can be used to determine when the current tracks (and therefore the mapping) changes. If
|
||||
* {@code rendererTrackGroups} is non-null then an override can be set. The next step is to query
|
||||
* the properties of the available tracks to determine the {@code groupIndex} of the track group you
|
||||
* want to select and the {@code trackIndices} within it. You can then create and set the override:
|
||||
*
|
||||
* <pre>{@code
|
||||
* trackSelector.setSelectionOverride(rendererIndex, rendererTrackGroups,
|
||||
* new SelectionOverride(groupIndex, trackIndices));
|
||||
* }</pre>
|
||||
*
|
||||
* If the override is {@code null} then no tracks will be selected.
|
||||
*
|
||||
* <p>Note that an override applies only when the track groups available to the renderer match the
|
||||
* {@link TrackGroupArray} for which the override was specified. Overrides can be cleared using the
|
||||
* {@code clearSelectionOverride} methods.
|
||||
*
|
||||
* <h3>Disabling renderers</h3>
|
||||
*
|
||||
* Renderers can be disabled using {@link #setRendererDisabled(int, boolean)}. Disabling a renderer
|
||||
* differs from setting a {@code null} override because the renderer is disabled unconditionally,
|
||||
* whereas a {@code null} override is applied only when the track groups available to the renderer
|
||||
* match the {@link TrackGroupArray} for which it was specified.
|
||||
*
|
||||
* <h3>Tunneling</h3>
|
||||
*
|
||||
* Tunneled playback can be enabled in cases where the combination of renderers and selected tracks
|
||||
* support it. See {@link #setTunnelingAudioSessionId(int)} for more details.
|
||||
* support it. Tunneled playback is enabled by passing an audio session ID to {@link
|
||||
* ParametersBuilder#setTunnelingAudioSessionId(int)}.
|
||||
*/
|
||||
public class DefaultTrackSelector extends MappingTrackSelector {
|
||||
|
||||
|
|
@ -125,6 +157,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public static final class ParametersBuilder {
|
||||
|
||||
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
|
||||
private final SparseBooleanArray rendererDisabledFlags;
|
||||
|
||||
private String preferredAudioLanguage;
|
||||
private String preferredTextLanguage;
|
||||
private boolean selectUndeterminedTextLanguage;
|
||||
|
|
@ -140,6 +175,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
private int viewportWidth;
|
||||
private int viewportHeight;
|
||||
private boolean viewportOrientationMayChange;
|
||||
private int tunnelingAudioSessionId;
|
||||
|
||||
/**
|
||||
* Creates a builder obtaining the initial values from {@link Parameters#DEFAULT}.
|
||||
|
|
@ -153,6 +189,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
* obtained.
|
||||
*/
|
||||
private ParametersBuilder(Parameters initialValues) {
|
||||
selectionOverrides = initialValues.selectionOverrides.clone();
|
||||
rendererDisabledFlags = initialValues.rendererDisabledFlags.clone();
|
||||
preferredAudioLanguage = initialValues.preferredAudioLanguage;
|
||||
preferredTextLanguage = initialValues.preferredTextLanguage;
|
||||
selectUndeterminedTextLanguage = initialValues.selectUndeterminedTextLanguage;
|
||||
|
|
@ -168,6 +206,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
viewportWidth = initialValues.viewportWidth;
|
||||
viewportHeight = initialValues.viewportHeight;
|
||||
viewportOrientationMayChange = initialValues.viewportOrientationMayChange;
|
||||
tunnelingAudioSessionId = initialValues.tunnelingAudioSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -342,11 +381,134 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents
|
||||
* the selector from selecting any tracks for it.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param disabled Whether the renderer is disabled.
|
||||
*/
|
||||
public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) {
|
||||
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
||||
// The disabled flag is unchanged.
|
||||
return this;
|
||||
}
|
||||
// Only true values are placed in the array to make it easier to check for equality.
|
||||
if (disabled) {
|
||||
rendererDisabledFlags.put(rendererIndex, true);
|
||||
} else {
|
||||
rendererDisabledFlags.delete(rendererIndex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the track selection for the renderer at the specified index.
|
||||
*
|
||||
* <p>When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the
|
||||
* override is applied. When the {@link TrackGroupArray} does not match, the override has no
|
||||
* effect. The override replaces any previous override for the specified {@link TrackGroupArray}
|
||||
* for the specified {@link Renderer}.
|
||||
*
|
||||
* <p>Passing a {@code null} override will cause the renderer to be disabled when the {@link
|
||||
* TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray} does
|
||||
* not match a {@code null} override has no effect. Hence a {@code null} override differs from
|
||||
* disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the renderer
|
||||
* is disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as {@link
|
||||
* #setRendererDisabled(int, boolean)} disables the renderer unconditionally.
|
||||
*
|
||||
* <p>To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)}, {@link
|
||||
* #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
||||
* @param override The override.
|
||||
*/
|
||||
public final ParametersBuilder setSelectionOverride(
|
||||
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
if (overrides == null) {
|
||||
overrides = new HashMap<>();
|
||||
selectionOverrides.put(rendererIndex, overrides);
|
||||
}
|
||||
if (overrides.containsKey(groups) && Util.areEqual(overrides.get(groups), override)) {
|
||||
// The override is unchanged.
|
||||
return this;
|
||||
}
|
||||
overrides.put(groups, override);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a track selection override for the specified renderer and {@link TrackGroupArray}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
||||
*/
|
||||
public final ParametersBuilder clearSelectionOverride(
|
||||
int rendererIndex, TrackGroupArray groups) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
if (overrides == null || !overrides.containsKey(groups)) {
|
||||
// Nothing to clear.
|
||||
return this;
|
||||
}
|
||||
overrides.remove(groups);
|
||||
if (overrides.isEmpty()) {
|
||||
selectionOverrides.remove(rendererIndex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all track selection overrides for the specified renderer.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
*/
|
||||
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
if (overrides == null || overrides.isEmpty()) {
|
||||
// Nothing to clear.
|
||||
return this;
|
||||
}
|
||||
selectionOverrides.remove(rendererIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Clears all track selection overrides for all renderers. */
|
||||
public final ParametersBuilder clearSelectionOverrides() {
|
||||
if (selectionOverrides.size() == 0) {
|
||||
// Nothing to clear.
|
||||
return this;
|
||||
}
|
||||
selectionOverrides.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in
|
||||
* tunneling mode. Session ids can be generated using {@link
|
||||
* C#generateAudioSessionIdV21(Context)}. To disable tunneling pass {@link
|
||||
* C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and
|
||||
* supported by the audio and video renderers for the selected tracks.
|
||||
*
|
||||
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
||||
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
||||
*/
|
||||
public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
||||
if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
|
||||
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link Parameters} instance with the selected values.
|
||||
*/
|
||||
public Parameters build() {
|
||||
return new Parameters(
|
||||
selectionOverrides,
|
||||
rendererDisabledFlags,
|
||||
preferredAudioLanguage,
|
||||
preferredTextLanguage,
|
||||
selectUndeterminedTextLanguage,
|
||||
|
|
@ -361,7 +523,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
exceedRendererCapabilitiesIfNecessary,
|
||||
viewportWidth,
|
||||
viewportHeight,
|
||||
viewportOrientationMayChange);
|
||||
viewportOrientationMayChange,
|
||||
tunnelingAudioSessionId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -390,6 +553,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public static final Parameters DEFAULT = new Parameters();
|
||||
|
||||
// Per renderer overrides.
|
||||
|
||||
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
|
||||
private final SparseBooleanArray rendererDisabledFlags;
|
||||
|
||||
// Audio
|
||||
/**
|
||||
* The preferred language for audio, as well as for forced text tracks, as an ISO 639-2/T tag.
|
||||
|
|
@ -465,9 +633,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
* Whether to exceed renderer capabilities when no selection can be made otherwise.
|
||||
*/
|
||||
public final boolean exceedRendererCapabilitiesIfNecessary;
|
||||
/**
|
||||
* The audio session id to use when tunneling, or {@link C#AUDIO_SESSION_ID_UNSET} if tunneling
|
||||
* is not to be enabled.
|
||||
*/
|
||||
public final int tunnelingAudioSessionId;
|
||||
|
||||
private Parameters() {
|
||||
this(
|
||||
new SparseArray<Map<TrackGroupArray, SelectionOverride>>(),
|
||||
new SparseBooleanArray(),
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
|
|
@ -482,10 +657,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
true,
|
||||
Integer.MAX_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
true);
|
||||
true,
|
||||
C.AUDIO_SESSION_ID_UNSET);
|
||||
}
|
||||
|
||||
/* package */ Parameters(
|
||||
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides,
|
||||
SparseBooleanArray rendererDisabledFlags,
|
||||
String preferredAudioLanguage,
|
||||
String preferredTextLanguage,
|
||||
boolean selectUndeterminedTextLanguage,
|
||||
|
|
@ -500,7 +678,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
boolean exceedRendererCapabilitiesIfNecessary,
|
||||
int viewportWidth,
|
||||
int viewportHeight,
|
||||
boolean viewportOrientationMayChange) {
|
||||
boolean viewportOrientationMayChange,
|
||||
int tunnelingAudioSessionId) {
|
||||
this.selectionOverrides = selectionOverrides;
|
||||
this.rendererDisabledFlags = rendererDisabledFlags;
|
||||
this.preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage);
|
||||
this.preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage);
|
||||
this.selectUndeterminedTextLanguage = selectUndeterminedTextLanguage;
|
||||
|
|
@ -516,9 +697,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
this.viewportOrientationMayChange = viewportOrientationMayChange;
|
||||
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
||||
}
|
||||
|
||||
/* package */ Parameters(Parcel in) {
|
||||
this.selectionOverrides = readSelectionOverrides(in);
|
||||
this.rendererDisabledFlags = in.readSparseBooleanArray();
|
||||
this.preferredAudioLanguage = in.readString();
|
||||
this.preferredTextLanguage = in.readString();
|
||||
this.selectUndeterminedTextLanguage = Util.readBoolean(in);
|
||||
|
|
@ -534,6 +718,41 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
this.viewportWidth = in.readInt();
|
||||
this.viewportHeight = in.readInt();
|
||||
this.viewportOrientationMayChange = Util.readBoolean(in);
|
||||
this.tunnelingAudioSessionId = in.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the renderer is disabled.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @return Whether the renderer is disabled.
|
||||
*/
|
||||
public final boolean getRendererDisabled(int rendererIndex) {
|
||||
return rendererDisabledFlags.get(rendererIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there is an override for the specified renderer and {@link TrackGroupArray}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray}.
|
||||
* @return Whether there is an override.
|
||||
*/
|
||||
public final boolean hasSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
return overrides != null && overrides.containsKey(groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the override for the specified renderer and {@link TrackGroupArray}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray}.
|
||||
* @return The override, or null if no override exists.
|
||||
*/
|
||||
public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
return overrides != null ? overrides.get(groups) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -565,8 +784,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
&& viewportWidth == other.viewportWidth
|
||||
&& viewportHeight == other.viewportHeight
|
||||
&& maxVideoBitrate == other.maxVideoBitrate
|
||||
&& tunnelingAudioSessionId == other.tunnelingAudioSessionId
|
||||
&& TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage)
|
||||
&& TextUtils.equals(preferredTextLanguage, other.preferredTextLanguage);
|
||||
&& TextUtils.equals(preferredTextLanguage, other.preferredTextLanguage)
|
||||
&& areRendererDisabledFlagsEqual(rendererDisabledFlags, other.rendererDisabledFlags)
|
||||
&& areSelectionOverridesEqual(selectionOverrides, other.selectionOverrides);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -584,6 +806,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
result = 31 * result + viewportWidth;
|
||||
result = 31 * result + viewportHeight;
|
||||
result = 31 * result + maxVideoBitrate;
|
||||
result = 31 * result + tunnelingAudioSessionId;
|
||||
result = 31 * result + preferredAudioLanguage.hashCode();
|
||||
result = 31 * result + preferredTextLanguage.hashCode();
|
||||
return result;
|
||||
|
|
@ -598,6 +821,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
writeSelectionOverridesToParcel(dest, selectionOverrides);
|
||||
dest.writeSparseBooleanArray(rendererDisabledFlags);
|
||||
dest.writeString(preferredAudioLanguage);
|
||||
dest.writeString(preferredTextLanguage);
|
||||
Util.writeBoolean(dest, selectUndeterminedTextLanguage);
|
||||
|
|
@ -613,6 +838,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
dest.writeInt(viewportWidth);
|
||||
dest.writeInt(viewportHeight);
|
||||
Util.writeBoolean(dest, viewportOrientationMayChange);
|
||||
dest.writeInt(tunnelingAudioSessionId);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Parameters> CREATOR =
|
||||
|
|
@ -628,6 +854,93 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
return new Parameters[size];
|
||||
}
|
||||
};
|
||||
|
||||
// Static utility methods.
|
||||
|
||||
private static SparseArray<Map<TrackGroupArray, SelectionOverride>> readSelectionOverrides(
|
||||
Parcel in) {
|
||||
int renderersWithOverridesCount = in.readInt();
|
||||
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides =
|
||||
new SparseArray<>(renderersWithOverridesCount);
|
||||
for (int i = 0; i < renderersWithOverridesCount; i++) {
|
||||
int rendererIndex = in.readInt();
|
||||
int overrideCount = in.readInt();
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = new HashMap<>(overrideCount);
|
||||
for (int j = 0; j < overrideCount; j++) {
|
||||
TrackGroupArray trackGroups = in.readParcelable(TrackGroupArray.class.getClassLoader());
|
||||
SelectionOverride override = in.readParcelable(SelectionOverride.class.getClassLoader());
|
||||
overrides.put(trackGroups, override);
|
||||
}
|
||||
selectionOverrides.put(rendererIndex, overrides);
|
||||
}
|
||||
return selectionOverrides;
|
||||
}
|
||||
|
||||
private static void writeSelectionOverridesToParcel(
|
||||
Parcel dest, SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides) {
|
||||
int renderersWithOverridesCount = selectionOverrides.size();
|
||||
dest.writeInt(renderersWithOverridesCount);
|
||||
for (int i = 0; i < renderersWithOverridesCount; i++) {
|
||||
int rendererIndex = selectionOverrides.keyAt(i);
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.valueAt(i);
|
||||
int overrideCount = overrides.size();
|
||||
dest.writeInt(rendererIndex);
|
||||
dest.writeInt(overrideCount);
|
||||
for (Map.Entry<TrackGroupArray, SelectionOverride> override : overrides.entrySet()) {
|
||||
dest.writeParcelable(override.getKey(), /* parcelableFlags= */ 0);
|
||||
dest.writeParcelable(override.getValue(), /* parcelableFlags= */ 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areRendererDisabledFlagsEqual(
|
||||
SparseBooleanArray first, SparseBooleanArray second) {
|
||||
int firstSize = first.size();
|
||||
if (second.size() != firstSize) {
|
||||
return false;
|
||||
}
|
||||
// Only true values are put into rendererDisabledFlags, so we don't need to compare values.
|
||||
for (int indexInFirst = 0; indexInFirst < firstSize; indexInFirst++) {
|
||||
if (second.indexOfKey(first.keyAt(indexInFirst)) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean areSelectionOverridesEqual(
|
||||
SparseArray<Map<TrackGroupArray, SelectionOverride>> first,
|
||||
SparseArray<Map<TrackGroupArray, SelectionOverride>> second) {
|
||||
int firstSize = first.size();
|
||||
if (second.size() != firstSize) {
|
||||
return false;
|
||||
}
|
||||
for (int indexInFirst = 0; indexInFirst < firstSize; indexInFirst++) {
|
||||
int indexInSecond = second.indexOfKey(first.keyAt(indexInFirst));
|
||||
if (indexInSecond < 0
|
||||
|| !areSelectionOverridesEqual(
|
||||
first.valueAt(indexInFirst), second.valueAt(indexInSecond))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean areSelectionOverridesEqual(
|
||||
Map<TrackGroupArray, SelectionOverride> first,
|
||||
Map<TrackGroupArray, SelectionOverride> second) {
|
||||
int firstSize = first.size();
|
||||
if (second.size() != firstSize) {
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<TrackGroupArray, SelectionOverride> firstEntry : first.entrySet()) {
|
||||
TrackGroupArray key = firstEntry.getKey();
|
||||
if (!second.containsKey(key) || !Util.areEqual(firstEntry.getValue(), second.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** A track selection override. */
|
||||
|
|
@ -720,11 +1033,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
|
||||
|
||||
private final TrackSelection.Factory adaptiveTrackSelectionFactory;
|
||||
private final AtomicReference<Parameters> paramsReference;
|
||||
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
|
||||
private final SparseBooleanArray rendererDisabledFlags;
|
||||
|
||||
private int tunnelingAudioSessionId;
|
||||
private final AtomicReference<Parameters> parametersReference;
|
||||
|
||||
/**
|
||||
* Constructs an instance that does not support adaptive track selection.
|
||||
|
|
@ -752,179 +1061,100 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
public DefaultTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
|
||||
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
|
||||
paramsReference = new AtomicReference<>(Parameters.DEFAULT);
|
||||
selectionOverrides = new SparseArray<>();
|
||||
rendererDisabledFlags = new SparseBooleanArray();
|
||||
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
|
||||
parametersReference = new AtomicReference<>(Parameters.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically sets the provided parameters for track selection.
|
||||
*
|
||||
* @param params The parameters for track selection.
|
||||
* @param parameters The parameters for track selection.
|
||||
*/
|
||||
public void setParameters(Parameters params) {
|
||||
Assertions.checkNotNull(params);
|
||||
if (!paramsReference.getAndSet(params).equals(params)) {
|
||||
public void setParameters(Parameters parameters) {
|
||||
Assertions.checkNotNull(parameters);
|
||||
if (!parametersReference.getAndSet(parameters).equals(parameters)) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically sets the provided parameters for track selection.
|
||||
*
|
||||
* @param parametersBuilder A builder from which to obtain the parameters for track selection.
|
||||
*/
|
||||
public void setParameters(ParametersBuilder parametersBuilder) {
|
||||
setParameters(parametersBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current selection parameters.
|
||||
*
|
||||
* @return The current selection parameters.
|
||||
*/
|
||||
public Parameters getParameters() {
|
||||
return paramsReference.get();
|
||||
return parametersReference.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents the
|
||||
* selector from selecting any tracks for it.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param disabled Whether the renderer is disabled.
|
||||
*/
|
||||
/** Returns a new {@link ParametersBuilder} initialized with the current selection parameters. */
|
||||
public ParametersBuilder buildUponParameters() {
|
||||
return getParameters().buildUpon();
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link ParametersBuilder#setRendererDisabled(int, boolean)}. */
|
||||
@Deprecated
|
||||
public final void setRendererDisabled(int rendererIndex, boolean disabled) {
|
||||
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
||||
// The disabled flag is unchanged.
|
||||
return;
|
||||
}
|
||||
rendererDisabledFlags.put(rendererIndex, disabled);
|
||||
invalidate();
|
||||
setParameters(buildUponParameters().setRendererDisabled(rendererIndex, disabled));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the renderer is disabled.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @return Whether the renderer is disabled.
|
||||
*/
|
||||
/** @deprecated Use {@link Parameters#getRendererDisabled(int)}. * */
|
||||
@Deprecated
|
||||
public final boolean getRendererDisabled(int rendererIndex) {
|
||||
return rendererDisabledFlags.get(rendererIndex);
|
||||
return getParameters().getRendererDisabled(rendererIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the track selection for the renderer at the specified index.
|
||||
*
|
||||
* <p>When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the
|
||||
* override is applied. When the {@link TrackGroupArray} does not match, the override has no
|
||||
* effect. The override replaces any previous override for the specified {@link TrackGroupArray}
|
||||
* for the specified {@link Renderer}.
|
||||
*
|
||||
* <p>Passing a {@code null} override will cause the renderer to be disabled when the {@link
|
||||
* TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray} does
|
||||
* not match a {@code null} override has no effect. Hence a {@code null} override differs from
|
||||
* disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the renderer is
|
||||
* disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as {@link
|
||||
* #setRendererDisabled(int, boolean)} disables the renderer unconditionally.
|
||||
*
|
||||
* <p>To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)}, {@link
|
||||
* #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
||||
* @param override The override.
|
||||
* @deprecated Use {@link ParametersBuilder#setSelectionOverride(int, TrackGroupArray,
|
||||
* SelectionOverride)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setSelectionOverride(
|
||||
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
if (overrides == null) {
|
||||
overrides = new HashMap<>();
|
||||
selectionOverrides.put(rendererIndex, overrides);
|
||||
}
|
||||
if (overrides.containsKey(groups) && Util.areEqual(overrides.get(groups), override)) {
|
||||
// The override is unchanged.
|
||||
return;
|
||||
}
|
||||
overrides.put(groups, override);
|
||||
invalidate();
|
||||
setParameters(buildUponParameters().setSelectionOverride(rendererIndex, groups, override));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there is an override for the specified renderer and {@link TrackGroupArray}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray}.
|
||||
* @return Whether there is an override.
|
||||
*/
|
||||
/** @deprecated Use {@link Parameters#hasSelectionOverride(int, TrackGroupArray)}. * */
|
||||
@Deprecated
|
||||
public final boolean hasSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
return overrides != null && overrides.containsKey(groups);
|
||||
return getParameters().hasSelectionOverride(rendererIndex, groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the override for the specified renderer and {@link TrackGroupArray}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray}.
|
||||
* @return The override, or null if no override exists.
|
||||
*/
|
||||
/** @deprecated Use {@link Parameters#getSelectionOverride(int, TrackGroupArray)}. */
|
||||
@Deprecated
|
||||
public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
return overrides != null ? overrides.get(groups) : null;
|
||||
return getParameters().getSelectionOverride(rendererIndex, groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a track selection override for the specified renderer and {@link TrackGroupArray}.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
||||
*/
|
||||
/** @deprecated Use {@link ParametersBuilder#clearSelectionOverride(int, TrackGroupArray)}. */
|
||||
@Deprecated
|
||||
public final void clearSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
if (overrides == null || !overrides.containsKey(groups)) {
|
||||
// Nothing to clear.
|
||||
return;
|
||||
}
|
||||
overrides.remove(groups);
|
||||
if (overrides.isEmpty()) {
|
||||
selectionOverrides.remove(rendererIndex);
|
||||
}
|
||||
invalidate();
|
||||
setParameters(buildUponParameters().clearSelectionOverride(rendererIndex, groups));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all track selection overrides for the specified renderer.
|
||||
*
|
||||
* @param rendererIndex The renderer index.
|
||||
*/
|
||||
/** @deprecated Use {@link ParametersBuilder#clearSelectionOverrides(int)}. */
|
||||
@Deprecated
|
||||
public final void clearSelectionOverrides(int rendererIndex) {
|
||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||
if (overrides == null || overrides.isEmpty()) {
|
||||
// Nothing to clear.
|
||||
return;
|
||||
}
|
||||
selectionOverrides.remove(rendererIndex);
|
||||
invalidate();
|
||||
setParameters(buildUponParameters().clearSelectionOverrides(rendererIndex));
|
||||
}
|
||||
|
||||
/** Clears all track selection overrides for all renderers. */
|
||||
/** @deprecated Use {@link ParametersBuilder#clearSelectionOverrides()}. */
|
||||
@Deprecated
|
||||
public final void clearSelectionOverrides() {
|
||||
if (selectionOverrides.size() == 0) {
|
||||
// Nothing to clear.
|
||||
return;
|
||||
}
|
||||
selectionOverrides.clear();
|
||||
invalidate();
|
||||
setParameters(buildUponParameters().clearSelectionOverrides());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in
|
||||
* tunneling mode. Session ids can be generated using {@link
|
||||
* C#generateAudioSessionIdV21(Context)}. To disable tunneling pass {@link
|
||||
* C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and supported
|
||||
* by the audio and video renderers for the selected tracks.
|
||||
*
|
||||
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
||||
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
||||
*/
|
||||
/** @deprecated Use {@link ParametersBuilder#setTunnelingAudioSessionId(int)}. */
|
||||
@Deprecated
|
||||
public void setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
||||
if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
|
||||
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
||||
invalidate();
|
||||
}
|
||||
setParameters(buildUponParameters().setTunnelingAudioSessionId(tunnelingAudioSessionId));
|
||||
}
|
||||
|
||||
// MappingTrackSelector implementation.
|
||||
|
|
@ -935,29 +1165,33 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
int[][][] rendererFormatSupports,
|
||||
int[] rendererMixedMimeTypeAdaptationSupports)
|
||||
throws ExoPlaybackException {
|
||||
Parameters params = parametersReference.get();
|
||||
int rendererCount = mappedTrackInfo.getRendererCount();
|
||||
TrackSelection[] rendererTrackSelections =
|
||||
selectAllTracks(
|
||||
mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports);
|
||||
mappedTrackInfo,
|
||||
rendererFormatSupports,
|
||||
rendererMixedMimeTypeAdaptationSupports,
|
||||
params);
|
||||
|
||||
// Apply track disabling and overriding.
|
||||
for (int i = 0; i < rendererCount; i++) {
|
||||
if (rendererDisabledFlags.get(i)) {
|
||||
if (params.getRendererDisabled(i)) {
|
||||
rendererTrackSelections[i] = null;
|
||||
} else {
|
||||
TrackGroupArray rendererTrackGroup = mappedTrackInfo.getTrackGroups(i);
|
||||
if (hasSelectionOverride(i, rendererTrackGroup)) {
|
||||
SelectionOverride override = selectionOverrides.get(i).get(rendererTrackGroup);
|
||||
TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(i);
|
||||
if (params.hasSelectionOverride(i, rendererTrackGroups)) {
|
||||
SelectionOverride override = params.getSelectionOverride(i, rendererTrackGroups);
|
||||
if (override == null) {
|
||||
rendererTrackSelections[i] = null;
|
||||
} else if (override.length == 1) {
|
||||
rendererTrackSelections[i] =
|
||||
new FixedTrackSelection(
|
||||
rendererTrackGroup.get(override.groupIndex), override.tracks[0]);
|
||||
rendererTrackGroups.get(override.groupIndex), override.tracks[0]);
|
||||
} else {
|
||||
rendererTrackSelections[i] =
|
||||
adaptiveTrackSelectionFactory.createTrackSelection(
|
||||
rendererTrackGroup.get(override.groupIndex), override.tracks);
|
||||
rendererTrackGroups.get(override.groupIndex), override.tracks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -967,7 +1201,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// selections, and null otherwise.
|
||||
RendererConfiguration[] rendererConfigurations = new RendererConfiguration[rendererCount];
|
||||
for (int i = 0; i < rendererCount; i++) {
|
||||
boolean forceRendererDisabled = rendererDisabledFlags.get(i);
|
||||
boolean forceRendererDisabled = params.getRendererDisabled(i);
|
||||
boolean rendererEnabled =
|
||||
!forceRendererDisabled
|
||||
&& (mappedTrackInfo.getRendererType(i) == C.TRACK_TYPE_NONE
|
||||
|
|
@ -981,7 +1215,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
rendererFormatSupports,
|
||||
rendererConfigurations,
|
||||
rendererTrackSelections,
|
||||
tunnelingAudioSessionId);
|
||||
params.tunnelingAudioSessionId);
|
||||
|
||||
return Pair.create(rendererConfigurations, rendererTrackSelections);
|
||||
}
|
||||
|
|
@ -1007,11 +1241,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
protected TrackSelection[] selectAllTracks(
|
||||
MappedTrackInfo mappedTrackInfo,
|
||||
int[][][] rendererFormatSupports,
|
||||
int[] rendererMixedMimeTypeAdaptationSupports)
|
||||
int[] rendererMixedMimeTypeAdaptationSupports,
|
||||
Parameters params)
|
||||
throws ExoPlaybackException {
|
||||
int rendererCount = mappedTrackInfo.getRendererCount();
|
||||
TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount];
|
||||
Parameters params = paramsReference.get();
|
||||
|
||||
boolean seenVideoRendererWithMappedTracks = false;
|
||||
boolean selectedVideoTracks = false;
|
||||
|
|
@ -1073,8 +1307,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// Video track selection implementation.
|
||||
|
||||
/**
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
|
||||
* TrackSelection} for a video renderer.
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
|
||||
* {@link TrackSelection} for a video renderer.
|
||||
*
|
||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||
* @param formatSupports The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
||||
|
|
@ -1279,8 +1513,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// Audio track selection implementation.
|
||||
|
||||
/**
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
|
||||
* TrackSelection} for an audio renderer.
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
|
||||
* {@link TrackSelection} for an audio renderer.
|
||||
*
|
||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||
* @param formatSupports The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
||||
|
|
@ -1394,8 +1628,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// Text track selection implementation.
|
||||
|
||||
/**
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
|
||||
* TrackSelection} for a text renderer.
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
|
||||
* {@link TrackSelection} for a text renderer.
|
||||
*
|
||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
||||
|
|
@ -1466,8 +1700,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// General track selection methods.
|
||||
|
||||
/**
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
|
||||
* TrackSelection} for a renderer whose type is neither video, audio or text.
|
||||
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
|
||||
* {@link TrackSelection} for a renderer whose type is neither video, audio or text.
|
||||
*
|
||||
* @param trackType The type of the renderer.
|
||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import static org.mockito.Mockito.verify;
|
|||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
|
|
@ -120,8 +122,18 @@ public final class DefaultTrackSelectorTest {
|
|||
/** Tests {@link Parameters} {@link android.os.Parcelable} implementation. */
|
||||
@Test
|
||||
public void testParametersParcelable() {
|
||||
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides = new SparseArray<>();
|
||||
Map<TrackGroupArray, SelectionOverride> videoOverrides = new HashMap<>();
|
||||
videoOverrides.put(new TrackGroupArray(VIDEO_TRACK_GROUP), new SelectionOverride(0, 1));
|
||||
selectionOverrides.put(2, videoOverrides);
|
||||
|
||||
SparseBooleanArray rendererDisabledFlags = new SparseBooleanArray();
|
||||
rendererDisabledFlags.put(3, true);
|
||||
|
||||
Parameters parametersToParcel =
|
||||
new Parameters(
|
||||
selectionOverrides,
|
||||
rendererDisabledFlags,
|
||||
/* preferredAudioLanguage= */ "en",
|
||||
/* preferredTextLanguage= */ "de",
|
||||
/* selectUndeterminedTextLanguage= */ false,
|
||||
|
|
@ -136,7 +148,8 @@ public final class DefaultTrackSelectorTest {
|
|||
/* exceedRendererCapabilitiesIfNecessary= */ true,
|
||||
/* viewportWidth= */ 4,
|
||||
/* viewportHeight= */ 5,
|
||||
/* viewportOrientationMayChange= */ false);
|
||||
/* viewportOrientationMayChange= */ false,
|
||||
/* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
parametersToParcel.writeToParcel(parcel, 0);
|
||||
|
|
@ -170,7 +183,10 @@ public final class DefaultTrackSelectorTest {
|
|||
@Test
|
||||
public void testSelectTracksWithNullOverride() throws ExoPlaybackException {
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||
trackSelector.setParameters(
|
||||
trackSelector
|
||||
.buildUponParameters()
|
||||
.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null));
|
||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||
assertTrackSelections(result, new TrackSelection[] {null, TRACK_SELECTIONS[1]});
|
||||
assertThat(result.rendererConfigurations)
|
||||
|
|
@ -181,8 +197,11 @@ public final class DefaultTrackSelectorTest {
|
|||
@Test
|
||||
public void testSelectTracksWithClearedNullOverride() throws ExoPlaybackException {
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||
trackSelector.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP));
|
||||
trackSelector.setParameters(
|
||||
trackSelector
|
||||
.buildUponParameters()
|
||||
.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null)
|
||||
.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP)));
|
||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||
assertTrackSelections(result, TRACK_SELECTIONS);
|
||||
assertThat(result.rendererConfigurations)
|
||||
|
|
@ -193,7 +212,10 @@ public final class DefaultTrackSelectorTest {
|
|||
@Test
|
||||
public void testSelectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException {
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||
trackSelector.setParameters(
|
||||
trackSelector
|
||||
.buildUponParameters()
|
||||
.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null));
|
||||
TrackSelectorResult result =
|
||||
trackSelector.selectTracks(
|
||||
RENDERER_CAPABILITIES,
|
||||
|
|
@ -207,7 +229,7 @@ public final class DefaultTrackSelectorTest {
|
|||
@Test
|
||||
public void testSelectTracksWithDisabledRenderer() throws ExoPlaybackException {
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||
trackSelector.setRendererDisabled(1, true);
|
||||
trackSelector.setParameters(trackSelector.buildUponParameters().setRendererDisabled(1, true));
|
||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||
assertTrackSelections(result, new TrackSelection[] {TRACK_SELECTIONS[0], null});
|
||||
assertThat(new RendererConfiguration[] {DEFAULT, null})
|
||||
|
|
@ -218,8 +240,11 @@ public final class DefaultTrackSelectorTest {
|
|||
@Test
|
||||
public void testSelectTracksWithClearedDisabledRenderer() throws ExoPlaybackException {
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||
trackSelector.setRendererDisabled(1, true);
|
||||
trackSelector.setRendererDisabled(1, false);
|
||||
trackSelector.setParameters(
|
||||
trackSelector
|
||||
.buildUponParameters()
|
||||
.setRendererDisabled(1, true)
|
||||
.setRendererDisabled(1, false));
|
||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||
assertTrackSelections(result, TRACK_SELECTIONS);
|
||||
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT})
|
||||
|
|
@ -241,7 +266,7 @@ public final class DefaultTrackSelectorTest {
|
|||
@Test
|
||||
public void testSelectTracksWithDisabledNoSampleRenderer() throws ExoPlaybackException {
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||
trackSelector.setRendererDisabled(1, true);
|
||||
trackSelector.setParameters(trackSelector.buildUponParameters().setRendererDisabled(1, true));
|
||||
TrackSelectorResult result =
|
||||
trackSelector.selectTracks(RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
|
||||
assertTrackSelections(result, TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER);
|
||||
|
|
|
|||
|
|
@ -397,7 +397,8 @@ public final class DashTestRunner {
|
|||
protected TrackSelection[] selectAllTracks(
|
||||
MappedTrackInfo mappedTrackInfo,
|
||||
int[][][] rendererFormatSupports,
|
||||
int[] rendererMixedMimeTypeAdaptationSupports)
|
||||
int[] rendererMixedMimeTypeAdaptationSupports,
|
||||
Parameters parameters)
|
||||
throws ExoPlaybackException {
|
||||
Assertions.checkState(
|
||||
mappedTrackInfo.getRendererType(VIDEO_RENDERER_INDEX) == C.TRACK_TYPE_VIDEO);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import com.google.android.exoplayer2.testutil.ActionSchedule.ActionNode;
|
|||
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
|
||||
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerTarget;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
|
||||
import com.google.android.exoplayer2.util.HandlerWrapper;
|
||||
|
||||
/**
|
||||
|
|
@ -219,7 +220,10 @@ public abstract class Action {
|
|||
|
||||
}
|
||||
|
||||
/** Calls {@link DefaultTrackSelector#setRendererDisabled(int, boolean)}. */
|
||||
/**
|
||||
* Updates the {@link Parameters} of a {@link DefaultTrackSelector} to specify whether the
|
||||
* renderer at a given index should be disabled.
|
||||
*/
|
||||
public static final class SetRendererDisabled extends Action {
|
||||
|
||||
private final int rendererIndex;
|
||||
|
|
@ -239,7 +243,8 @@ public abstract class Action {
|
|||
@Override
|
||||
protected void doActionImpl(
|
||||
SimpleExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) {
|
||||
trackSelector.setRendererDisabled(rendererIndex, disabled);
|
||||
trackSelector.setParameters(
|
||||
trackSelector.buildUponParameters().setRendererDisabled(rendererIndex, disabled));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ public class FakeTrackSelector extends DefaultTrackSelector {
|
|||
protected TrackSelection[] selectAllTracks(
|
||||
MappedTrackInfo mappedTrackInfo,
|
||||
int[][][] rendererFormatSupports,
|
||||
int[] rendererMixedMimeTypeAdaptationSupports)
|
||||
int[] rendererMixedMimeTypeAdaptationSupports,
|
||||
Parameters params)
|
||||
throws ExoPlaybackException {
|
||||
TrackSelection[] selections = new TrackSelection[mappedTrackInfo.length];
|
||||
for (int i = 0; i < mappedTrackInfo.length; i++) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue