diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6e21b74398..ecf43f8c54 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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`. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/PreloadMediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/PreloadMediaSource.java index 934b4646f2..2bc72c003c 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/PreloadMediaSource.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/PreloadMediaSource.java @@ -306,26 +306,29 @@ public final class PreloadMediaSource extends WrappingMediaSource { protected void onChildSourceInfoRefreshed(Timeline newTimeline) { this.timeline = newTimeline; refreshSourceInfo(newTimeline); - if (isUsedByPlayer() || onSourcePreparedNotified) { - return; - } - onSourcePreparedNotified = true; - if (!preloadControl.onSourcePrepared(this)) { - stopPreloading(); - return; - } - Pair 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 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 @@ -455,53 +458,59 @@ public final class PreloadMediaSource extends WrappingMediaSource { @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()); + }); } }