HLS.js provides an extensible architecture with advanced controllers, utilities, and customization options for complex use cases.
Advanced controllers for specialized functionality.
// Adaptive Bitrate Controller
class AbrController {
/**
* Reset bandwidth estimator with optional default estimate
* @param abrEwmaDefaultEstimate - Default bandwidth estimate in bps
*/
resetEstimator(abrEwmaDefaultEstimate?: number): void;
}
// Buffer Controller
class BufferController {
// Manages MediaSource and SourceBuffer operations
}
// Capability Level Controller
class CapLevelController {
// Caps quality based on player dimensions and performance
}
// Common Media Client Data Controller
class CMCDController {
// Provides CMCD headers for analytics and optimization
}
// Content Steering Controller
class ContentSteeringController {
// Handles CDN steering and failover
}
// Encrypted Media Extensions Controller
class EMEController {
// Manages DRM and encrypted content
}
// Error Controller
class ErrorController {
// Handles error recovery and retry logic
}
// Frames Per Second Controller
class FPSController {
// Monitors frame drops and caps quality accordingly
}
// Timeline Controller
class TimelineController {
// Manages timeline metadata and ID3 tags
}
// Interstitials Controller (for ads and mid-rolls)
class InterstitialsController {
// Manages interstitial content scheduling and playback
}
// Subtitle Stream Controller
class SubtitleStreamController {
// Handles subtitle fragment loading and parsing
}
// Base Controllers (for extension)
class BasePlaylistController {
// Base class for playlist controllers
}
class BaseStreamController {
// Base class for stream controllers
}Pluggable loaders for different transport mechanisms.
/**
* XMLHttpRequest-based loader
*/
class XhrLoader {
constructor(config: HlsConfig);
destroy(): void;
abort(): void;
load(
context: LoaderContext,
config: LoaderConfig,
callbacks: LoaderCallbacks<LoaderContext>
): void;
}
/**
* Fetch API-based loader
*/
class FetchLoader {
constructor(config: HlsConfig);
destroy(): void;
abort(): void;
load(
context: LoaderContext,
config: LoaderConfig,
callbacks: LoaderCallbacks<LoaderContext>
): void;
}
/**
* Check if Fetch API is supported
* @returns true if fetch is available
*/
function fetchSupported(): boolean;Usage Examples:
import { XhrLoader, FetchLoader, fetchSupported } from "hls.js";
// Custom loader configuration
const hls = new Hls({
loader: fetchSupported() ? FetchLoader : XhrLoader,
// Loader-specific configuration
xhrSetup: (xhr, url) => {
// Customize XHR requests
xhr.setRequestHeader("Custom-Header", "value");
},
fetchSetup: (context, initParams) => {
// Customize Fetch requests
return new Request(context.url, {
...initParams,
headers: {
...initParams.headers,
"Custom-Header": "value"
}
});
}
});Parse and manipulate HLS manifests.
/**
* M3U8 playlist parser
*/
class M3U8Parser {
static findGroup(
groups: MediaPlaylist[],
mediaGroupId: string
): MediaPlaylist | undefined;
static parseMasterPlaylist(
string: string,
baseurl: string
): ParsedMasterPlaylist;
static parseMasterPlaylistMedia(
string: string,
baseurl: string,
type: string,
audioCodecs?: string[]
): MediaPlaylist[];
static parseMediaPlaylist(
string: string,
baseurl: string,
id: number,
type: PlaylistLevelType,
levelUrlId: number
): LevelDetails;
}Usage Example:
import { M3U8Parser } from "hls.js";
// Parse custom manifest
const manifestText = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360
low.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720
high.m3u8`;
const parsed = M3U8Parser.parseMasterPlaylist(manifestText, "https://example.com/");
console.log("Parsed levels:", parsed.levels);Various utility classes and functions.
/**
* VTT cue management utility
*/
class Cues {
static newCue(
track: TextTrack,
startTime: number,
endTime: number,
captionScreen: any
): VTTCue[];
}
/**
* HLS attribute list parser
*/
class AttrList {
constructor(attrs: string);
decimalInteger(attrName: string): number;
hexadecimalInteger(attrName: string): Uint8Array;
decimalFloatingPoint(attrName: string): number;
optionalFloat(attrName: string, defaultValue: number): number;
enumeratedString(attrName: string): string | undefined;
bool(attrName: string): boolean;
decimalResolution(attrName: string): { width: number; height: number } | undefined;
}
/**
* DRM/EME utility functions
*/
function requestMediaKeySystemAccess(
keySystem: string,
supportedConfigurations: MediaKeySystemConfiguration[]
): Promise<MediaKeySystemAccess>;
/**
* Key systems and formats for DRM
*/
interface KeySystems {
WIDEVINE: string;
PLAYREADY: string;
FAIRPLAY: string;
CLEARKEY: string;
}
interface KeySystemFormats {
[keySystem: string]: string;
}Usage Examples:
import { Cues, AttrList, requestMediaKeySystemAccess, KeySystems } from "hls.js";
// Create VTT cues
const textTrack = video.addTextTrack("subtitles", "English", "en");
const cues = Cues.newCue(textTrack, 0, 10, captionData);
// Parse HLS attributes
const attrs = new AttrList('BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.42e01e,mp4a.40.2"');
console.log("Bandwidth:", attrs.decimalInteger("BANDWIDTH"));
console.log("Resolution:", attrs.decimalResolution("RESOLUTION"));
// DRM key system access
try {
const keySystemAccess = await requestMediaKeySystemAccess(
KeySystems.WIDEVINE,
[{
initDataTypes: ['cenc'],
audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}],
videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}]
}]
);
console.log("Widevine supported:", keySystemAccess.keySystem);
} catch (error) {
console.error("DRM not supported:", error);
}
console.log("Codecs:", attrs.enumeratedString("CODECS"));DRM and encrypted media utilities.
/**
* DRM system identifiers
*/
enum KeySystems {
CLEARKEY = "org.w3.clearkey",
FAIRPLAY = "com.apple.fps",
PLAYREADY = "com.microsoft.playready",
WIDEVINE = "com.widevine.alpha"
}
/**
* Key system format identifiers for HLS
*/
enum KeySystemFormats {
CLEARKEY = "org.w3.clearkey",
FAIRPLAY = "com.apple.streamingkeydelivery",
PLAYREADY = "com.microsoft.playready",
WIDEVINE = "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
}
/**
* Request media key system access
*/
type MediaKeyFunc = typeof navigator.requestMediaKeySystemAccess;
const requestMediaKeySystemAccess: MediaKeyFunc;Usage Example:
import { KeySystems, requestMediaKeySystemAccess } from "hls.js";
// Configure DRM
const hls = new Hls({
emeEnabled: true,
drmSystems: {
[KeySystems.WIDEVINE]: {
licenseUrl: "https://license.example.com/widevine",
audioRobustness: "SW_SECURE_CRYPTO",
videoRobustness: "SW_SECURE_DECODE"
},
[KeySystems.PLAYREADY]: {
licenseUrl: "https://license.example.com/playready"
}
}
});
// Custom key system access
async function setupDRM() {
try {
const keySystemAccess = await requestMediaKeySystemAccess(
KeySystems.WIDEVINE,
[{
initDataTypes: ["cenc"],
audioCapabilities: [{ contentType: "audio/mp4; codecs=\"mp4a.40.2\"" }],
videoCapabilities: [{ contentType: "video/mp4; codecs=\"avc1.42E01E\"" }]
}]
);
console.log("Key system access granted");
} catch (error) {
console.error("DRM not supported:", error);
}
}Core data structures for HLS streaming.
/**
* Base segment class
*/
class BaseSegment {
readonly relurl?: string;
readonly baseurl: string;
readonly duration: number;
readonly start: number;
}
/**
* Media fragment representation
*/
class Fragment extends BaseSegment {
readonly type: string;
readonly level: number;
readonly id: number;
readonly sn: number;
readonly urlId: number;
readonly cc: number;
readonly byteRange?: ByteRange;
readonly decryptdata?: LevelKey;
}
/**
* Partial segment for low-latency
*/
class Part extends BaseSegment {
readonly fragOffset: number;
readonly independent: boolean;
readonly gap: boolean;
}
/**
* Date range metadata
*/
class DateRange {
readonly id: string;
readonly startTime: number;
readonly endTime?: number;
readonly duration?: number;
readonly plannedDuration?: number;
readonly endOnNext: boolean;
readonly attr: AttrList;
}
/**
* Loading statistics
*/
class LoadStats {
aborted: boolean = false;
loaded: number = 0;
retry: number = 0;
total: number = 0;
chunkCount: number = 0;
bwEstimate: number = 0;
loading: { start: number; first: number; end: number };
parsing: { start: number; end: number };
buffering: { start: number; first: number; end: number };
}
/**
* Level encryption key
*/
class LevelKey {
readonly method: string;
readonly uri?: string;
readonly keyFormat?: string;
readonly keyFormatVersions?: string;
readonly keyId?: string;
readonly iv?: Uint8Array;
}Advanced configuration options for fine-tuning behavior.
interface HlsConfig {
// Worker configuration
enableWorker: boolean;
enableSoftwareAES: boolean;
enableCEA708Captions: boolean;
// Performance options
startFragPrefetch: boolean;
testBandwidth: boolean;
progressive: boolean;
// Advanced buffering
nudgeOffset: number;
nudgeMaxRetry: number;
maxFragLookUpTolerance: number;
maxBufferHole: number;
// Latency optimization
backBufferLength: number;
frontBufferFlushThreshold: number;
// Network optimization
fragLoadPolicy: LoadPolicy;
keyLoadPolicy: LoadPolicy;
certLoadPolicy: LoadPolicy;
playlistLoadPolicy: LoadPolicy;
manifestLoadPolicy: LoadPolicy;
// Custom callbacks
xhrSetup?: (xhr: XMLHttpRequest, url: string) => void;
fetchSetup?: (context: LoaderContext, initParams: any) => Request;
// Advanced features
cmcd: CMCDConfiguration;
contentSteeringEnabled: boolean;
useMediaCapabilities: boolean;
}
interface LoadPolicy {
default: LoaderConfig;
}
interface LoaderConfig {
maxTimeToFirstByteMs: number;
maxLoadTimeMs: number;
timeoutRetry: RetryConfig | null;
errorRetry: RetryConfig | null;
}
interface RetryConfig {
maxNumRetry: number;
retryDelayMs: number;
maxRetryDelayMs: number;
backoff?: "linear" | "exponential";
}interface ByteRange {
offset: number;
length: number;
}
interface ChunkMetadata {
level: number;
sn: number;
part?: number;
id: number;
size: number;
partial: boolean;
chunkIndex: number;
}
enum MetadataSchema {
none = "",
dateTime = "https://aomedia.org/emsg/ID3",
klv = "https://aomedia.org/emsg/KLV"
}
enum PlaylistLevelType {
MAIN = "main",
AUDIO = "audio",
SUBTITLE = "subtitle"
}
interface CMCDConfiguration {
enabled: boolean;
cid?: string;
sid?: string;
useHeaders: boolean;
}
interface ParsedMasterPlaylist {
levels: Level[];
sessionData: any[];
sessionKeys: LevelKey[];
startTimeOffset: number | null;
variableList: { [key: string]: string } | null;
}