private void sendMessageToTargetThread(final PlayerMessage message) { Handler handler = message.getHandler(); handler.post( () -> { try { deliverMessage(message); } catch (ExoPlaybackException e) { Log.e(TAG, "Unexpected error delivering message on external thread.", e); throw new RuntimeException(e); } }); }
switch (msg.what) { case MSG_PREPARE: prepareInternal( (MediaSource) msg.obj, /* resetPosition= */ msg.arg1 != 0, break; case MSG_SET_PLAY_WHEN_READY: setPlayWhenReadyInternal(msg.arg1 != 0); break; case MSG_SET_REPEAT_MODE: setRepeatModeInternal(msg.arg1); break; case MSG_SET_SHUFFLE_ENABLED: setShuffleModeEnabledInternal(msg.arg1 != 0); break; case MSG_DO_SOME_WORK: doSomeWork(); break; case MSG_SEEK_TO: seekToInternal((SeekPosition) msg.obj); break; case MSG_SET_PLAYBACK_PARAMETERS: setPlaybackParametersInternal((PlaybackParameters) msg.obj); break; case MSG_SET_SEEK_PARAMETERS: setSeekParametersInternal((SeekParameters) msg.obj); break; case MSG_STOP:
private void enableRenderers(boolean[] rendererWasEnabledFlags, int totalEnabledRendererCount) throws ExoPlaybackException { enabledRenderers = new Renderer[totalEnabledRendererCount]; int enabledRendererCount = 0; MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); for (int i = 0; i < renderers.length; i++) { if (playingPeriodHolder.trackSelectorResult.isRendererEnabled(i)) { enableRenderer(i, rendererWasEnabledFlags[i], enabledRendererCount++); } } }
queue.setTimeline(timeline); playbackInfo = playbackInfo.copyWithTimeline(timeline, manifest); resolvePendingMessagePositions(); try { periodPosition = resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true); } catch (IllegalSeekPositionException e) { MediaPeriodId firstMediaPeriodId = handleSourceInfoRefreshEndedPlayback(); } else { Object periodUid = periodPosition.first; handleSourceInfoRefreshEndedPlayback(); } else { Pair<Object, Long> defaultPosition = getPeriodPosition( timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET); Object periodUid = defaultPosition.first; getPeriodPosition( timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET); Object periodUid = defaultPosition.first; Object newPeriodUid = resolveSubsequentPeriod(playingPeriodUid, oldTimeline, timeline); if (newPeriodUid == null) { handleSourceInfoRefreshEndedPlayback();
maybeUpdateLoadingPeriod(); MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod(); if (loadingPeriodHolder == null || loadingPeriodHolder.isFullyBuffered()) { setIsLoading(false); } else if (!playbackInfo.isLoading) { maybeContinueLoading(); maybeNotifyPlaybackInfoChanged(); MediaPeriodHolder oldPlayingPeriodHolder = playingPeriodHolder; playingPeriodHolder = queue.advancePlayingPeriod(); updatePlayingPeriodRenderers(oldPlayingPeriodHolder); playbackInfo = playbackInfo.copyWithNewPosition( playingPeriodHolder.info.startPositionUs, playingPeriodHolder.info.contentPositionUs, getTotalBufferedDurationUs()); playbackInfoUpdate.setPositionDiscontinuity(discontinuityReason); updatePlaybackPositions(); advancedPlayingPeriod = true; maybeThrowPeriodPrepareError(); return; Format[] formats = getFormats(newSelection); renderer.replaceStream(formats, readingPeriodHolder.sampleStreams[i], readingPeriodHolder.getRendererOffset());
private long seekToPeriodPosition( MediaPeriodId periodId, long periodPositionUs, boolean forceDisableRenderers) throws ExoPlaybackException { stopRenderers(); rebuffering = false; setState(Player.STATE_BUFFERING); disableRenderer(renderer); updatePlayingPeriodRenderers(oldPlayingPeriodHolder); if (newPlayingPeriodHolder.hasEnabledTracks) { periodPositionUs = newPlayingPeriodHolder.mediaPeriod.seekToUs(periodPositionUs); periodPositionUs - backBufferDurationUs, retainBackBufferFromKeyframe); resetRendererPosition(periodPositionUs); maybeContinueLoading(); } else { queue.clear(/* keepFrontPeriodUid= */ true); resetRendererPosition(periodPositionUs); handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false); handler.sendEmptyMessage(MSG_DO_SOME_WORK); return periodPositionUs;
periodPositionUs, playbackInfo.contentPositionUs, getTotalBufferedDurationUs()); playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL); resetRendererPosition(periodPositionUs); if (sampleStream != renderer.getStream()) { disableRenderer(renderer); } else if (streamResetFlags[i]) { playbackInfo.copyWithTrackInfo( playingPeriodHolder.trackGroups, playingPeriodHolder.trackSelectorResult); enableRenderers(rendererWasEnabledFlags, enabledRendererCount); } else { handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ true); if (playbackInfo.playbackState != Player.STATE_ENDED) { maybeContinueLoading(); updatePlaybackPositions(); handler.sendEmptyMessage(MSG_DO_SOME_WORK);
pendingPlaybackInfoUpdates = new ArrayDeque<>(); internalPlayer = new ExoPlayerImplInternal( renderers, trackSelector, this, clock); internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
@SuppressWarnings("ParameterNotNullable") private void updatePlayingPeriodRenderers(@Nullable MediaPeriodHolder oldPlayingPeriodHolder) throws ExoPlaybackException { MediaPeriodHolder newPlayingPeriodHolder = queue.getPlayingPeriod(); if (newPlayingPeriodHolder == null || oldPlayingPeriodHolder == newPlayingPeriodHolder) { return; } int enabledRendererCount = 0; boolean[] rendererWasEnabledFlags = new boolean[renderers.length]; for (int i = 0; i < renderers.length; i++) { Renderer renderer = renderers[i]; rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED; if (newPlayingPeriodHolder.trackSelectorResult.isRendererEnabled(i)) { enabledRendererCount++; } if (rendererWasEnabledFlags[i] && (!newPlayingPeriodHolder.trackSelectorResult.isRendererEnabled(i) || (renderer.isCurrentStreamFinal() && renderer.getStream() == oldPlayingPeriodHolder.sampleStreams[i]))) { // The renderer should be disabled before playing the next period, either because it's not // needed to play the next period, or because we need to re-enable it as its current stream // is final and it's not reading ahead. disableRenderer(renderer); } } playbackInfo = playbackInfo.copyWithTrackInfo( newPlayingPeriodHolder.trackGroups, newPlayingPeriodHolder.trackSelectorResult); enableRenderers(rendererWasEnabledFlags, enabledRendererCount); }
Object periodUid = resolveSubsequentPeriod(periodPosition.first, seekTimeline, timeline); if (periodUid != null) { return getPeriodPosition( timeline, timeline.getPeriod(periodIndex, period).windowIndex, C.TIME_UNSET);
for (Renderer renderer : enabledRenderers) { try { disableRenderer(renderer); } catch (ExoPlaybackException | RuntimeException e) { setIsLoading(false); if (resetPosition) { pendingInitialSeekPosition = null;
private void stopRenderers() throws ExoPlaybackException { mediaClock.stop(); for (Renderer renderer : enabledRenderers) { ensureStopped(renderer); } }
@Override public Looper getPlaybackLooper() { return internalPlayer.getPlaybackLooper(); }
private void enableRenderer( int rendererIndex, boolean wasRendererEnabled, int enabledRendererIndex) throws ExoPlaybackException { MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); Renderer renderer = renderers[rendererIndex]; enabledRenderers[enabledRendererIndex] = renderer; if (renderer.getState() == Renderer.STATE_DISABLED) { RendererConfiguration rendererConfiguration = playingPeriodHolder.trackSelectorResult.rendererConfigurations[rendererIndex]; TrackSelection newSelection = playingPeriodHolder.trackSelectorResult.selections.get( rendererIndex); Format[] formats = getFormats(newSelection); // The renderer needs enabling with its new track selection. boolean playing = playWhenReady && playbackInfo.playbackState == Player.STATE_READY; // Consider as joining only if the renderer was previously disabled. boolean joining = !wasRendererEnabled && playing; // Enable the renderer. renderer.enable(rendererConfiguration, formats, playingPeriodHolder.sampleStreams[rendererIndex], rendererPositionUs, joining, playingPeriodHolder.getRendererOffset()); mediaClock.onRendererEnabled(renderer); // Start the renderer if playing. if (playing) { renderer.start(); } } }
private void disableRenderer(Renderer renderer) throws ExoPlaybackException { mediaClock.onRendererDisabled(renderer); ensureStopped(renderer); renderer.disable(); }
private void sendMessageToTarget(PlayerMessage message) throws ExoPlaybackException { if (message.getHandler().getLooper() == handler.getLooper()) { deliverMessage(message); if (playbackInfo.playbackState == Player.STATE_READY || playbackInfo.playbackState == Player.STATE_BUFFERING) { // The message may have caused something to change that now requires us to do work. handler.sendEmptyMessage(MSG_DO_SOME_WORK); } } else { handler.obtainMessage(MSG_SEND_MESSAGE_TO_TARGET_THREAD, message).sendToTarget(); } }