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

PiperOrigin-RevId: 662550622
(cherry picked from commit cd532c5fb2)
This commit is contained in:
tianyifeng 2024-08-13 09:43:07 -07:00 committed by Tianyi Feng
parent 07e9c659d7
commit f139d709c7
2 changed files with 64 additions and 53 deletions

View file

@ -4,6 +4,8 @@
* Common Library: * Common Library:
* ExoPlayer: * ExoPlayer:
* Handle preload callbacks asynchronously in `PreloadMediaSource`
([#1568](https://github.com/androidx/media/issues/1568)).
* Transformer: * Transformer:
* Track Selection: * Track Selection:
* Extractors: * Extractors:

View file

@ -293,6 +293,8 @@ public final class PreloadMediaSource extends WrappingMediaSource {
protected void onChildSourceInfoRefreshed(Timeline newTimeline) { protected void onChildSourceInfoRefreshed(Timeline newTimeline) {
this.timeline = newTimeline; this.timeline = newTimeline;
refreshSourceInfo(newTimeline); refreshSourceInfo(newTimeline);
preloadHandler.post(
() -> {
if (isUsedByPlayer() || onSourcePreparedNotified) { if (isUsedByPlayer() || onSourcePreparedNotified) {
return; return;
} }
@ -312,6 +314,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
mediaPeriod.preload( mediaPeriod.preload(
new PreloadMediaPeriodCallback(periodPosition.second), new PreloadMediaPeriodCallback(periodPosition.second),
/* positionUs= */ periodPosition.second); /* positionUs= */ periodPosition.second);
});
} }
@Override @Override
@ -405,6 +408,8 @@ public final class PreloadMediaSource extends WrappingMediaSource {
@Override @Override
public void onPrepared(MediaPeriod mediaPeriod) { public void onPrepared(MediaPeriod mediaPeriod) {
prepared = true; prepared = true;
preloadHandler.post(
() -> {
if (isUsedByPlayer()) { if (isUsedByPlayer()) {
return; return;
} }
@ -427,10 +432,13 @@ public final class PreloadMediaSource extends WrappingMediaSource {
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build()); new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
} }
} }
});
} }
@Override @Override
public void onContinueLoadingRequested(MediaPeriod mediaPeriod) { public void onContinueLoadingRequested(MediaPeriod mediaPeriod) {
preloadHandler.post(
() -> {
if (isUsedByPlayer()) { if (isUsedByPlayer()) {
return; return;
} }
@ -443,6 +451,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
preloadMediaPeriod.continueLoading( preloadMediaPeriod.continueLoading(
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build()); new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
} }
});
} }
} }