@gcorevideo/player 2.3.1 → 2.4.0
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/dist/index.js +97 -70
- package/lib/Player.d.ts +1 -1
- package/lib/Player.d.ts.map +1 -1
- package/lib/Player.js +23 -68
- package/lib/internal.types.d.ts +2 -3
- package/lib/internal.types.d.ts.map +1 -1
- package/lib/plugins/dash-playback/DashPlayback.js +1 -0
- package/lib/types.d.ts +2 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/utils/mediaSources.d.ts +13 -0
- package/lib/utils/mediaSources.d.ts.map +1 -0
- package/lib/utils/mediaSources.js +82 -0
- package/package.json +1 -1
- package/src/Player.ts +26 -77
- package/src/internal.types.ts +2 -2
- package/src/plugins/dash-playback/DashPlayback.ts +1 -0
- package/src/types.ts +3 -2
- package/src/typings/@clappr/core/player.d.ts +58 -58
- package/src/utils/mediaSources.ts +104 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/Player.ts
CHANGED
|
@@ -13,19 +13,20 @@ import type {
|
|
|
13
13
|
CorePlayerEvents,
|
|
14
14
|
CoreOptions,
|
|
15
15
|
CorePluginOptions,
|
|
16
|
+
PlayerMediaSource,
|
|
16
17
|
} from './internal.types.js'
|
|
17
18
|
import type {
|
|
18
19
|
PlaybackType,
|
|
19
20
|
PlayerPlugin,
|
|
20
21
|
QualityLevelInfo,
|
|
21
22
|
StreamMediaSource,
|
|
23
|
+
TransportPreference,
|
|
22
24
|
} from './types.js'
|
|
23
25
|
import { reportError, trace } from './trace/index.js'
|
|
24
26
|
import { PlayerConfig, PlayerEvent } from './types.js'
|
|
25
27
|
import DashPlayback from './plugins/dash-playback/DashPlayback.js'
|
|
26
28
|
import HlsPlayback from './plugins/hls-playback/HlsPlayback.js'
|
|
27
|
-
|
|
28
|
-
// import '../assets/style/main.scss' // TODO check if needed
|
|
29
|
+
import { buildSourcesPriorityList, buildSourcesSet, unwrapSource } from './utils/mediaSources.js'
|
|
29
30
|
|
|
30
31
|
// TODO implement transport retry/failover and fallback logic
|
|
31
32
|
|
|
@@ -35,15 +36,16 @@ const T = 'GPlayer'
|
|
|
35
36
|
|
|
36
37
|
const DEFAULT_OPTIONS: PlayerConfig = {
|
|
37
38
|
autoPlay: false,
|
|
38
|
-
|
|
39
|
+
debug: 'none',
|
|
39
40
|
loop: false,
|
|
41
|
+
mute: false,
|
|
40
42
|
multisources: [],
|
|
41
43
|
playbackType: 'vod',
|
|
42
|
-
priorityTransport: 'dash',
|
|
43
|
-
debug: 'none',
|
|
44
44
|
pluginSettings: {},
|
|
45
|
-
strings: {},
|
|
46
45
|
poster: '',
|
|
46
|
+
priorityTransport: 'dash',
|
|
47
|
+
sources: [],
|
|
48
|
+
strings: {},
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export type PlaybackModule = 'dash' | 'hls' | 'native'
|
|
@@ -236,7 +238,6 @@ export class Player {
|
|
|
236
238
|
player.core.on(
|
|
237
239
|
ClapprEvents.CORE_ACTIVE_CONTAINER_CHANGED,
|
|
238
240
|
() => {
|
|
239
|
-
// this.trigger(Events.ContainerChanged)
|
|
240
241
|
this.bindBitrateChangeHandler()
|
|
241
242
|
},
|
|
242
243
|
null,
|
|
@@ -345,16 +346,20 @@ export class Player {
|
|
|
345
346
|
}
|
|
346
347
|
|
|
347
348
|
private buildCoreOptions(rootNode: HTMLElement): CoreOptions {
|
|
348
|
-
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
349
|
+
// TODO extract
|
|
350
|
+
// const multisources = this.config.multisources
|
|
351
|
+
// const mainSource =
|
|
352
|
+
// this.config.playbackType === 'live'
|
|
353
|
+
// ? multisources.find((ms) => ms.live !== false)
|
|
354
|
+
// : multisources[0]
|
|
355
|
+
// const mediaSources = mainSource
|
|
356
|
+
// ? this.buildMediaSourcesList(mainSource)
|
|
357
|
+
// : []
|
|
356
358
|
// const mainSourceUrl = mediaSources[0];
|
|
357
|
-
const poster = mainSource?.poster ?? this.config.poster
|
|
359
|
+
// const poster = mainSource?.poster ?? this.config.poster
|
|
360
|
+
const poster = this.config.poster
|
|
361
|
+
|
|
362
|
+
const source = this.selectMediaSource(); // TODO
|
|
358
363
|
|
|
359
364
|
this.rootNode = rootNode
|
|
360
365
|
|
|
@@ -366,7 +371,6 @@ export class Player {
|
|
|
366
371
|
events: this.events,
|
|
367
372
|
height: rootNode.clientHeight,
|
|
368
373
|
loop: this.config.loop,
|
|
369
|
-
multisources,
|
|
370
374
|
mute: this.config.mute,
|
|
371
375
|
playback: {
|
|
372
376
|
controls: false,
|
|
@@ -382,8 +386,8 @@ export class Player {
|
|
|
382
386
|
playbackType: this.config.playbackType,
|
|
383
387
|
poster,
|
|
384
388
|
width: rootNode.clientWidth,
|
|
385
|
-
|
|
386
|
-
sources: mediaSources,
|
|
389
|
+
source: source ? unwrapSource(source) : undefined,
|
|
390
|
+
// sources: mediaSources,
|
|
387
391
|
strings: this.config.strings,
|
|
388
392
|
}
|
|
389
393
|
return coreOptions
|
|
@@ -404,63 +408,8 @@ export class Player {
|
|
|
404
408
|
)
|
|
405
409
|
}
|
|
406
410
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
{
|
|
411
|
-
dash: ms.sourceDash,
|
|
412
|
-
master: ms.source,
|
|
413
|
-
hls: ms.hlsCmafUrl,
|
|
414
|
-
mpegts: ms.hlsMpegtsUrl,
|
|
415
|
-
}
|
|
416
|
-
switch (this.config.priorityTransport) {
|
|
417
|
-
case 'dash':
|
|
418
|
-
addDash()
|
|
419
|
-
break
|
|
420
|
-
case 'hls':
|
|
421
|
-
addHls()
|
|
422
|
-
break
|
|
423
|
-
case 'mpegts':
|
|
424
|
-
addMpegts()
|
|
425
|
-
break
|
|
426
|
-
case 'auto':
|
|
427
|
-
addDash()
|
|
428
|
-
addHls()
|
|
429
|
-
break
|
|
430
|
-
}
|
|
431
|
-
Object.values(sources).forEach((s) => {
|
|
432
|
-
if (s) {
|
|
433
|
-
msl.push(s)
|
|
434
|
-
}
|
|
435
|
-
})
|
|
436
|
-
return msl
|
|
437
|
-
|
|
438
|
-
function addMpegts() {
|
|
439
|
-
if (sources.mpegts) {
|
|
440
|
-
msl.push(sources.mpegts)
|
|
441
|
-
sources.mpegts = null
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
function addHls() {
|
|
446
|
-
if (sources.hls && HlsPlayback.canPlay(sources.hls)) {
|
|
447
|
-
msl.push(sources.hls)
|
|
448
|
-
sources.hls = null
|
|
449
|
-
}
|
|
450
|
-
if (
|
|
451
|
-
sources.master?.endsWith('.m3u8') &&
|
|
452
|
-
HlsPlayback.canPlay(sources.master)
|
|
453
|
-
) {
|
|
454
|
-
msl.push(sources.master)
|
|
455
|
-
sources.master = null
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function addDash() {
|
|
460
|
-
if (sources.dash && DashPlayback.canPlay(sources.dash)) {
|
|
461
|
-
msl.push(sources.dash)
|
|
462
|
-
sources.dash = null
|
|
463
|
-
}
|
|
464
|
-
}
|
|
411
|
+
// TODO select a single source to play according to the priority transport and the modules support
|
|
412
|
+
private selectMediaSource(): PlayerMediaSource | undefined {
|
|
413
|
+
return buildSourcesPriorityList(buildSourcesSet(this.config.sources), this.config.priorityTransport)[0]
|
|
465
414
|
}
|
|
466
415
|
}
|
package/src/internal.types.ts
CHANGED
|
@@ -18,7 +18,7 @@ type MediacontrolStyles = {
|
|
|
18
18
|
buttons?: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
type PlayerMediaSourceDesc = {
|
|
21
|
+
export type PlayerMediaSourceDesc = {
|
|
22
22
|
mimeType?: string;
|
|
23
23
|
source: string;
|
|
24
24
|
}
|
|
@@ -116,7 +116,7 @@ export type CoreOptions = {
|
|
|
116
116
|
maxBufferLength?: number;
|
|
117
117
|
mediacontrol?: MediacontrolStyles;
|
|
118
118
|
mimeType?: string;
|
|
119
|
-
multisources: StreamMediaSource[];
|
|
119
|
+
// multisources: StreamMediaSource[];
|
|
120
120
|
mute?: boolean;
|
|
121
121
|
persistConfig?: boolean;
|
|
122
122
|
preload?: "auto" | "metadata" | "none";
|
|
@@ -788,6 +788,7 @@ DashPlayback.canPlay = function (resource, mimeType) {
|
|
|
788
788
|
const resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
|
|
789
789
|
const isDash = ((resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'mpd') ||
|
|
790
790
|
mimeType === 'application/dash+xml' || mimeType === 'video/mp4');
|
|
791
|
+
// TODO check
|
|
791
792
|
const ctor = window.MediaSource || ('WebKitMediaSource' in window ? window.WebKitMediaSource : undefined);
|
|
792
793
|
const hasSupport = typeof ctor === 'function';
|
|
793
794
|
trace(`${T} canPlay`, {hasSupport, isDash, resource});
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PlayerMediaSource } from "./internal.types"
|
|
2
|
+
|
|
1
3
|
export type PlayerDebugTag = 'all' | 'clappr' | 'dash' | 'hls' | 'none'
|
|
2
4
|
export type PlayerDebugSettings = PlayerDebugTag | boolean
|
|
3
5
|
|
|
@@ -21,6 +23,7 @@ export type PlayerConfig = {
|
|
|
21
23
|
pluginSettings?: Record<string, unknown>
|
|
22
24
|
poster?: string
|
|
23
25
|
priorityTransport?: TransportPreference
|
|
26
|
+
sources: PlayerMediaSource[];
|
|
24
27
|
strings: TranslationSettings
|
|
25
28
|
}
|
|
26
29
|
|
|
@@ -104,8 +107,6 @@ export type QualityLevelInfo = {
|
|
|
104
107
|
bitrate: number
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
export type BitrateInfo = QualityLevelInfo
|
|
108
|
-
|
|
109
110
|
export enum PlayerEvent {
|
|
110
111
|
Ready = 'ready',
|
|
111
112
|
Play = 'play',
|
|
@@ -1,73 +1,73 @@
|
|
|
1
1
|
import "@clappr/core";
|
|
2
2
|
|
|
3
3
|
declare module "@clappr/core" {
|
|
4
|
-
type MediacontrolStyles = {
|
|
5
|
-
|
|
6
|
-
}
|
|
4
|
+
// type MediacontrolStyles = {
|
|
5
|
+
// // TODO
|
|
6
|
+
// }
|
|
7
7
|
|
|
8
|
-
type PlayerMediaSourceDesc = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
8
|
+
// type PlayerMediaSourceDesc = {
|
|
9
|
+
// mimeType?: string;
|
|
10
|
+
// source: string;
|
|
11
|
+
// }
|
|
12
12
|
|
|
13
|
-
type PlayerMediaSource = string | PlayerMediaSourceDesc;
|
|
13
|
+
// type PlayerMediaSource = string | PlayerMediaSourceDesc;
|
|
14
14
|
|
|
15
|
-
type HlsjsConfig = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} & Record<string, unknown>;
|
|
15
|
+
// type HlsjsConfig = {
|
|
16
|
+
// debug?: boolean;
|
|
17
|
+
// startLevel?: number;
|
|
18
|
+
// } & Record<string, unknown>;
|
|
19
19
|
|
|
20
|
-
type ShakaConfig = Record<string, unknown>;
|
|
20
|
+
// type ShakaConfig = Record<string, unknown>;
|
|
21
21
|
|
|
22
|
-
declare type CorePlaybackConfig = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
22
|
+
// declare type CorePlaybackConfig = {
|
|
23
|
+
// // audioOnly: boolean;
|
|
24
|
+
// disableContextMenu?: boolean;
|
|
25
|
+
// controls?: boolean;
|
|
26
|
+
// crossOrigin?: 'anonymous' | 'use-credentials';
|
|
27
|
+
// // enableAutomaticABR?: boolean;
|
|
28
|
+
// externalTracks?: unknown[]; // TODO
|
|
29
|
+
// hlsjsConfig?: HlsjsConfig;
|
|
30
|
+
// // initialBandwidthEstimate?: number;
|
|
31
|
+
// // maxBufferLength?: number;
|
|
32
|
+
// // maxBackBufferLength?: number;
|
|
33
|
+
// // minBufferLength?: number;
|
|
34
|
+
// minimumDvrSize?: number; // TODO ?
|
|
35
|
+
// // maxAdaptiveBitrate?: number;
|
|
36
|
+
// // maxAdaptiveVideoDimensions?: unknown; // TODO
|
|
37
|
+
// playInline: boolean;
|
|
38
|
+
// preload?: 'metadata' | 'auto' | 'none';
|
|
39
|
+
// // preferredTextLanguage?: string;
|
|
40
|
+
// // preferredAudioLanguage?: string;
|
|
41
|
+
// shakaConfiguration?: ShakaConfig;
|
|
42
|
+
// }
|
|
43
43
|
|
|
44
|
-
type ErrorLevel = "FATAL" | "WARN" | "INFO";
|
|
44
|
+
// type ErrorLevel = "FATAL" | "WARN" | "INFO";
|
|
45
45
|
|
|
46
|
-
declare type EventSpec = string;
|
|
47
|
-
declare type EventHandlerSpec = string;
|
|
48
|
-
declare type PluginEventsConfig = Record<EventSpec, EventHandlerSpec>;
|
|
46
|
+
// declare type EventSpec = string;
|
|
47
|
+
// declare type EventHandlerSpec = string;
|
|
48
|
+
// declare type PluginEventsConfig = Record<EventSpec, EventHandlerSpec>;
|
|
49
49
|
|
|
50
|
-
declare type PlaybackError = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
50
|
+
// declare type PlaybackError = {
|
|
51
|
+
// code?: number | string;
|
|
52
|
+
// description: string;
|
|
53
|
+
// raw?: MediaError;
|
|
54
|
+
// level?: ErrorLevel;
|
|
55
|
+
// }
|
|
56
56
|
|
|
57
|
-
declare type CorePlayerEvents = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
57
|
+
// declare type CorePlayerEvents = {
|
|
58
|
+
// // TODO event arguments types
|
|
59
|
+
// onReady?: () => void;
|
|
60
|
+
// onResize?: (data: { width: number; height: number }) => void;
|
|
61
|
+
// onPlay?: (metadata: unknown) => void;
|
|
62
|
+
// onPause?: (metadata: unknown) => void;
|
|
63
|
+
// onStop?: (metadata: unknown) => void;
|
|
64
|
+
// onEnded?: () => void;
|
|
65
|
+
// onSeek?: (currentTime: number) => void;
|
|
66
|
+
// onError?: (err: PlaybackError) => void;
|
|
67
|
+
// onTimeUpdate?: (timeProgress: { current: number; total: number }) => void;
|
|
68
|
+
// onVolumeUpdate?: (value: number) => void;
|
|
69
|
+
// onSubtitleAvailable?: () => void;
|
|
70
|
+
// }
|
|
71
71
|
|
|
72
72
|
declare type ClapprVersionSpec = {
|
|
73
73
|
min: string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { PlayerMediaSource } from '../internal.types'
|
|
2
|
+
import DashPlayback from '../plugins/dash-playback/DashPlayback'
|
|
3
|
+
import HlsPlayback from '../plugins/hls-playback/HlsPlayback'
|
|
4
|
+
import { StreamMediaSource, TransportPreference } from '../types'
|
|
5
|
+
|
|
6
|
+
export type SourceVariants = {
|
|
7
|
+
dash: string | null
|
|
8
|
+
master: string | null
|
|
9
|
+
hls: string | null
|
|
10
|
+
mpegts: string | null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function buildSourcesSet(sources: PlayerMediaSource[]): SourceVariants {
|
|
14
|
+
const sv: SourceVariants = {
|
|
15
|
+
dash: null,
|
|
16
|
+
master: null,
|
|
17
|
+
hls: null,
|
|
18
|
+
mpegts: null,
|
|
19
|
+
}
|
|
20
|
+
sources.forEach((ps) => {
|
|
21
|
+
const [s, t] = typeof ps === 'string' ? [ps, ''] : [ps.source, ps.mimeType]
|
|
22
|
+
if (DashPlayback.canPlay(s, t)) {
|
|
23
|
+
sv.dash = s
|
|
24
|
+
} else if (HlsPlayback.canPlay(s, t)) {
|
|
25
|
+
sv.hls = s
|
|
26
|
+
} else {
|
|
27
|
+
sv.master = s
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
return sv
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function buildSourcesPriorityList(
|
|
34
|
+
sources: SourceVariants,
|
|
35
|
+
priorityTransport: TransportPreference = 'auto',
|
|
36
|
+
): PlayerMediaSource[] {
|
|
37
|
+
const msl: string[] = []
|
|
38
|
+
switch (priorityTransport) {
|
|
39
|
+
case 'dash':
|
|
40
|
+
addDash()
|
|
41
|
+
break
|
|
42
|
+
case 'hls':
|
|
43
|
+
addHls()
|
|
44
|
+
break
|
|
45
|
+
case 'mpegts':
|
|
46
|
+
addMpegts()
|
|
47
|
+
break
|
|
48
|
+
case 'auto':
|
|
49
|
+
addDash()
|
|
50
|
+
addHls()
|
|
51
|
+
break
|
|
52
|
+
}
|
|
53
|
+
Object.values(sources).forEach((s) => {
|
|
54
|
+
if (s) {
|
|
55
|
+
msl.push(s)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
return msl
|
|
59
|
+
|
|
60
|
+
function addMpegts() {
|
|
61
|
+
if (sources.mpegts) {
|
|
62
|
+
msl.push(sources.mpegts)
|
|
63
|
+
sources.mpegts = null
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function addHls() {
|
|
68
|
+
if (sources.hls && HlsPlayback.canPlay(sources.hls)) {
|
|
69
|
+
msl.push(sources.hls)
|
|
70
|
+
sources.hls = null
|
|
71
|
+
}
|
|
72
|
+
if (
|
|
73
|
+
sources.master?.endsWith('.m3u8') &&
|
|
74
|
+
HlsPlayback.canPlay(sources.master)
|
|
75
|
+
) {
|
|
76
|
+
msl.push(sources.master)
|
|
77
|
+
sources.master = null
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function addDash() {
|
|
82
|
+
if (sources.dash && DashPlayback.canPlay(sources.dash)) {
|
|
83
|
+
msl.push(sources.dash)
|
|
84
|
+
sources.dash = null
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function unwrapSource(s: PlayerMediaSource): string {
|
|
90
|
+
return typeof s === 'string' ? s : s.source
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function buildGcoreStreamSourcesList(
|
|
94
|
+
ms: StreamMediaSource,
|
|
95
|
+
priorityTransport: TransportPreference,
|
|
96
|
+
): PlayerMediaSource[] {
|
|
97
|
+
const sources: Record<'dash' | 'master' | 'hls' | 'mpegts', string | null> = {
|
|
98
|
+
dash: ms.sourceDash,
|
|
99
|
+
master: ms.source,
|
|
100
|
+
hls: ms.hlsCmafUrl,
|
|
101
|
+
mpegts: ms.hlsMpegtsUrl,
|
|
102
|
+
}
|
|
103
|
+
return buildSourcesPriorityList(sources, priorityTransport)
|
|
104
|
+
}
|