mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Reset only renderers that have been enabled
#exofixit PiperOrigin-RevId: 396938258
This commit is contained in:
parent
5a2fd983a9
commit
86dc31f291
3 changed files with 167 additions and 8 deletions
|
|
@ -57,10 +57,12 @@ import com.google.android.exoplayer2.util.TraceUtil;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/** Implements the internal behavior of {@link ExoPlayerImpl}. */
|
/** Implements the internal behavior of {@link ExoPlayerImpl}. */
|
||||||
|
|
@ -165,6 +167,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
private static final long MIN_RENDERER_SLEEP_DURATION_MS = 2000;
|
private static final long MIN_RENDERER_SLEEP_DURATION_MS = 2000;
|
||||||
|
|
||||||
private final Renderer[] renderers;
|
private final Renderer[] renderers;
|
||||||
|
private final Set<Renderer> renderersToReset;
|
||||||
private final RendererCapabilities[] rendererCapabilities;
|
private final RendererCapabilities[] rendererCapabilities;
|
||||||
private final TrackSelector trackSelector;
|
private final TrackSelector trackSelector;
|
||||||
private final TrackSelectorResult emptyTrackSelectorResult;
|
private final TrackSelectorResult emptyTrackSelectorResult;
|
||||||
|
|
@ -254,6 +257,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
}
|
}
|
||||||
mediaClock = new DefaultMediaClock(this, clock);
|
mediaClock = new DefaultMediaClock(this, clock);
|
||||||
pendingMessages = new ArrayList<>();
|
pendingMessages = new ArrayList<>();
|
||||||
|
renderersToReset = Sets.newIdentityHashSet();
|
||||||
window = new Timeline.Window();
|
window = new Timeline.Window();
|
||||||
period = new Timeline.Period();
|
period = new Timeline.Period();
|
||||||
trackSelector.init(/* listener= */ this, bandwidthMeter);
|
trackSelector.init(/* listener= */ this, bandwidthMeter);
|
||||||
|
|
@ -1322,7 +1326,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
this.foregroundMode = foregroundMode;
|
this.foregroundMode = foregroundMode;
|
||||||
if (!foregroundMode) {
|
if (!foregroundMode) {
|
||||||
for (Renderer renderer : renderers) {
|
for (Renderer renderer : renderers) {
|
||||||
if (!isRendererEnabled(renderer)) {
|
if (!isRendererEnabled(renderer) && renderersToReset.remove(renderer)) {
|
||||||
renderer.reset();
|
renderer.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1382,11 +1386,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
}
|
}
|
||||||
if (resetRenderers) {
|
if (resetRenderers) {
|
||||||
for (Renderer renderer : renderers) {
|
for (Renderer renderer : renderers) {
|
||||||
try {
|
if (renderersToReset.remove(renderer)) {
|
||||||
renderer.reset();
|
try {
|
||||||
} catch (RuntimeException e) {
|
renderer.reset();
|
||||||
// There's nothing we can do.
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "Reset failed.", e);
|
// There's nothing we can do.
|
||||||
|
Log.e(TAG, "Reset failed.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2385,7 +2391,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
// Reset all disabled renderers before enabling any new ones. This makes sure resources released
|
// Reset all disabled renderers before enabling any new ones. This makes sure resources released
|
||||||
// by the disabled renderers will be available to renderers that are being enabled.
|
// by the disabled renderers will be available to renderers that are being enabled.
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
if (!trackSelectorResult.isRendererEnabled(i)) {
|
if (!trackSelectorResult.isRendererEnabled(i) && renderersToReset.remove(renderers[i])) {
|
||||||
renderers[i].reset();
|
renderers[i].reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2417,6 +2423,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
boolean joining = !wasRendererEnabled && playing;
|
boolean joining = !wasRendererEnabled && playing;
|
||||||
// Enable the renderer.
|
// Enable the renderer.
|
||||||
enabledRendererCount++;
|
enabledRendererCount++;
|
||||||
|
renderersToReset.add(renderer);
|
||||||
renderer.enable(
|
renderer.enable(
|
||||||
rendererConfiguration,
|
rendererConfiguration,
|
||||||
formats,
|
formats,
|
||||||
|
|
@ -2426,7 +2433,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
mayRenderStartOfStream,
|
mayRenderStartOfStream,
|
||||||
periodHolder.getStartPositionRendererTime(),
|
periodHolder.getStartPositionRendererTime(),
|
||||||
periodHolder.getRendererOffset());
|
periodHolder.getRendererOffset());
|
||||||
|
|
||||||
renderer.handleMessage(
|
renderer.handleMessage(
|
||||||
Renderer.MSG_SET_WAKEUP_LISTENER,
|
Renderer.MSG_SET_WAKEUP_LISTENER,
|
||||||
new Renderer.WakeupListener() {
|
new Renderer.WakeupListener() {
|
||||||
|
|
|
||||||
|
|
@ -335,6 +335,146 @@ public final class ExoPlayerTest {
|
||||||
assertThat(renderer.isEnded).isTrue();
|
assertThat(renderer.isEnded).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderersLifecycle_renderersThatAreNeverEnabled_areNotReset() throws Exception {
|
||||||
|
Timeline timeline = new FakeTimeline();
|
||||||
|
final FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
|
||||||
|
final FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO);
|
||||||
|
SimpleExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(context).setRenderers(videoRenderer, audioRenderer).build();
|
||||||
|
Player.Listener mockPlayerListener = mock(Player.Listener.class);
|
||||||
|
player.addListener(mockPlayerListener);
|
||||||
|
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||||
|
player.prepare();
|
||||||
|
|
||||||
|
player.play();
|
||||||
|
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
assertThat(audioRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(audioRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(videoRenderer.enabledCount).isEqualTo(0);
|
||||||
|
assertThat(videoRenderer.resetCount).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderersLifecycle_setForegroundMode_resetsDisabledRenderersThatHaveBeenEnabled()
|
||||||
|
throws Exception {
|
||||||
|
Timeline timeline = new FakeTimeline();
|
||||||
|
final FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
|
||||||
|
final FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO);
|
||||||
|
final FakeRenderer textRenderer = new FakeRenderer(C.TRACK_TYPE_TEXT);
|
||||||
|
SimpleExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(context).setRenderers(videoRenderer, audioRenderer).build();
|
||||||
|
Player.Listener mockPlayerListener = mock(Player.Listener.class);
|
||||||
|
player.addListener(mockPlayerListener);
|
||||||
|
player.setMediaSources(
|
||||||
|
ImmutableList.of(
|
||||||
|
new FakeMediaSource(
|
||||||
|
timeline, ExoPlayerTestRunner.AUDIO_FORMAT, ExoPlayerTestRunner.VIDEO_FORMAT),
|
||||||
|
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT)));
|
||||||
|
player.prepare();
|
||||||
|
|
||||||
|
player.play();
|
||||||
|
runUntilPositionDiscontinuity(player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
player.setForegroundMode(/* foregroundMode= */ true);
|
||||||
|
// Only the video renderer that is disabled in the second window has been reset.
|
||||||
|
assertThat(audioRenderer.resetCount).isEqualTo(0);
|
||||||
|
assertThat(videoRenderer.resetCount).isEqualTo(1);
|
||||||
|
|
||||||
|
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||||
|
player.release();
|
||||||
|
// After release the audio renderer is reset as well.
|
||||||
|
assertThat(audioRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(audioRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(videoRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(videoRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(textRenderer.enabledCount).isEqualTo(0);
|
||||||
|
assertThat(textRenderer.resetCount).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderersLifecycle_selectTextTracksWhilePlaying_textRendererEnabledAndReset()
|
||||||
|
throws Exception {
|
||||||
|
Timeline timeline = new FakeTimeline();
|
||||||
|
final FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO);
|
||||||
|
final FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
|
||||||
|
final FakeRenderer textRenderer = new FakeRenderer(C.TRACK_TYPE_TEXT);
|
||||||
|
Format textFormat =
|
||||||
|
new Format.Builder().setSampleMimeType(MimeTypes.TEXT_VTT).setLanguage("en").build();
|
||||||
|
SimpleExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(context).setRenderers(audioRenderer, textRenderer).build();
|
||||||
|
Player.Listener mockPlayerListener = mock(Player.Listener.class);
|
||||||
|
player.addListener(mockPlayerListener);
|
||||||
|
player.setMediaSources(
|
||||||
|
ImmutableList.of(
|
||||||
|
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT),
|
||||||
|
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT, textFormat)));
|
||||||
|
player.prepare();
|
||||||
|
|
||||||
|
player.play();
|
||||||
|
runUntilPositionDiscontinuity(player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
// Only the audio renderer enabled so far.
|
||||||
|
assertThat(audioRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(textRenderer.enabledCount).isEqualTo(0);
|
||||||
|
player.setTrackSelectionParameters(
|
||||||
|
player.getTrackSelectionParameters().buildUpon().setPreferredTextLanguage("en").build());
|
||||||
|
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
assertThat(audioRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(audioRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(textRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(textRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(videoRenderer.enabledCount).isEqualTo(0);
|
||||||
|
assertThat(videoRenderer.resetCount).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderersLifecycle_seekTo_resetsDisabledRenderersIfRequired() throws Exception {
|
||||||
|
Timeline timeline = new FakeTimeline();
|
||||||
|
final FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO);
|
||||||
|
final FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
|
||||||
|
final FakeRenderer textRenderer = new FakeRenderer(C.TRACK_TYPE_TEXT);
|
||||||
|
Format textFormat =
|
||||||
|
new Format.Builder().setSampleMimeType(MimeTypes.TEXT_VTT).setLanguage("en").build();
|
||||||
|
SimpleExoPlayer player =
|
||||||
|
new TestExoPlayerBuilder(context)
|
||||||
|
.setRenderers(videoRenderer, audioRenderer, textRenderer)
|
||||||
|
.build();
|
||||||
|
Player.Listener mockPlayerListener = mock(Player.Listener.class);
|
||||||
|
player.addListener(mockPlayerListener);
|
||||||
|
player.setTrackSelectionParameters(
|
||||||
|
player.getTrackSelectionParameters().buildUpon().setPreferredTextLanguage("en").build());
|
||||||
|
player.setMediaSources(
|
||||||
|
ImmutableList.of(
|
||||||
|
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT),
|
||||||
|
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT, textFormat)));
|
||||||
|
player.prepare();
|
||||||
|
|
||||||
|
player.play();
|
||||||
|
runUntilPositionDiscontinuity(player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
// Disable text renderer by selecting a language that is not available.
|
||||||
|
player.setTrackSelectionParameters(
|
||||||
|
player.getTrackSelectionParameters().buildUpon().setPreferredTextLanguage("de").build());
|
||||||
|
player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1000);
|
||||||
|
runUntilPlaybackState(player, Player.STATE_READY);
|
||||||
|
// Expect formerly enabled renderers to be reset after seek.
|
||||||
|
assertThat(textRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(audioRenderer.resetCount).isEqualTo(0);
|
||||||
|
assertThat(videoRenderer.resetCount).isEqualTo(0);
|
||||||
|
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
// Verify that the text renderer has not been reset a second time.
|
||||||
|
assertThat(audioRenderer.enabledCount).isEqualTo(2);
|
||||||
|
assertThat(audioRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(textRenderer.enabledCount).isEqualTo(1);
|
||||||
|
assertThat(textRenderer.resetCount).isEqualTo(1);
|
||||||
|
assertThat(videoRenderer.enabledCount).isEqualTo(0);
|
||||||
|
assertThat(videoRenderer.resetCount).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that the player does not unnecessarily reset renderers when playing a multi-period
|
* Tests that the player does not unnecessarily reset renderers when playing a multi-period
|
||||||
* source.
|
* source.
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ public class FakeRenderer extends BaseRenderer {
|
||||||
public boolean isEnded;
|
public boolean isEnded;
|
||||||
public int positionResetCount;
|
public int positionResetCount;
|
||||||
public int sampleBufferReadCount;
|
public int sampleBufferReadCount;
|
||||||
|
public int enabledCount;
|
||||||
|
public int resetCount;
|
||||||
|
|
||||||
public FakeRenderer(@C.TrackType int trackType) {
|
public FakeRenderer(@C.TrackType int trackType) {
|
||||||
super(trackType);
|
super(trackType);
|
||||||
|
|
@ -136,6 +138,17 @@ public class FakeRenderer extends BaseRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEnabled(boolean joining, boolean mayRenderStartOfStream)
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
enabledCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReset() {
|
||||||
|
resetCount++;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return lastSamplePositionUs >= playbackPositionUs || hasPendingBuffer || isSourceReady();
|
return lastSamplePositionUs >= playbackPositionUs || hasPendingBuffer || isSourceReady();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue