UNPKG

bitmovin-player-ui

Version:
193 lines (170 loc) 6.24 kB
import { ContainerConfig, Container } from '../Container'; import { Label, LabelConfig } from '../labels/Label'; import { UIInstanceManager } from '../../UIManager'; import { TvNoiseCanvas } from '../TvNoiseCanvas'; import { ErrorUtils } from '../../utils/ErrorUtils'; import { ErrorEvent, PlayerAPI, PlayerEventBase } from 'bitmovin-player'; import { isMobileV3PlayerAPI, MobileV3PlayerAPI, MobileV3PlayerErrorEvent, MobileV3PlayerEvent, MobileV3SourceErrorEvent, } from '../../utils/MobileV3PlayerAPI'; export interface ErrorMessageTranslator { (error: ErrorEvent | MobileV3PlayerErrorEvent): string; } export interface ErrorMessageMap { [code: number]: string | ErrorMessageTranslator; } /** * Configuration interface for the {@link ErrorMessageOverlay}. * * @category Configs */ export interface ErrorMessageOverlayConfig extends ContainerConfig { /** * Allows overwriting of the error messages displayed in the overlay for customization and localization. * This is either a function that receives any {@link ErrorEvent} as parameter and translates error messages, * or a map of error codes that overwrites specific error messages with a plain string or a function that * receives the {@link ErrorEvent} as parameter and returns a customized string. * The translation functions can be used to extract data (e.g. parameters) from the original error message. * * Example 1 (catch-all translation function): * <code> * errorMessageOverlayConfig = { * messages: function(error) { * switch (error.code) { * // Overwrite error 1000 'Unknown error' * case 1000: * return 'Houston, we have a problem' * * // Transform error 1201 'The downloaded manifest is invalid' to uppercase * case 1201: * var description = ErrorUtils.defaultErrorMessages[error.code]; * return description.toUpperCase(); * * // Customize error 1207 'The manifest could not be loaded' * case 1207: * var statusCode = error.data.statusCode; * return 'Manifest loading failed with HTTP error ' + statusCode; * } * // Return unmodified error message for all other errors * return error.message; * } * }; * </code> * * Example 2 (translating specific errors): * <code> * errorMessageOverlayConfig = { * messages: { * // Overwrite error 1000 'Unknown error' * 1000: 'Houston, we have a problem', * * // Transform error 1201 'Unsupported manifest format' to uppercase * 1201: function(error) { * var description = ErrorUtils.defaultErrorMessages[error.code]; * return description.toUpperCase(); * }, * * // Customize error 1207 'The manifest could not be loaded' * 1207: function(error) { * var statusCode = error.data.statusCode; * return 'Manifest loading failed with HTTP error ' + statusCode; * } * } * }; * </code> */ messages?: ErrorMessageMap | ErrorMessageTranslator; } /** * Overlays the player and displays error messages. * * @category Components */ export class ErrorMessageOverlay extends Container<ErrorMessageOverlayConfig> { private errorLabel: Label<LabelConfig>; private tvNoiseBackground: TvNoiseCanvas; constructor(config: ErrorMessageOverlayConfig = {}) { super(config); this.errorLabel = new Label<LabelConfig>({ cssClass: 'ui-errormessage-label' }); this.tvNoiseBackground = new TvNoiseCanvas(); this.config = this.mergeConfig( config, { cssClass: 'ui-errormessage-overlay', components: [this.tvNoiseBackground, this.errorLabel], hidden: true, role: 'status', }, this.config, ); } configure(player: PlayerAPI | MobileV3PlayerAPI, uimanager: UIInstanceManager): void { super.configure(player, uimanager); const config = this.getConfig(); const handleErrorMessage = ( event: ErrorEvent | MobileV3SourceErrorEvent | MobileV3PlayerErrorEvent, message: string, ) => { const customizedMessage = customizeErrorMessage(uimanager.getConfig().errorMessages || config.messages, event); if (customizedMessage) { message = customizedMessage; } this.display(message); }; if (isMobileV3PlayerAPI(player)) { const errorEventHandler = (event: MobileV3SourceErrorEvent | MobileV3PlayerErrorEvent) => { const message = ErrorUtils.defaultMobileV3ErrorMessageTranslator(event); handleErrorMessage(event, message); }; player.on(MobileV3PlayerEvent.PlayerError, errorEventHandler); player.on(MobileV3PlayerEvent.SourceError, errorEventHandler); } else { player.on(player.exports.PlayerEvent.Error, (event: ErrorEvent) => { const message = ErrorUtils.defaultWebErrorMessageTranslator(event); handleErrorMessage(event, message); }); } player.on(player.exports.PlayerEvent.SourceLoaded, (event: PlayerEventBase) => { if (this.isShown()) { this.clear(); } }); } display(errorMessage: string): void { this.errorLabel.setText(errorMessage); this.tvNoiseBackground.start(); this.show(); } private clear(): void { this.errorLabel.setText(''); // Canvas rendering must be explicitly stopped, else it just continues forever and hogs resources this.tvNoiseBackground.stop(); this.hide(); } release(): void { super.release(); this.clear(); } } function customizeErrorMessage( errorMessages: ErrorMessageTranslator | ErrorMessageMap, event: ErrorEvent | MobileV3PlayerErrorEvent | MobileV3SourceErrorEvent, ): string | undefined { if (!errorMessages) { return undefined; } // Process message vocabularies if (typeof errorMessages === 'function') { // Translation function for all errors return errorMessages(event); } if (errorMessages[event.code]) { // It's not a translation function, so it must be a map of strings or translation functions const customMessage = errorMessages[event.code]; return typeof customMessage === 'string' ? customMessage : customMessage(event); } }