UNPKG

playable

Version:

Video player based on HTML5Video

226 lines (194 loc) 5.7 kB
import { VideoEvent, EngineState } from '../../constants'; import { IEventEmitter } from '../event-emitter/types'; import { IPlaybackEngine } from '../playback-engine/types'; import { IReportReasons, ITimeoutMap, IReportTypes, IReportType, } from './types'; import playerAPI from '../../core/player-api-decorator'; export const REPORT_REASONS: IReportReasons = { LONG_INITIAL_VIDEO_PARTS_LOADING: 'long-initial-video-parts-loading', LONG_METADATA_LOADING: 'long-metadata-loading', LONG_SEEK_PROCESSING: 'long-seek-processing', BUFFER_EMPTY_FOR_CURRENT_SEGMENT: 'buffer-empty-for-current-segment', LONG_PLAY_REQUESTED_PROCESSING: 'long-play-requested-processing', }; export const DELAYED_REPORT_TYPES: IReportTypes = { INITIAL_VIDEO_PARTS_LOADING: { id: '_initialVideoPartsLoading', timeoutTime: 5000, }, METADATA_LOADING: { id: '_metadataLoading', timeoutTime: 5000, }, RUNTIME_LOADING: { id: '_runtimeLoading', timeoutTime: 5000, }, }; export default class AnomalyBloodhound { static moduleName = 'anomalyBloodhound'; static dependencies = ['eventEmitter', 'engine']; private _engine: IPlaybackEngine; private _eventEmitter: IEventEmitter; private _timeoutMap: ITimeoutMap; private _unbindEvents: () => void; private _callback: (anomalyData: any) => void; constructor({ engine, eventEmitter, }: { engine: IPlaybackEngine; eventEmitter: IEventEmitter; }) { this._engine = engine; this._eventEmitter = eventEmitter; this._timeoutMap = Object.create(null); this._bindEvents(); } private _bindEvents() { this._unbindEvents = this._eventEmitter.bindEvents( [[VideoEvent.STATE_CHANGED, this._processStateChange]], this, ); } private _processStateChange({ prevState, nextState, }: { prevState: EngineState; nextState: EngineState; }) { switch (nextState) { case EngineState.LOAD_STARTED: if (this._engine.isAutoPlayActive || this._engine.isPreloadActive) { this.startDelayedReport( DELAYED_REPORT_TYPES.METADATA_LOADING, REPORT_REASONS.LONG_METADATA_LOADING, ); } break; case EngineState.METADATA_LOADED: if (this.isDelayedReportExist(DELAYED_REPORT_TYPES.METADATA_LOADING)) { this.stopDelayedReport(DELAYED_REPORT_TYPES.METADATA_LOADING); if (this._engine.getPreload() !== 'metadata') { this.startDelayedReport( DELAYED_REPORT_TYPES.INITIAL_VIDEO_PARTS_LOADING, REPORT_REASONS.LONG_INITIAL_VIDEO_PARTS_LOADING, ); } } break; case EngineState.READY_TO_PLAY: if ( this.isDelayedReportExist( DELAYED_REPORT_TYPES.INITIAL_VIDEO_PARTS_LOADING, ) ) { this.stopDelayedReport( DELAYED_REPORT_TYPES.INITIAL_VIDEO_PARTS_LOADING, ); } if (this.isDelayedReportExist(DELAYED_REPORT_TYPES.RUNTIME_LOADING)) { this.stopDelayedReport(DELAYED_REPORT_TYPES.RUNTIME_LOADING); } break; case EngineState.SEEK_IN_PROGRESS: if (prevState === EngineState.PAUSED) { this.startDelayedReport( DELAYED_REPORT_TYPES.RUNTIME_LOADING, REPORT_REASONS.LONG_SEEK_PROCESSING, ); } break; case EngineState.WAITING: switch (prevState) { case EngineState.PLAYING: { this.reportDebugInfo({ reason: REPORT_REASONS.BUFFER_EMPTY_FOR_CURRENT_SEGMENT, }); break; } case EngineState.PLAY_REQUESTED: if ( !this.isDelayedReportExist(DELAYED_REPORT_TYPES.RUNTIME_LOADING) ) { this.startDelayedReport( DELAYED_REPORT_TYPES.RUNTIME_LOADING, REPORT_REASONS.LONG_PLAY_REQUESTED_PROCESSING, ); } break; /* ignore coverage */ default: break; } break; case EngineState.PLAYING: if (this.isDelayedReportExist(DELAYED_REPORT_TYPES.RUNTIME_LOADING)) { this.stopDelayedReport(DELAYED_REPORT_TYPES.RUNTIME_LOADING); } break; default: break; } } isDelayedReportExist(type: IReportType) { return Boolean(this._timeoutMap[type.id]); } startDelayedReport(type: IReportType, reason: string) { if (this.isDelayedReportExist(type)) { this.stopDelayedReport(type); } const startTS = Date.now(); this._timeoutMap[type.id] = window.setTimeout(() => { const endTS = Date.now(); delete this._timeoutMap; this.reportDebugInfo({ reason, startTS, endTS, }); }, type.timeoutTime); } stopDelayedReport(type: IReportType) { window.clearTimeout(this._timeoutMap[type.id]); delete this._timeoutMap[type.id]; } stopAllDelayedReports() { Object.keys(this._timeoutMap).forEach(key => { window.clearTimeout(this._timeoutMap[key]); delete this._timeoutMap[key]; }); } @playerAPI() setAnomalyCallback(callback: (anomalyData: any) => void) { if (callback) { this._callback = callback; } } reportDebugInfo({ reason, startTS, endTS, }: { reason: string; startTS?: number; endTS?: number; }) { this._callback && this._callback({ reason, startTS, endTS, ...this._engine.getDebugInfo(), }); } destroy() { this.stopAllDelayedReports(); this._unbindEvents(); } }