JavaScript HLS client using MediaSourceExtension for smooth video stream playback
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
HLS.js provides comprehensive error handling with detailed error types, automatic recovery mechanisms, and configurable retry logic.
All errors are reported through the ERROR event with detailed information.
hls.on(Hls.Events.ERROR, (event, data: ErrorData) => {
// Handle error based on type and severity
});
interface ErrorData {
/** Error category */
type: ErrorTypes;
/** Specific error details */
details: ErrorDetails;
/** Whether error is fatal (stops playback) */
fatal: boolean;
/** Human-readable error reason */
reason?: string;
/** Associated quality level */
level?: number;
/** Associated fragment */
frag?: Fragment;
/** Failed URL */
url?: string;
/** HTTP response object */
response?: Response;
/** Additional context */
context?: any;
/** Error handling action taken */
action?: NetworkErrorAction;
/** Retry count */
retryCount?: number;
/** Internal error object */
error?: Error;
}Usage Example:
const hls = new Hls();
hls.on(Hls.Events.ERROR, (event, data) => {
console.error(`HLS Error: ${data.type} - ${data.details}`);
console.error(`Fatal: ${data.fatal}, Reason: ${data.reason}`);
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.error("Network error, try to recover");
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.error("Media error, try to recover");
hls.recoverMediaError();
break;
default:
console.error("Fatal error, cannot recover");
hls.destroy();
break;
}
}
});Categories of errors that can occur.
enum ErrorTypes {
/** Network loading and timeout errors */
NETWORK_ERROR = "networkError",
/** Video/audio parsing and MediaSource errors */
MEDIA_ERROR = "mediaError",
/** DRM and EME errors */
KEY_SYSTEM_ERROR = "keySystemError",
/** Demuxing and remuxing errors */
MUX_ERROR = "muxError",
/** All other errors */
OTHER_ERROR = "otherError"
}Specific error details with over 50 different error types.
enum ErrorDetails {
// Key system/DRM errors
KEY_SYSTEM_NO_KEYS = "keySystemNoKeys",
KEY_SYSTEM_NO_ACCESS = "keySystemNoAccess",
KEY_SYSTEM_NO_SESSION = "keySystemNoSession",
KEY_SYSTEM_NO_CONFIGURED_LICENSE = "keySystemNoConfiguredLicense",
KEY_SYSTEM_LICENSE_REQUEST_FAILED = "keySystemLicenseRequestFailed",
KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED = "keySystemServerCertificateRequestFailed",
KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED = "keySystemServerCertificateUpdateFailed",
KEY_SYSTEM_SESSION_UPDATE_FAILED = "keySystemSessionUpdateFailed",
KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED = "keySystemStatusOutputRestricted",
KEY_SYSTEM_STATUS_INTERNAL_ERROR = "keySystemStatusInternalError",
KEY_SYSTEM_DESTROY_MEDIA_KEYS_ERROR = "keySystemDestroyMediaKeysError",
KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR = "keySystemDestroyCloseSessionError",
KEY_SYSTEM_DESTROY_REMOVE_SESSION_ERROR = "keySystemDestroyRemoveSessionError",
// Manifest errors
MANIFEST_LOAD_ERROR = "manifestLoadError",
MANIFEST_LOAD_TIMEOUT = "manifestLoadTimeOut",
MANIFEST_PARSING_ERROR = "manifestParsingError",
MANIFEST_INCOMPATIBLE_CODECS_ERROR = "manifestIncompatibleCodecsError",
// Level errors
LEVEL_EMPTY_ERROR = "levelEmptyError",
LEVEL_LOAD_ERROR = "levelLoadError",
LEVEL_LOAD_TIMEOUT = "levelLoadTimeOut",
LEVEL_PARSING_ERROR = "levelParsingError",
LEVEL_SWITCH_ERROR = "levelSwitchError",
// Audio track errors
AUDIO_TRACK_LOAD_ERROR = "audioTrackLoadError",
AUDIO_TRACK_LOAD_TIMEOUT = "audioTrackLoadTimeOut",
// Subtitle track errors
SUBTITLE_LOAD_ERROR = "subtitleTrackLoadError",
SUBTITLE_TRACK_LOAD_TIMEOUT = "subtitleTrackLoadTimeOut",
// Fragment errors
FRAG_LOAD_ERROR = "fragLoadError",
FRAG_LOAD_TIMEOUT = "fragLoadTimeOut",
FRAG_DECRYPT_ERROR = "fragDecryptError",
FRAG_PARSING_ERROR = "fragParsingError",
FRAG_GAP = "fragGap",
// Remux errors
REMUX_ALLOC_ERROR = "remuxAllocError",
// Key loading errors
KEY_LOAD_ERROR = "keyLoadError",
KEY_LOAD_TIMEOUT = "keyLoadTimeOut",
// Buffer errors
BUFFER_ADD_CODEC_ERROR = "bufferAddCodecError",
BUFFER_INCOMPATIBLE_CODECS_ERROR = "bufferIncompatibleCodecsError",
BUFFER_APPEND_ERROR = "bufferAppendError",
BUFFER_APPENDING_ERROR = "bufferAppendingError",
BUFFER_STALLED_ERROR = "bufferStalledError",
BUFFER_FULL_ERROR = "bufferFullError",
BUFFER_SEEK_OVER_HOLE = "bufferSeekOverHole",
BUFFER_NUDGE_ON_STALL = "bufferNudgeOnStall",
// Interstitial/asset errors
ASSET_LIST_LOAD_ERROR = "assetListLoadError",
ASSET_LIST_LOAD_TIMEOUT = "assetListLoadTimeout",
ASSET_LIST_PARSING_ERROR = "assetListParsingError",
INTERSTITIAL_ASSET_ITEM_ERROR = "interstitialAssetItemError",
// Internal errors
INTERNAL_EXCEPTION = "internalException",
INTERNAL_ABORTED = "aborted",
ATTACH_MEDIA_ERROR = "attachMediaError",
UNKNOWN = "unknown"
}Built-in recovery mechanisms and manual recovery methods.
interface Hls {
/**
* Attempt to recover from media errors
*/
recoverMediaError(): void;
/**
* Swap audio codec and try to recover from media error
*/
swapAudioCodec(): void;
}Usage Examples:
const hls = new Hls();
hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
// Network error recovery
console.log("Network error, restarting load...");
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
// Media error recovery
console.log("Media error, attempting recovery...");
hls.recoverMediaError();
break;
case Hls.ErrorTypes.KEY_SYSTEM_ERROR:
// DRM error - usually fatal
console.error("DRM error, cannot recover");
hls.destroy();
break;
default:
// Other fatal errors
console.error("Fatal error, destroying player");
hls.destroy();
break;
}
} else {
// Non-fatal errors are usually handled automatically
console.warn("Non-fatal error:", data.details);
}
});
// Advanced recovery with retry logic
let mediaErrorRecoveryCount = 0;
const MAX_MEDIA_ERROR_RECOVERY = 3;
hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal && data.type === Hls.ErrorTypes.MEDIA_ERROR) {
if (mediaErrorRecoveryCount < MAX_MEDIA_ERROR_RECOVERY) {
mediaErrorRecoveryCount++;
console.log(`Media error recovery attempt ${mediaErrorRecoveryCount}`);
if (mediaErrorRecoveryCount === 1) {
hls.recoverMediaError();
} else if (mediaErrorRecoveryCount === 2) {
hls.swapAudioCodec();
} else {
// Last attempt - full reload
hls.loadSource(hls.url);
}
} else {
console.error("Max media error recovery attempts reached");
hls.destroy();
}
}
});
// Reset recovery count on successful recovery
hls.on(Hls.Events.FRAG_LOADED, () => {
mediaErrorRecoveryCount = 0;
});Configure error handling behavior through HlsConfig.
interface HlsConfig {
// Retry configuration
manifestLoadingMaxRetry: number;
manifestLoadingRetryDelay: number;
levelLoadingMaxRetry: number;
levelLoadingRetryDelay: number;
fragLoadingMaxRetry: number;
fragLoadingRetryDelay: number;
keyLoadingMaxRetry: number;
keyLoadingRetryDelay: number;
// Timeout configuration
manifestLoadingTimeOut: number;
levelLoadingTimeOut: number;
fragLoadingTimeOut: number;
keyLoadingTimeOut: number;
// Error handling options
enableWorker: boolean;
enableSoftwareAES: boolean;
startFragPrefetch: boolean;
ignoreDevicePixelRatio: boolean;
}Usage Example:
const hls = new Hls({
// Increase retry counts
manifestLoadingMaxRetry: 6,
fragLoadingMaxRetry: 6,
// Longer timeouts
manifestLoadingTimeOut: 20000,
fragLoadingTimeOut: 30000,
// Enable fallback options
enableSoftwareAES: true,
enableWorker: true
});Error controller actions for handling network errors.
enum NetworkErrorAction {
DoNothing = 0,
SendEndCallback = 1,
SendAlternateToPenaltyBox = 2,
RemoveAlternatePermanently = 3,
InsertDiscontinuity = 4,
RetryRequest = 5
}
enum ErrorActionFlags {
None = 0,
MoveAllAlternatesMatchingHost = 1,
MoveAllAlternatesMatchingHDCP = 2,
SwitchToSDR = 4
}Create custom error handling logic.
// Custom error handler function
function handleCustomError(hls: Hls, errorData: ErrorData): boolean {
// Return true if error was handled, false to use default handling
if (errorData.details === Hls.ErrorDetails.FRAG_LOAD_ERROR) {
// Custom fragment load error handling
console.log("Custom fragment error handling");
// Try alternative URL or CDN
if (errorData.frag && errorData.response?.status === 404) {
// Switch to backup CDN
return true; // Handled
}
}
return false; // Not handled, use default behavior
}
// Apply custom error handling
hls.on(Hls.Events.ERROR, (event, data) => {
const handled = handleCustomError(hls, data);
if (!handled) {
// Fall back to default error handling
console.log("Using default error handling");
}
});interface Response {
url: string;
status: number;
statusText: string;
headers: Record<string, string>;
}
interface Fragment {
url: string;
byteRange?: ByteRange;
level: number;
sn: number;
start: number;
duration: number;
type: string;
}
interface LoadStats {
aborted: boolean;
loaded: number;
retry: number;
total: number;
chunkCount: number;
bwEstimate: number;
loading: { start: number; first: number; end: number };
parsing: { start: number; end: number };
buffering: { start: number; first: number; end: number };
}