@@ -12,45 +12,19 @@ import type {
12
12
} from "./types" ;
13
13
import type { Level } from "hls.js" ;
14
14
15
- export interface HlsPlayerOptions {
16
- multiMediaEl ?: boolean ;
17
- }
18
-
19
15
export class HlsPlayer {
20
- private primaryMedia_ : HTMLMediaElement ;
21
-
22
- private assetMedias_ : HTMLMediaElement [ ] = [ ] ;
23
-
24
- private assetMediaIndex_ = 0 ;
16
+ private media_ : HTMLMediaElement ;
25
17
26
18
private eventManager_ = new EventManager ( ) ;
27
19
28
- private activeMedia_ : HTMLMediaElement ;
29
-
30
- private activeMediaEventManager_ = new EventManager ( ) ;
31
-
32
20
private hls_ : Hls | null = null ;
33
21
34
22
private state_ : State | null = null ;
35
23
36
24
private emitter_ = new EventEmitter < HlsPlayerEventMap > ( ) ;
37
25
38
- constructor (
39
- public container : HTMLDivElement ,
40
- userOptions ?: HlsPlayerOptions ,
41
- ) {
42
- const options = {
43
- ...userOptions ,
44
- multiMediaEl : true ,
45
- } ;
46
-
47
- this . primaryMedia_ = this . activeMedia_ = this . createMedia_ ( ) ;
48
-
49
- if ( options . multiMediaEl ) {
50
- // Create separate media elements for interstitial assets. This is to ensure a smoother
51
- // transition across different playlists.
52
- this . assetMedias_ = [ this . createMedia_ ( ) , this . createMedia_ ( ) ] ;
53
- }
26
+ constructor ( public container : HTMLDivElement ) {
27
+ this . media_ = this . createMedia_ ( ) ;
54
28
55
29
// Make sure we're in unload state.
56
30
this . unload ( ) ;
@@ -69,25 +43,21 @@ export class HlsPlayer {
69
43
}
70
44
71
45
load ( url : string ) {
46
+ this . bindMediaListeners_ ( ) ;
72
47
const hls = this . createHls_ ( ) ;
73
48
74
49
this . state_ = new State ( {
75
50
emitter : this . emitter_ ,
76
- getTiming : ( ) => hls . interstitialsManager ?. primary ?? hls . media ?? null ,
77
- getAssetTiming : ( ) => {
78
- if ( ! hls . interstitialsManager ) {
79
- return null ;
80
- }
81
- return (
82
- hls . interstitialsManager . playerQueue . find (
83
- ( player ) =>
84
- player . assetItem === hls . interstitialsManager ?. playingAsset ,
85
- ) ?? null
86
- ) ;
87
- } ,
51
+ getTiming : ( ) => ( {
52
+ primary : hls . interstitialsManager ?. primary ?? hls . media ,
53
+ asset : hls . interstitialsManager ?. playerQueue . find (
54
+ ( player ) =>
55
+ player . assetItem === hls . interstitialsManager ?. playingAsset ,
56
+ ) ,
57
+ } ) ,
88
58
} ) ;
89
59
90
- hls . attachMedia ( this . primaryMedia_ ) ;
60
+ hls . attachMedia ( this . media_ ) ;
91
61
hls . loadSource ( url ) ;
92
62
93
63
this . hls_ = hls ;
@@ -97,8 +67,6 @@ export class HlsPlayer {
97
67
this . eventManager_ . removeAll ( ) ;
98
68
this . state_ = null ;
99
69
100
- this . setActiveMedia_ ( this . primaryMedia_ ) ;
101
-
102
70
if ( this . hls_ ) {
103
71
this . hls_ . destroy ( ) ;
104
72
this . hls_ = null ;
@@ -108,10 +76,6 @@ export class HlsPlayer {
108
76
destroy ( ) {
109
77
this . emitter_ . removeAllListeners ( ) ;
110
78
this . unload ( ) ;
111
-
112
- this . allMedias_ . forEach ( ( media ) => {
113
- media . remove ( ) ;
114
- } ) ;
115
79
}
116
80
117
81
on = this . emitter_ . on . bind ( this . emitter_ ) ;
@@ -125,9 +89,9 @@ export class HlsPlayer {
125
89
const shouldPause =
126
90
this . state_ . playhead === "play" || this . state_ . playhead === "playing" ;
127
91
if ( shouldPause ) {
128
- this . activeMedia_ . pause ( ) ;
92
+ this . media_ . pause ( ) ;
129
93
} else {
130
- this . activeMedia_ . play ( ) ;
94
+ this . media_ . play ( ) ;
131
95
}
132
96
}
133
97
@@ -137,7 +101,7 @@ export class HlsPlayer {
137
101
if ( this . hls_ . interstitialsManager ) {
138
102
this . hls_ . interstitialsManager . primary . seekTo ( time ) ;
139
103
} else {
140
- this . primaryMedia_ . currentTime = time ;
104
+ this . media_ . currentTime = time ;
141
105
}
142
106
}
143
107
@@ -203,10 +167,8 @@ export class HlsPlayer {
203
167
}
204
168
205
169
setVolume ( volume : number ) {
206
- this . allMedias_ . forEach ( ( media ) => {
207
- media . volume = volume ;
208
- media . muted = volume === 0 ;
209
- } ) ;
170
+ this . media_ . volume = volume ;
171
+ this . media_ . muted = volume === 0 ;
210
172
this . state_ ?. setVolume ( volume ) ;
211
173
}
212
174
@@ -234,8 +196,8 @@ export class HlsPlayer {
234
196
return getState ( this . state_ , "seeking" ) ;
235
197
}
236
198
237
- get asset ( ) {
238
- return getState ( this . state_ , "asset " ) ;
199
+ get interstitial ( ) {
200
+ return getState ( this . state_ , "interstitial " ) ;
239
201
}
240
202
241
203
get qualities ( ) {
@@ -270,26 +232,19 @@ export class HlsPlayer {
270
232
} ) ;
271
233
272
234
listen ( Hls . Events . INTERSTITIAL_STARTED , ( ) => {
273
- if ( this . assetMedias_ . length ) {
274
- this . primaryMedia_ . pause ( ) ;
275
- }
235
+ this . state_ ?. setInterstitial ( {
236
+ asset : null ,
237
+ } ) ;
276
238
} ) ;
277
239
278
240
listen ( Hls . Events . INTERSTITIAL_ASSET_STARTED , ( _ , data ) => {
279
- const media = this . claimAssetMedia_ ( ) ;
280
- if ( media ) {
281
- data . player . attachMedia ( media ) ;
282
- this . setActiveMedia_ ( media ) ;
283
- }
284
-
285
241
const listResponseAsset = data . event . assetListResponse ?. ASSETS [
286
242
data . assetListIndex
287
243
] as {
288
244
"SPRS-KIND" ?: "ad" | "bumper" ;
289
245
} ;
290
246
291
247
this . state_ ?. setAsset ( {
292
- player : data . player ,
293
248
type : listResponseAsset [ "SPRS-KIND" ] ,
294
249
} ) ;
295
250
} ) ;
@@ -298,9 +253,8 @@ export class HlsPlayer {
298
253
this . state_ ?. setAsset ( null ) ;
299
254
} ) ;
300
255
301
- listen ( Hls . Events . INTERSTITIALS_PRIMARY_RESUMED , ( ) => {
302
- this . assetMediaIndex_ = 0 ;
303
- this . setActiveMedia_ ( this . primaryMedia_ ) ;
256
+ listen ( Hls . Events . INTERSTITIAL_ENDED , ( ) => {
257
+ this . state_ ?. setInterstitial ( null ) ;
304
258
} ) ;
305
259
306
260
listen ( Hls . Events . LEVELS_UPDATED , ( ) => {
@@ -330,63 +284,6 @@ export class HlsPlayer {
330
284
return hls ;
331
285
}
332
286
333
- private claimAssetMedia_ ( ) {
334
- if ( ! this . assetMedias_ . length ) {
335
- return null ;
336
- }
337
-
338
- const media = this . assetMedias_ [ this . assetMediaIndex_ ] ;
339
- this . assetMediaIndex_ =
340
- ( this . assetMediaIndex_ + 1 ) % this . assetMedias_ . length ;
341
-
342
- return media ;
343
- }
344
-
345
- private setActiveMedia_ ( media : HTMLMediaElement ) {
346
- this . allMedias_ . forEach ( ( element ) => {
347
- element . style . opacity = element === media ? "1" : "0" ;
348
- } ) ;
349
-
350
- this . activeMedia_ = media ;
351
-
352
- this . activeMediaEventManager_ . removeAll ( ) ;
353
- const listen = this . activeMediaEventManager_ . listen ( media ) ;
354
-
355
- listen ( "canplay" , ( ) => {
356
- this . state_ ?. setReady ( ) ;
357
- } ) ;
358
-
359
- listen ( "play" , ( ) => {
360
- this . state_ ?. setPlayhead ( "play" ) ;
361
- } ) ;
362
-
363
- listen ( "playing" , ( ) => {
364
- this . state_ ?. setStarted ( ) ;
365
-
366
- this . state_ ?. setPlayhead ( "playing" ) ;
367
- } ) ;
368
-
369
- listen ( "pause" , ( ) => {
370
- this . state_ ?. setPlayhead ( "pause" ) ;
371
- } ) ;
372
-
373
- listen ( "volumechange" , ( ) => {
374
- this . state_ ?. setVolume ( media . volume ) ;
375
- } ) ;
376
-
377
- listen ( "seeking" , ( ) => {
378
- this . state_ ?. setSeeking ( true ) ;
379
- } ) ;
380
-
381
- listen ( "seeked" , ( ) => {
382
- this . state_ ?. setSeeking ( false ) ;
383
- } ) ;
384
- }
385
-
386
- private get allMedias_ ( ) {
387
- return [ this . primaryMedia_ , ...this . assetMedias_ ] ;
388
- }
389
-
390
287
private updateQualities_ ( ) {
391
288
assert ( this . hls_ ) ;
392
289
@@ -461,4 +358,38 @@ export class HlsPlayer {
461
358
462
359
this . state_ ?. setSubtitleTracks ( tracks ) ;
463
360
}
361
+
362
+ private bindMediaListeners_ ( ) {
363
+ const listen = this . eventManager_ . listen ( this . media_ ) ;
364
+
365
+ listen ( "canplay" , ( ) => {
366
+ this . state_ ?. setReady ( ) ;
367
+ } ) ;
368
+
369
+ listen ( "play" , ( ) => {
370
+ this . state_ ?. setPlayhead ( "play" ) ;
371
+ } ) ;
372
+
373
+ listen ( "playing" , ( ) => {
374
+ this . state_ ?. setStarted ( ) ;
375
+
376
+ this . state_ ?. setPlayhead ( "playing" ) ;
377
+ } ) ;
378
+
379
+ listen ( "pause" , ( ) => {
380
+ this . state_ ?. setPlayhead ( "pause" ) ;
381
+ } ) ;
382
+
383
+ listen ( "volumechange" , ( ) => {
384
+ this . state_ ?. setVolume ( this . media_ . volume ) ;
385
+ } ) ;
386
+
387
+ listen ( "seeking" , ( ) => {
388
+ this . state_ ?. setSeeking ( true ) ;
389
+ } ) ;
390
+
391
+ listen ( "seeked" , ( ) => {
392
+ this . state_ ?. setSeeking ( false ) ;
393
+ } ) ;
394
+ }
464
395
}
0 commit comments