Skip to main content

Handling common player errors

This document provides solutions and best practices for addressing common errors encountered during video playback using the rn-qp-nxg-player library. These errors include issues related to live streaming, DRM, session expiry, and more. By following the guidelines here, you can ensure a smoother playback experience.

Mitigating Player Errors

BehindLiveWindowException (Error: 40020d)

The Player throws a BehindLiveWindowException when the playback strays so far away from live edge that it falls behind the available live window. The playback can fall behind because of continuous buffering or pausing of a live stream. This exception can be prevented by turning on the live monitor via PlaybackProperties and passing a LiveStreamMonitorConfiguration, if needed.
Live stream monitoring is disabled by default.

Property NameTypeDefault ValueDescription
liveStreamMonitorConfigurationLiveStreamMonitorConfigurationmonitoringTimeIntervalMs = 10000
liveEdgePositionThreshold = 20
currentWindowBufferedPositionThreshold = 40
The live stream configuration to be employed.
monitorLiveStreamBooleanfalseRepresents whether to monitor live stream position or not.

let liveStreamMonitorConfig: LiveStreamMonitorConfiguration = {
monitoringTimeIntervalMs: 3000,
currentWindowBufferedPositionThreshold: 40
}

}

DECODER_INIT_FAILURE (Error: 400208)

One possible cause of this error is when the app attempts to play DRM streams exceeding the device's supported limit. To address this, a new parameter, shouldCleanupPreviousPlayers, has been added to PlayerConfig. This ensures that any existing player is stopped before creating a new one.


let playerConfig: PlayerConfig = {
...
shouldCleanupPreviousPlayers: true
...
}

let player = await createPlayer(playerConfig)

Handling Player Error

Here is step-by-step guide to handle playback errors

export interface PlatformError {
errorCode: number;
errorDescription: string;
contextDescription?: string;
httpStatusCode?: number;
internalError?: PlatformError;
readonly componentErrorCode: number;
readonly hexErrorCode: string;
doesBelongToCategory:(category: number) => boolean;
toString: () => string;
}

When the player encounters a failure, we report the playback error using the `onError` callback:

onError(error: PlatformError): void {
...
// Handle error
},

SSAI Session Expiry

In SSAI playbacks, ads are added dynamically from the server, so the server needs to keep a session for each playback to handle the ads properly. It's important for the server to end sessions when playback finishes or if the user takes action. Also, the server usually cleans up idle sessions after a while. But in iOS apps, playback can pause for a long time, causing sessions to be removed from the server. When users come back to the app, errors can occur because the player tries to resume the previous playback. To fix this, ad-serving companies suggest apps close the playback session before the app becomes idle. However, just relying on the app's background and foreground states isn't enough because some app features like Picture-in-Picture mode and Airplay support need special consideration. To prevent session problems, the app needs to handle these cases properly.

Background

App become background

  1. Open the iOS/tvOS app.
  2. Play any SSAI stream.
  3. Pause the playback.
  4. Put the app on a background.
  5. Open the app after the SSAI session keep-alive time has elapsed, causing the player to throw a session expiry error.

Solution

Deinitialize the player instance when the app is backgrounded. This prevents the player from encountering errors when it becomes active after a session expiry.

Implementation

import { AppState, AppStateStatus } from 'react-native';
import React, { useRef, useEffect } from 'react';
const appState = useRef<AppStateStatus>(AppState.currentState);
useEffect(() => {
const handleAppStateChange = async (nextAppState: AppStateStatus) => {
if (nextAppState === "background") {
appState.current = nextAppState;
appState.current = nextAppState;
}
};
const subscription = AppState.addEventListener("change", handleAppStateChange);

return () => {
subscription.remove();
};
}, []);

Picture-in-Picture

Scenario

  1. Open the iOS app
  2. Play any SSAI-enabled stream
  3. Put the app in the background; the stream should resume playing in PiP window
  4. Close the pip window
  5. Open the app after the SSAI session elapses, causing the player to throw a session expiry error.

Solution

Deinitialize the player instance when the PiP window is closed. This prevents the player from encountering errors when it becomes active after a session expiry.

Implementation

let playerListener = {
async onPictureInPictureStopped(): Promise<void> {
if (appState.current === "background") {}
if (appState.current === "background") {
// TODO: Deinitialize the player
}
},
};

Airplay

Scenario

  1. Open the iOS App.
  2. Play any Server-Side Ad Insertion (SSAI) stream.
  3. Airplay the playback on an external device.
  4. Put the iOS app in the background and close the playback on the external device using a remote.
  5. Open the app after the SSAI session keep-alive time has elapsed, causing the player to throw a session expiry error.

Solution

Deinitialize the player instance when the app is backgrounded and the Airplay device quits the playback. This prevents the player from encountering errors when it becomes active after a session expiry.

Implementation

let playerListener = {
async onAudiorouteChanged(routeChange: string, fromPort: string, toPort: string): Promise<void> {
if (fromPort === "AirPlay" && toPort !== "AirPlay" && appState.current === "background") {
console.log("AirPlay stopped in background, stopping player...");
// TODO: Deinitialize the player
}
},
};

HTTP Failures

Playback may pause for an extended period, causing sessions to be removed from the server. When users return, errors can occur as the player tries to resume the previous session

onError(error: PlatformError): void {
// Check if httpStatusCode is available in the error
if (error.httpStatusCode) {
switch (error.httpStatusCode) {
case 410:
}
}
}

Note SSAI session expiry varies for different SSAI vendors and environments. Picture-in-Picture and Airplay not applicable for tvOS