Search in sources :

Example 11 with ExoPlayer

use of com.google.android.exoplayer2.ExoPlayer in project ExoPlayer by google.

the class ExoPlayerImplInternal method doSomeWork.

private void doSomeWork() throws ExoPlaybackException, IOException {
    long operationStartTimeMs = clock.uptimeMillis();
    updatePeriods();
    if (playbackInfo.playbackState == Player.STATE_IDLE || playbackInfo.playbackState == Player.STATE_ENDED) {
        // Remove all messages. Prepare (in case of IDLE) or seek (in case of ENDED) will resume.
        handler.removeMessages(MSG_DO_SOME_WORK);
        return;
    }
    @Nullable MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
    if (playingPeriodHolder == null) {
        // We're still waiting until the playing period is available.
        scheduleNextWork(operationStartTimeMs, ACTIVE_INTERVAL_MS);
        return;
    }
    TraceUtil.beginSection("doSomeWork");
    updatePlaybackPositions();
    boolean renderersEnded = true;
    boolean renderersAllowPlayback = true;
    if (playingPeriodHolder.prepared) {
        long rendererPositionElapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
        playingPeriodHolder.mediaPeriod.discardBuffer(playbackInfo.positionUs - backBufferDurationUs, retainBackBufferFromKeyframe);
        for (int i = 0; i < renderers.length; i++) {
            Renderer renderer = renderers[i];
            if (!isRendererEnabled(renderer)) {
                continue;
            }
            // TODO: Each renderer should return the maximum delay before which it wishes to be called
            // again. The minimum of these values should then be used as the delay before the next
            // invocation of this method.
            renderer.render(rendererPositionUs, rendererPositionElapsedRealtimeUs);
            renderersEnded = renderersEnded && renderer.isEnded();
            // Determine whether the renderer allows playback to continue. Playback can continue if the
            // renderer is ready or ended. Also continue playback if the renderer is reading ahead into
            // the next stream or is waiting for the next stream. This is to avoid getting stuck if
            // tracks in the current period have uneven durations and are still being read by another
            // renderer. See: https://github.com/google/ExoPlayer/issues/1874.
            boolean isReadingAhead = playingPeriodHolder.sampleStreams[i] != renderer.getStream();
            boolean isWaitingForNextStream = !isReadingAhead && renderer.hasReadStreamToEnd();
            boolean allowsPlayback = isReadingAhead || isWaitingForNextStream || renderer.isReady() || renderer.isEnded();
            renderersAllowPlayback = renderersAllowPlayback && allowsPlayback;
            if (!allowsPlayback) {
                renderer.maybeThrowStreamError();
            }
        }
    } else {
        playingPeriodHolder.mediaPeriod.maybeThrowPrepareError();
    }
    long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
    boolean finishedRendering = renderersEnded && playingPeriodHolder.prepared && (playingPeriodDurationUs == C.TIME_UNSET || playingPeriodDurationUs <= playbackInfo.positionUs);
    if (finishedRendering && pendingPauseAtEndOfPeriod) {
        pendingPauseAtEndOfPeriod = false;
        setPlayWhenReadyInternal(/* playWhenReady= */
        false, playbackInfo.playbackSuppressionReason, /* operationAck= */
        false, Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM);
    }
    if (finishedRendering && playingPeriodHolder.info.isFinal) {
        setState(Player.STATE_ENDED);
        stopRenderers();
    } else if (playbackInfo.playbackState == Player.STATE_BUFFERING && shouldTransitionToReadyState(renderersAllowPlayback)) {
        setState(Player.STATE_READY);
        // Any pending error was successfully recovered from.
        pendingRecoverableRendererError = null;
        if (shouldPlayWhenReady()) {
            startRenderers();
        }
    } else if (playbackInfo.playbackState == Player.STATE_READY && !(enabledRendererCount == 0 ? isTimelineReady() : renderersAllowPlayback)) {
        isRebuffering = shouldPlayWhenReady();
        setState(Player.STATE_BUFFERING);
        if (isRebuffering) {
            notifyTrackSelectionRebuffer();
            livePlaybackSpeedControl.notifyRebuffer();
        }
        stopRenderers();
    }
    boolean playbackMaybeStuck = false;
    if (playbackInfo.playbackState == Player.STATE_BUFFERING) {
        for (int i = 0; i < renderers.length; i++) {
            if (isRendererEnabled(renderers[i]) && renderers[i].getStream() == playingPeriodHolder.sampleStreams[i]) {
                renderers[i].maybeThrowStreamError();
            }
        }
        if (!playbackInfo.isLoading && playbackInfo.totalBufferedDurationUs < 500_000 && isLoadingPossible()) {
            // The renderers are not ready, there is more media available to load, and the LoadControl
            // is refusing to load it (indicated by !playbackInfo.isLoading). This could be because the
            // renderers are still transitioning to their ready states, but it could also indicate a
            // stuck playback. The playbackInfo.totalBufferedDurationUs check further isolates the
            // cause to a lack of media for the renderers to consume, to avoid classifying playbacks as
            // stuck when they're waiting for other reasons (in particular, loading DRM keys).
            playbackMaybeStuck = true;
        }
    }
    if (!playbackMaybeStuck) {
        playbackMaybeBecameStuckAtMs = C.TIME_UNSET;
    } else if (playbackMaybeBecameStuckAtMs == C.TIME_UNSET) {
        playbackMaybeBecameStuckAtMs = clock.elapsedRealtime();
    } else if (clock.elapsedRealtime() - playbackMaybeBecameStuckAtMs >= PLAYBACK_STUCK_AFTER_MS) {
        throw new IllegalStateException("Playback stuck buffering and not loading");
    }
    if (offloadSchedulingEnabled != playbackInfo.offloadSchedulingEnabled) {
        playbackInfo = playbackInfo.copyWithOffloadSchedulingEnabled(offloadSchedulingEnabled);
    }
    boolean sleepingForOffload = false;
    if ((shouldPlayWhenReady() && playbackInfo.playbackState == Player.STATE_READY) || playbackInfo.playbackState == Player.STATE_BUFFERING) {
        sleepingForOffload = !maybeScheduleWakeup(operationStartTimeMs, ACTIVE_INTERVAL_MS);
    } else if (enabledRendererCount != 0 && playbackInfo.playbackState != Player.STATE_ENDED) {
        scheduleNextWork(operationStartTimeMs, IDLE_INTERVAL_MS);
    } else {
        handler.removeMessages(MSG_DO_SOME_WORK);
    }
    if (playbackInfo.sleepingForOffload != sleepingForOffload) {
        playbackInfo = playbackInfo.copyWithSleepingForOffload(sleepingForOffload);
    }
    // A sleep request is only valid for the current doSomeWork.
    requestForRendererSleep = false;
    TraceUtil.endSection();
}
Also used : TextRenderer(com.google.android.exoplayer2.text.TextRenderer) Nullable(androidx.annotation.Nullable)

Example 12 with ExoPlayer

use of com.google.android.exoplayer2.ExoPlayer in project ExoPlayer by google.

the class DrmPlaybackTest method clearkeyPlayback.

@Test
public void clearkeyPlayback() throws Exception {
    MockWebServer mockWebServer = new MockWebServer();
    mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(CLEARKEY_RESPONSE));
    mockWebServer.start();
    MediaItem mediaItem = new MediaItem.Builder().setUri("asset:///media/drm/sample_fragmented_clearkey.mp4").setDrmConfiguration(new MediaItem.DrmConfiguration.Builder(C.CLEARKEY_UUID).setLicenseUri(mockWebServer.url("license").toString()).build()).build();
    AtomicReference<ExoPlayer> player = new AtomicReference<>();
    ConditionVariable playbackComplete = new ConditionVariable();
    AtomicReference<PlaybackException> playbackException = new AtomicReference<>();
    getInstrumentation().runOnMainSync(() -> {
        player.set(new ExoPlayer.Builder(getInstrumentation().getContext()).build());
        player.get().addListener(new Player.Listener() {

            @Override
            public void onPlaybackStateChanged(@Player.State int playbackState) {
                if (playbackState == Player.STATE_ENDED) {
                    playbackComplete.open();
                }
            }

            @Override
            public void onPlayerError(PlaybackException error) {
                playbackException.set(error);
                playbackComplete.open();
            }
        });
        player.get().setMediaItem(mediaItem);
        player.get().prepare();
        player.get().play();
    });
    playbackComplete.block();
    getInstrumentation().runOnMainSync(() -> player.get().release());
    getInstrumentation().waitForIdleSync();
    assertThat(playbackException.get()).isNull();
}
Also used : PlaybackException(com.google.android.exoplayer2.PlaybackException) MockResponse(okhttp3.mockwebserver.MockResponse) Player(com.google.android.exoplayer2.Player) ExoPlayer(com.google.android.exoplayer2.ExoPlayer) AtomicReference(java.util.concurrent.atomic.AtomicReference) ExoPlayer(com.google.android.exoplayer2.ExoPlayer) ConditionVariable(com.google.android.exoplayer2.util.ConditionVariable) MediaItem(com.google.android.exoplayer2.MediaItem) MockWebServer(okhttp3.mockwebserver.MockWebServer) Test(org.junit.Test)

Example 13 with ExoPlayer

use of com.google.android.exoplayer2.ExoPlayer in project ExoPlayer by google.

the class AdTagLoader method loadAdInternal.

private void loadAdInternal(AdMediaInfo adMediaInfo, AdPodInfo adPodInfo) {
    if (adsManager == null) {
        // Drop events after release.
        if (configuration.debugModeEnabled) {
            Log.d(TAG, "loadAd after release " + getAdMediaInfoString(adMediaInfo) + ", ad pod " + adPodInfo);
        }
        return;
    }
    int adGroupIndex = getAdGroupIndexForAdPod(adPodInfo);
    int adIndexInAdGroup = adPodInfo.getAdPosition() - 1;
    AdInfo adInfo = new AdInfo(adGroupIndex, adIndexInAdGroup);
    // The ad URI may already be known, so force put to update it if needed.
    adInfoByAdMediaInfo.forcePut(adMediaInfo, adInfo);
    if (configuration.debugModeEnabled) {
        Log.d(TAG, "loadAd " + getAdMediaInfoString(adMediaInfo));
    }
    if (adPlaybackState.isAdInErrorState(adGroupIndex, adIndexInAdGroup)) {
        // timeout after its media load timeout.
        return;
    }
    // The ad count may increase on successive loads of ads in the same ad pod, for example, due to
    // separate requests for ad tags with multiple ads within the ad pod completing after an earlier
    // ad has loaded. See also https://github.com/google/ExoPlayer/issues/7477.
    AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
    adPlaybackState = adPlaybackState.withAdCount(adInfo.adGroupIndex, max(adPodInfo.getTotalAds(), adGroup.states.length));
    adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
    for (int i = 0; i < adIndexInAdGroup; i++) {
        // Any preceding ads that haven't loaded are not going to load.
        if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
            adPlaybackState = adPlaybackState.withAdLoadError(adGroupIndex, /* adIndexInAdGroup= */
            i);
        }
    }
    Uri adUri = Uri.parse(adMediaInfo.getUrl());
    adPlaybackState = adPlaybackState.withAdUri(adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adUri);
    updateAdPlaybackState();
}
Also used : AdPlaybackState(com.google.android.exoplayer2.source.ads.AdPlaybackState) Uri(android.net.Uri)

Example 14 with ExoPlayer

use of com.google.android.exoplayer2.ExoPlayer in project ExoPlayer by google.

the class ProgressiveMediaSource method notifySourceInfoRefreshed.

// Internal methods.
private void notifySourceInfoRefreshed() {
    // TODO: Split up isDynamic into multiple fields to indicate which values may change. Then
    // indicate that the duration may change until it's known. See [internal: b/69703223].
    Timeline timeline = new SinglePeriodTimeline(timelineDurationUs, timelineIsSeekable, /* isDynamic= */
    false, /* useLiveConfiguration= */
    timelineIsLive, /* manifest= */
    null, mediaItem);
    if (timelineIsPlaceholder) {
        // TODO: Actually prepare the extractors during preparation so that we don't need a
        // placeholder. See https://github.com/google/ExoPlayer/issues/4727.
        timeline = new ForwardingTimeline(timeline) {

            @Override
            public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
                super.getWindow(windowIndex, window, defaultPositionProjectionUs);
                window.isPlaceholder = true;
                return window;
            }

            @Override
            public Period getPeriod(int periodIndex, Period period, boolean setIds) {
                super.getPeriod(periodIndex, period, setIds);
                period.isPlaceholder = true;
                return period;
            }
        };
    }
    refreshSourceInfo(timeline);
}
Also used : Timeline(com.google.android.exoplayer2.Timeline)

Example 15 with ExoPlayer

use of com.google.android.exoplayer2.ExoPlayer in project ExoPlayer by google.

the class ExoPlayerTest method setRepeatMode_all_notifiesAvailableCommandsChanged.

@Test
public void setRepeatMode_all_notifiesAvailableCommandsChanged() {
    Player.Commands defaultCommands = createWithDefaultCommands();
    Player.Commands commandsWithSeekToPreviousAndNextWindow = createWithDefaultCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT);
    Player.Listener mockListener = mock(Player.Listener.class);
    ExoPlayer player = new TestExoPlayerBuilder(context).build();
    player.addListener(mockListener);
    player.addMediaSource(new FakeMediaSource());
    verify(mockListener).onAvailableCommandsChanged(defaultCommands);
    // Check that there were no other calls to onAvailableCommandsChanged.
    verify(mockListener).onAvailableCommandsChanged(any());
    player.setRepeatMode(Player.REPEAT_MODE_ALL);
    verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPreviousAndNextWindow);
    verify(mockListener, times(2)).onAvailableCommandsChanged(any());
}
Also used : Listener(com.google.android.exoplayer2.Player.Listener) FakeMediaSource(com.google.android.exoplayer2.testutil.FakeMediaSource) TestExoPlayerBuilder(com.google.android.exoplayer2.testutil.TestExoPlayerBuilder) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)248 FakeMediaSource (com.google.android.exoplayer2.testutil.FakeMediaSource)179 TestExoPlayerBuilder (com.google.android.exoplayer2.testutil.TestExoPlayerBuilder)172 FakeTimeline (com.google.android.exoplayer2.testutil.FakeTimeline)121 PlayerRunnable (com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable)108 ActionSchedule (com.google.android.exoplayer2.testutil.ActionSchedule)92 SinglePeriodTimeline (com.google.android.exoplayer2.source.SinglePeriodTimeline)89 NoUidTimeline (com.google.android.exoplayer2.testutil.NoUidTimeline)89 Listener (com.google.android.exoplayer2.Player.Listener)85 TimelineWindowDefinition (com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition)73 ExoPlayerTestRunner (com.google.android.exoplayer2.testutil.ExoPlayerTestRunner)67 ConcatenatingMediaSource (com.google.android.exoplayer2.source.ConcatenatingMediaSource)65 MediaSource (com.google.android.exoplayer2.source.MediaSource)55 FakeClock (com.google.android.exoplayer2.testutil.FakeClock)48 ClippingMediaSource (com.google.android.exoplayer2.source.ClippingMediaSource)47 CompositeMediaSource (com.google.android.exoplayer2.source.CompositeMediaSource)47 MaskingMediaSource (com.google.android.exoplayer2.source.MaskingMediaSource)47 ServerSideAdInsertionMediaSource (com.google.android.exoplayer2.source.ads.ServerSideAdInsertionMediaSource)47 FakeAdaptiveMediaSource (com.google.android.exoplayer2.testutil.FakeAdaptiveMediaSource)47 ExoPlayer (com.google.android.exoplayer2.ExoPlayer)44