use of com.google.android.exoplayer2.LoadControl in project Signal-Android by signalapp.
the class VideoPlayer method setExoViewSource.
private void setExoViewSource(@NonNull VideoSlide videoSource, boolean autoplay) throws IOException {
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
exoPlayer = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, loadControl);
exoPlayer.addListener(new ExoPlayerListener(window));
// noinspection ConstantConditions
exoView.setPlayer(exoPlayer);
DefaultDataSourceFactory defaultDataSourceFactory = new DefaultDataSourceFactory(getContext(), "GenericUserAgent", null);
AttachmentDataSourceFactory attachmentDataSourceFactory = new AttachmentDataSourceFactory(getContext(), defaultDataSourceFactory, null);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(videoSource.getUri(), attachmentDataSourceFactory, extractorsFactory, null, null);
exoPlayer.prepare(mediaSource);
exoPlayer.setPlayWhenReady(autoplay);
}
use of com.google.android.exoplayer2.LoadControl in project NewPipe by TeamNewPipe.
the class BasePlayer method initPlayer.
public void initPlayer() {
if (DEBUG)
Log.d(TAG, "initPlayer() called with: context = [" + context + "]");
if (databaseUpdateReactor != null)
databaseUpdateReactor.dispose();
databaseUpdateReactor = new CompositeDisposable();
final String userAgent = Downloader.USER_AGENT;
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
final AdaptiveTrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
trackSelector = new CustomTrackSelector(trackSelectionFactory);
final LoadControl loadControl = new LoadController(context);
final RenderersFactory renderFactory = new DefaultRenderersFactory(context);
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderFactory, trackSelector, loadControl);
simpleExoPlayer.addListener(this);
simpleExoPlayer.setPlayWhenReady(true);
simpleExoPlayer.setSeekParameters(PlayerHelper.getSeekParameters(context));
audioReactor = new AudioReactor(context, simpleExoPlayer);
mediaSessionManager = new MediaSessionManager(context, simpleExoPlayer, new BasePlayerMediaSession(this));
}
use of com.google.android.exoplayer2.LoadControl 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();
}
use of com.google.android.exoplayer2.LoadControl in project ExoPlayer by google.
the class ExoPlayerTest method loadControlNeverWantsToLoad_throwsIllegalStateException.
@Test
public void loadControlNeverWantsToLoad_throwsIllegalStateException() {
LoadControl neverLoadingLoadControl = new DefaultLoadControl() {
@Override
public boolean shouldContinueLoading(long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) {
return false;
}
@Override
public boolean shouldStartPlayback(long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
return true;
}
};
// Use chunked data to ensure the player actually needs to continue loading and playing.
FakeAdaptiveDataSet.Factory dataSetFactory = new FakeAdaptiveDataSet.Factory(/* chunkDurationUs= */
500_000, /* bitratePercentStdDev= */
10.0, new Random(0));
MediaSource chunkedMediaSource = new FakeAdaptiveMediaSource(new FakeTimeline(), new TrackGroupArray(new TrackGroup(ExoPlayerTestRunner.VIDEO_FORMAT)), new FakeChunkSource.Factory(dataSetFactory, new FakeDataSource.Factory()));
ExoPlaybackException exception = assertThrows(ExoPlaybackException.class, () -> new ExoPlayerTestRunner.Builder(context).setLoadControl(neverLoadingLoadControl).setMediaSources(chunkedMediaSource).build().start().blockUntilEnded(TIMEOUT_MS));
assertThat(exception.type).isEqualTo(ExoPlaybackException.TYPE_UNEXPECTED);
assertThat(exception.getUnexpectedException()).isInstanceOf(IllegalStateException.class);
}
use of com.google.android.exoplayer2.LoadControl in project ExoPlayer by google.
the class ExoPlayerTest method nextLoadPositionExceedingLoadControlMaxBuffer_whileCurrentLoadInProgress_doesNotThrowException.
@Test
public void nextLoadPositionExceedingLoadControlMaxBuffer_whileCurrentLoadInProgress_doesNotThrowException() throws Exception {
long maxBufferUs = 2 * C.MICROS_PER_SECOND;
LoadControl loadControlWithMaxBufferUs = new DefaultLoadControl() {
@Override
public boolean shouldContinueLoading(long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) {
return bufferedDurationUs < maxBufferUs;
}
@Override
public boolean shouldStartPlayback(long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
return true;
}
};
MediaSource mediaSourceWithLoadInProgress = new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT) {
@Override
protected MediaPeriod createMediaPeriod(MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator, MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher, DrmSessionManager drmSessionManager, DrmSessionEventListener.EventDispatcher drmEventDispatcher, @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, allocator, TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US, mediaSourceEventDispatcher) {
@Override
public long getBufferedPositionUs() {
// Pretend not to have buffered data yet.
return 0;
}
@Override
public long getNextLoadPositionUs() {
// Set next load position beyond the maxBufferUs configured in the LoadControl.
return Long.MAX_VALUE;
}
@Override
public boolean isLoading() {
return true;
}
};
}
};
FakeRenderer rendererWaitingForData = new FakeRenderer(C.TRACK_TYPE_VIDEO) {
@Override
public boolean isReady() {
return false;
}
};
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(rendererWaitingForData).setLoadControl(loadControlWithMaxBufferUs).build();
player.setMediaSource(mediaSourceWithLoadInProgress);
player.prepare();
// Wait until the MediaSource is prepared, i.e. returned its timeline, and at least one
// iteration of doSomeWork after this was run.
TestPlayerRunHelper.runUntilTimelineChanged(player);
runUntilPendingCommandsAreFullyHandled(player);
assertThat(player.getPlayerError()).isNull();
}
Aggregations