Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion api-extractor/report/hls.js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,14 @@ export class ErrorController extends Logger implements NetworkComponentAPI {
stopLoad(): void;
}

// Warning: (ae-missing-release-tag) "ErrorControllerConfig" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type ErrorControllerConfig = {
onErrorHandler?: (data: ErrorData) => boolean;
onErrorOutHandler?: (data: ErrorData) => boolean;
};

// Warning: (ae-missing-release-tag) "ErrorData" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down Expand Up @@ -2297,7 +2305,7 @@ export type HlsConfig = {
progressive: boolean;
lowLatencyMode: boolean;
primarySessionId?: string;
} & ABRControllerConfig & BufferControllerConfig & CapLevelControllerConfig & EMEControllerConfig & FPSControllerConfig & GapControllerConfig & LevelControllerConfig & MP4RemuxerConfig & StreamControllerConfig & SelectionPreferences & LatencyControllerConfig & MetadataControllerConfig & TimelineControllerConfig & TSDemuxerConfig & HlsLoadPolicies & FragmentLoaderConfig & PlaylistLoaderConfig;
} & ABRControllerConfig & BufferControllerConfig & CapLevelControllerConfig & EMEControllerConfig & ErrorControllerConfig & FPSControllerConfig & GapControllerConfig & LevelControllerConfig & MP4RemuxerConfig & StreamControllerConfig & SelectionPreferences & LatencyControllerConfig & MetadataControllerConfig & TimelineControllerConfig & TSDemuxerConfig & HlsLoadPolicies & FragmentLoaderConfig & PlaylistLoaderConfig;

// Warning: (ae-missing-release-tag) "HlsEventEmitter" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
Expand Down
66 changes: 66 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ See [API Reference](https://hlsjs-dev.video-dev.org/api-docs/) for a complete li
- [`capLevelController`](#caplevelcontroller)
- [`fpsController`](#fpscontroller)
- [`errorController`](#errorcontroller)
- [`onErrorHandler`](#onerrorhandler)
- [`onErrorOutHandler`](#onerrorouthandler)
- [`timelineController`](#timelinecontroller)
- [`enableDateRangeMetadataCues`](#enabledaterangemetadatacues)
- [`enableEmsgMetadataCues`](#enableemsgmetadatacues)
Expand Down Expand Up @@ -1393,6 +1395,70 @@ Customized error controller.

A class in charge of handling errors and error recovery logic. The error controller processes error events and implements recovery strategies such as level switching and fragment retry logic.

### `onErrorHandler`

(default: `undefined`, type: `(data: ErrorData) => boolean`)

Early error handler callback invoked **before** HLS.js attempts any error recovery.

This callback is called immediately when an error occurs, giving you the earliest opportunity to inspect and handle errors. When you return `true`, HLS.js will **not attempt any error recovery** and you are responsible for handling the error manually. Return `false` or `undefined` to allow HLS.js to proceed with its normal error recovery logic.

**Important:** Returning `true` prevents all error recovery attempts including fragment retries, level switching, and other recovery strategies.

```js
var config = {
onErrorHandler: function (data) {
console.log(
'Error handler called before recovery:',
data.type,
data.details,
);

// Example: Handle specific errors manually
if (data.details === Hls.ErrorDetails.FRAG_LOAD_ERROR) {
// Custom handling logic here
console.log('Manually handling fragment load error');
return true; // Prevent HLS.js from attempting recovery
}

// Let HLS.js handle other errors
return false;
},
};
```

### `onErrorOutHandler`

(default: `undefined`, type: `(data: ErrorData) => boolean`)

Error handler callback invoked **after** HLS.js has completed its error recovery attempts.

This callback is called after HLS.js has exhausted its recovery strategies (such as retries and level switching). When you return `true`, HLS.js will **not execute its default error handling** and you are responsible for handling the error manually. Return `false` or `undefined` to allow HLS.js to proceed with its default error handling (which may include destroying the player or switching streams).

**Important:** Returning `true` prevents default error handling after recovery has been attempted. This is useful for implementing custom fallback logic when HLS.js cannot recover from an error.

```js
var config = {
onErrorOutHandler: function (data) {
console.log(
'Error handler called after recovery:',
data.type,
data.details,
);

// Example: Custom fallback for unrecoverable errors
if (data.fatal && data.type === Hls.ErrorTypes.NETWORK_ERROR) {
// Custom handling logic here
console.log('Manually handling fragment load error');
return true; // Prevent HLS.js default handling
}

// Let HLS.js handle other errors with its default behavior
return false;
},
};
```

### `timelineController`

(default: internal track timeline controller)
Expand Down
7 changes: 7 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { stringify } from './utils/safe-json-stringify';
import XhrLoader from './utils/xhr-loader';
import type { MediaKeySessionContext } from './controller/eme-controller';
import type Hls from './hls';
import type { ErrorData } from './hls';
import type {
FragmentLoaderContext,
Loader,
Expand Down Expand Up @@ -125,6 +126,11 @@ export type EMEControllerConfig = {
requireKeySystemAccessOnStart: boolean;
};

export type ErrorControllerConfig = {
onErrorHandler?: (data: ErrorData) => boolean;
onErrorOutHandler?: (data: ErrorData) => boolean;
};

export interface FragmentLoaderConstructor {
new (confg: HlsConfig): Loader<FragmentLoaderContext>;
}
Expand Down Expand Up @@ -335,6 +341,7 @@ export type HlsConfig = {
BufferControllerConfig &
CapLevelControllerConfig &
EMEControllerConfig &
ErrorControllerConfig &
FPSControllerConfig &
GapControllerConfig &
LevelControllerConfig &
Expand Down
10 changes: 8 additions & 2 deletions src/controller/error-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,11 @@ export default class ErrorController
}

private onError(event: Events.ERROR, data: ErrorData) {
if (data.fatal) {
const hls = this.hls;
// If the error is handled by onErrorHandler or is fatal, do not proceed with error recovery
if (hls.config.onErrorHandler?.(data) || data.fatal) {
return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still won't stop propagation through other event listeners, nor should we attempt to make it. Adding resolved: true to data is how error handling signals that other components do not need to take any further action.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just updated the PR with this.

}
const hls = this.hls;
const context = data.context;

switch (data.details) {
Expand Down Expand Up @@ -465,6 +466,11 @@ export default class ErrorController
}

public onErrorOut(event: Events.ERROR, data: ErrorData) {
const hls = this.hls;
// If the error is handled by onErrorOutHandler, do not proceed with the default error handling
if (hls.config.onErrorOutHandler?.(data)) {
return;
}
switch (data.errorAction?.action) {
case NetworkErrorAction.DoNothing:
break;
Expand Down
1 change: 1 addition & 0 deletions src/hls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,7 @@ export type {
CapLevelControllerConfig,
CMCDControllerConfig,
EMEControllerConfig,
ErrorControllerConfig,
DRMSystemConfiguration,
DRMSystemsConfiguration,
DRMSystemOptions,
Expand Down
Loading