@gcorevideo/player 2.6.0 → 2.6.2

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.
@@ -2,14 +2,8 @@
2
2
  // Use of this source code is governed by a BSD-style
3
3
  // license that can be found in the LICENSE file.
4
4
 
5
- import {
6
- Events,
7
- HTML5Video,
8
- Log,
9
- Playback,
10
- Utils,
11
- } from '@clappr/core'
12
- import assert from 'assert' // uses Node.js's assert types
5
+ import { Events, HTML5Video, Log, Playback, Utils } from '@clappr/core'
6
+ import assert from 'assert'
13
7
  import DASHJS, {
14
8
  ErrorEvent as DashErrorEvent,
15
9
  PlaybackErrorEvent as DashPlaybackErrorEvent,
@@ -50,16 +44,29 @@ export default class DashPlayback extends HTML5Video {
50
44
 
51
45
  _currentLevel: number | null = null
52
46
 
47
+ // true when the actual duration is longer than hlsjs's live sync point
48
+ // when this is false playableRegionDuration will be the actual duration
49
+ // when this is true playableRegionDuration will exclude the time after the sync point
53
50
  _durationExcludesAfterLiveSyncPoint: boolean = false
54
51
 
55
52
  _isReadyState: boolean = false
56
53
 
54
+ // if content is removed from the beginning then this empty area should
55
+ // be ignored. "playableRegionDuration" excludes the empty area
57
56
  _playableRegionDuration: number = 0
58
57
 
58
+ // for hls streams which have dvr with a sliding window,
59
+ // the content at the start of the playlist is removed as new
60
+ // content is appended at the end.
61
+ // this means the actual playable start time will increase as the
62
+ // start content is deleted
63
+ // For streams with dvr where the entire recording is kept from the
64
+ // beginning this should stay as 0
59
65
  _playableRegionStartTime: number = 0
60
66
 
61
67
  _playbackType: PlaybackType = Playback.VOD
62
68
 
69
+ // #EXT-X-PLAYLIST-TYPE
63
70
  _playlistType: PlaylistType | null = null
64
71
 
65
72
  // #EXT-X-PROGRAM-DATE-TIME
@@ -69,22 +76,20 @@ export default class DashPlayback extends HTML5Video {
69
76
 
70
77
  _extrapolatedWindowDuration: number = 0
71
78
 
72
- _extrapolatedWindowNumSegments: number = 0
79
+ // _extrapolatedWindowNumSegments: number = 0
73
80
 
74
81
  _lastDuration: TimeValue | null = null
75
82
 
76
83
  _lastTimeUpdate: TimePosition = { current: 0, total: 0 }
77
84
 
85
+ // {local, remote} remote is the time in the video element that should represent 0
86
+ // local is the system time when the 'remote' measurment took place
78
87
  _localStartTimeCorrelation: LocalTimeCorrelation | null = null
79
88
 
89
+ // {local, remote} remote is the time in the video element that should represents the end
90
+ // local is the system time when the 'remote' measurment took place
80
91
  _localEndTimeCorrelation: LocalTimeCorrelation | null = null
81
92
 
82
- _recoverAttemptsRemaining: number = 0
83
-
84
- _recoveredAudioCodecError = false
85
-
86
- _recoveredDecodingError = false
87
-
88
93
  startChangeQuality = false
89
94
 
90
95
  manifestInfo: IManifestInfo | null = null
@@ -114,27 +119,23 @@ export default class DashPlayback extends HTML5Video {
114
119
  return this._isReadyState
115
120
  }
116
121
 
117
- set currentLevel(id) {
122
+ set currentLevel(id: number) {
118
123
  this._currentLevel = id
119
124
 
120
125
  this.trigger(Events.PLAYBACK_LEVEL_SWITCH_START)
121
- const cfg = {
122
- streaming: {
123
- abr: {
124
- autoSwitchBitrate: {
125
- video: id === -1,
126
- },
127
- ABRStrategy: 'abrL2A',
128
- },
129
- },
130
- }
126
+
127
+ const settings = this.options.dash ? structuredClone(this.options.dash) : {}
128
+ settings.streaming = settings.streaming || {}
129
+ settings.streaming.abr = settings.streaming.abr || {}
130
+ settings.streaming.abr.autoSwitchBitrate = settings.streaming.abr.autoSwitchBitrate || {}
131
+ settings.streaming.abr.autoSwitchBitrate.video = id === -1
131
132
 
132
133
  assert.ok(
133
134
  this._dash,
134
135
  'An instance of dashjs MediaPlayer is required to switch levels',
135
136
  )
136
137
  const dash = this._dash
137
- this.options.dash && dash.updateSettings({ ...this.options.dash, ...cfg })
138
+ dash.updateSettings(settings)
138
139
  if (id !== -1) {
139
140
  this._dash.setQualityFor('video', id)
140
141
  }
@@ -213,52 +214,9 @@ export default class DashPlayback extends HTML5Video {
213
214
 
214
215
  constructor(options: any, i18n: string, playerError?: any) {
215
216
  super(options, i18n, playerError)
216
- // backwards compatibility (TODO: remove on 0.3.0)
217
- // this.options.playback || (this.options.playback = this.options);
218
- // The size of the start time extrapolation window measured as a multiple of segments.
219
- // Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
220
- // removed from the start of the playlist at a time. E.g if the playlist is cached for 10 seconds and new chunks are
221
- // added/removed every 5.
222
- this._extrapolatedWindowNumSegments =
223
- this.options.playback?.extrapolatedWindowNumSegments ?? 2
224
-
225
217
  if (this.options.playbackType) {
226
218
  this._playbackType = this.options.playbackType
227
219
  }
228
- // this._lastTimeUpdate = { current: 0, total: 0 };
229
- // this._lastDuration = null;
230
- // for hls streams which have dvr with a sliding window,
231
- // the content at the start of the playlist is removed as new
232
- // content is appended at the end.
233
- // this means the actual playable start time will increase as the
234
- // start content is deleted
235
- // For streams with dvr where the entire recording is kept from the
236
- // beginning this should stay as 0
237
- // this._playableRegionStartTime = 0;
238
- // {local, remote} remote is the time in the video element that should represent 0
239
- // local is the system time when the 'remote' measurment took place
240
- // this._localStartTimeCorrelation = null;
241
- // {local, remote} remote is the time in the video element that should represents the end
242
- // local is the system time when the 'remote' measurment took place
243
- // this._localEndTimeCorrelation = null;
244
- // if content is removed from the beginning then this empty area should
245
- // be ignored. "playableRegionDuration" excludes the empty area
246
- // this._playableRegionDuration = 0;
247
- // #EXT-X-PROGRAM-DATE-TIME
248
- // this._programDateTime = 0;
249
-
250
- // this.manifestInfo = null;
251
- // true when the actual duration is longer than hlsjs's live sync point
252
- // when this is false playableRegionDuration will be the actual duration
253
- // when this is true playableRegionDuration will exclude the time after the sync point
254
- // this._durationExcludesAfterLiveSyncPoint = false;
255
- // // #EXT-X-TARGETDURATION
256
- // this._segmentTargetDuration = null;
257
- // #EXT-X-PLAYLIST-TYPE
258
- // this._playlistType = null;
259
- if (this.options.hlsRecoverAttempts) {
260
- this._recoverAttemptsRemaining = this.options.hlsRecoverAttempts
261
- }
262
220
  }
263
221
 
264
222
  _setup() {
@@ -266,12 +224,18 @@ export default class DashPlayback extends HTML5Video {
266
224
  this._dash = dash
267
225
  this._dash.initialize()
268
226
 
269
- const cfg = this.options.dash ?? {}
270
-
271
- cfg.streaming = cfg.streaming || {}
272
- cfg.streaming.text = cfg.streaming.text || { defaultEnabled: false }
273
-
274
- this.options.dash && this._dash.updateSettings(cfg)
227
+ if (this.options.dash) {
228
+ const settings = structuredClone(this.options.dash)
229
+ if (!settings.streaming) {
230
+ settings.streaming = {}
231
+ }
232
+ if (!settings.streaming.text) {
233
+ settings.streaming.text = {
234
+ defaultEnabled: false,
235
+ }
236
+ }
237
+ this._dash.updateSettings(this.options.dash)
238
+ }
275
239
 
276
240
  this._dash.attachView(this.el)
277
241
 
@@ -338,30 +302,6 @@ export default class DashPlayback extends HTML5Video {
338
302
  this.trigger(Events.PLAYBACK_READY, this.name)
339
303
  }
340
304
 
341
- // TODO
342
- // _recover(evt, data, error) {
343
- // console.warn('recover', evt, data, error);
344
- // assert.ok(this._dash, 'An instance of dashjs MediaPlayer is required to recover');
345
- // // TODO figure out what's going on here
346
- // const dash = this._dash;
347
- // if (!this._recoveredDecodingError) {
348
- // this._recoveredDecodingError = true;
349
- // // dash.recoverMediaError();
350
- // } else if (!this._recoveredAudioCodecError) {
351
- // this._recoveredAudioCodecError = true;
352
- // // dash.swapAudioCodec();
353
- // // dash.recoverMediaError();
354
- // } else {
355
- // // TODO what does it have to do with hlsjs?
356
- // Log.error('hlsjs: failed to recover', { evt, data });
357
- // error.level = PlayerError.Levels.FATAL;
358
- // const formattedError = this.createError(error);
359
-
360
- // this.trigger(Events.PLAYBACK_ERROR, formattedError);
361
- // this.stop();
362
- // }
363
- // }
364
-
365
305
  // override
366
306
  _setupSrc() {
367
307
  // this playback manages the src on the video element itself
@@ -453,7 +393,6 @@ export default class DashPlayback extends HTML5Video {
453
393
  _updateSettings() {
454
394
  if (this._playbackType === Playback.VOD) {
455
395
  this.settings.left = ['playpause', 'position', 'duration']
456
- // this.settings.left.push('playstop');
457
396
  } else if (this.dvrEnabled) {
458
397
  this.settings.left = ['playpause']
459
398
  } else {
@@ -700,147 +639,6 @@ export default class DashPlayback extends HTML5Video {
700
639
  this.trigger(Events.PLAYBACK_LEVELS_AVAILABLE, this._levels)
701
640
  }
702
641
 
703
- // _onLevelUpdated(_: any, data) {
704
- // this._segmentTargetDuration = data.details.targetduration;
705
- // this._playlistType = data.details.type || null;
706
-
707
- // let startTimeChanged = false;
708
- // let durationChanged = false;
709
- // const fragments = data.details.fragments;
710
- // const previousPlayableRegionStartTime = this._playableRegionStartTime;
711
- // const previousPlayableRegionDuration = this._playableRegionDuration;
712
-
713
- // if (fragments.length === 0) {
714
- // return;
715
- // }
716
-
717
- // // #EXT-X-PROGRAM-DATE-TIME
718
- // if (fragments[0].rawProgramDateTime) {
719
- // this._programDateTime = fragments[0].rawProgramDateTime;
720
- // }
721
-
722
- // if (this._playableRegionStartTime !== fragments[0].start) {
723
- // startTimeChanged = true;
724
- // this._playableRegionStartTime = fragments[0].start;
725
- // }
726
-
727
- // if (startTimeChanged) {
728
- // if (!this._localStartTimeCorrelation) {
729
- // // set the correlation to map to middle of the extrapolation window
730
- // this._localStartTimeCorrelation = {
731
- // local: this._now,
732
- // remote: (fragments[0].start + (this._extrapolatedWindowDuration / 2)) * 1000
733
- // };
734
- // } else {
735
- // // check if the correlation still works
736
- // const corr = this._localStartTimeCorrelation;
737
- // const timePassed = this._now - corr.local;
738
- // // this should point to a time within the extrapolation window
739
- // const startTime = (corr.remote + timePassed) / 1000;
740
-
741
- // if (startTime < fragments[0].start) {
742
- // // our start time is now earlier than the first chunk
743
- // // (maybe the chunk was removed early)
744
- // // reset correlation so that it sits at the beginning of the first available chunk
745
- // this._localStartTimeCorrelation = {
746
- // local: this._now,
747
- // remote: fragments[0].start * 1000
748
- // };
749
- // } else if (startTime > previousPlayableRegionStartTime + this._extrapolatedWindowDuration) {
750
- // // start time was past the end of the old extrapolation window (so would have been capped)
751
- // // see if now that time would be inside the window, and if it would be set the correlation
752
- // // so that it resumes from the time it was at at the end of the old window
753
- // // update the correlation so that the time starts counting again from the value it's on now
754
- // this._localStartTimeCorrelation = {
755
- // local: this._now,
756
- // remote: Math.max(
757
- // fragments[0].start,
758
- // previousPlayableRegionStartTime + this._extrapolatedWindowDuration
759
- // ) * 1000
760
- // };
761
- // }
762
- // }
763
- // }
764
-
765
- // let newDuration = data.details.totalduration;
766
-
767
- // // if it's a live stream then shorten the duration to remove access
768
- // // to the area after hlsjs's live sync point
769
- // // seeks to areas after this point sometimes have issues
770
- // if (this._playbackType === Playback.LIVE) {
771
- // const fragmentTargetDuration = data.details.targetduration;
772
- // const hlsjsConfig = this.options.playback.hlsjsConfig || {};
773
- // // eslint-disable-next-line no-undef
774
- // const liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount || HLSJS.DefaultConfig.liveSyncDurationCount;
775
- // const hiddenAreaDuration = fragmentTargetDuration * liveSyncDurationCount;
776
-
777
- // if (hiddenAreaDuration <= newDuration) {
778
- // newDuration -= hiddenAreaDuration;
779
- // this._durationExcludesAfterLiveSyncPoint = true;
780
- // } else {
781
- // this._durationExcludesAfterLiveSyncPoint = false;
782
- // }
783
- // }
784
-
785
- // if (newDuration !== this._playableRegionDuration) {
786
- // durationChanged = true;
787
- // this._playableRegionDuration = newDuration;
788
- // }
789
-
790
- // // Note the end time is not the playableRegionDuration
791
- // // The end time will always increase even if content is removed from the beginning
792
- // const endTime = fragments[0].start + newDuration;
793
- // const previousEndTime = previousPlayableRegionStartTime + previousPlayableRegionDuration;
794
- // const endTimeChanged = endTime !== previousEndTime;
795
-
796
- // if (endTimeChanged) {
797
- // if (!this._localEndTimeCorrelation) {
798
- // // set the correlation to map to the end
799
- // this._localEndTimeCorrelation = {
800
- // local: this._now,
801
- // remote: endTime * 1000
802
- // };
803
- // } else {
804
- // // check if the correlation still works
805
- // const corr = this._localEndTimeCorrelation;
806
- // const timePassed = this._now - corr.local;
807
- // // this should point to a time within the extrapolation window from the end
808
- // const extrapolatedEndTime = (corr.remote + timePassed) / 1000;
809
-
810
- // if (extrapolatedEndTime > endTime) {
811
- // this._localEndTimeCorrelation = {
812
- // local: this._now,
813
- // remote: endTime * 1000
814
- // };
815
- // } else if (extrapolatedEndTime < endTime - this._extrapolatedWindowDuration) {
816
- // // our extrapolated end time is now earlier than the extrapolation window from the actual end time
817
- // // (maybe a chunk became available early)
818
- // // reset correlation so that it sits at the beginning of the extrapolation window from the end time
819
- // this._localEndTimeCorrelation = {
820
- // local: this._now,
821
- // remote: (endTime - this._extrapolatedWindowDuration) * 1000
822
- // };
823
- // } else if (extrapolatedEndTime > previousEndTime) {
824
- // // end time was past the old end time (so would have been capped)
825
- // // set the correlation so that it resumes from the time it was at at the end of the old window
826
- // this._localEndTimeCorrelation = {
827
- // local: this._now,
828
- // remote: previousEndTime * 1000
829
- // };
830
- // }
831
- // }
832
- // }
833
-
834
- // // now that the values have been updated call any methods that use on them so they get the updated values
835
- // // immediately
836
- // durationChanged && this._onDurationChange();
837
- // startTimeChanged && this._onProgress();
838
- // }
839
-
840
- // _onFragmentLoaded(evt, data) {
841
- // this.trigger(Events.PLAYBACK_FRAGMENT_LOADED, data);
842
- // }
843
-
844
642
  private onLevelSwitch(currentLevel: BitrateInfo) {
845
643
  this.trigger(Events.PLAYBACK_BITRATE, {
846
644
  height: currentLevel.height,
@@ -865,7 +663,6 @@ DashPlayback.canPlay = function (resource, mimeType) {
865
663
  (resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'mpd') ||
866
664
  mimeType === 'application/dash+xml' ||
867
665
  mimeType === 'video/mp4'
868
- // TODO check
869
666
  const ms = window.MediaSource
870
667
  const mms =
871
668
  'ManagedMediaSource' in window ? window.ManagedMediaSource : undefined