@gcorevideo/player 2.10.0 → 2.12.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.
- 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 -1209
- package/lib/Player.d.ts +3 -2
- package/lib/Player.d.ts.map +1 -1
- package/lib/Player.js +32 -24
- package/lib/index.d.ts +5 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -5
- package/lib/internal.types.d.ts +1 -10
- 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 +19 -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 +1 -1
- package/lib/plugins/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/plugins/dash-playback/DashPlayback.js +39 -100
- 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 +6 -7
- package/lib/plugins/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/plugins/hls-playback/HlsPlayback.js +131 -80
- 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 +40 -31
- package/src/__tests__/Player.test.ts +357 -0
- package/src/index.ts +5 -5
- package/src/internal.types.ts +1 -12
- package/src/playback/index.ts +17 -0
- package/src/playback.types.ts +29 -8
- package/src/plugins/dash-playback/DashPlayback.ts +44 -120
- package/src/plugins/hls-playback/HlsPlayback.ts +544 -390
- 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 +78 -64
- 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
package/src/internal.types.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
} from "@clappr/core";
|
|
6
6
|
|
|
7
7
|
import { PlaybackType, PlayerDebugTag, PlayerMediaSource } from "./types";
|
|
8
|
+
import { PlaybackError } from "./playback.types";
|
|
8
9
|
|
|
9
10
|
type ExternalTrack = {
|
|
10
11
|
kind?: "subtitles" | "captions";
|
|
@@ -56,18 +57,6 @@ export interface CorePlaybackConfig {
|
|
|
56
57
|
shakaConfiguration?: ShakaConfig;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
type ErrorLevel = "FATAL" | "WARN" | "INFO";
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @internal
|
|
63
|
-
*/
|
|
64
|
-
export type PlaybackError = {
|
|
65
|
-
code?: number | string;
|
|
66
|
-
description: string;
|
|
67
|
-
raw?: MediaError;
|
|
68
|
-
level?: ErrorLevel;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
60
|
/**
|
|
72
61
|
* @internal
|
|
73
62
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Loader } from '@clappr/core'
|
|
2
|
+
|
|
3
|
+
import DashPlayback from '../plugins/dash-playback/DashPlayback.js'
|
|
4
|
+
import HlsPlayback from '../plugins/hls-playback/HlsPlayback.js'
|
|
5
|
+
|
|
6
|
+
export function registerPlaybacks() {
|
|
7
|
+
Loader.registerPlayback(DashPlayback)
|
|
8
|
+
Loader.registerPlayback(HlsPlayback)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function canPlayDash(source: string, mimeType?: string) {
|
|
12
|
+
return DashPlayback.canPlay(source, mimeType)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function canPlayHls(source: string, mimeType?: string) {
|
|
16
|
+
return HlsPlayback.canPlay(source, mimeType)
|
|
17
|
+
}
|
package/src/playback.types.ts
CHANGED
|
@@ -1,39 +1,60 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
2
|
+
* Playback time in seconds since the beginning of the stream (or a segment for the live streams)
|
|
3
3
|
* For the plugin development
|
|
4
4
|
* @internal
|
|
5
5
|
*/
|
|
6
|
-
export type TimeValue = number
|
|
6
|
+
export type TimeValue = number
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* For the plugin development
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
12
|
export type TimePosition = {
|
|
13
|
-
current: TimeValue
|
|
14
|
-
total: TimeValue
|
|
13
|
+
current: TimeValue
|
|
14
|
+
total: TimeValue
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* For the plugin development
|
|
19
19
|
* @internal
|
|
20
20
|
*/
|
|
21
|
-
export type TimeProgress = TimePosition & { start: number
|
|
21
|
+
export type TimeProgress = TimePosition & { start: number }
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* For the plugin development
|
|
25
25
|
* @internal
|
|
26
26
|
*/
|
|
27
27
|
export type TimeUpdate = TimePosition & {
|
|
28
|
-
firstFragDateTime: number
|
|
29
|
-
}
|
|
28
|
+
firstFragDateTime: number
|
|
29
|
+
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* @beta
|
|
33
33
|
*/
|
|
34
34
|
export type QualityLevel = {
|
|
35
|
-
level: number // index
|
|
35
|
+
level: number // 0-based index
|
|
36
36
|
width: number
|
|
37
37
|
height: number
|
|
38
38
|
bitrate: number
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @beta
|
|
43
|
+
*/
|
|
44
|
+
export enum PlaybackErrorCode {
|
|
45
|
+
Generic = 0,
|
|
46
|
+
MediaSourceUnavailable = 1,
|
|
47
|
+
QualityLevelUnavailable = 2,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type ErrorLevel = 'FATAL' | 'WARN' | 'INFO'
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @beta
|
|
54
|
+
*/
|
|
55
|
+
export interface PlaybackError {
|
|
56
|
+
code: PlaybackErrorCode
|
|
57
|
+
description: string
|
|
58
|
+
level: ErrorLevel
|
|
59
|
+
message: string
|
|
60
|
+
}
|
|
@@ -2,18 +2,19 @@
|
|
|
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 { Events, HTML5Video, Log, Playback, Utils } from '@clappr/core'
|
|
5
|
+
import { Events, HTML5Video, Log, Playback, PlayerError, Utils } from '@clappr/core'
|
|
6
|
+
import { trace } from '@gcorevideo/utils'
|
|
6
7
|
import assert from 'assert'
|
|
7
8
|
import DASHJS, {
|
|
8
9
|
ErrorEvent as DashErrorEvent,
|
|
10
|
+
MediaPlayerErrorEvent,
|
|
9
11
|
PlaybackErrorEvent as DashPlaybackErrorEvent,
|
|
10
12
|
type BitrateInfo as DashBitrateInfo,
|
|
11
13
|
MetricEvent as DashMetricEvent,
|
|
12
14
|
IManifestInfo,
|
|
13
15
|
} from 'dashjs'
|
|
14
|
-
import { trace } from '@gcorevideo/utils'
|
|
15
16
|
|
|
16
|
-
import { QualityLevel, TimePosition, TimeValue } from '../../playback.types.js'
|
|
17
|
+
import { PlaybackError, PlaybackErrorCode, QualityLevel, TimePosition, TimeUpdate, TimeValue } from '../../playback.types.js'
|
|
17
18
|
|
|
18
19
|
const AUTO = -1
|
|
19
20
|
|
|
@@ -88,9 +89,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
88
89
|
|
|
89
90
|
manifestInfo: IManifestInfo | null = null
|
|
90
91
|
|
|
91
|
-
// #EXT-X-TARGETDURATION
|
|
92
|
-
_segmentTargetDuration: TimeValue | null = null
|
|
93
|
-
|
|
94
92
|
_timeUpdateTimer: ReturnType<typeof setInterval> | null = null
|
|
95
93
|
|
|
96
94
|
get name() {
|
|
@@ -118,6 +116,12 @@ export default class DashPlayback extends HTML5Video {
|
|
|
118
116
|
|
|
119
117
|
this.trigger(Events.PLAYBACK_LEVEL_SWITCH_START)
|
|
120
118
|
|
|
119
|
+
assert.ok(
|
|
120
|
+
this._dash,
|
|
121
|
+
'An instance of dashjs MediaPlayer is required to switch levels',
|
|
122
|
+
)
|
|
123
|
+
const dash = this._dash
|
|
124
|
+
|
|
121
125
|
// TODO use $.extend
|
|
122
126
|
const settings = this.options.dash ? structuredClone(this.options.dash) : {}
|
|
123
127
|
settings.streaming = settings.streaming || {}
|
|
@@ -126,11 +130,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
126
130
|
settings.streaming.abr.autoSwitchBitrate || {}
|
|
127
131
|
settings.streaming.abr.autoSwitchBitrate.video = id === -1
|
|
128
132
|
|
|
129
|
-
assert.ok(
|
|
130
|
-
this._dash,
|
|
131
|
-
'An instance of dashjs MediaPlayer is required to switch levels',
|
|
132
|
-
)
|
|
133
|
-
const dash = this._dash
|
|
134
133
|
dash.updateSettings(settings)
|
|
135
134
|
if (id !== -1) {
|
|
136
135
|
this._dash.setQualityFor('video', id)
|
|
@@ -334,9 +333,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
334
333
|
}
|
|
335
334
|
|
|
336
335
|
getCurrentTime(): TimeValue {
|
|
337
|
-
// e.g. can be < 0 if user pauses near the start
|
|
338
|
-
// eventually they will then be kicked to the end by hlsjs if they run out of buffer
|
|
339
|
-
// before the official start time
|
|
340
336
|
return this._dash ? this._dash.time() : 0
|
|
341
337
|
}
|
|
342
338
|
|
|
@@ -410,107 +406,39 @@ export default class DashPlayback extends HTML5Video {
|
|
|
410
406
|
|
|
411
407
|
private _onDASHJSSError = (event: DashErrorEvent) => {
|
|
412
408
|
trace(`${T} _onDASHJSSError`, { event })
|
|
413
|
-
// TODO
|
|
414
|
-
// only report/handle errors if they are fatal
|
|
415
409
|
this._stopTimeUpdateTimer()
|
|
416
|
-
if (event.error === 'capability' && event.event === 'mediasource') {
|
|
417
|
-
// No support for MSE
|
|
418
|
-
const formattedError = this.createError(event.error)
|
|
419
|
-
|
|
420
|
-
this.trigger(Events.PLAYBACK_ERROR, formattedError)
|
|
421
|
-
Log.error(
|
|
422
|
-
'The media cannot be played because it requires a feature ' +
|
|
423
|
-
'that your browser does not support.',
|
|
424
|
-
)
|
|
425
|
-
} else if (
|
|
426
|
-
event.error === 'manifestError' &&
|
|
427
|
-
// Manifest type not supported
|
|
428
|
-
(event.event.id === 'createParser' ||
|
|
429
|
-
// Codec(s) not supported
|
|
430
|
-
event.event.id === 'codec' ||
|
|
431
|
-
// No streams available to stream
|
|
432
|
-
event.event.id === 'nostreams' ||
|
|
433
|
-
// Error creating Stream object
|
|
434
|
-
event.event.id === 'nostreamscomposed' ||
|
|
435
|
-
// syntax error parsing the manifest
|
|
436
|
-
event.event.id === 'parse' ||
|
|
437
|
-
// a stream has multiplexed audio+video
|
|
438
|
-
event.event.id === 'multiplexedrep')
|
|
439
|
-
) {
|
|
440
|
-
// These errors have useful error messages, so we forward it on
|
|
441
|
-
const formattedError = this.createError(event.error)
|
|
442
410
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const formattedError = this.createError(event.error)
|
|
465
|
-
|
|
466
|
-
this.trigger(Events.PLAYBACK_ERROR, formattedError)
|
|
467
|
-
Log.error(
|
|
468
|
-
'The media cannot be played because it requires encryption ' +
|
|
469
|
-
'that your browser does not support.',
|
|
470
|
-
)
|
|
471
|
-
} else if (event.error === 'key_session') {
|
|
472
|
-
// This block handles pretty much all errors thrown by the
|
|
473
|
-
// encryption subsystem
|
|
474
|
-
const formattedError = this.createError(event.error)
|
|
475
|
-
|
|
476
|
-
this.trigger(Events.PLAYBACK_ERROR, formattedError)
|
|
477
|
-
Log.error(event.event)
|
|
478
|
-
} else if (event.error === 'download') {
|
|
479
|
-
const formattedError = this.createError(event.error)
|
|
480
|
-
|
|
481
|
-
this.trigger(Events.PLAYBACK_ERROR, formattedError)
|
|
482
|
-
Log.error(
|
|
483
|
-
'The media playback was aborted because too many consecutive ' +
|
|
484
|
-
'download errors occurred.',
|
|
485
|
-
)
|
|
486
|
-
// } else if (event.error === 'mssError') {
|
|
487
|
-
// const formattedError = this.createError(event.error);
|
|
488
|
-
|
|
489
|
-
// this.trigger(Events.PLAYBACK_ERROR, formattedError);
|
|
490
|
-
// if (event.error) {
|
|
491
|
-
// Log.error(event.error.message);
|
|
492
|
-
// }
|
|
493
|
-
} else {
|
|
494
|
-
// ignore the error
|
|
495
|
-
if (typeof event.error === 'object') {
|
|
496
|
-
const formattedError = this.createError(event.error)
|
|
497
|
-
|
|
498
|
-
this.trigger(Events.PLAYBACK_ERROR, formattedError)
|
|
499
|
-
Log.error(event.error.message)
|
|
500
|
-
} else {
|
|
501
|
-
Log.error(event.error)
|
|
502
|
-
}
|
|
503
|
-
return
|
|
411
|
+
const e = (event as MediaPlayerErrorEvent).error
|
|
412
|
+
switch (e.code) {
|
|
413
|
+
case DASHJS.MediaPlayer.errors.MANIFEST_LOADER_PARSING_FAILURE_ERROR_CODE:
|
|
414
|
+
case DASHJS.MediaPlayer.errors.MANIFEST_LOADER_LOADING_FAILURE_ERROR_CODE:
|
|
415
|
+
case DASHJS.MediaPlayer.errors.DOWNLOAD_ERROR_ID_MANIFEST_CODE:
|
|
416
|
+
case DASHJS.MediaPlayer.errors.DOWNLOAD_ERROR_ID_CONTENT_CODE:
|
|
417
|
+
this.triggerError({
|
|
418
|
+
code: PlaybackErrorCode.MediaSourceUnavailable,
|
|
419
|
+
message: e.message,
|
|
420
|
+
description: e.message,
|
|
421
|
+
level: PlayerError.Levels.FATAL,
|
|
422
|
+
})
|
|
423
|
+
break;
|
|
424
|
+
// TODO more cases
|
|
425
|
+
default:
|
|
426
|
+
this.triggerError({
|
|
427
|
+
code: PlaybackErrorCode.Generic,
|
|
428
|
+
message: e.message,
|
|
429
|
+
description: e.message,
|
|
430
|
+
level: PlayerError.Levels.FATAL,
|
|
431
|
+
})
|
|
504
432
|
}
|
|
433
|
+
}
|
|
505
434
|
|
|
435
|
+
private triggerError(error: PlaybackError) {
|
|
436
|
+
trace(`${T} triggerError`, { error })
|
|
437
|
+
this.trigger(Events.PLAYBACK_ERROR, error)
|
|
506
438
|
// only reset the dash player in 10ms async, so that the rest of the
|
|
507
439
|
// calling function finishes
|
|
508
440
|
setTimeout(() => {
|
|
509
|
-
|
|
510
|
-
this._dash,
|
|
511
|
-
'An instance of dashjs MediaPlayer is required to reset',
|
|
512
|
-
)
|
|
513
|
-
this._dash.reset()
|
|
441
|
+
this.stop()
|
|
514
442
|
}, 10)
|
|
515
443
|
}
|
|
516
444
|
|
|
@@ -518,7 +446,7 @@ export default class DashPlayback extends HTML5Video {
|
|
|
518
446
|
if (this.startChangeQuality) {
|
|
519
447
|
return
|
|
520
448
|
}
|
|
521
|
-
const update = {
|
|
449
|
+
const update: TimeUpdate = {
|
|
522
450
|
current: this.getCurrentTime(),
|
|
523
451
|
total: this.getDuration(),
|
|
524
452
|
firstFragDateTime: this.getProgramDateTime(),
|
|
@@ -650,6 +578,9 @@ export default class DashPlayback extends HTML5Video {
|
|
|
650
578
|
}
|
|
651
579
|
|
|
652
580
|
private onLevelSwitch(currentLevel: QualityLevel) {
|
|
581
|
+
// TODO check the two below
|
|
582
|
+
this.trigger(Events.PLAYBACK_LEVEL_SWITCH, currentLevel)
|
|
583
|
+
this.trigger(Events.PLAYBACK_LEVEL_SWITCH_END)
|
|
653
584
|
const isHD = (currentLevel.height >= 720 || (currentLevel.bitrate / 1000) >= 2000);
|
|
654
585
|
this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE, isHD);
|
|
655
586
|
this.trigger(Events.PLAYBACK_BITRATE, currentLevel)
|
|
@@ -670,21 +601,14 @@ DashPlayback.canPlay = function (resource, mimeType) {
|
|
|
670
601
|
(resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'mpd') ||
|
|
671
602
|
mimeType === 'application/dash+xml' ||
|
|
672
603
|
mimeType === 'video/mp4'
|
|
604
|
+
if (!isDash) {
|
|
605
|
+
return false
|
|
606
|
+
}
|
|
673
607
|
const ms = window.MediaSource
|
|
674
608
|
const mms =
|
|
675
609
|
'ManagedMediaSource' in window ? window.ManagedMediaSource : undefined
|
|
676
610
|
const wms =
|
|
677
611
|
'WebKitMediaSource' in window ? window.WebKitMediaSource : undefined
|
|
678
612
|
const ctor = ms || mms || wms
|
|
679
|
-
|
|
680
|
-
const hasSupport = typeof ctor === 'function'
|
|
681
|
-
trace(`${T} canPlay`, {
|
|
682
|
-
hasSupport,
|
|
683
|
-
isDash,
|
|
684
|
-
resource,
|
|
685
|
-
ms: typeof ms === 'function',
|
|
686
|
-
mms: typeof mms === 'function',
|
|
687
|
-
wms: typeof wms === 'function',
|
|
688
|
-
})
|
|
689
|
-
return !!(hasSupport && isDash)
|
|
613
|
+
return typeof ctor === 'function'
|
|
690
614
|
}
|