@eluvio/elv-player-js 1.0.136 → 1.0.137
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/README.md +20 -12
- package/dist/Analytics-Bi5tPfDl.mjs +2028 -0
- package/dist/dash.all.min-6lnccozJ.mjs +19428 -0
- package/dist/elv-player-js.es.js +6 -0
- package/dist/elv-player-js.umd.js +227 -0
- package/dist/hls-1eCRapWm.mjs +15461 -0
- package/dist/index-ObsDfNAj.mjs +2273 -0
- package/dist/index-WOzcLuQQ.mjs +41292 -0
- package/dist/style.css +1 -0
- package/package.json +4 -3
- package/src/Analytics.js +114 -0
- package/src/PlayerControls.js +195 -24
- package/src/index.js +291 -73
- package/src/static/icons/Icons.js +11 -8
- package/src/static/icons/media/list.svg +1 -0
- package/src/static/icons/media/next.svg +1 -0
- package/src/static/icons/media/previous.svg +1 -0
- package/src/static/stylesheets/player.scss +68 -6
- package/webpack.config.js +16 -7
- package/dist/5897e28fa3e8ac0a2fae.png +0 -0
- package/dist/bundle.333.7815f5ebcb1488f0e077.js +0 -2
- package/dist/bundle.333.7815f5ebcb1488f0e077.js.LICENSE.txt +0 -1
- package/dist/bundle.542.13fbfeeb92e41067e9da.js +0 -2
- package/dist/bundle.542.13fbfeeb92e41067e9da.js.LICENSE.txt +0 -13
- package/dist/bundle.543.f78d7c10787a91d4b582.js +0 -2
- package/dist/bundle.543.f78d7c10787a91d4b582.js.LICENSE.txt +0 -1
- package/dist/bundle.552.fbfc2e2fc68f6287f12c.js +0 -1
- package/dist/bundle.688.ef6032af9f304acb167f.js +0 -1
- package/dist/bundle.978.40fe2f1d0a843e187793.js +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.LICENSE.txt +0 -64
package/src/index.js
CHANGED
|
@@ -48,6 +48,10 @@ export const EluvioPlayerParameters = {
|
|
|
48
48
|
ON: true,
|
|
49
49
|
DEFAULT: "default"
|
|
50
50
|
},
|
|
51
|
+
title: {
|
|
52
|
+
ON: true,
|
|
53
|
+
OFF: false
|
|
54
|
+
},
|
|
51
55
|
loop: {
|
|
52
56
|
OFF: false,
|
|
53
57
|
ON: true
|
|
@@ -69,6 +73,11 @@ export const EluvioPlayerParameters = {
|
|
|
69
73
|
capLevelToPlayerSize: {
|
|
70
74
|
OFF: false,
|
|
71
75
|
ON: true
|
|
76
|
+
},
|
|
77
|
+
collectVideoAnalytics: {
|
|
78
|
+
OFF: false,
|
|
79
|
+
ON: true,
|
|
80
|
+
DISABLE_COOKIES: "disable_cookies"
|
|
72
81
|
}
|
|
73
82
|
};
|
|
74
83
|
|
|
@@ -93,8 +102,17 @@ const DefaultParameters = {
|
|
|
93
102
|
EluvioPlayerParameters.drms.SAMPLE_AES,
|
|
94
103
|
EluvioPlayerParameters.drms.AES128,
|
|
95
104
|
EluvioPlayerParameters.drms.WIDEVINE,
|
|
96
|
-
EluvioPlayerParameters.drms.CLEAR
|
|
105
|
+
EluvioPlayerParameters.drms.CLEAR
|
|
97
106
|
],
|
|
107
|
+
contentOptions: {
|
|
108
|
+
title: undefined,
|
|
109
|
+
description: undefined
|
|
110
|
+
},
|
|
111
|
+
mediaCollectionOptions: {
|
|
112
|
+
mediaCatalogObjectId: undefined,
|
|
113
|
+
mediaCatalogVersionHash: undefined,
|
|
114
|
+
collectionId: undefined
|
|
115
|
+
},
|
|
98
116
|
playoutOptions: undefined,
|
|
99
117
|
playoutParameters: {
|
|
100
118
|
objectId: undefined,
|
|
@@ -113,12 +131,14 @@ const DefaultParameters = {
|
|
|
113
131
|
}
|
|
114
132
|
},
|
|
115
133
|
playerOptions: {
|
|
134
|
+
appName: undefined,
|
|
116
135
|
controls: EluvioPlayerParameters.controls.AUTO_HIDE,
|
|
117
136
|
autoplay: EluvioPlayerParameters.autoplay.OFF,
|
|
118
137
|
muted: EluvioPlayerParameters.muted.OFF,
|
|
119
138
|
loop: EluvioPlayerParameters.loop.OFF,
|
|
120
139
|
watermark: EluvioPlayerParameters.watermark.ON,
|
|
121
140
|
capLevelToPlayerSize: EluvioPlayerParameters.capLevelToPlayerSize.OFF,
|
|
141
|
+
title: EluvioPlayerParameters.title.ON,
|
|
122
142
|
posterUrl: undefined,
|
|
123
143
|
className: undefined,
|
|
124
144
|
controlsClassName: undefined,
|
|
@@ -126,6 +146,8 @@ const DefaultParameters = {
|
|
|
126
146
|
hlsjsOptions: undefined,
|
|
127
147
|
dashjsOptions: undefined,
|
|
128
148
|
debugLogging: false,
|
|
149
|
+
collectVideoAnalytics: true,
|
|
150
|
+
maxBitrate: undefined,
|
|
129
151
|
// eslint-disable-next-line no-unused-vars
|
|
130
152
|
playerCallback: ({player, videoElement, hlsPlayer, dashPlayer, posterUrl}) => {},
|
|
131
153
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -177,6 +199,9 @@ export class EluvioPlayer {
|
|
|
177
199
|
|
|
178
200
|
this.DetectRemoval = this.DetectRemoval.bind(this);
|
|
179
201
|
|
|
202
|
+
this.target = target;
|
|
203
|
+
this.originalParameters = parameters;
|
|
204
|
+
|
|
180
205
|
this.Initialize(target, parameters);
|
|
181
206
|
|
|
182
207
|
window.EluvioPlayer = this;
|
|
@@ -209,6 +234,26 @@ export class EluvioPlayer {
|
|
|
209
234
|
this.target.innerHTML = "";
|
|
210
235
|
}
|
|
211
236
|
|
|
237
|
+
SetErrorMessage(message) {
|
|
238
|
+
let errorMessage = this.target.querySelector(".eluvio-player__error-message");
|
|
239
|
+
|
|
240
|
+
if(!errorMessage) {
|
|
241
|
+
errorMessage = CreateElement({
|
|
242
|
+
parent: this.target,
|
|
243
|
+
classes: ["eluvio-player__error-message"]
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
errorMessage.innerHTML = "";
|
|
248
|
+
|
|
249
|
+
CreateElement({
|
|
250
|
+
parent: errorMessage,
|
|
251
|
+
classes: ["eluvio-player__error-message__text"]
|
|
252
|
+
}).innerHTML = message;
|
|
253
|
+
|
|
254
|
+
this.target.classList.add("eluvio-player--error");
|
|
255
|
+
}
|
|
256
|
+
|
|
212
257
|
RegisterVisibilityCallback() {
|
|
213
258
|
if(
|
|
214
259
|
this.playerOptions.autoplay !== EluvioPlayerParameters.autoplay.WHEN_VISIBLE &&
|
|
@@ -275,7 +320,9 @@ export class EluvioPlayer {
|
|
|
275
320
|
}
|
|
276
321
|
|
|
277
322
|
async RedeemCode(code) {
|
|
278
|
-
if(!this.clientOptions.tenantId
|
|
323
|
+
if(!this.clientOptions.tenantId || !this.clientOptions.ntpId) {
|
|
324
|
+
throw { displayMessage: "Tenant ID and NTP ID must be provided if ticket code is specified." };
|
|
325
|
+
}
|
|
279
326
|
|
|
280
327
|
code = code || this.clientOptions.ticketCode;
|
|
281
328
|
let subject = this.clientOptions.ticketSubject;
|
|
@@ -334,6 +381,11 @@ export class EluvioPlayer {
|
|
|
334
381
|
async PlayoutOptions() {
|
|
335
382
|
const client = await this.Client();
|
|
336
383
|
|
|
384
|
+
if(this.collectionInfo) {
|
|
385
|
+
const activeMedia = this.ActiveCollectionMedia();
|
|
386
|
+
this.sourceOptions.playoutParameters.versionHash = activeMedia.mediaHash;
|
|
387
|
+
}
|
|
388
|
+
|
|
337
389
|
let offeringURI, options = {};
|
|
338
390
|
if(this.sourceOptions.playoutParameters.clipStart || this.sourceOptions.playoutParameters.clipEnd) {
|
|
339
391
|
options.clip_start = parseFloat(this.sourceOptions.playoutParameters.clipStart || 0);
|
|
@@ -422,12 +474,14 @@ export class EluvioPlayer {
|
|
|
422
474
|
PlayPause(this.video, false);
|
|
423
475
|
}
|
|
424
476
|
|
|
425
|
-
if(this.
|
|
426
|
-
this.
|
|
427
|
-
} else if(this.
|
|
428
|
-
this.
|
|
477
|
+
if(this.hlsPlayer) {
|
|
478
|
+
this.hlsPlayer.destroy();
|
|
479
|
+
} else if(this.dashPlayer) {
|
|
480
|
+
this.dashPlayer.destroy();
|
|
429
481
|
}
|
|
430
482
|
|
|
483
|
+
this.hlsPlayer = undefined;
|
|
484
|
+
this.dashPlayer = undefined;
|
|
431
485
|
this.player = undefined;
|
|
432
486
|
}
|
|
433
487
|
|
|
@@ -468,6 +522,7 @@ export class EluvioPlayer {
|
|
|
468
522
|
}
|
|
469
523
|
}
|
|
470
524
|
|
|
525
|
+
this.SetErrorMessage(error.displayMessage || "Something went wrong, reloading player...");
|
|
471
526
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
472
527
|
|
|
473
528
|
if(this.__destroyed) { return; }
|
|
@@ -497,11 +552,101 @@ export class EluvioPlayer {
|
|
|
497
552
|
}
|
|
498
553
|
}
|
|
499
554
|
|
|
555
|
+
ActiveCollectionMedia() {
|
|
556
|
+
if(!this.collectionInfo || !this.collectionInfo.content) { return; }
|
|
557
|
+
|
|
558
|
+
return this.collectionInfo.content[this.collectionInfo.mediaIndex];
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
CollectionPlay({mediaIndex, mediaId}) {
|
|
562
|
+
if(mediaId) {
|
|
563
|
+
mediaIndex = this.collectionInfo.content.find(media => media.id === mediaId);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
this.collectionInfo.mediaIndex = mediaIndex;
|
|
567
|
+
this.Initialize(
|
|
568
|
+
this.target,
|
|
569
|
+
this.originalParameters,
|
|
570
|
+
!this.video ? null :
|
|
571
|
+
{
|
|
572
|
+
muted: this.video.muted,
|
|
573
|
+
volume: this.video.volume,
|
|
574
|
+
playing: !this.video.paused
|
|
575
|
+
}
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
CollectionPlayNext() {
|
|
580
|
+
const nextIndex = Math.min(this.collectionInfo.mediaIndex + 1, this.collectionInfo.mediaLength - 1);
|
|
581
|
+
|
|
582
|
+
if(nextIndex === this.collectionInfo.mediaIndex) { return; }
|
|
583
|
+
|
|
584
|
+
this.CollectionPlay({mediaIndex: nextIndex});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
CollectionPlayPrevious() {
|
|
588
|
+
const previousIndex = Math.max(0, this.collectionInfo.mediaIndex - 1);
|
|
589
|
+
|
|
590
|
+
if(previousIndex === this.collectionInfo.mediaIndex) { return; }
|
|
591
|
+
|
|
592
|
+
this.CollectionPlay({mediaIndex: previousIndex});
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async LoadCollection() {
|
|
596
|
+
if(this.collectionInfo) { return; }
|
|
597
|
+
|
|
598
|
+
let {mediaCatalogObjectId, mediaCatalogVersionHash, collectionId} = (this.sourceOptions?.mediaCollectionOptions || {});
|
|
599
|
+
|
|
600
|
+
if(!collectionId) { return; }
|
|
601
|
+
|
|
602
|
+
if(!mediaCatalogObjectId && !mediaCatalogVersionHash) {
|
|
603
|
+
throw { displayMessage: "Invalid collection options: Media catalog not specified" };
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const client = await this.Client();
|
|
607
|
+
|
|
608
|
+
try {
|
|
609
|
+
const authorizationToken = this.sourceOptions.playoutParameters.authorizationToken;
|
|
610
|
+
|
|
611
|
+
mediaCatalogVersionHash = mediaCatalogVersionHash || await client.LatestVersionHash({objectId: mediaCatalogObjectId});
|
|
612
|
+
const collections = (await client.ContentObjectMetadata({
|
|
613
|
+
versionHash: mediaCatalogVersionHash,
|
|
614
|
+
metadataSubtree: "public/asset_metadata/info/collections",
|
|
615
|
+
authorizationToken
|
|
616
|
+
})) || [];
|
|
617
|
+
|
|
618
|
+
const collectionInfo = collections.find(collection => collection.id === collectionId);
|
|
619
|
+
|
|
620
|
+
if(!collectionInfo) {
|
|
621
|
+
throw { displayMessage: `No collection with ID ${collectionId} found for media catalog ${mediaCatalogObjectId || mediaCatalogVersionHash}` };
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
collectionInfo.content = collectionInfo.content
|
|
625
|
+
.filter(content => content.media)
|
|
626
|
+
.map(content => ({
|
|
627
|
+
...content,
|
|
628
|
+
mediaHash: content.media?.["/"]?.split("/").find(segment => segment.startsWith("hq__"))
|
|
629
|
+
}));
|
|
630
|
+
|
|
631
|
+
this.collectionInfo = {
|
|
632
|
+
...collectionInfo,
|
|
633
|
+
isPlaylist: collectionInfo.type === "playlist",
|
|
634
|
+
mediaIndex: 0,
|
|
635
|
+
mediaLength: collectionInfo.content.length
|
|
636
|
+
};
|
|
637
|
+
} catch (error) {
|
|
638
|
+
this.Log("Failed to load collection:");
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
500
643
|
async Initialize(target, parameters, restartParameters) {
|
|
501
644
|
if(this.__destroyed) { return; }
|
|
502
645
|
|
|
503
646
|
this.__DestroyPlayer();
|
|
504
647
|
|
|
648
|
+
this.initTime = Date.now();
|
|
649
|
+
|
|
505
650
|
this.target = target;
|
|
506
651
|
|
|
507
652
|
// Clear target
|
|
@@ -531,35 +676,36 @@ export class EluvioPlayer {
|
|
|
531
676
|
|
|
532
677
|
this.errors = 0;
|
|
533
678
|
|
|
534
|
-
|
|
535
679
|
this.target.classList.add("eluvio-player");
|
|
536
680
|
|
|
537
681
|
// Start client loading
|
|
538
682
|
this.Client();
|
|
539
683
|
|
|
684
|
+
// Handle ticket authorization
|
|
540
685
|
if(this.clientOptions.promptTicket && !this.ticketInitialized) {
|
|
541
|
-
if(!this.clientOptions.tenantId) {
|
|
542
|
-
throw
|
|
686
|
+
if(!this.clientOptions.tenantId || !this.clientOptions.ntpId) {
|
|
687
|
+
throw { displayMessage: "Tenant ID and NTP ID must be provided if ticket code is needed." };
|
|
543
688
|
}
|
|
544
689
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
690
|
+
InitializeTicketPrompt(
|
|
691
|
+
this.target,
|
|
692
|
+
this.clientOptions.ticketCode,
|
|
693
|
+
async code => {
|
|
549
694
|
await this.RedeemCode(code);
|
|
550
695
|
|
|
551
696
|
this.Initialize(target, parameters);
|
|
552
|
-
}
|
|
697
|
+
}
|
|
698
|
+
);
|
|
553
699
|
|
|
554
|
-
|
|
555
|
-
}
|
|
700
|
+
return;
|
|
556
701
|
}
|
|
557
702
|
|
|
558
703
|
try {
|
|
559
|
-
const playoutOptionsPromise = this.PlayoutOptions();
|
|
560
|
-
|
|
561
704
|
this.target.classList.add("eluvio-player");
|
|
562
705
|
|
|
706
|
+
// Load collection info, if present
|
|
707
|
+
await this.LoadCollection();
|
|
708
|
+
|
|
563
709
|
if(this.restarted) {
|
|
564
710
|
// Prevent big play button from flashing on restart
|
|
565
711
|
this.target.classList.add("eluvio-player-restarted");
|
|
@@ -594,11 +740,27 @@ export class EluvioPlayer {
|
|
|
594
740
|
className: this.playerOptions.controlsClassName
|
|
595
741
|
});
|
|
596
742
|
|
|
743
|
+
if(this.playerOptions.title !== false && this.playerOptions.controls !== EluvioPlayerParameters.controls.DEFAULT) {
|
|
744
|
+
if(this.ActiveCollectionMedia()) {
|
|
745
|
+
const {title, description} = this.ActiveCollectionMedia();
|
|
746
|
+
|
|
747
|
+
this.controls.InitializeContentTitle({title, description});
|
|
748
|
+
} else if(this.sourceOptions.contentOptions.title) {
|
|
749
|
+
this.controls.InitializeContentTitle({
|
|
750
|
+
title: this.sourceOptions.contentOptions.title,
|
|
751
|
+
description: this.sourceOptions.contentOptions.description
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
597
756
|
if(restartParameters) {
|
|
598
757
|
this.video.addEventListener("loadedmetadata", async () => {
|
|
599
758
|
this.video.volume = restartParameters.volume;
|
|
600
759
|
this.video.muted = restartParameters.muted;
|
|
601
|
-
|
|
760
|
+
|
|
761
|
+
if(restartParameters.currentTime) {
|
|
762
|
+
this.video.currentTime = restartParameters.currentTime;
|
|
763
|
+
}
|
|
602
764
|
|
|
603
765
|
if(restartParameters.playing) {
|
|
604
766
|
PlayPause(this.video, true);
|
|
@@ -656,9 +818,14 @@ export class EluvioPlayer {
|
|
|
656
818
|
this.target.classList.remove("eluvio-player-landscape");
|
|
657
819
|
}
|
|
658
820
|
});
|
|
821
|
+
|
|
659
822
|
this.resizeObserver.observe(this.target);
|
|
660
823
|
|
|
661
|
-
|
|
824
|
+
if(this.collectionInfo && this.collectionInfo.isPlaylist && this.collectionInfo.mediaIndex < this.collectionInfo.mediaLength - 1) {
|
|
825
|
+
this.video.addEventListener("ended", () => this.CollectionPlayNext());
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
let { protocol, drm, playoutUrl, drms, multiviewOptions } = await this.PlayoutOptions();
|
|
662
829
|
|
|
663
830
|
this.PosterUrl().then(posterUrl => this.controls.SetPosterUrl(posterUrl));
|
|
664
831
|
|
|
@@ -675,6 +842,17 @@ export class EluvioPlayer {
|
|
|
675
842
|
await this.InitializeDash({playoutUrl, authorizationToken, drm, drms, multiviewOptions});
|
|
676
843
|
}
|
|
677
844
|
|
|
845
|
+
if(this.playerOptions.collectVideoAnalytics) {
|
|
846
|
+
import("./Analytics")
|
|
847
|
+
.then(({InitializeMuxMonitoring}) => InitializeMuxMonitoring({
|
|
848
|
+
appName: this.playerOptions.appName || "elv-player-js",
|
|
849
|
+
elvPlayer: this,
|
|
850
|
+
playoutUrl,
|
|
851
|
+
authorizationToken,
|
|
852
|
+
disableCookies: this.playerOptions.collectVideoAnalytics === EluvioPlayerParameters.collectVideoAnalytics.DISABLE_COOKIES
|
|
853
|
+
}));
|
|
854
|
+
}
|
|
855
|
+
|
|
678
856
|
if(this.playerOptions.playerCallback) {
|
|
679
857
|
this.playerOptions.playerCallback({
|
|
680
858
|
player: this,
|
|
@@ -730,37 +908,36 @@ export class EluvioPlayer {
|
|
|
730
908
|
|
|
731
909
|
if(permissionErrorMessage) {
|
|
732
910
|
error.permission_message = permissionErrorMessage;
|
|
733
|
-
|
|
734
|
-
parent: this.target,
|
|
735
|
-
classes: ["eluvio-player__error-message"]
|
|
736
|
-
});
|
|
911
|
+
this.SetErrorMessage(permissionErrorMessage);
|
|
737
912
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
913
|
+
if(typeof error === "object") {
|
|
914
|
+
error.permission_message = permissionErrorMessage;
|
|
915
|
+
} else {
|
|
916
|
+
this.Log(permissionErrorMessage, true);
|
|
917
|
+
}
|
|
918
|
+
} else {
|
|
919
|
+
this.SetErrorMessage(error.displayMessage || "Insufficient permissions");
|
|
744
920
|
}
|
|
745
921
|
// eslint-disable-next-line no-empty
|
|
746
|
-
} catch (error) {
|
|
922
|
+
} catch (error) {
|
|
923
|
+
this.SetErrorMessage(error.displayMessage || "Insufficient permissions");
|
|
924
|
+
}
|
|
925
|
+
} else if(error.status === 500) {
|
|
926
|
+
this.HardReload(error, 10000);
|
|
927
|
+
} else {
|
|
928
|
+
this.SetErrorMessage(error.displayMessage || "Something went wrong");
|
|
747
929
|
}
|
|
748
930
|
|
|
749
|
-
error.permission_message = permissionErrorMessage;
|
|
750
931
|
if(this.playerOptions.errorCallback) {
|
|
751
932
|
this.playerOptions.errorCallback(error, this);
|
|
752
933
|
}
|
|
753
|
-
|
|
754
|
-
if(error.status === 500) {
|
|
755
|
-
this.HardReload(error, 10000);
|
|
756
|
-
}
|
|
757
934
|
}
|
|
758
935
|
}
|
|
759
936
|
|
|
760
937
|
async InitializeHLS({playoutUrl, authorizationToken, drm, multiviewOptions}) {
|
|
761
|
-
|
|
938
|
+
this.HLS = (await import("hls.js")).default;
|
|
762
939
|
|
|
763
|
-
if(["fairplay", "sample-aes"].includes(drm) || !
|
|
940
|
+
if(["fairplay", "sample-aes"].includes(drm) || !this.HLS.isSupported()) {
|
|
764
941
|
// HLS JS NOT SUPPORTED - Handle native player
|
|
765
942
|
|
|
766
943
|
if(drm === "fairplay") {
|
|
@@ -828,7 +1005,7 @@ export class EluvioPlayer {
|
|
|
828
1005
|
...customProfileSettings
|
|
829
1006
|
};
|
|
830
1007
|
|
|
831
|
-
const hlsPlayer = new
|
|
1008
|
+
const hlsPlayer = new this.HLS({
|
|
832
1009
|
xhrSetup: xhr => {
|
|
833
1010
|
xhr.setRequestHeader("Authorization", `Bearer ${authorizationToken}`);
|
|
834
1011
|
|
|
@@ -840,6 +1017,34 @@ export class EluvioPlayer {
|
|
|
840
1017
|
},
|
|
841
1018
|
...this.hlsOptions
|
|
842
1019
|
});
|
|
1020
|
+
|
|
1021
|
+
// Limit playback to maximum bitrate, if specified
|
|
1022
|
+
if(this.playerOptions.maxBitrate) {
|
|
1023
|
+
hlsPlayer.on(this.HLS.Events.MANIFEST_PARSED, (_, {levels, firstLevel}) => {
|
|
1024
|
+
let levelsToRemove = levels
|
|
1025
|
+
.map((level, i) => level.bitrate > this.playerOptions.maxBitrate ? i : undefined)
|
|
1026
|
+
.filter(i => typeof i !== "undefined")
|
|
1027
|
+
// Note: Remove levels from highest to lowest index
|
|
1028
|
+
.reverse();
|
|
1029
|
+
|
|
1030
|
+
if(levelsToRemove.length === levels.length) {
|
|
1031
|
+
this.Log(`Warning: Max bitrate '${this.playerOptions.maxBitrate}bps' is less than all available levels for this content.`);
|
|
1032
|
+
// Keep first level
|
|
1033
|
+
levelsToRemove = levelsToRemove.filter(i => i > 0);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
this.Log("Removing the following levels due to maxBitrate setting:");
|
|
1037
|
+
this.Log(levelsToRemove.map(i => [levels[i].width, "x", levels[i].height, ` (${(levels[i].bitrate / 1000 / 1000).toFixed(1)}Mbps)`].join("")).join(", "));
|
|
1038
|
+
|
|
1039
|
+
if(levelsToRemove.find(i => firstLevel === i)) {
|
|
1040
|
+
// Player will start on level that is being removed - switch to highest level that will not be removed
|
|
1041
|
+
hlsPlayer.startLevel = levels.map((_, i) => i).filter(i => !levelsToRemove.includes(i)).reverse()[0];
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
levelsToRemove.map(i => hlsPlayer.removeLevel(i));
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
|
|
843
1048
|
hlsPlayer.loadSource(playoutUrl.toString());
|
|
844
1049
|
hlsPlayer.attachMedia(this.video);
|
|
845
1050
|
|
|
@@ -892,11 +1097,11 @@ export class EluvioPlayer {
|
|
|
892
1097
|
}
|
|
893
1098
|
};
|
|
894
1099
|
|
|
895
|
-
hlsPlayer.on(
|
|
896
|
-
hlsPlayer.on(
|
|
897
|
-
hlsPlayer.on(
|
|
898
|
-
hlsPlayer.on(
|
|
899
|
-
hlsPlayer.on(
|
|
1100
|
+
hlsPlayer.on(this.HLS.Events.SUBTITLE_TRACKS_UPDATED, () => this.UpdateTextTracks());
|
|
1101
|
+
hlsPlayer.on(this.HLS.Events.LEVEL_LOADED, () => UpdateQualityOptions());
|
|
1102
|
+
hlsPlayer.on(this.HLS.Events.LEVEL_SWITCHED, () => UpdateQualityOptions());
|
|
1103
|
+
hlsPlayer.on(this.HLS.Events.SUBTITLE_TRACK_SWITCH, () => this.UpdateTextTracks());
|
|
1104
|
+
hlsPlayer.on(this.HLS.Events.AUDIO_TRACKS_UPDATED, () => {
|
|
900
1105
|
this.controls.SetAudioTrackControls({
|
|
901
1106
|
GetAudioTracks: () => {
|
|
902
1107
|
const tracks = hlsPlayer.audioTracks.map(track => ({
|
|
@@ -954,7 +1159,7 @@ export class EluvioPlayer {
|
|
|
954
1159
|
this.controls.ShowHLSOptionsForm({
|
|
955
1160
|
hlsOptions: this.hlsOptions,
|
|
956
1161
|
SetPlayerProfile,
|
|
957
|
-
hlsVersion:
|
|
1162
|
+
hlsVersion: this.HLS.version
|
|
958
1163
|
});
|
|
959
1164
|
} else {
|
|
960
1165
|
SetPlayerProfile({profile: key});
|
|
@@ -963,34 +1168,31 @@ export class EluvioPlayer {
|
|
|
963
1168
|
});
|
|
964
1169
|
}
|
|
965
1170
|
|
|
966
|
-
hlsPlayer.on(
|
|
1171
|
+
hlsPlayer.on(this.HLS.Events.FRAG_LOADED, () => {
|
|
967
1172
|
this.errors = 0;
|
|
968
1173
|
clearTimeout(this.bufferFullRestartTimeout);
|
|
969
1174
|
});
|
|
970
1175
|
|
|
971
|
-
hlsPlayer.on(
|
|
1176
|
+
hlsPlayer.on(this.HLS.Events.ERROR, async (event, error) => {
|
|
972
1177
|
this.errors += 1;
|
|
973
1178
|
|
|
974
|
-
this.Log(`Encountered ${error.details}
|
|
975
|
-
this.Log(error);
|
|
976
|
-
|
|
977
|
-
if(error.
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1179
|
+
this.Log(`Encountered ${error.details}`, true);
|
|
1180
|
+
this.Log(error, true);
|
|
1181
|
+
|
|
1182
|
+
if(error.response && error.response.code === 403) {
|
|
1183
|
+
// Not allowed to access
|
|
1184
|
+
this.SetErrorMessage("Insufficient permissions");
|
|
1185
|
+
} else if(this.errors < 5) {
|
|
1186
|
+
if(error.fatal) {
|
|
1187
|
+
if(data.type === this.HLS.ErrorTypes.MEDIA_ERROR) {
|
|
1188
|
+
this.Log("Attempting to recover using hlsPlayer.recoverMediaError");
|
|
1189
|
+
hlsPlayer.recoverMediaError();
|
|
1190
|
+
} else {
|
|
1191
|
+
this.HardReload(error);
|
|
983
1192
|
}
|
|
984
|
-
}, 5000);
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
if(error.fatal || this.errors === 3) {
|
|
988
|
-
if(error.response.code === 403) {
|
|
989
|
-
// Not allowed to access
|
|
990
|
-
this.Destroy();
|
|
991
|
-
} else {
|
|
992
|
-
this.HardReload(error);
|
|
993
1193
|
}
|
|
1194
|
+
} else {
|
|
1195
|
+
this.HardReload(error);
|
|
994
1196
|
}
|
|
995
1197
|
});
|
|
996
1198
|
|
|
@@ -1000,20 +1202,24 @@ export class EluvioPlayer {
|
|
|
1000
1202
|
}
|
|
1001
1203
|
|
|
1002
1204
|
async InitializeDash({playoutUrl, authorizationToken, drm, drms, multiviewOptions}) {
|
|
1003
|
-
|
|
1004
|
-
const dashPlayer =
|
|
1205
|
+
this.Dash = (await import("dashjs")).default;
|
|
1206
|
+
const dashPlayer = this.Dash.MediaPlayer().create();
|
|
1005
1207
|
|
|
1208
|
+
const customDashOptions = this.playerOptions.dashjsOptions || {};
|
|
1006
1209
|
dashPlayer.updateSettings({
|
|
1210
|
+
...customDashOptions,
|
|
1007
1211
|
"streaming": {
|
|
1008
1212
|
"buffer": {
|
|
1009
1213
|
"fastSwitchEnabled": true
|
|
1010
1214
|
},
|
|
1011
1215
|
"text": {
|
|
1012
|
-
"defaultEnabled": false
|
|
1013
|
-
}
|
|
1216
|
+
"defaultEnabled": false,
|
|
1217
|
+
},
|
|
1218
|
+
...(customDashOptions.streaming || {})
|
|
1014
1219
|
},
|
|
1015
1220
|
"text": {
|
|
1016
|
-
"defaultEnabled": false
|
|
1221
|
+
"defaultEnabled": false,
|
|
1222
|
+
...(customDashOptions.text || {})
|
|
1017
1223
|
}
|
|
1018
1224
|
});
|
|
1019
1225
|
|
|
@@ -1027,6 +1233,16 @@ export class EluvioPlayer {
|
|
|
1027
1233
|
});
|
|
1028
1234
|
}
|
|
1029
1235
|
|
|
1236
|
+
if(this.playerOptions.maxBitrate) {
|
|
1237
|
+
dashPlayer.updateSettings({
|
|
1238
|
+
"streaming": {
|
|
1239
|
+
"abr": {
|
|
1240
|
+
"maxBitrate": { "video": this.playerOptions.maxBitrate / 1000 }
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1030
1246
|
playoutUrl.searchParams.delete("authorization");
|
|
1031
1247
|
dashPlayer.extend("RequestModifier", function () {
|
|
1032
1248
|
return {
|
|
@@ -1119,12 +1335,12 @@ export class EluvioPlayer {
|
|
|
1119
1335
|
});
|
|
1120
1336
|
};
|
|
1121
1337
|
|
|
1122
|
-
dashPlayer.on(
|
|
1123
|
-
dashPlayer.on(
|
|
1338
|
+
dashPlayer.on(this.Dash.MediaPlayer.events.QUALITY_CHANGE_RENDERED, () => UpdateQualityOptions());
|
|
1339
|
+
dashPlayer.on(this.Dash.MediaPlayer.events.TRACK_CHANGE_RENDERED, () => {
|
|
1124
1340
|
UpdateAudioTracks();
|
|
1125
1341
|
this.UpdateTextTracks({dashPlayer});
|
|
1126
1342
|
});
|
|
1127
|
-
dashPlayer.on(
|
|
1343
|
+
dashPlayer.on(this.Dash.MediaPlayer.events.MANIFEST_LOADED, () => {
|
|
1128
1344
|
UpdateQualityOptions();
|
|
1129
1345
|
UpdateAudioTracks();
|
|
1130
1346
|
});
|
|
@@ -1189,5 +1405,7 @@ export class EluvioPlayer {
|
|
|
1189
1405
|
}
|
|
1190
1406
|
}
|
|
1191
1407
|
|
|
1408
|
+
EluvioPlayer.EluvioPlayerParameters = EluvioPlayerParameters;
|
|
1409
|
+
|
|
1192
1410
|
export default EluvioPlayer;
|
|
1193
1411
|
|