Skip to content

Commit

Permalink
Notify TrackSelection when it's enabled and disabled.
Browse files Browse the repository at this point in the history
Add onEnable() and onDisable() call-backs to TrackSelection. This allows
TrackSelection to perform interesting operations (like subscribe to
NetworkStatus) and clean up after itself.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175558485
  • Loading branch information
botaydotcom authored and ojw28 committed Dec 12, 2017
1 parent 877c89a commit 5bf4c24
Show file tree
Hide file tree
Showing 6 changed files with 420 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.FakeTrackSelection;
import com.google.android.exoplayer2.testutil.FakeTrackSelector;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
Expand Down Expand Up @@ -311,4 +313,143 @@ public void onSeekProcessed() {
assertEquals(Player.STATE_BUFFERING, (int) playbackStatesWhenSeekProcessed.get(2));
}

public void testAllActivatedTrackSelectionAreReleasedForSinglePeriod() throws Exception {
Timeline timeline =
new FakeTimeline(new TimelineWindowDefinition(false, false, /* durationUs= */ 500_000));
MediaSource mediaSource =
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT, Builder.AUDIO_FORMAT);
FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
FakeRenderer audioRenderer = new FakeRenderer(Builder.AUDIO_FORMAT);
FakeTrackSelector trackSelector = new FakeTrackSelector();

new ExoPlayerTestRunner.Builder()
.setMediaSource(mediaSource)
.setRenderers(videoRenderer, audioRenderer)
.setTrackSelector(trackSelector)
.build().start().blockUntilEnded(TIMEOUT_MS);

List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
int numSelectionsEnabled = 0;
// Assert that all tracks selection are disabled at the end of the playback.
for (FakeTrackSelection trackSelection : createdTrackSelections) {
assertFalse(trackSelection.isEnabled);
numSelectionsEnabled += trackSelection.enableCount;
}
// There are 2 renderers, and track selections are made once (1 period).
// Track selections are not reused, so there are 2 track selections made.
assertEquals(2, createdTrackSelections.size());
// There should be 2 track selections enabled in total.
assertEquals(2, numSelectionsEnabled);
}

public void testAllActivatedTrackSelectionAreReleasedForMultiPeriods() throws Exception {
Timeline timeline =
new FakeTimeline(new TimelineWindowDefinition(false, false, /* durationUs= */ 500_000),
new TimelineWindowDefinition(false, false, /* durationUs= */ 500_000));
MediaSource mediaSource =
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT, Builder.AUDIO_FORMAT);
FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
FakeRenderer audioRenderer = new FakeRenderer(Builder.AUDIO_FORMAT);
FakeTrackSelector trackSelector = new FakeTrackSelector();

new ExoPlayerTestRunner.Builder()
.setMediaSource(mediaSource)
.setRenderers(videoRenderer, audioRenderer)
.setTrackSelector(trackSelector)
.build().start().blockUntilEnded(TIMEOUT_MS);

List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
int numSelectionsEnabled = 0;
// Assert that all tracks selection are disabled at the end of the playback.
for (FakeTrackSelection trackSelection : createdTrackSelections) {
assertFalse(trackSelection.isEnabled);
numSelectionsEnabled += trackSelection.enableCount;
}
// There are 2 renderers, and track selections are made twice (2 periods).
// Track selections are not reused, so there are 4 track selections made.
assertEquals(4, createdTrackSelections.size());
// There should be 4 track selections enabled in total.
assertEquals(4, numSelectionsEnabled);
}

public void testAllActivatedTrackSelectionAreReleasedWhenTrackSelectionsAreRemade()
throws Exception {
Timeline timeline =
new FakeTimeline(new TimelineWindowDefinition(false, false, /* durationUs= */ 500_000));
MediaSource mediaSource =
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT, Builder.AUDIO_FORMAT);
FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
FakeRenderer audioRenderer = new FakeRenderer(Builder.AUDIO_FORMAT);
final FakeTrackSelector trackSelector = new FakeTrackSelector();
ActionSchedule disableTrackAction = new ActionSchedule.Builder("testChangeTrackSelection")
.waitForPlaybackState(Player.STATE_READY)
.executeRunnable(new Runnable() {
@Override
public void run() {
trackSelector.setRendererDisabled(0, true);
}
}).build();

new ExoPlayerTestRunner.Builder()
.setMediaSource(mediaSource)
.setRenderers(videoRenderer, audioRenderer)
.setTrackSelector(trackSelector)
.setActionSchedule(disableTrackAction)
.build().start().blockUntilEnded(TIMEOUT_MS);

List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
int numSelectionsEnabled = 0;
// Assert that all tracks selection are disabled at the end of the playback.
for (FakeTrackSelection trackSelection : createdTrackSelections) {
assertFalse(trackSelection.isEnabled);
numSelectionsEnabled += trackSelection.enableCount;
}
// There are 2 renderers, and track selections are made twice.
// Track selections are not reused, so there are 4 track selections made.
assertEquals(4, createdTrackSelections.size());
// Initially there are 2 track selections enabled.
// The second time one renderer is disabled, so only 1 track selection should be enabled.
assertEquals(3, numSelectionsEnabled);
}

public void testAllActivatedTrackSelectionAreReleasedWhenTrackSelectionsAreUsed()
throws Exception {
Timeline timeline =
new FakeTimeline(new TimelineWindowDefinition(false, false, /* durationUs= */ 500_000));
MediaSource mediaSource =
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT, Builder.AUDIO_FORMAT);
FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
FakeRenderer audioRenderer = new FakeRenderer(Builder.AUDIO_FORMAT);
final FakeTrackSelector trackSelector = new FakeTrackSelector(/* reuse track selection */ true);
ActionSchedule disableTrackAction = new ActionSchedule.Builder("testReuseTrackSelection")
.waitForPlaybackState(Player.STATE_READY)
.executeRunnable(new Runnable() {
@Override
public void run() {
trackSelector.setRendererDisabled(0, true);
}
}).build();

new ExoPlayerTestRunner.Builder()
.setMediaSource(mediaSource)
.setRenderers(videoRenderer, audioRenderer)
.setTrackSelector(trackSelector)
.setActionSchedule(disableTrackAction)
.build().start().blockUntilEnded(TIMEOUT_MS);

List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
int numSelectionsEnabled = 0;
// Assert that all tracks selection are disabled at the end of the playback.
for (FakeTrackSelection trackSelection : createdTrackSelections) {
assertFalse(trackSelection.isEnabled);
numSelectionsEnabled += trackSelection.enableCount;
}
// There are 2 renderers, and track selections are made twice.
// TrackSelections are reused, so there are only 2 track selections made for 2 renderers.
assertEquals(2, createdTrackSelections.size());
// Initially there are 2 track selections enabled.
// The second time one renderer is disabled, so only 1 track selection should be enabled.
assertEquals(3, numSelectionsEnabled);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1666,11 +1666,11 @@ public long updatePeriodTrackSelection(long positionUs, boolean forceRecreateStr
// Undo the effect of previous call to associate no-sample renderers with empty tracks
// so the mediaPeriod receives back whatever it sent us before.
disassociateNoSampleRenderersWithEmptySampleStream(sampleStreams);
updatePeriodTrackSelectorResult(trackSelectorResult);
// Disable streams on the period and get new streams for updated/newly-enabled tracks.
positionUs = mediaPeriod.selectTracks(trackSelections.getAll(), mayRetainStreamFlags,
sampleStreams, streamResetFlags, positionUs);
associateNoSampleRenderersWithEmptySampleStream(sampleStreams);
periodTrackSelectorResult = trackSelectorResult;

// Update whether we have enabled tracks and sanity check the expected streams are non-null.
hasEnabledTracks = false;
Expand All @@ -1692,6 +1692,7 @@ public long updatePeriodTrackSelection(long positionUs, boolean forceRecreateStr
}

public void release() {
updatePeriodTrackSelectorResult(null);
try {
if (info.endPositionUs != C.TIME_END_OF_SOURCE) {
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
Expand All @@ -1704,6 +1705,36 @@ public void release() {
}
}

private void updatePeriodTrackSelectorResult(TrackSelectorResult trackSelectorResult) {
if (periodTrackSelectorResult != null) {
disableTrackSelectionsInResult(periodTrackSelectorResult);
}
periodTrackSelectorResult = trackSelectorResult;
if (periodTrackSelectorResult != null) {
enableTrackSelectionsInResult(periodTrackSelectorResult);
}
}

private void enableTrackSelectionsInResult(TrackSelectorResult trackSelectorResult) {
for (int i = 0; i < trackSelectorResult.renderersEnabled.length; i++) {
boolean rendererEnabled = trackSelectorResult.renderersEnabled[i];
TrackSelection trackSelection = trackSelectorResult.selections.get(i);
if (rendererEnabled && trackSelection != null) {
trackSelection.enable();
}
}
}

private void disableTrackSelectionsInResult(TrackSelectorResult trackSelectorResult) {
for (int i = 0; i < trackSelectorResult.renderersEnabled.length; i++) {
boolean rendererEnabled = trackSelectorResult.renderersEnabled[i];
TrackSelection trackSelection = trackSelectorResult.selections.get(i);
if (rendererEnabled && trackSelection != null) {
trackSelection.disable();
}
}
}

/**
* For each renderer of type {@link C#TRACK_TYPE_NONE}, we will remove the dummy
* {@link EmptySampleStream} that was associated with it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ public BaseTrackSelection(TrackGroup group, int... tracks) {
blacklistUntilTimes = new long[length];
}

@Override
public void enable() {
// Do nothing.
}

@Override
public void disable() {
// Do nothing.
}

@Override
public final TrackGroup getTrackGroup() {
return group;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ interface Factory {

}

/**
* Enables the track selection.
* <p>
* This method may not be called when the track selection is already enabled.
*/
void enable();

/**
* Disables this track selection.
* <p>
* This method may only be called when the track selection is already enabled.
*/
void disable();

/**
* Returns the {@link TrackGroup} to which the selected tracks belong.
*/
Expand Down Expand Up @@ -124,6 +138,8 @@ interface Factory {

/**
* Updates the selected track.
* <p>
* This method may only be called when the selection is enabled.
*
* @param playbackPositionUs The current playback position in microseconds. If playback of the
* period to which this track selection belongs has not yet started, the value will be the
Expand All @@ -150,7 +166,7 @@ void updateSelectedTrack(long playbackPositionUs, long bufferedDurationUs,
* An example of a case where a smaller value may be returned is if network conditions have
* improved dramatically, allowing chunks to be discarded and re-buffered in a track of
* significantly higher quality. Discarding chunks may allow faster switching to a higher quality
* track in this case.
* track in this case. This method may only be called when the selection is enabled.
*
* @param playbackPositionUs The current playback position in microseconds. If playback of the
* period to which this track selection belongs has not yet started, the value will be the
Expand All @@ -167,6 +183,8 @@ void updateSelectedTrack(long playbackPositionUs, long bufferedDurationUs,
* period of time. Blacklisting will fail if all other tracks are currently blacklisted. If
* blacklisting the currently selected track, note that it will remain selected until the next
* call to {@link #updateSelectedTrack(long, long, long)}.
* <p>
* This method may only be called when the selection is enabled.
*
* @param index The index of the track in the selection.
* @param blacklistDurationMs The duration of time for which the track should be blacklisted, in
Expand Down
Loading

0 comments on commit 5bf4c24

Please sign in to comment.