Skip to content

DefaultPreloadManager queue stalls on specifiedRangeCached items that are consumed before download completes #3458

Open

Description

@akhilesh-dubey

Version

Media3 1.10.1

More version details

Media3 1.10.1

Devices that reproduce the issue

All

Devices that do not reproduce the issue

N/A

Reproducible in the demo app?

Yes

Reproduction steps

  • Build a vertical-feed app with DefaultPreloadManager and TargetPreloadStatusControl returning PreloadStatus.specifiedRangeCached(0, 5000) for items at rank ≥ 1.
  • Register ~5 items with ranks 0..4 and call invalidate().
  • Immediately getMediaSource(itemAtRank1) and start playback on it (consume) before rank 0 reaches 100% download.

Expected result

The preload queue advances past the consumed/stalled item and starts preloading ranks 2, 3, 4.

Actual result

getTargetPreloadStatus(rankingData) is never called for ranks 2, 3, 4. The queue stays stuck on the earlier item whose PreCacheHelper download never reports 100%. Subsequent invalidate() calls do not help because the priority list restarts from the same stuck index.

Media

DefaultPreloadManager iterates its priority list strictly one source at a time: BasePreloadManager.invalidate() kicks off a single preload, and the queue advances to the next-ranked item only when onCompleted / onSkipped / onError fires on the currently preloading source.

For PreloadStatus.specifiedRangeLoaded(...), PreloadMediaSourceControl has three paths that advance the queue:

  • onContinueLoadingRequested → onCompleted once bufferedDurationUs >= durationMs
  • onLoadedToTheEndOfSource → onCompleted
  • onUsedByPlayer → onSkipped when the main player attaches to the preloaded MediaSource

For PreloadStatus.specifiedRangeCached(...), there is only one path:

  • PreCacheHelper.Listener.onDownloadProgress(..., percentageDownloaded == 100f) → onCompleted

There is no onUsedByPlayer equivalent for pre-cached items. On consume, onPrepared constructs a fresh MediaSource via preloadMediaSourceFactory.createMediaSource(updatedMediaItem) rather than attaching to the one being pre-cached, so the PreCacheHelper for the original MediaItem keeps running in the background and never reaches 100% in the user-visible timeline.

Result: when the user navigates past a specifiedRangeCached item before its download completes (common in short-form video / vertical feed UX), maybeAdvanceToNextMediaSourceHolder() is never called, and every lower-ranked source in the priority list stays unpreloaded indefinitely — even across subsequent invalidate() calls, since indexForSourceHolderToPreload is pinned to the stuck item.

Suggested fix
In DefaultPreloadManager hook PreloadMediaSource.PreloadControl.onUsedByPlayer(mediaSource) (or the matching PreCacheHelper lifecycle) to call onSkipped for the corresponding pre-cached MediaItem so the queue can advance. Alternatively, give PreCacheHelper an explicit "consumed/cancelled" terminal signal that DefaultPreloadManager can translate to onSkipped.

Bug Report

Activity

  1. tonihei commented on Oct 12, 2026

    @tonihei
    Collaborator

    @tianyif Could you take a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions