@gcorevideo/player 2.10.0 → 2.12.1
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.
- package/LICENSE +13 -0
- package/coverage/clover.xml +6 -0
- package/coverage/coverage-final.json +1 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +101 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov.info +0 -0
- package/dist/index.js +3115 -1185
- package/lib/Player.d.ts +3 -2
- package/lib/Player.d.ts.map +1 -1
- package/lib/Player.js +33 -20
- package/lib/index.d.ts +6 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -5
- package/lib/internal.types.d.ts +3 -1
- package/lib/internal.types.d.ts.map +1 -1
- package/lib/playback/index.d.ts +4 -0
- package/lib/playback/index.d.ts.map +1 -0
- package/lib/playback/index.js +13 -0
- package/lib/playback.types.d.ts +9 -0
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/playback.types.js +9 -1
- package/lib/plugins/dash-playback/DashPlayback.d.ts +0 -1
- package/lib/plugins/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/plugins/dash-playback/DashPlayback.js +32 -96
- package/lib/plugins/dash-playback/types.d.ts +6 -0
- package/lib/plugins/dash-playback/types.d.ts.map +1 -0
- package/lib/plugins/dash-playback/types.js +1 -0
- package/lib/plugins/hls-playback/HlsPlayback.d.ts +3 -3
- package/lib/plugins/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/plugins/hls-playback/HlsPlayback.js +136 -63
- package/lib/types.d.ts +3 -3
- package/lib/types.d.ts.map +1 -1
- package/lib/utils/mediaSources.d.ts +14 -6
- package/lib/utils/mediaSources.d.ts.map +1 -1
- package/lib/utils/mediaSources.js +56 -53
- package/lib/utils/testUtils.d.ts +3 -0
- package/lib/utils/testUtils.d.ts.map +1 -0
- package/lib/utils/testUtils.js +12 -0
- package/package.json +6 -4
- package/src/Player.ts +46 -26
- package/src/__tests__/Player.test.ts +357 -0
- package/src/index.ts +6 -5
- package/src/internal.types.ts +3 -1
- package/src/playback/index.ts +17 -0
- package/src/playback.types.ts +11 -1
- package/src/plugins/dash-playback/DashPlayback.ts +38 -114
- package/src/plugins/hls-playback/HlsPlayback.ts +561 -386
- package/src/types.ts +5 -3
- package/src/typings/@clappr/core/error_mixin.d.ts +0 -2
- package/src/typings/@clappr/core/index.d.ts +5 -0
- package/src/typings/@clappr/index.d.ts +1 -0
- package/src/utils/__tests__/mediaSources.test.ts +230 -0
- package/src/utils/mediaSources.ts +67 -63
- package/src/utils/testUtils.ts +15 -0
- package/tsconfig.json +0 -9
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +8 -0
- package/licenses.json +0 -782
- package/src/utils/queryParams.ts +0 -5
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// Copyright 2014 Globo.com Player authors. All rights reserved.
|
|
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
|
-
import { Events, HTML5Video, Log, Playback, PlayerError, Utils } from '@clappr/core';
|
|
4
|
+
import { Events, HTML5Video, Log, Playback, PlayerError, Utils, } from '@clappr/core';
|
|
5
|
+
import { trace } from '@gcorevideo/utils';
|
|
5
6
|
import assert from 'assert';
|
|
6
7
|
import HLSJS from 'hls.js';
|
|
7
|
-
import {
|
|
8
|
-
import { CLAPPR_VERSION } from
|
|
8
|
+
import { PlaybackErrorCode } from '../../playback.types.js';
|
|
9
|
+
import { CLAPPR_VERSION } from '../../build.js';
|
|
9
10
|
const { now, listContainsIgnoreCase } = Utils;
|
|
10
11
|
const AUTO = -1;
|
|
11
12
|
const DEFAULT_RECOVER_ATTEMPTS = 16;
|
|
@@ -75,7 +76,8 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
75
76
|
return this._hls.playingDate;
|
|
76
77
|
}
|
|
77
78
|
get _startTime() {
|
|
78
|
-
if (this._playbackType === Playback.LIVE &&
|
|
79
|
+
if (this._playbackType === Playback.LIVE &&
|
|
80
|
+
this._playlistType !== 'EVENT') {
|
|
79
81
|
return this._extrapolatedStartTime;
|
|
80
82
|
}
|
|
81
83
|
return this._playableRegionStartTime;
|
|
@@ -140,7 +142,8 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
140
142
|
return { preload: true };
|
|
141
143
|
}
|
|
142
144
|
get customListeners() {
|
|
143
|
-
return this.options.hlsPlayback && this.options.hlsPlayback.customListeners ||
|
|
145
|
+
return ((this.options.hlsPlayback && this.options.hlsPlayback.customListeners) ||
|
|
146
|
+
[]);
|
|
144
147
|
}
|
|
145
148
|
get sourceMedia() {
|
|
146
149
|
return this.options.src;
|
|
@@ -162,17 +165,27 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
162
165
|
constructor(...args) {
|
|
163
166
|
// @ts-ignore
|
|
164
167
|
super(...args);
|
|
165
|
-
this.options.hlsPlayback = {
|
|
168
|
+
this.options.hlsPlayback = {
|
|
169
|
+
...this.defaultOptions,
|
|
170
|
+
...this.options.hlsPlayback,
|
|
171
|
+
};
|
|
166
172
|
this._setInitialState();
|
|
167
173
|
}
|
|
168
174
|
_setInitialState() {
|
|
169
175
|
// @ts-ignore
|
|
170
|
-
this._minDvrSize =
|
|
176
|
+
this._minDvrSize =
|
|
177
|
+
typeof this.options.hlsMinimumDvrSize === 'undefined'
|
|
178
|
+
? 60
|
|
179
|
+
: this.options.hlsMinimumDvrSize;
|
|
171
180
|
// The size of the start time extrapolation window measured as a multiple of segments.
|
|
172
181
|
// Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
|
|
173
182
|
// removed from the start of the playlist at a time. E.g if the playlist is cached for 10 seconds and new chunks are
|
|
174
183
|
// added/removed every 5.
|
|
175
|
-
this._extrapolatedWindowNumSegments =
|
|
184
|
+
this._extrapolatedWindowNumSegments =
|
|
185
|
+
!this.options.playback ||
|
|
186
|
+
typeof this.options.playback.extrapolatedWindowNumSegments === 'undefined'
|
|
187
|
+
? 2
|
|
188
|
+
: this.options.playback.extrapolatedWindowNumSegments;
|
|
176
189
|
this._playbackType = Playback.VOD;
|
|
177
190
|
this._lastTimeUpdate = { current: 0, total: 0 };
|
|
178
191
|
this._lastDuration = null;
|
|
@@ -204,7 +217,8 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
204
217
|
// #EXT-X-PLAYLIST-TYPE
|
|
205
218
|
this._playlistType = null;
|
|
206
219
|
// TODO options.hlsRecoverAttempts
|
|
207
|
-
this._recoverAttemptsRemaining =
|
|
220
|
+
this._recoverAttemptsRemaining =
|
|
221
|
+
this.options.hlsRecoverAttempts || DEFAULT_RECOVER_ATTEMPTS;
|
|
208
222
|
}
|
|
209
223
|
_setup() {
|
|
210
224
|
this._destroyHLSInstance();
|
|
@@ -247,13 +261,15 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
247
261
|
});
|
|
248
262
|
const onPlaying = () => {
|
|
249
263
|
if (this._hls) {
|
|
250
|
-
this._hls.config.maxBufferLength =
|
|
251
|
-
|
|
264
|
+
this._hls.config.maxBufferLength =
|
|
265
|
+
this.options.hlsPlayback.maxBufferLength || 30;
|
|
266
|
+
this._hls.config.maxMaxBufferLength =
|
|
267
|
+
this.options.hlsPlayback.maxMaxBufferLength || 60;
|
|
252
268
|
}
|
|
253
269
|
this.el.removeEventListener('playing', onPlaying);
|
|
254
270
|
};
|
|
255
271
|
this.el.addEventListener('playing', onPlaying);
|
|
256
|
-
this._hls.on(HLSJS.Events.MANIFEST_PARSED, () => this._manifestParsed = true);
|
|
272
|
+
this._hls.on(HLSJS.Events.MANIFEST_PARSED, () => (this._manifestParsed = true));
|
|
257
273
|
this._hls.on(HLSJS.Events.LEVEL_LOADED, (evt, data) => this._updatePlaybackType(evt, data));
|
|
258
274
|
this._hls.on(HLSJS.Events.LEVEL_UPDATED, (evt, data) => this._onLevelUpdated(evt, data));
|
|
259
275
|
this._hls.on(HLSJS.Events.LEVEL_SWITCHING, (evt, data) => this._onLevelSwitch(evt, data));
|
|
@@ -263,7 +279,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
263
279
|
this._hls.on(HLSJS.Events.ERROR, (evt, data) => this._onHLSJSError(evt, data));
|
|
264
280
|
// this._hls.on(HLSJS.Events.SUBTITLE_TRACK_LOADED, (evt, data) => this._onSubtitleLoaded(evt, data));
|
|
265
281
|
this._hls.on(HLSJS.Events.SUBTITLE_TRACK_LOADED, () => this._onSubtitleLoaded());
|
|
266
|
-
this._hls.on(HLSJS.Events.SUBTITLE_TRACKS_UPDATED, () => this._ccTracksUpdated = true);
|
|
282
|
+
this._hls.on(HLSJS.Events.SUBTITLE_TRACKS_UPDATED, () => (this._ccTracksUpdated = true));
|
|
267
283
|
this.bindCustomListeners();
|
|
268
284
|
}
|
|
269
285
|
bindCustomListeners() {
|
|
@@ -271,7 +287,8 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
271
287
|
const requestedEventName = item.eventName;
|
|
272
288
|
const typeOfListener = item.once ? 'once' : 'on';
|
|
273
289
|
assert.ok(this._hls, 'Hls.js instance is not available');
|
|
274
|
-
requestedEventName &&
|
|
290
|
+
requestedEventName &&
|
|
291
|
+
this._hls[`${typeOfListener}`](requestedEventName, item.callback);
|
|
275
292
|
});
|
|
276
293
|
}
|
|
277
294
|
unbindCustomListeners() {
|
|
@@ -283,7 +300,10 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
283
300
|
}
|
|
284
301
|
_onFragmentParsingMetadata(evt, data) {
|
|
285
302
|
// @ts-ignore
|
|
286
|
-
this.trigger(Events.Custom.PLAYBACK_FRAGMENT_PARSING_METADATA, {
|
|
303
|
+
this.trigger(Events.Custom.PLAYBACK_FRAGMENT_PARSING_METADATA, {
|
|
304
|
+
evt,
|
|
305
|
+
data,
|
|
306
|
+
});
|
|
287
307
|
}
|
|
288
308
|
render() {
|
|
289
309
|
this._ready();
|
|
@@ -316,7 +336,6 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
316
336
|
this.stop();
|
|
317
337
|
}
|
|
318
338
|
}
|
|
319
|
-
// override
|
|
320
339
|
// this playback manages the src on the video element itself
|
|
321
340
|
_setupSrc(srcUrl) { } // eslint-disable-line no-unused-vars
|
|
322
341
|
_startTimeUpdateTimer() {
|
|
@@ -336,7 +355,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
336
355
|
this._timeUpdateTimer = null;
|
|
337
356
|
}
|
|
338
357
|
getProgramDateTime() {
|
|
339
|
-
return this._programDateTime;
|
|
358
|
+
return this._programDateTime ?? 0;
|
|
340
359
|
}
|
|
341
360
|
// the duration on the video element itself should not be used
|
|
342
361
|
// as this does not necesarily represent the duration of the stream
|
|
@@ -357,9 +376,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
357
376
|
return this._startTime;
|
|
358
377
|
}
|
|
359
378
|
seekPercentage(percentage) {
|
|
360
|
-
const seekTo =
|
|
361
|
-
? this._duration * (percentage / 100)
|
|
362
|
-
: this._duration;
|
|
379
|
+
const seekTo = percentage > 0 ? this._duration * (percentage / 100) : this._duration;
|
|
363
380
|
this.seek(seekTo);
|
|
364
381
|
}
|
|
365
382
|
seek(time) {
|
|
@@ -377,7 +394,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
377
394
|
}
|
|
378
395
|
_updateDvr(status) {
|
|
379
396
|
this.trigger(Events.PLAYBACK_DVR, status);
|
|
380
|
-
this.trigger(Events.PLAYBACK_STATS_ADD, {
|
|
397
|
+
this.trigger(Events.PLAYBACK_STATS_ADD, { dvr: status });
|
|
381
398
|
}
|
|
382
399
|
_updateSettings() {
|
|
383
400
|
if (this._playbackType === Playback.VOD) {
|
|
@@ -398,7 +415,8 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
398
415
|
}
|
|
399
416
|
_onHLSJSError(evt, data) {
|
|
400
417
|
const error = {
|
|
401
|
-
code: `${data.type}_${data.details}`,
|
|
418
|
+
// code: `${data.type}_${data.details}`,
|
|
419
|
+
code: PlaybackErrorCode.Generic,
|
|
402
420
|
description: `${this.name} error: type: ${data.type}, details: ${data.details}`,
|
|
403
421
|
raw: data,
|
|
404
422
|
};
|
|
@@ -422,13 +440,28 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
422
440
|
case HLSJS.ErrorDetails.MANIFEST_PARSING_ERROR:
|
|
423
441
|
case HLSJS.ErrorDetails.LEVEL_LOAD_ERROR:
|
|
424
442
|
case HLSJS.ErrorDetails.LEVEL_LOAD_TIMEOUT:
|
|
425
|
-
Log.error('hlsjs: unrecoverable network fatal error.', {
|
|
426
|
-
|
|
443
|
+
Log.error('hlsjs: unrecoverable network fatal error.', {
|
|
444
|
+
evt,
|
|
445
|
+
data,
|
|
446
|
+
});
|
|
447
|
+
error.code = [
|
|
448
|
+
HLSJS.ErrorDetails.MANIFEST_LOAD_ERROR,
|
|
449
|
+
HLSJS.ErrorDetails.MANIFEST_LOAD_TIMEOUT,
|
|
450
|
+
HLSJS.ErrorDetails.MANIFEST_PARSING_ERROR
|
|
451
|
+
].includes(data.details)
|
|
452
|
+
? PlaybackErrorCode.MediaSourceUnavailable
|
|
453
|
+
: PlaybackErrorCode.QualityLevelUnavailable;
|
|
454
|
+
formattedError = this.createError(error, {
|
|
455
|
+
useCodePrefix: false,
|
|
456
|
+
});
|
|
427
457
|
this.trigger(Events.PLAYBACK_ERROR, formattedError);
|
|
428
458
|
this.stop();
|
|
429
459
|
break;
|
|
430
460
|
default:
|
|
431
|
-
Log.warn('hlsjs: trying to recover from network error.', {
|
|
461
|
+
Log.warn('hlsjs: trying to recover from network error.', {
|
|
462
|
+
evt,
|
|
463
|
+
data,
|
|
464
|
+
});
|
|
432
465
|
error.level = PlayerError.Levels.WARN;
|
|
433
466
|
assert(this._hls, 'Hls.js instance is not available');
|
|
434
467
|
this._hls.startLoad();
|
|
@@ -436,13 +469,18 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
436
469
|
}
|
|
437
470
|
break;
|
|
438
471
|
case HLSJS.ErrorTypes.MEDIA_ERROR:
|
|
439
|
-
Log.warn('hlsjs: trying to recover from media error.', {
|
|
472
|
+
Log.warn('hlsjs: trying to recover from media error.', {
|
|
473
|
+
evt,
|
|
474
|
+
data,
|
|
475
|
+
});
|
|
440
476
|
error.level = PlayerError.Levels.WARN;
|
|
441
477
|
this._recover(evt, data, error);
|
|
442
478
|
break;
|
|
443
479
|
default:
|
|
444
480
|
Log.error('hlsjs: could not recover from error.', { evt, data });
|
|
445
|
-
formattedError = this.createError(error
|
|
481
|
+
formattedError = this.createError(error, {
|
|
482
|
+
useCodePrefix: false,
|
|
483
|
+
});
|
|
446
484
|
this.trigger(Events.PLAYBACK_ERROR, formattedError);
|
|
447
485
|
this.stop();
|
|
448
486
|
break;
|
|
@@ -450,7 +488,10 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
450
488
|
}
|
|
451
489
|
else {
|
|
452
490
|
Log.error('hlsjs: could not recover from error after maximum number of attempts.', { evt, data });
|
|
453
|
-
|
|
491
|
+
// TODO
|
|
492
|
+
formattedError = this.createError(error, {
|
|
493
|
+
useCodePrefix: false,
|
|
494
|
+
});
|
|
454
495
|
this.trigger(Events.PLAYBACK_ERROR, formattedError);
|
|
455
496
|
this.stop();
|
|
456
497
|
}
|
|
@@ -460,9 +501,12 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
460
501
|
// playback fatal error if triggerFatalErrorOnResourceDenied playback
|
|
461
502
|
// option is set. HLSJS.ErrorTypes.KEY_SYSTEM_ERROR are fatal errors
|
|
462
503
|
// and therefore already handled.
|
|
463
|
-
if (this.options.playback.triggerFatalErrorOnResourceDenied &&
|
|
504
|
+
if (this.options.playback.triggerFatalErrorOnResourceDenied &&
|
|
505
|
+
this._keyIsDenied(data)) {
|
|
464
506
|
Log.error('hlsjs: could not load decrypt key.', { evt, data });
|
|
465
|
-
formattedError = this.createError(error
|
|
507
|
+
formattedError = this.createError(error, {
|
|
508
|
+
useCodePrefix: false,
|
|
509
|
+
});
|
|
466
510
|
this.trigger(Events.PLAYBACK_ERROR, formattedError);
|
|
467
511
|
this.stop();
|
|
468
512
|
return;
|
|
@@ -472,16 +516,21 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
472
516
|
}
|
|
473
517
|
}
|
|
474
518
|
_keyIsDenied(data) {
|
|
475
|
-
return data.type === HLSJS.ErrorTypes.NETWORK_ERROR
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
519
|
+
return (data.type === HLSJS.ErrorTypes.NETWORK_ERROR &&
|
|
520
|
+
data.details === HLSJS.ErrorDetails.KEY_LOAD_ERROR &&
|
|
521
|
+
data.response &&
|
|
522
|
+
data.response.code &&
|
|
523
|
+
data.response.code >= 400);
|
|
480
524
|
}
|
|
481
525
|
_onTimeUpdate() {
|
|
482
|
-
const update = {
|
|
483
|
-
|
|
484
|
-
|
|
526
|
+
const update = {
|
|
527
|
+
current: this.getCurrentTime(),
|
|
528
|
+
total: this.getDuration(),
|
|
529
|
+
firstFragDateTime: this.getProgramDateTime(),
|
|
530
|
+
};
|
|
531
|
+
const isSame = this._lastTimeUpdate &&
|
|
532
|
+
update.current === this._lastTimeUpdate.current &&
|
|
533
|
+
update.total === this._lastTimeUpdate.total;
|
|
485
534
|
if (isSame) {
|
|
486
535
|
return;
|
|
487
536
|
}
|
|
@@ -503,19 +552,25 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
503
552
|
let buffered = [];
|
|
504
553
|
let bufferedPos = 0;
|
|
505
554
|
for (let i = 0; i < this.el.buffered.length; i++) {
|
|
506
|
-
buffered = [
|
|
555
|
+
buffered = [
|
|
556
|
+
...buffered,
|
|
557
|
+
{
|
|
507
558
|
// for a stream with sliding window dvr something that is buffered my slide off the start of the timeline
|
|
508
|
-
start: Math.max(0, this.el.buffered.start(i) -
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
559
|
+
start: Math.max(0, this.el.buffered.start(i) -
|
|
560
|
+
this._playableRegionStartTime),
|
|
561
|
+
end: Math.max(0, this.el.buffered.end(i) -
|
|
562
|
+
this._playableRegionStartTime),
|
|
563
|
+
},
|
|
564
|
+
];
|
|
565
|
+
if (this.el.currentTime >= buffered[i].start &&
|
|
566
|
+
this.el.currentTime <= buffered[i].end) {
|
|
512
567
|
bufferedPos = i;
|
|
513
568
|
}
|
|
514
569
|
}
|
|
515
570
|
const progress = {
|
|
516
571
|
start: buffered[bufferedPos].start,
|
|
517
572
|
current: buffered[bufferedPos].end,
|
|
518
|
-
total: this.getDuration()
|
|
573
|
+
total: this.getDuration(),
|
|
519
574
|
};
|
|
520
575
|
this.trigger(Events.PLAYBACK_PROGRESS, progress, buffered);
|
|
521
576
|
}
|
|
@@ -528,7 +583,9 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
528
583
|
trace(`${T} play`, { hls: !!this._hls, ...this.options.hlsPlayback });
|
|
529
584
|
!this._hls && this._setup();
|
|
530
585
|
assert.ok(this._hls, 'Hls.js instance is not available');
|
|
531
|
-
!this._manifestParsed &&
|
|
586
|
+
!this._manifestParsed &&
|
|
587
|
+
!this.options.hlsPlayback.preload &&
|
|
588
|
+
this._hls.loadSource(this.options.src);
|
|
532
589
|
super.play();
|
|
533
590
|
this._startTimeUpdateTimer();
|
|
534
591
|
}
|
|
@@ -536,6 +593,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
536
593
|
if (!this._hls) {
|
|
537
594
|
return;
|
|
538
595
|
}
|
|
596
|
+
;
|
|
539
597
|
this.el.pause();
|
|
540
598
|
if (this.dvrEnabled) {
|
|
541
599
|
this._updateDvr(true);
|
|
@@ -558,7 +616,9 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
558
616
|
this._playbackType = (data.details.live ? Playback.LIVE : Playback.VOD);
|
|
559
617
|
this._onLevelUpdated(evt, data);
|
|
560
618
|
// Live stream subtitle tracks detection hack (may not immediately available)
|
|
561
|
-
if (this._ccTracksUpdated &&
|
|
619
|
+
if (this._ccTracksUpdated &&
|
|
620
|
+
this._playbackType === Playback.LIVE &&
|
|
621
|
+
this.hasClosedCaptionsTracks) {
|
|
562
622
|
this._onSubtitleLoaded();
|
|
563
623
|
}
|
|
564
624
|
if (prevPlaybackType !== this._playbackType) {
|
|
@@ -590,7 +650,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
590
650
|
}
|
|
591
651
|
// #EXT-X-PROGRAM-DATE-TIME
|
|
592
652
|
if (fragments[0].rawProgramDateTime) {
|
|
593
|
-
this._programDateTime = fragments[0].rawProgramDateTime;
|
|
653
|
+
this._programDateTime = Number(fragments[0].rawProgramDateTime);
|
|
594
654
|
}
|
|
595
655
|
if (this._playableRegionStartTime !== fragments[0].start) {
|
|
596
656
|
startTimeChanged = true;
|
|
@@ -601,7 +661,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
601
661
|
// set the correlation to map to middle of the extrapolation window
|
|
602
662
|
this._localStartTimeCorrelation = {
|
|
603
663
|
local: this._now,
|
|
604
|
-
remote: (fragments[0].start +
|
|
664
|
+
remote: (fragments[0].start + this._extrapolatedWindowDuration / 2) * 1000,
|
|
605
665
|
};
|
|
606
666
|
}
|
|
607
667
|
else {
|
|
@@ -616,17 +676,19 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
616
676
|
// reset correlation so that it sits at the beginning of the first available chunk
|
|
617
677
|
this._localStartTimeCorrelation = {
|
|
618
678
|
local: this._now,
|
|
619
|
-
remote: fragments[0].start * 1000
|
|
679
|
+
remote: fragments[0].start * 1000,
|
|
620
680
|
};
|
|
621
681
|
}
|
|
622
|
-
else if (startTime >
|
|
682
|
+
else if (startTime >
|
|
683
|
+
previousPlayableRegionStartTime + this._extrapolatedWindowDuration) {
|
|
623
684
|
// start time was past the end of the old extrapolation window (so would have been capped)
|
|
624
685
|
// see if now that time would be inside the window, and if it would be set the correlation
|
|
625
686
|
// so that it resumes from the time it was at at the end of the old window
|
|
626
687
|
// update the correlation so that the time starts counting again from the value it's on now
|
|
627
688
|
this._localStartTimeCorrelation = {
|
|
628
689
|
local: this._now,
|
|
629
|
-
remote: Math.max(fragments[0].start, previousPlayableRegionStartTime +
|
|
690
|
+
remote: Math.max(fragments[0].start, previousPlayableRegionStartTime +
|
|
691
|
+
this._extrapolatedWindowDuration) * 1000,
|
|
630
692
|
};
|
|
631
693
|
}
|
|
632
694
|
}
|
|
@@ -638,7 +700,8 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
638
700
|
if (this._playbackType === Playback.LIVE) {
|
|
639
701
|
const fragmentTargetDuration = data.details.targetduration;
|
|
640
702
|
const hlsjsConfig = this.options.playback.hlsjsConfig || {};
|
|
641
|
-
const liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount ||
|
|
703
|
+
const liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount ||
|
|
704
|
+
HLSJS.DefaultConfig.liveSyncDurationCount;
|
|
642
705
|
const hiddenAreaDuration = fragmentTargetDuration * liveSyncDurationCount;
|
|
643
706
|
if (hiddenAreaDuration <= newDuration) {
|
|
644
707
|
newDuration -= hiddenAreaDuration;
|
|
@@ -662,7 +725,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
662
725
|
// set the correlation to map to the end
|
|
663
726
|
this._localEndTimeCorrelation = {
|
|
664
727
|
local: this._now,
|
|
665
|
-
remote: endTime * 1000
|
|
728
|
+
remote: endTime * 1000,
|
|
666
729
|
};
|
|
667
730
|
}
|
|
668
731
|
else {
|
|
@@ -674,16 +737,17 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
674
737
|
if (extrapolatedEndTime > endTime) {
|
|
675
738
|
this._localEndTimeCorrelation = {
|
|
676
739
|
local: this._now,
|
|
677
|
-
remote: endTime * 1000
|
|
740
|
+
remote: endTime * 1000,
|
|
678
741
|
};
|
|
679
742
|
}
|
|
680
|
-
else if (extrapolatedEndTime <
|
|
743
|
+
else if (extrapolatedEndTime <
|
|
744
|
+
endTime - this._extrapolatedWindowDuration) {
|
|
681
745
|
// our extrapolated end time is now earlier than the extrapolation window from the actual end time
|
|
682
746
|
// (maybe a chunk became available early)
|
|
683
747
|
// reset correlation so that it sits at the beginning of the extrapolation window from the end time
|
|
684
748
|
this._localEndTimeCorrelation = {
|
|
685
749
|
local: this._now,
|
|
686
|
-
remote: (endTime - this._extrapolatedWindowDuration) * 1000
|
|
750
|
+
remote: (endTime - this._extrapolatedWindowDuration) * 1000,
|
|
687
751
|
};
|
|
688
752
|
}
|
|
689
753
|
else if (extrapolatedEndTime > previousEndTime) {
|
|
@@ -691,7 +755,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
691
755
|
// set the correlation so that it resumes from the time it was at at the end of the old window
|
|
692
756
|
this._localEndTimeCorrelation = {
|
|
693
757
|
local: this._now,
|
|
694
|
-
remote: previousEndTime * 1000
|
|
758
|
+
remote: previousEndTime * 1000,
|
|
695
759
|
};
|
|
696
760
|
}
|
|
697
761
|
}
|
|
@@ -729,13 +793,14 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
729
793
|
const currentLevel = this._hls.levels[data.level];
|
|
730
794
|
if (currentLevel) {
|
|
731
795
|
// TODO should highDefinition be private and maybe have a read only accessor if it's used somewhere
|
|
732
|
-
this.highDefinition =
|
|
796
|
+
this.highDefinition =
|
|
797
|
+
currentLevel.height >= 720 || currentLevel.bitrate / 1000 >= 2000;
|
|
733
798
|
this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition);
|
|
734
799
|
this.trigger(Events.PLAYBACK_BITRATE, {
|
|
735
800
|
height: currentLevel.height,
|
|
736
801
|
width: currentLevel.width,
|
|
737
802
|
bitrate: currentLevel.bitrate,
|
|
738
|
-
level: data.level
|
|
803
|
+
level: data.level,
|
|
739
804
|
});
|
|
740
805
|
}
|
|
741
806
|
}
|
|
@@ -744,21 +809,29 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
744
809
|
// - the duration does not include content after hlsjs's live sync point
|
|
745
810
|
// - the playable region duration is longer than the configured duration to enable dvr after
|
|
746
811
|
// - the playback type is LIVE.
|
|
747
|
-
return (this._durationExcludesAfterLiveSyncPoint &&
|
|
812
|
+
return (this._durationExcludesAfterLiveSyncPoint &&
|
|
813
|
+
this._duration >= this._minDvrSize &&
|
|
814
|
+
this.getPlaybackType() === Playback.LIVE);
|
|
748
815
|
}
|
|
749
816
|
getPlaybackType() {
|
|
750
817
|
return this._playbackType;
|
|
751
818
|
}
|
|
752
819
|
isSeekEnabled() {
|
|
753
|
-
return
|
|
820
|
+
return this._playbackType === Playback.VOD || this.dvrEnabled;
|
|
754
821
|
}
|
|
755
822
|
}
|
|
756
823
|
HlsPlayback.canPlay = function (resource, mimeType) {
|
|
757
824
|
const resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
|
|
758
|
-
const isHls = (
|
|
825
|
+
const isHls = (resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'm3u8') ||
|
|
826
|
+
listContainsIgnoreCase(mimeType, [
|
|
827
|
+
'application/vnd.apple.mpegurl',
|
|
828
|
+
'application/x-mpegURL',
|
|
829
|
+
]);
|
|
759
830
|
const hasSupport = HLSJS.isSupported();
|
|
760
831
|
trace(`${T} canPlay`, {
|
|
761
|
-
hasSupport,
|
|
832
|
+
hasSupport,
|
|
833
|
+
isHls,
|
|
834
|
+
resource,
|
|
762
835
|
});
|
|
763
836
|
return !!(hasSupport && isHls);
|
|
764
837
|
};
|
package/lib/types.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export type PlaybackType = 'live' | 'vod';
|
|
|
38
38
|
/**
|
|
39
39
|
* @beta
|
|
40
40
|
*/
|
|
41
|
-
export type MediaTransport = 'dash' | 'hls'
|
|
41
|
+
export type MediaTransport = 'dash' | 'hls';
|
|
42
42
|
/**
|
|
43
43
|
* @beta
|
|
44
44
|
*/
|
|
@@ -49,7 +49,7 @@ export type TransportPreference = MediaTransport | 'auto';
|
|
|
49
49
|
*/
|
|
50
50
|
export type PlayerPlugin = {
|
|
51
51
|
new (...args: any[]): unknown;
|
|
52
|
-
|
|
52
|
+
name: string;
|
|
53
53
|
};
|
|
54
54
|
/**
|
|
55
55
|
* Configuration options for the player
|
|
@@ -143,7 +143,7 @@ export interface PlayerConfig extends Record<string, unknown> {
|
|
|
143
143
|
/**
|
|
144
144
|
* Localization strings for the player UI.
|
|
145
145
|
*/
|
|
146
|
-
strings
|
|
146
|
+
strings?: TranslationSettings;
|
|
147
147
|
}
|
|
148
148
|
/**
|
|
149
149
|
* @beta
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,qBAAqB,CAAA;AAE9D;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;AAEvE;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,OAAO,CAAA;AAE1D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAA;AAEzC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAA;AAE3C;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,MAAM,CAAA;AAEzD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;IAC7B,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,WAAW,YAAa,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3D;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;;OAIG;IACH,IAAI,CAAC,EAAE,YAAY,CAAA;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,mBAAmB,CAAA;IAE3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAA;IAEvC;;OAEG;IACH,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAE5B;;OAEG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAA;AAE5B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAA;AAEnC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,CACvC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAChD,CAAA;AAED;;;GAGG;AACH,oBAAY,WAAW;IACrB;;OAEG;IACH,KAAK,UAAU;IACf;;OAEG;IACH,IAAI,SAAS;IACb;;OAEG;IACH,KAAK,UAAU;IACf;;OAEG;IACH,IAAI,SAAS;IACb;;OAEG;IACH,KAAK,UAAU;CAChB"}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import type { PlayerMediaSource, TransportPreference } from '../types';
|
|
1
|
+
import type { PlayerMediaSource, PlayerMediaSourceDesc, TransportPreference } from '../types';
|
|
2
2
|
export type SourceVariants = {
|
|
3
|
-
dash:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
mpegts: string | null;
|
|
3
|
+
dash: PlayerMediaSourceDesc | null;
|
|
4
|
+
hls: PlayerMediaSourceDesc | null;
|
|
5
|
+
mpegts: PlayerMediaSourceDesc | null;
|
|
7
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param sources
|
|
10
|
+
* @deprecated
|
|
11
|
+
* @returns
|
|
12
|
+
*/
|
|
8
13
|
export declare function buildSourcesSet(sources: PlayerMediaSource[]): SourceVariants;
|
|
9
|
-
export declare function
|
|
14
|
+
export declare function buildMediaSourcesList(sources: PlayerMediaSourceDesc[], priorityTransport?: TransportPreference): PlayerMediaSourceDesc[];
|
|
10
15
|
export declare function unwrapSource(s: PlayerMediaSource): string;
|
|
16
|
+
export declare function wrapSource(s: PlayerMediaSource): PlayerMediaSourceDesc;
|
|
17
|
+
export declare function isDashSource(source: string, mimeType?: string): boolean;
|
|
18
|
+
export declare function isHlsSource(source: string, mimeType?: string): boolean;
|
|
11
19
|
//# sourceMappingURL=mediaSources.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaSources.d.ts","sourceRoot":"","sources":["../../src/utils/mediaSources.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mediaSources.d.ts","sourceRoot":"","sources":["../../src/utils/mediaSources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG7F,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAAA;IAClC,GAAG,EAAE,qBAAqB,GAAG,IAAI,CAAA;IACjC,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAA;CACrC,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,cAAc,CAiB5E;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,qBAAqB,EAAE,EAChC,iBAAiB,GAAE,mBAA4B,GAC9C,qBAAqB,EAAE,CAsBzB;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAEzD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,iBAAiB,GAAG,qBAAqB,CAEtE;AAYD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,WAK7D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,WAO5D"}
|