ABR and Bandwidth
Three methods that expose throughput estimation and decode-capability probing.
bandwidth()
bandwidth(): number
Last-known throughput estimate in bits per second.
Returns 0 until an active stream source reports a measurement (the player core itself does not drive estimation, the value comes from the active backend or a consumer-supplied estimator).
const bps = player.bandwidth();
const kbps = Math.round(bps / 1000);
console.log(`Estimated bandwidth: ${kbps} kbps`);
The value is updated by the active stream source whenever it completes a segment download.
On networks where the backend does not report throughput (native <audio> or <video> without HLS), bandwidth() remains 0.
bandwidthEstimator()
bandwidthEstimator(): (() => number) | undefined
bandwidthEstimator(fn: () => number): void
Read or replace the bandwidth estimator function.
Reading returns the currently wired estimator (or undefined if none is set).
Writing installs a custom estimator. The active stream source calls the function on every ABR level decision. Install your own estimator when you have out-of-band signal (SignalR quality report, server-sent bitrate hint) that is more accurate than the default download-speed measurement.
player.bandwidthEstimator(() => {
return myQualitySignal.getRecommendedBitsPerSecond();
});
const estimator = player.bandwidthEstimator();
console.log(typeof estimator); // 'function'
The estimator is called synchronously on the ABR decision path, so keep it fast.
canPlay()
canPlay(profile: {
contentType: string;
width?: number;
height?: number;
bitrate?: number;
framerate?: number;
}): Promise<CanPlayResult>
Probes whether the browser can decode a specific media profile smoothly.
Delegates to the platform adapter’s capabilities.canDecode bridge, which wraps the standard MediaCapabilities.decodingInfo() API.
const result = await player.canPlay({
contentType: 'video/mp4; codecs="avc1.64001f, mp4a.40.2"',
width: 1920,
height: 1080,
bitrate: 8_000_000, // 8 Mbps
framerate: 30,
});
if (result.supported && result.smooth) {
player.quality(targetIndex); // safe to lock this level
}
CanPlayResult
interface CanPlayResult {
supported: boolean; // browser can decode this codec/container
smooth: boolean; // browser can decode without dropped frames
powerEfficient: boolean; // browser can decode without excessive battery drain
}
supported: false means the codec is not supported, so do not select this quality level.
supported: true, smooth: false means the level is playable but the browser may drop frames under load, so use it as a last resort only.
powerEfficient: false is typically seen on mobile devices with high-bitrate streams that the CPU decodes in software rather than through the hardware decoder pipeline.
It is informational, and smooth: true takes precedence for quality selection.
Using canPlay for quality filtering
Before rendering a quality picker, filter out levels the browser cannot handle:
const levels = player.qualityLevels();
const probes = await Promise.all(
levels.map((level) =>
player.canPlay({
contentType: 'application/vnd.apple.mpegurl',
width: level.width,
height: level.height,
bitrate: level.bitrate,
framerate: 30,
}),
),
);
const supportedLevels = levels.filter((_, index) => {
return probes[index].supported && probes[index].smooth;
});
For HLS streams, the video player’s HDR-aware ABR logic does this filtering automatically, using canPlay internally to exclude HDR levels on SDR displays.
Calling canPlay manually is only needed when building a custom quality UI that must pre-filter the level list.
See also
- Media Tracks:
qualityLevels()andquality() - Player State:
qualityMode()for the ABR/MANUAL mode flag - Metrics:
avgBitrateinPlaybackMetrics - Platform: the
capabilities.canDecodeplatform port