@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/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) { throw Error("ELUVIO PLAYER: Tenant ID must be provided if ticket code is specified."); }
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.player.destroy) {
426
- this.player.destroy();
427
- } else if(this.player.reset) {
428
- this.player.reset();
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 Error("ELUVIO PLAYER: Tenant ID must be provided if ticket code is needed.");
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
- if(this.clientOptions.ticketCode) {
546
- await this.RedeemCode(this.clientOptions.ticketCode);
547
- } else {
548
- InitializeTicketPrompt(this.target, async code => {
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
- return;
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
- this.video.currentTime = restartParameters.currentTime;
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
- let { protocol, drm, playoutUrl, drms, multiviewOptions } = await playoutOptionsPromise;
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
- const errorMessage = CreateElement({
734
- parent: this.target,
735
- classes: ["eluvio-player__error-message"]
736
- });
911
+ this.SetErrorMessage(permissionErrorMessage);
737
912
 
738
- CreateElement({
739
- parent: errorMessage,
740
- classes: ["eluvio-player__error-message__text"]
741
- }).innerHTML = permissionErrorMessage;
742
-
743
- this.target.classList.add("eluvio-player--error");
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
- const HLSPlayer = (await import("hls.js")).default;
938
+ this.HLS = (await import("hls.js")).default;
762
939
 
763
- if(["fairplay", "sample-aes"].includes(drm) || !HLSPlayer.isSupported()) {
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 HLSPlayer({
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(HLSPlayer.Events.SUBTITLE_TRACKS_UPDATED, () => this.UpdateTextTracks());
896
- hlsPlayer.on(HLSPlayer.Events.LEVEL_LOADED, () => UpdateQualityOptions());
897
- hlsPlayer.on(HLSPlayer.Events.LEVEL_SWITCHED, () => UpdateQualityOptions());
898
- hlsPlayer.on(HLSPlayer.Events.SUBTITLE_TRACK_SWITCH, () => this.UpdateTextTracks());
899
- hlsPlayer.on(HLSPlayer.Events.AUDIO_TRACKS_UPDATED, () => {
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: HLSPlayer.version
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(HLSPlayer.Events.FRAG_LOADED, () => {
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(HLSPlayer.Events.ERROR, async (event, error) => {
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.details === "bufferStalledError") {
978
- const stallTime = this.video.currentTime;
979
-
980
- setTimeout(() => {
981
- if(!this.video.paused && this.video.currentTime === stallTime) {
982
- this.Log("Buffer stalled error, no progress in 5 seconds - Restarting player", true);
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
- const DashPlayer = (await import("dashjs")).default;
1004
- const dashPlayer = DashPlayer.MediaPlayer().create();
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(DashPlayer.MediaPlayer.events.QUALITY_CHANGE_RENDERED, () => UpdateQualityOptions());
1123
- dashPlayer.on(DashPlayer.MediaPlayer.events.TRACK_CHANGE_RENDERED, () => {
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(DashPlayer.MediaPlayer.events.MANIFEST_LOADED, () => {
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