Skip to content

Commit

Permalink
Handle preload callbacks asynchronously in PreloadMediaSource
Browse files Browse the repository at this point in the history
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: #1568

#cherrypick

PiperOrigin-RevId: 662550622
  • Loading branch information
tianyif authored and copybara-github committed Aug 13, 2024
1 parent 0b23285 commit cd532c5
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 63 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
zero.
* Allow the user to select the built-in speaker for playback on Wear OS
API 35+ (where the device advertises support for this).
* Handle preload callbacks asynchronously in `PreloadMediaSource`
([#1568](https://github.com/androidx/media/issues/1568)).
* Transformer:
* Add `SurfaceAssetLoader`, which supports queueing video data to
Transformer via a `Surface`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,26 +306,29 @@ protected void prepareSourceInternal() {
protected void onChildSourceInfoRefreshed(Timeline newTimeline) {
this.timeline = newTimeline;
refreshSourceInfo(newTimeline);
if (isUsedByPlayer() || onSourcePreparedNotified) {
return;
}
onSourcePreparedNotified = true;
if (!preloadControl.onSourcePrepared(this)) {
stopPreloading();
return;
}
Pair<Object, Long> periodPosition =
newTimeline.getPeriodPositionUs(
new Timeline.Window(),
new Timeline.Period(),
/* windowIndex= */ 0,
/* windowPositionUs= */ startPositionUs);
MediaPeriodId mediaPeriodId = new MediaPeriodId(periodPosition.first);
PreloadMediaPeriod mediaPeriod =
PreloadMediaSource.this.createPeriod(mediaPeriodId, allocator, periodPosition.second);
mediaPeriod.preload(
new PreloadMediaPeriodCallback(periodPosition.second),
/* positionUs= */ periodPosition.second);
preloadHandler.post(
() -> {
if (isUsedByPlayer() || onSourcePreparedNotified) {
return;
}
onSourcePreparedNotified = true;
if (!preloadControl.onSourcePrepared(this)) {
stopPreloading();
return;
}
Pair<Object, Long> periodPosition =
newTimeline.getPeriodPositionUs(
new Timeline.Window(),
new Timeline.Period(),
/* windowIndex= */ 0,
/* windowPositionUs= */ startPositionUs);
MediaPeriodId mediaPeriodId = new MediaPeriodId(periodPosition.first);
PreloadMediaPeriod mediaPeriod =
PreloadMediaSource.this.createPeriod(mediaPeriodId, allocator, periodPosition.second);
mediaPeriod.preload(
new PreloadMediaPeriodCallback(periodPosition.second),
/* positionUs= */ periodPosition.second);
});
}

@Override
Expand Down Expand Up @@ -455,53 +458,59 @@ public PreloadMediaPeriodCallback(long periodStartPositionUs) {
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
prepared = true;
if (isUsedByPlayer()) {
return;
}
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
TrackGroupArray trackGroups = preloadMediaPeriod.getTrackGroups();
@Nullable TrackSelectorResult trackSelectorResult = null;
MediaPeriodKey key = checkNotNull(preloadingMediaPeriodAndKey).second;
try {
trackSelectorResult =
trackSelector.selectTracks(
rendererCapabilities, trackGroups, key.mediaPeriodId, checkNotNull(timeline));
} catch (ExoPlaybackException e) {
Log.e(TAG, "Failed to select tracks", e);
}
if (trackSelectorResult == null) {
stopPreloading();
return;
}
preloadMediaPeriod.selectTracksForPreloading(
trackSelectorResult.selections, periodStartPositionUs);
if (!preloadControl.onTracksSelected(PreloadMediaSource.this)) {
stopPreloading();
return;
}
preloadMediaPeriod.continueLoading(
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
preloadHandler.post(
() -> {
if (isUsedByPlayer()) {
return;
}
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
TrackGroupArray trackGroups = preloadMediaPeriod.getTrackGroups();
@Nullable TrackSelectorResult trackSelectorResult = null;
MediaPeriodKey key = checkNotNull(preloadingMediaPeriodAndKey).second;
try {
trackSelectorResult =
trackSelector.selectTracks(
rendererCapabilities, trackGroups, key.mediaPeriodId, checkNotNull(timeline));
} catch (ExoPlaybackException e) {
Log.e(TAG, "Failed to select tracks", e);
}
if (trackSelectorResult == null) {
stopPreloading();
return;
}
preloadMediaPeriod.selectTracksForPreloading(
trackSelectorResult.selections, periodStartPositionUs);
if (!preloadControl.onTracksSelected(PreloadMediaSource.this)) {
stopPreloading();
return;
}
preloadMediaPeriod.continueLoading(
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
});
}

@Override
public void onContinueLoadingRequested(MediaPeriod mediaPeriod) {
if (isUsedByPlayer()) {
return;
}
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
stopPreloading();
return;
}
if (prepared
&& !preloadControl.onContinueLoadingRequested(
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
stopPreloading();
return;
}
preloadMediaPeriod.continueLoading(
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
preloadHandler.post(
() -> {
if (isUsedByPlayer()) {
return;
}
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
stopPreloading();
return;
}
if (prepared
&& !preloadControl.onContinueLoadingRequested(
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
stopPreloading();
return;
}
preloadMediaPeriod.continueLoading(
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
});
}
}

Expand Down

0 comments on commit cd532c5

Please sign in to comment.