X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=client%2Fsrc%2Fassets%2Fplayer%2Fp2p-media-loader%2Fhls-plugin.ts;h=672a85d0b0525bfd1d54bf9ed0982d8ca81f6610;hb=87da0a30ab197985917d8457e8388adc46cec10f;hp=d78e1ab9021ec498f8afd6dc38a577010530ac54;hpb=a30a136c9896c656cab98d2c92cde32c534dc098;p=github%2FChocobozzz%2FPeerTube.git diff --git a/client/src/assets/player/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/p2p-media-loader/hls-plugin.ts index d78e1ab90..672a85d0b 100644 --- a/client/src/assets/player/p2p-media-loader/hls-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/hls-plugin.ts @@ -1,8 +1,8 @@ // Thanks https://github.com/streamroot/videojs-hlsjs-plugin // We duplicated this plugin to choose the hls.js version we want, because streamroot only provide a bundled file -import * as Hlsjs from 'hls.js' -import videojs, { VideoJsPlayer } from 'video.js' +import * as Hlsjs from 'hls.js/dist/hls.light.js' +import videojs from 'video.js' import { HlsjsConfigHandlerOptions, QualityLevelRepresentation, QualityLevels, VideoJSTechHLS } from '../peertube-videojs-typings' type ErrorCounts = { @@ -13,6 +13,8 @@ type Metadata = { levels: Hlsjs.Level[] } +type CustomAudioTrack = Hlsjs.HlsAudioTrack & { name?: string, lang?: string } + const registerSourceHandler = function (vjs: typeof videojs) { if (!Hlsjs.isSupported()) { console.warn('Hls.js is not supported in this browser!') @@ -53,7 +55,7 @@ const registerSourceHandler = function (vjs: typeof videojs) { (vjs as any).Html5Hlsjs = Html5Hlsjs } -function hlsjsConfigHandler (this: VideoJsPlayer, options: HlsjsConfigHandlerOptions) { +function hlsjsConfigHandler (this: videojs.Player, options: HlsjsConfigHandlerOptions) { const player = this if (!options) return @@ -86,12 +88,12 @@ class Html5Hlsjs { private readonly videoElement: HTMLVideoElement private readonly errorCounts: ErrorCounts = {} - private readonly player: VideoJsPlayer + private readonly player: videojs.Player private readonly tech: videojs.Tech private readonly source: videojs.Tech.SourceObject private readonly vjs: typeof videojs - private hls: Hlsjs & { manualLevel?: number } // FIXME: typings + private hls: Hlsjs & { manualLevel?: number, audioTrack?: any, audioTracks?: CustomAudioTrack[] } // FIXME: typings private hlsjsConfig: Partial = null private _duration: number = null @@ -100,9 +102,8 @@ class Html5Hlsjs { private dvrDuration: number = null private edgeMargin: number = null - private handlers: { [ id in 'play' | 'addtrack' | 'playing' | 'textTracksChange' | 'audioTracksChange' ]: EventListener } = { + private handlers: { [ id in 'play' | 'playing' | 'textTracksChange' | 'audioTracksChange' ]: EventListener } = { play: null, - addtrack: null, playing: null, textTracksChange: null, audioTracksChange: null @@ -122,8 +123,11 @@ class Html5Hlsjs { this.videoElement.addEventListener('error', event => { let errorTxt: string - const mediaError = (event.currentTarget as HTMLVideoElement).error + const mediaError = ((event.currentTarget || event.target) as HTMLVideoElement).error + + if (!mediaError) return + console.log(mediaError) switch (mediaError.code) { case mediaError.MEDIA_ERR_ABORTED: errorTxt = 'You aborted the video playback' @@ -172,14 +176,11 @@ class Html5Hlsjs { // See comment for `initialize` method. dispose () { this.videoElement.removeEventListener('play', this.handlers.play) - this.videoElement.textTracks.removeEventListener('addtrack', this.handlers.addtrack) this.videoElement.removeEventListener('playing', this.handlers.playing) this.player.textTracks().removeEventListener('change', this.handlers.textTracksChange) this.uiTextTrackHandled = false - this.player.audioTracks().removeEventListener('change', this.handlers.audioTracksChange) - this.hls.destroy() } @@ -226,12 +227,34 @@ class Html5Hlsjs { if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] > 2) { console.info('bubbling media error up to VIDEOJS') + this.hls.destroy() this.tech.error = () => error this.tech.trigger('error') return } } + private _handleNetworkError (error: any) { + if (this.errorCounts[ Hlsjs.ErrorTypes.NETWORK_ERROR] <= 5) { + console.info('trying to recover network error') + + // Wait 1 second and retry + setTimeout(() => this.hls.startLoad(), 1000) + + // Reset error count on success + this.hls.once(Hlsjs.Events.FRAG_LOADED, () => { + this.errorCounts[ Hlsjs.ErrorTypes.NETWORK_ERROR] = 0 + }) + + return + } + + console.info('bubbling network error up to VIDEOJS') + this.hls.destroy() + this.tech.error = () => error + this.tech.trigger('error') + } + private _onError (_event: any, data: Hlsjs.errorData) { const error: { message: string, code?: number } = { message: `HLS.js error: ${data.type} - fatal: ${data.fatal} - ${data.details}` @@ -242,30 +265,19 @@ class Html5Hlsjs { if (this.errorCounts[ data.type ]) this.errorCounts[ data.type ] += 1 else this.errorCounts[ data.type ] = 1 - // Implement simple error handling based on hls.js documentation - // https://github.com/dailymotion/hls.js/blob/master/API.md#fifth-step-error-handling - if (data.fatal) { - switch (data.type) { - case Hlsjs.ErrorTypes.NETWORK_ERROR: - console.info('bubbling network error up to VIDEOJS') - error.code = 2 - this.tech.error = () => error as any - this.tech.trigger('error') - break - - case Hlsjs.ErrorTypes.MEDIA_ERROR: - error.code = 3 - this._handleMediaError(error) - break - - default: - // cannot recover - this.hls.destroy() - console.info('bubbling error up to VIDEOJS') - this.tech.error = () => error as any - this.tech.trigger('error') - break - } + if (!data.fatal) return + + if (data.type === Hlsjs.ErrorTypes.NETWORK_ERROR) { + error.code = 2 + this._handleNetworkError(error) + } else if (data.type === Hlsjs.ErrorTypes.MEDIA_ERROR && data.details !== 'manifestIncompatibleCodecsError') { + error.code = 3 + this._handleMediaError(error) + } else { + this.hls.destroy() + console.info('bubbling error up to VIDEOJS') + this.tech.error = () => error as any + this.tech.trigger('error') } } @@ -393,7 +405,7 @@ class Html5Hlsjs { } private _onAudioTracks () { - const hlsAudioTracks = this.hls.audioTracks as (AudioTrack & { name?: string, lang?: string })[] // FIXME typings + const hlsAudioTracks = this.hls.audioTracks const playerAudioTracks = this.tech.audioTracks() if (hlsAudioTracks.length > 1 && playerAudioTracks.length === 0) { @@ -608,9 +620,6 @@ class Html5Hlsjs { this.hls.attachMedia(this.videoElement) - this.handlers.addtrack = this._updateTextTrackList.bind(this) - this.videoElement.textTracks.addEventListener('addtrack', this.handlers.addtrack) - this.hls.loadSource(this.source.src) }