aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts')
-rw-r--r--client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts89
1 files changed, 60 insertions, 29 deletions
diff --git a/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
index d05d6193c..d83ec625a 100644
--- a/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
+++ b/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
@@ -14,6 +14,10 @@ type Metadata = {
14 levels: Level[] 14 levels: Level[]
15} 15}
16 16
17// ---------------------------------------------------------------------------
18// Source handler registration
19// ---------------------------------------------------------------------------
20
17type HookFn = (player: videojs.Player, hljs: Hlsjs) => void 21type HookFn = (player: videojs.Player, hljs: Hlsjs) => void
18 22
19const registerSourceHandler = function (vjs: typeof videojs) { 23const registerSourceHandler = function (vjs: typeof videojs) {
@@ -25,10 +29,13 @@ const registerSourceHandler = function (vjs: typeof videojs) {
25 const html5 = vjs.getTech('Html5') 29 const html5 = vjs.getTech('Html5')
26 30
27 if (!html5) { 31 if (!html5) {
28 logger.error('No Hml5 tech found in videojs') 32 logger.error('No "Html5" tech found in videojs')
29 return 33 return
30 } 34 }
31 35
36 // Already registered
37 if ((html5 as any).canPlaySource({ type: 'application/x-mpegURL' })) return
38
32 // FIXME: typings 39 // FIXME: typings
33 (html5 as any).registerSourceHandler({ 40 (html5 as any).registerSourceHandler({
34 canHandleSource: function (source: videojs.Tech.SourceObject) { 41 canHandleSource: function (source: videojs.Tech.SourceObject) {
@@ -56,32 +63,55 @@ const registerSourceHandler = function (vjs: typeof videojs) {
56 (vjs as any).Html5Hlsjs = Html5Hlsjs 63 (vjs as any).Html5Hlsjs = Html5Hlsjs
57} 64}
58 65
59function hlsjsConfigHandler (this: videojs.Player, options: HlsjsConfigHandlerOptions) { 66// ---------------------------------------------------------------------------
60 const player = this 67// HLS options plugin
68// ---------------------------------------------------------------------------
61 69
62 if (!options) return 70const Plugin = videojs.getPlugin('plugin')
63 71
64 if (!player.srOptions_) { 72class HLSJSConfigHandler extends Plugin {
65 player.srOptions_ = {} 73
66 } 74 constructor (player: videojs.Player, options: HlsjsConfigHandlerOptions) {
75 super(player, options)
76
77 if (!options) return
78
79 if (!player.srOptions_) {
80 player.srOptions_ = {}
81 }
82
83 if (!player.srOptions_.hlsjsConfig) {
84 player.srOptions_.hlsjsConfig = options.hlsjsConfig
85 }
67 86
68 if (!player.srOptions_.hlsjsConfig) { 87 if (options.levelLabelHandler && !player.srOptions_.levelLabelHandler) {
69 player.srOptions_.hlsjsConfig = options.hlsjsConfig 88 player.srOptions_.levelLabelHandler = options.levelLabelHandler
89 }
90
91 registerSourceHandler(videojs)
70 } 92 }
71 93
72 if (options.levelLabelHandler && !player.srOptions_.levelLabelHandler) { 94 dispose () {
73 player.srOptions_.levelLabelHandler = options.levelLabelHandler 95 this.player.srOptions_ = undefined
96
97 const tech = this.player.tech(true) as any
98 if (tech.hlsProvider) {
99 tech.hlsProvider.dispose()
100 tech.hlsProvider = undefined
101 }
102
103 super.dispose()
74 } 104 }
75} 105}
76 106
77const registerConfigPlugin = function (vjs: typeof videojs) { 107videojs.registerPlugin('hlsjs', HLSJSConfigHandler)
78 // Used in Brightcove since we don't pass options directly there 108
79 const registerVjsPlugin = vjs.registerPlugin || vjs.plugin 109// ---------------------------------------------------------------------------
80 registerVjsPlugin('hlsjs', hlsjsConfigHandler) 110// HLS JS source handler
81} 111// ---------------------------------------------------------------------------
82 112
83class Html5Hlsjs { 113export class Html5Hlsjs {
84 private static readonly hooks: { [id: string]: HookFn[] } = {} 114 private static hooks: { [id: string]: HookFn[] } = {}
85 115
86 private readonly videoElement: HTMLVideoElement 116 private readonly videoElement: HTMLVideoElement
87 private readonly errorCounts: ErrorCounts = {} 117 private readonly errorCounts: ErrorCounts = {}
@@ -101,8 +131,9 @@ class Html5Hlsjs {
101 private dvrDuration: number = null 131 private dvrDuration: number = null
102 private edgeMargin: number = null 132 private edgeMargin: number = null
103 133
104 private handlers: { [ id in 'play' ]: EventListener } = { 134 private handlers: { [ id in 'play' | 'error' ]: EventListener } = {
105 play: null 135 play: null,
136 error: null
106 } 137 }
107 138
108 constructor (vjs: typeof videojs, source: videojs.Tech.SourceObject, tech: videojs.Tech) { 139 constructor (vjs: typeof videojs, source: videojs.Tech.SourceObject, tech: videojs.Tech) {
@@ -115,7 +146,7 @@ class Html5Hlsjs {
115 this.videoElement = tech.el() as HTMLVideoElement 146 this.videoElement = tech.el() as HTMLVideoElement
116 this.player = vjs((tech.options_ as any).playerId) 147 this.player = vjs((tech.options_ as any).playerId)
117 148
118 this.videoElement.addEventListener('error', event => { 149 this.handlers.error = event => {
119 let errorTxt: string 150 let errorTxt: string
120 const mediaError = ((event.currentTarget || event.target) as HTMLVideoElement).error 151 const mediaError = ((event.currentTarget || event.target) as HTMLVideoElement).error
121 152
@@ -143,7 +174,8 @@ class Html5Hlsjs {
143 } 174 }
144 175
145 logger.error(`MEDIA_ERROR: ${errorTxt}`) 176 logger.error(`MEDIA_ERROR: ${errorTxt}`)
146 }) 177 }
178 this.videoElement.addEventListener('error', this.handlers.error)
147 179
148 this.initialize() 180 this.initialize()
149 } 181 }
@@ -174,6 +206,7 @@ class Html5Hlsjs {
174 // See comment for `initialize` method. 206 // See comment for `initialize` method.
175 dispose () { 207 dispose () {
176 this.videoElement.removeEventListener('play', this.handlers.play) 208 this.videoElement.removeEventListener('play', this.handlers.play)
209 this.videoElement.removeEventListener('error', this.handlers.error)
177 210
178 // FIXME: https://github.com/video-dev/hls.js/issues/4092 211 // FIXME: https://github.com/video-dev/hls.js/issues/4092
179 const untypedHLS = this.hls as any 212 const untypedHLS = this.hls as any
@@ -200,6 +233,10 @@ class Html5Hlsjs {
200 return true 233 return true
201 } 234 }
202 235
236 static removeAllHooks () {
237 Html5Hlsjs.hooks = {}
238 }
239
203 private _executeHooksFor (type: string) { 240 private _executeHooksFor (type: string) {
204 if (Html5Hlsjs.hooks[type] === undefined) { 241 if (Html5Hlsjs.hooks[type] === undefined) {
205 return 242 return
@@ -421,7 +458,7 @@ class Html5Hlsjs {
421 ? data.level 458 ? data.level
422 : -1 459 : -1
423 460
424 this.player.peertubeResolutions().select({ id: resolutionId, autoResolutionChosenId, byEngine: true }) 461 this.player.peertubeResolutions().select({ id: resolutionId, autoResolutionChosenId, fireCallback: false })
425 }) 462 })
426 463
427 this.hls.attachMedia(this.videoElement) 464 this.hls.attachMedia(this.videoElement)
@@ -433,9 +470,3 @@ class Html5Hlsjs {
433 this._initHlsjs() 470 this._initHlsjs()
434 } 471 }
435} 472}
436
437export {
438 Html5Hlsjs,
439 registerSourceHandler,
440 registerConfigPlugin
441}