|
147 | 147 | import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
148 | 148 | import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
149 | 149 | import androidx.media3.exoplayer.drm.DrmSessionManager;
|
| 150 | +import androidx.media3.exoplayer.mediacodec.MediaCodecRenderer; |
150 | 151 | import androidx.media3.exoplayer.metadata.MetadataOutput;
|
151 | 152 | import androidx.media3.exoplayer.source.ClippingMediaSource;
|
152 | 153 | import androidx.media3.exoplayer.source.ConcatenatingMediaSource;
|
@@ -16748,6 +16749,84 @@ public void handleMessage(
|
16748 | 16749 | assertThat(videoScalingSetOnSecondaryVideoRenderer.get()).isTrue();
|
16749 | 16750 | }
|
16750 | 16751 |
|
| 16752 | + @Test |
| 16753 | + public void |
| 16754 | + play_withRecoverableErrorAfterAdvancingReadingPeriod_advancesPlayingPeriodWhileErrorHandling() |
| 16755 | + throws Exception { |
| 16756 | + Clock fakeClock = new FakeClock(/* isAutoAdvancing= */ true); |
| 16757 | + AtomicBoolean shouldRendererThrowRecoverableError = new AtomicBoolean(false); |
| 16758 | + AtomicInteger onStreamChangedCount = new AtomicInteger(0); |
| 16759 | + ExoPlayer player = |
| 16760 | + new TestExoPlayerBuilder(context) |
| 16761 | + .setClock(fakeClock) |
| 16762 | + .setRenderersFactory( |
| 16763 | + new RenderersFactory() { |
| 16764 | + @Override |
| 16765 | + public Renderer[] createRenderers( |
| 16766 | + Handler eventHandler, |
| 16767 | + VideoRendererEventListener videoRendererEventListener, |
| 16768 | + AudioRendererEventListener audioRendererEventListener, |
| 16769 | + TextOutput textRendererOutput, |
| 16770 | + MetadataOutput metadataRendererOutput) { |
| 16771 | + return new Renderer[] { |
| 16772 | + new FakeVideoRenderer( |
| 16773 | + SystemClock.DEFAULT.createHandler( |
| 16774 | + eventHandler.getLooper(), /* callback= */ null), |
| 16775 | + videoRendererEventListener) { |
| 16776 | + @Override |
| 16777 | + protected void onStreamChanged( |
| 16778 | + Format[] formats, |
| 16779 | + long startPositionUs, |
| 16780 | + long offsetUs, |
| 16781 | + MediaSource.MediaPeriodId mediaPeriodId) |
| 16782 | + throws ExoPlaybackException { |
| 16783 | + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); |
| 16784 | + onStreamChangedCount.getAndIncrement(); |
| 16785 | + } |
| 16786 | + |
| 16787 | + @Override |
| 16788 | + public void render(long positionUs, long elapsedRealtimeUs) |
| 16789 | + throws ExoPlaybackException { |
| 16790 | + if (!shouldRendererThrowRecoverableError.get()) { |
| 16791 | + super.render(positionUs, elapsedRealtimeUs); |
| 16792 | + } else { |
| 16793 | + shouldRendererThrowRecoverableError.set(false); |
| 16794 | + throw createRendererException( |
| 16795 | + new MediaCodecRenderer.DecoderInitializationException( |
| 16796 | + new Format.Builder().build(), |
| 16797 | + new IllegalArgumentException(), |
| 16798 | + false, |
| 16799 | + 0), |
| 16800 | + this.getFormatHolder().format, |
| 16801 | + true, |
| 16802 | + PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); |
| 16803 | + } |
| 16804 | + } |
| 16805 | + } |
| 16806 | + }; |
| 16807 | + } |
| 16808 | + }) |
| 16809 | + .build(); |
| 16810 | + player.setMediaSources( |
| 16811 | + ImmutableList.of( |
| 16812 | + new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT), |
| 16813 | + new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT))); |
| 16814 | + player.prepare(); |
| 16815 | + |
| 16816 | + // Play a bit until the reading period has advanced. |
| 16817 | + player.play(); |
| 16818 | + advance(player).untilBackgroundThreadCondition(() -> onStreamChangedCount.get() == 2); |
| 16819 | + shouldRendererThrowRecoverableError.set(true); |
| 16820 | + runUntilPlaybackState(player, Player.STATE_ENDED); |
| 16821 | + |
| 16822 | + player.release(); |
| 16823 | + |
| 16824 | + // onStreamChanged should occur thrice; |
| 16825 | + // 1 during first enable, 2 during replace stream, 3 during error recovery |
| 16826 | + assertThat(onStreamChangedCount.get()).isEqualTo(3); |
| 16827 | + assertThat(shouldRendererThrowRecoverableError.get()).isFalse(); |
| 16828 | + } |
| 16829 | + |
16751 | 16830 | // Internal methods.
|
16752 | 16831 |
|
16753 | 16832 | private void addWatchAsSystemFeature() {
|
|
0 commit comments