Skip to content

Commit cd532c5

Browse files
tianyifcopybara-github
authored andcommitted
Handle preload callbacks asynchronously in PreloadMediaSource
When there is an exception thrown from the `LoadTask`, the `Loader` will call `Loader.Callback.onLoadError`. Some implementations of `onLoadError` method may call `MediaPeriod.onContinueLoadingRequested`, and in the `PreloadMediaSource`, its `PreloadMediaPeriodCallback` will be triggered and then it can further call `continueLoading` if it finds needed. However the above process is currently done synchronously, which will cause problem. By calling `continueLoading`, the `Loader` is set with a `currentTask`, and when that long sync logic in `Loader.Callback.onLoadError` ends, the `Loader` will immediately retry, and then a non-null `currentTask` will cause the `IllegalStateException`. Issue: androidx/media#1568 #cherrypick PiperOrigin-RevId: 662550622
1 parent 0b23285 commit cd532c5

File tree

2 files changed

+74
-63
lines changed

2 files changed

+74
-63
lines changed

RELEASENOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
zero.
3333
* Allow the user to select the built-in speaker for playback on Wear OS
3434
API 35+ (where the device advertises support for this).
35+
* Handle preload callbacks asynchronously in `PreloadMediaSource`
36+
([#1568](https://github.com/androidx/media/issues/1568)).
3537
* Transformer:
3638
* Add `SurfaceAssetLoader`, which supports queueing video data to
3739
Transformer via a `Surface`.

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/PreloadMediaSource.java

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -306,26 +306,29 @@ protected void prepareSourceInternal() {
306306
protected void onChildSourceInfoRefreshed(Timeline newTimeline) {
307307
this.timeline = newTimeline;
308308
refreshSourceInfo(newTimeline);
309-
if (isUsedByPlayer() || onSourcePreparedNotified) {
310-
return;
311-
}
312-
onSourcePreparedNotified = true;
313-
if (!preloadControl.onSourcePrepared(this)) {
314-
stopPreloading();
315-
return;
316-
}
317-
Pair<Object, Long> periodPosition =
318-
newTimeline.getPeriodPositionUs(
319-
new Timeline.Window(),
320-
new Timeline.Period(),
321-
/* windowIndex= */ 0,
322-
/* windowPositionUs= */ startPositionUs);
323-
MediaPeriodId mediaPeriodId = new MediaPeriodId(periodPosition.first);
324-
PreloadMediaPeriod mediaPeriod =
325-
PreloadMediaSource.this.createPeriod(mediaPeriodId, allocator, periodPosition.second);
326-
mediaPeriod.preload(
327-
new PreloadMediaPeriodCallback(periodPosition.second),
328-
/* positionUs= */ periodPosition.second);
309+
preloadHandler.post(
310+
() -> {
311+
if (isUsedByPlayer() || onSourcePreparedNotified) {
312+
return;
313+
}
314+
onSourcePreparedNotified = true;
315+
if (!preloadControl.onSourcePrepared(this)) {
316+
stopPreloading();
317+
return;
318+
}
319+
Pair<Object, Long> periodPosition =
320+
newTimeline.getPeriodPositionUs(
321+
new Timeline.Window(),
322+
new Timeline.Period(),
323+
/* windowIndex= */ 0,
324+
/* windowPositionUs= */ startPositionUs);
325+
MediaPeriodId mediaPeriodId = new MediaPeriodId(periodPosition.first);
326+
PreloadMediaPeriod mediaPeriod =
327+
PreloadMediaSource.this.createPeriod(mediaPeriodId, allocator, periodPosition.second);
328+
mediaPeriod.preload(
329+
new PreloadMediaPeriodCallback(periodPosition.second),
330+
/* positionUs= */ periodPosition.second);
331+
});
329332
}
330333

331334
@Override
@@ -455,53 +458,59 @@ public PreloadMediaPeriodCallback(long periodStartPositionUs) {
455458
@Override
456459
public void onPrepared(MediaPeriod mediaPeriod) {
457460
prepared = true;
458-
if (isUsedByPlayer()) {
459-
return;
460-
}
461-
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
462-
TrackGroupArray trackGroups = preloadMediaPeriod.getTrackGroups();
463-
@Nullable TrackSelectorResult trackSelectorResult = null;
464-
MediaPeriodKey key = checkNotNull(preloadingMediaPeriodAndKey).second;
465-
try {
466-
trackSelectorResult =
467-
trackSelector.selectTracks(
468-
rendererCapabilities, trackGroups, key.mediaPeriodId, checkNotNull(timeline));
469-
} catch (ExoPlaybackException e) {
470-
Log.e(TAG, "Failed to select tracks", e);
471-
}
472-
if (trackSelectorResult == null) {
473-
stopPreloading();
474-
return;
475-
}
476-
preloadMediaPeriod.selectTracksForPreloading(
477-
trackSelectorResult.selections, periodStartPositionUs);
478-
if (!preloadControl.onTracksSelected(PreloadMediaSource.this)) {
479-
stopPreloading();
480-
return;
481-
}
482-
preloadMediaPeriod.continueLoading(
483-
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
461+
preloadHandler.post(
462+
() -> {
463+
if (isUsedByPlayer()) {
464+
return;
465+
}
466+
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
467+
TrackGroupArray trackGroups = preloadMediaPeriod.getTrackGroups();
468+
@Nullable TrackSelectorResult trackSelectorResult = null;
469+
MediaPeriodKey key = checkNotNull(preloadingMediaPeriodAndKey).second;
470+
try {
471+
trackSelectorResult =
472+
trackSelector.selectTracks(
473+
rendererCapabilities, trackGroups, key.mediaPeriodId, checkNotNull(timeline));
474+
} catch (ExoPlaybackException e) {
475+
Log.e(TAG, "Failed to select tracks", e);
476+
}
477+
if (trackSelectorResult == null) {
478+
stopPreloading();
479+
return;
480+
}
481+
preloadMediaPeriod.selectTracksForPreloading(
482+
trackSelectorResult.selections, periodStartPositionUs);
483+
if (!preloadControl.onTracksSelected(PreloadMediaSource.this)) {
484+
stopPreloading();
485+
return;
486+
}
487+
preloadMediaPeriod.continueLoading(
488+
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
489+
});
484490
}
485491

486492
@Override
487493
public void onContinueLoadingRequested(MediaPeriod mediaPeriod) {
488-
if (isUsedByPlayer()) {
489-
return;
490-
}
491-
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
492-
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
493-
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
494-
stopPreloading();
495-
return;
496-
}
497-
if (prepared
498-
&& !preloadControl.onContinueLoadingRequested(
499-
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
500-
stopPreloading();
501-
return;
502-
}
503-
preloadMediaPeriod.continueLoading(
504-
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
494+
preloadHandler.post(
495+
() -> {
496+
if (isUsedByPlayer()) {
497+
return;
498+
}
499+
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
500+
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
501+
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
502+
stopPreloading();
503+
return;
504+
}
505+
if (prepared
506+
&& !preloadControl.onContinueLoadingRequested(
507+
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
508+
stopPreloading();
509+
return;
510+
}
511+
preloadMediaPeriod.continueLoading(
512+
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
513+
});
505514
}
506515
}
507516

0 commit comments

Comments
 (0)