@gcorevideo/player 2.28.27 → 2.28.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,13 +6,22 @@
6
6
  import { Events, Log, Playback, PlayerError, Utils, $ } from '@clappr/core'
7
7
  import { trace } from '@gcorevideo/utils'
8
8
  import assert from 'assert'
9
- import DASHJS, {
9
+ import {
10
10
  ErrorEvent as DashErrorEvent,
11
+ MediaPlayer,
12
+ MediaPlayerClass,
11
13
  MediaPlayerErrorEvent,
12
14
  PlaybackErrorEvent as DashPlaybackErrorEvent,
13
- type BitrateInfo as DashBitrateInfo,
15
+ MediaInfo as DashMediaInfo,
14
16
  MetricEvent as DashMetricEvent,
15
17
  IManifestInfo,
18
+ MediaInfo,
19
+ QualityChangeRenderedEvent,
20
+ TrackChangeRenderedEvent,
21
+ PlaybackRateChangedEvent,
22
+ Representation,
23
+ CueEnterEvent,
24
+ CueExitEvent,
16
25
  } from 'dashjs'
17
26
 
18
27
  import {
@@ -21,6 +30,7 @@ import {
21
30
  QualityLevel,
22
31
  TimePosition,
23
32
  TimeValue,
33
+ VTTCueInfo,
24
34
  } from '../../playback.types.js'
25
35
  import { isDashSource } from '../../utils/mediaSources.js'
26
36
  import { BasePlayback } from '../BasePlayback.js'
@@ -47,9 +57,9 @@ type LocalTimeCorrelation = {
47
57
  const T = 'playback.dash'
48
58
 
49
59
  export default class DashPlayback extends BasePlayback {
50
- _levels: QualityLevel[] | null = null
60
+ _levels: QualityLevel[] = []
51
61
 
52
- _currentLevel: number | null = null
62
+ _currentLevel: number = AUTO
53
63
 
54
64
  // true when the actual duration is longer than hlsjs's live sync point
55
65
  // when this is false playableRegionDuration will be the actual duration
@@ -78,7 +88,7 @@ export default class DashPlayback extends BasePlayback {
78
88
 
79
89
  _programDateTime: TimeValue = 0
80
90
 
81
- _dash: DASHJS.MediaPlayerClass | null = null
91
+ _dash: MediaPlayerClass | null = null
82
92
 
83
93
  _extrapolatedWindowDuration: number = 0
84
94
 
@@ -100,19 +110,19 @@ export default class DashPlayback extends BasePlayback {
100
110
 
101
111
  _timeUpdateTimer: ReturnType<typeof setInterval> | null = null
102
112
 
113
+ oncueenter: ((e: VTTCueInfo) => void) | null = null
114
+
115
+ oncueexit: ((e: { id: string }) => void) | null = null
116
+
103
117
  get name() {
104
118
  return 'dash'
105
119
  }
106
120
 
107
121
  get levels(): QualityLevel[] {
108
- return this._levels || []
122
+ return this._levels
109
123
  }
110
124
 
111
125
  get currentLevel(): number {
112
- if (this._currentLevel === null) {
113
- return AUTO
114
- }
115
- // 0 is a valid level ID
116
126
  return this._currentLevel
117
127
  }
118
128
 
@@ -143,7 +153,7 @@ export default class DashPlayback extends BasePlayback {
143
153
 
144
154
  dash.updateSettings(settings)
145
155
  if (id !== -1) {
146
- this._dash.setQualityFor('video', id)
156
+ this._dash.setRepresentationForTypeByIndex('video', id)
147
157
  }
148
158
  if (this._playbackType === Playback.VOD) {
149
159
  const curr_time = this._dash.time()
@@ -159,6 +169,7 @@ export default class DashPlayback extends BasePlayback {
159
169
  }
160
170
 
161
171
  get _startTime() {
172
+ // TODO review
162
173
  if (
163
174
  this._playbackType === Playback.LIVE &&
164
175
  this._playlistType !== 'EVENT'
@@ -226,7 +237,7 @@ export default class DashPlayback extends BasePlayback {
226
237
  }
227
238
 
228
239
  _setup() {
229
- const dash = DASHJS.MediaPlayer().create()
240
+ const dash = MediaPlayer().create()
230
241
  this._dash = dash
231
242
  this._dash.initialize()
232
243
 
@@ -237,6 +248,7 @@ export default class DashPlayback extends BasePlayback {
237
248
  streaming: {
238
249
  text: {
239
250
  defaultEnabled: false,
251
+ dispatchForManualRendering: true,
240
252
  },
241
253
  },
242
254
  },
@@ -245,29 +257,29 @@ export default class DashPlayback extends BasePlayback {
245
257
  this._dash.updateSettings(settings)
246
258
  }
247
259
 
248
- this._dash.attachView(this.el)
260
+ this._dash.attachView(this.el as HTMLMediaElement)
249
261
 
250
262
  this._dash.setAutoPlay(false)
251
263
  this._dash.attachSource(this.options.src)
252
264
 
253
- this._dash.on(DASHJS.MediaPlayer.events.ERROR, this._onDASHJSSError)
265
+ this._dash.on(MediaPlayer.events.ERROR, this._onDASHJSSError)
254
266
  this._dash.on(
255
- DASHJS.MediaPlayer.events.PLAYBACK_ERROR,
267
+ MediaPlayer.events.PLAYBACK_ERROR,
256
268
  this._onPlaybackError,
257
269
  )
258
270
 
259
- this._dash.on(DASHJS.MediaPlayer.events.STREAM_INITIALIZED, () => {
260
- const bitrates = dash.getBitrateInfoListFor('video')
271
+ this._dash.on(MediaPlayer.events.STREAM_INITIALIZED, () => {
272
+ const bitrates = dash.getRepresentationsByType('video')
261
273
 
262
274
  this._updatePlaybackType()
263
275
  this._fillLevels(bitrates)
264
- const currentLevel = dash.getQualityFor('video')
265
- if (currentLevel !== -1) {
266
- this.trigger(Events.PLAYBACK_BITRATE, this.getLevel(currentLevel))
276
+ const currentLevel = dash.getCurrentRepresentationForType('video')
277
+ if (currentLevel) {
278
+ this.trigger(Events.PLAYBACK_BITRATE, this.getLevel(currentLevel.index))
267
279
  }
268
280
 
269
- dash.on(DASHJS.MediaPlayer.events.QUALITY_CHANGE_REQUESTED, (evt) => {
270
- const newLevel = this.getLevel(evt.newQuality)
281
+ dash.on(MediaPlayer.events.QUALITY_CHANGE_REQUESTED, (evt) => {
282
+ const newLevel = this.getLevel(evt.newRepresentation.index)
271
283
  this.onLevelSwitch(newLevel)
272
284
  })
273
285
 
@@ -275,15 +287,15 @@ export default class DashPlayback extends BasePlayback {
275
287
  })
276
288
 
277
289
  this._dash.on(
278
- DASHJS.MediaPlayer.events.QUALITY_CHANGE_RENDERED,
279
- (evt: DASHJS.QualityChangeRenderedEvent) => {
280
- const currentLevel = this.getLevel(evt.newQuality)
290
+ MediaPlayer.events.QUALITY_CHANGE_RENDERED,
291
+ (evt: QualityChangeRenderedEvent) => {
292
+ const currentLevel = this.getLevel(evt.newRepresentation.index)
281
293
  this.onLevelSwitchEnd(currentLevel)
282
294
  },
283
295
  )
284
296
 
285
297
  this._dash.on(
286
- DASHJS.MediaPlayer.events.METRIC_ADDED,
298
+ MediaPlayer.events.METRIC_ADDED,
287
299
  (e: DashMetricEvent) => {
288
300
  // Listen for the first manifest request in order to update player UI
289
301
  if ((e.metric as string) === 'DVRInfo') {
@@ -302,20 +314,34 @@ export default class DashPlayback extends BasePlayback {
302
314
  )
303
315
 
304
316
  this._dash.on(
305
- DASHJS.MediaPlayer.events.PLAYBACK_RATE_CHANGED,
306
- (e: DASHJS.PlaybackRateChangedEvent) => {
317
+ MediaPlayer.events.PLAYBACK_RATE_CHANGED,
318
+ (e: PlaybackRateChangedEvent) => {
307
319
  this.trigger(PlaybackEvents.PLAYBACK_RATE_CHANGED, e.playbackRate)
308
320
  },
309
321
  )
310
322
 
311
- this._dash.on(DASHJS.MediaPlayer.events.TRACK_CHANGE_RENDERED, (e: any) => {
312
- if ((e as DASHJS.TrackChangeRenderedEvent).mediaType === 'audio') {
323
+ this._dash.on(MediaPlayer.events.TRACK_CHANGE_RENDERED, (e: any) => {
324
+ if ((e as TrackChangeRenderedEvent).mediaType === 'audio') {
313
325
  this.trigger(
314
326
  Events.PLAYBACK_AUDIO_CHANGED,
315
327
  toClapprTrack(e.newMediaInfo),
316
328
  )
317
329
  }
318
330
  })
331
+
332
+ this._dash.on(MediaPlayer.events.CUE_ENTER, (e: CueEnterEvent) => {
333
+ this.oncueenter?.({
334
+ end: e.end,
335
+ id: e.id,
336
+ start: e.start,
337
+ text: e.text,
338
+ })
339
+ })
340
+ this._dash.on(MediaPlayer.events.CUE_EXIT, (e: CueExitEvent) => {
341
+ this.oncueexit?.({
342
+ id: e.id,
343
+ })
344
+ })
319
345
  }
320
346
 
321
347
  render() {
@@ -431,8 +457,7 @@ export default class DashPlayback extends BasePlayback {
431
457
  }
432
458
 
433
459
  private _onPlaybackError = (event: DashPlaybackErrorEvent) => {
434
- // TODO
435
- trace(`${T} _onPlaybackError`, { event })
460
+ trace(`${T} _onPlaybackError`, { type: event.type, code: event.error.code, message: event.error.message })
436
461
  }
437
462
 
438
463
  private _onDASHJSSError = (event: DashErrorEvent) => {
@@ -442,17 +467,17 @@ export default class DashPlayback extends BasePlayback {
442
467
  const e = (event as MediaPlayerErrorEvent).error
443
468
  switch (e.code) {
444
469
  // TODO test handling of these errors
445
- case DASHJS.MediaPlayer.errors.MANIFEST_LOADER_PARSING_FAILURE_ERROR_CODE:
446
- case DASHJS.MediaPlayer.errors.MANIFEST_LOADER_LOADING_FAILURE_ERROR_CODE:
447
- case DASHJS.MediaPlayer.errors.DOWNLOAD_ERROR_ID_MANIFEST_CODE:
448
- case DASHJS.MediaPlayer.errors.DOWNLOAD_ERROR_ID_CONTENT_CODE:
449
- case DASHJS.MediaPlayer.errors.DOWNLOAD_ERROR_ID_INITIALIZATION_CODE:
470
+ case MediaPlayer.errors.MANIFEST_LOADER_PARSING_FAILURE_ERROR_CODE:
471
+ case MediaPlayer.errors.MANIFEST_LOADER_LOADING_FAILURE_ERROR_CODE:
472
+ case MediaPlayer.errors.DOWNLOAD_ERROR_ID_MANIFEST_CODE:
473
+ case MediaPlayer.errors.DOWNLOAD_ERROR_ID_CONTENT_CODE:
474
+ case MediaPlayer.errors.DOWNLOAD_ERROR_ID_INITIALIZATION_CODE:
450
475
  // TODO these probably indicate a broken manifest and should be treated by removing the source
451
- case DASHJS.MediaPlayer.errors.MANIFEST_ERROR_ID_NOSTREAMS_CODE:
452
- case DASHJS.MediaPlayer.errors.MANIFEST_ERROR_ID_PARSE_CODE:
453
- case DASHJS.MediaPlayer.errors.MANIFEST_ERROR_ID_MULTIPLEXED_CODE:
454
- case DASHJS.MediaPlayer.errors.MEDIASOURCE_TYPE_UNSUPPORTED_CODE:
455
- case DASHJS.MediaPlayer.errors.SEGMENT_BASE_LOADER_ERROR_CODE:
476
+ case MediaPlayer.errors.MANIFEST_ERROR_ID_NOSTREAMS_CODE:
477
+ case MediaPlayer.errors.MANIFEST_ERROR_ID_PARSE_CODE:
478
+ case MediaPlayer.errors.MANIFEST_ERROR_ID_MULTIPLEXED_CODE:
479
+ case MediaPlayer.errors.MEDIASOURCE_TYPE_UNSUPPORTED_CODE:
480
+ case MediaPlayer.errors.SEGMENT_BASE_LOADER_ERROR_CODE:
456
481
  this.triggerError({
457
482
  code: PlaybackErrorCode.MediaSourceUnavailable,
458
483
  message: e.message,
@@ -525,7 +550,7 @@ export default class DashPlayback extends BasePlayback {
525
550
  return false
526
551
  }
527
552
  return (
528
- this._dash?.getDVRWindowSize() >= this._minDvrSize &&
553
+ this._dash?.getDvrWindow()?.size >= this._minDvrSize &&
529
554
  this.getPlaybackType() === Playback.LIVE
530
555
  )
531
556
  }
@@ -572,16 +597,23 @@ export default class DashPlayback extends BasePlayback {
572
597
 
573
598
  private destroyInstance() {
574
599
  if (this._dash) {
575
- this._dash.off(DASHJS.MediaPlayer.events.ERROR, this._onDASHJSSError)
600
+ this._dash.off(MediaPlayer.events.ERROR, this._onDASHJSSError)
576
601
  this._dash.off(
577
- DASHJS.MediaPlayer.events.PLAYBACK_ERROR,
602
+ MediaPlayer.events.PLAYBACK_ERROR,
578
603
  this._onPlaybackError,
579
604
  )
580
605
  this._dash.off(
581
- DASHJS.MediaPlayer.events.MANIFEST_LOADED,
606
+ MediaPlayer.events.MANIFEST_LOADED,
582
607
  this.getDuration,
583
608
  )
609
+ const tracks = this._dash.getTracksFor('text')
610
+ tracks.forEach(track => {
611
+ if (track.id) {
612
+ this._dash!.removeExternalSubtitleById(track.id)
613
+ }
614
+ })
584
615
  this._dash.reset()
616
+ this._dash.destroy()
585
617
  this._dash = null
586
618
  }
587
619
  }
@@ -601,12 +633,11 @@ export default class DashPlayback extends BasePlayback {
601
633
  }
602
634
  }
603
635
 
604
- _fillLevels(levels: DashBitrateInfo[]) {
605
- // TOOD check that levels[i].qualityIndex === i
636
+ private _fillLevels(levels: Representation[]) {
606
637
  this._levels = levels.map((level) => {
607
638
  return {
608
- level: level.qualityIndex,
609
- bitrate: level.bitrate,
639
+ level: level.index,
640
+ bitrate: level.bitrateInKbit * 1000,
610
641
  width: level.width,
611
642
  height: level.height,
612
643
  }
@@ -635,10 +666,10 @@ export default class DashPlayback extends BasePlayback {
635
666
  return this._playbackType === Playback.VOD || this.dvrEnabled
636
667
  }
637
668
 
638
- private getLevel(quality: number) {
639
- const ret = this.levels.find((level) => level.level === quality)
640
- assert.ok(ret, 'Invalid quality level')
641
- return ret
669
+ private getLevel(quality: number): QualityLevel {
670
+ const level = this.levels.find((level) => level.level === quality)
671
+ assert.ok(level, 'Invalid quality level')
672
+ return level
642
673
  }
643
674
 
644
675
  setPlaybackRate(rate: number) {
@@ -692,6 +723,35 @@ export default class DashPlayback extends BasePlayback {
692
723
  super._handleTextTrackChange()
693
724
  this._dash?.setTextTrack(this.closedCaptionsTrackId)
694
725
  }
726
+
727
+ setTextTrack(id: number) {
728
+ this._dash?.setTextTrack(id)
729
+ }
730
+
731
+ /**
732
+ * @override
733
+ */
734
+ get closedCaptionsTracks() {
735
+ const tt = this.getTextTracks()
736
+ return tt;
737
+ }
738
+
739
+ private getTextTracks() {
740
+ return this._dash?.getTracksFor('text').map((t: DashMediaInfo, index: number) => ({
741
+ id: index,
742
+ name: getTextTrackLabel(t) || "",
743
+ track: {
744
+ id: index,
745
+ label: getTextTrackLabel(t) || "",
746
+ language: t.lang,
747
+ mode: "hidden",
748
+ },
749
+ })) || []
750
+ }
751
+ }
752
+
753
+ function getTextTrackLabel(t: DashMediaInfo) {
754
+ return t.labels.find((l) => !l.lang || l.lang === t.lang)?.text
695
755
  }
696
756
 
697
757
  DashPlayback.canPlay = function (resource, mimeType) {
@@ -707,7 +767,7 @@ DashPlayback.canPlay = function (resource, mimeType) {
707
767
  return typeof ctor === 'function'
708
768
  }
709
769
 
710
- function toClapprTrack(t: DASHJS.MediaInfo): AudioTrack {
770
+ function toClapprTrack(t: MediaInfo): AudioTrack {
711
771
  return {
712
772
  id: t.id,
713
773
  kind: t.roles && t.roles?.length > 0 ? t.roles[0] : 'main', // TODO