Skip to main content

Look-ahead cache

Proactively prefetches upcoming streamed tracks to disk so they start instantly and survive brief network drops. It applies to http(s):// sources only — file:// (local) tracks are already on disk and are skipped.

Methods live on the TrackPlayer singleton:

import { getTrackPlayer } from 'react-native-queue-player';

const player = getTrackPlayer();

// Disk budget + eviction policy are configure-time (fixed at cache
// construction), not runtime controls. Set them once at app init alongside your
// other config; changing either later means calling configure() again (a full
// player reinit) with your complete config.
await player.configure({
// ...your other PlayerConfig (httpHeaders, userAgent, ...)
lookaheadCacheMaxSizeMb: 200, // disk budget; default 100 MB
lookaheadCacheEvictionPolicy: 'lru', // 'lru' (default) or 'fifo'
});

// Runtime controls: enable/disable + how many tracks to prefetch. These apply
// live, no configure() cycle needed.
await player.setLookaheadCache({
enabled: true,
lookaheadCount: 3, // prefetch the next N tracks
allowsCellularAccess: true, // default; false backs a "Wi-Fi only" setting
});

:::note Protecting the playing track Eviction runs on every download commit, so the entry backing the track being played can otherwise be deleted mid-playback. iOS protects the playing track and its neighbours under both eviction policies. Android protects them under 'fifo' only — Media3's LRU evictor has no protected-key concept, and its recency bump is per byte-range span rather than per track.

Where the playing track is protected, lookaheadCacheMaxSizeMb behaves as a budget rather than a hard cap: if the protected tracks alone exceed it, nothing is evictable and currentSizeMb can read above maxSizeMb until the window moves. :::

Methods​

setLookaheadCache(config: LookaheadCacheConfig): Promise<void>
getLookaheadCacheStatus(): Promise<CacheStatus>
clearLookaheadCache(): Promise<void> // wipes + stops; does not auto-restart prefetch
onCacheStatusChange(callback: (status: CacheStatus) => void): () => void // fires once on subscribe with current status

Types​

type LookaheadCacheConfig = {
enabled: boolean; // disabled: every read goes to the origin, nothing is written
lookaheadCount: number; // prefetch the next N tracks
allowsCellularAccess?: boolean; // default true
};

// allowsCellularAccess — prefetch downloads whole upcoming tracks, so on a
// metered connection it can spend a lot of data on tracks the listener skips
// past. Set false to back a "download over Wi-Fi only" setting. It is a runtime
// control like the two above, so a settings toggle can flip it without a
// configure() cycle. It gates prefetch only — playback is never blocked by it.

// Disk budget + eviction policy live on PlayerConfig (configure-time only):
// configure({ lookaheadCacheMaxSizeMb?: number,
// lookaheadCacheEvictionPolicy?: 'lru' | 'fifo' })
// Both are fixed at cache construction (Android's SimpleCache can't resize or
// swap its evictor live); read the active ceiling back from CacheStatus.maxSizeMb.
//
// Eviction policy — default 'lru'. Changing it clears the cache and rebuilds:
// 'lru' evicts the least-recently-used track first (recently played tracks
// are kept).
// 'fifo' evicts the oldest-fetched track first, regardless of replays
// ("keep the newest-fetched"); suits a forward-only prefetch queue.

type CacheStatus = {
enabled: boolean;
currentSizeMb: number; // current disk usage
maxSizeMb: number; // the configured budget
tracksFullyCached: number; // total tracks fully downloaded on disk
currentlyCaching: string[]; // URLs downloading right now
};

:::note How allowsCellularAccess is enforced The two platforms offer different primitives, so the enforcement point differs:

  • iOS sets the flag on each prefetch request and the OS refuses to run that request over cellular. A download already on the wire keeps the value it started with and runs to completion.
  • Android has no per-request equivalent, so prefetch stops being scheduled while the default network is cellular. That also cancels the download in flight; its partial data stays in the cache and resumes once prefetch is permitted again.

So a prefetch issued while it is false never crosses a cellular link on either platform; a download that was already in flight when the value changed finishes on iOS and is cancelled on Android. Playback is unaffected on both. :::

In React, see useLookaheadCache.