stormcloud-video-player 0.3.66 → 0.3.68

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.
@@ -1819,7 +1819,7 @@ function createHlsAdPlayer(contentVideo, options) {
1819
1819
  }
1820
1820
  var adElement = xmlDoc.querySelector("Ad");
1821
1821
  if (!adElement) {
1822
- console.warn("[HlsAdPlayer] No Ad element found in VAST XML");
1822
+ console.warn("[HlsAdPlayer] No Ad element found in VAST XML (no fill). Content (first 2000 chars):", xmlString.substring(0, 2e3));
1823
1823
  return null;
1824
1824
  }
1825
1825
  var adId = adElement.getAttribute("id") || "unknown";
@@ -1915,7 +1915,7 @@ function createHlsAdPlayer(contentVideo, options) {
1915
1915
  }
1916
1916
  function fetchAndParseVastAd(vastTagUrl) {
1917
1917
  return _async_to_generator(function() {
1918
- var response, vastXml;
1918
+ var response, vastXml, trimmedXml;
1919
1919
  return _ts_generator(this, function(_state) {
1920
1920
  switch(_state.label){
1921
1921
  case 0:
@@ -1941,8 +1941,16 @@ function createHlsAdPlayer(contentVideo, options) {
1941
1941
  ];
1942
1942
  case 2:
1943
1943
  vastXml = _state.sent();
1944
- console.log("[HlsAdPlayer] VAST XML received");
1944
+ console.log("[HlsAdPlayer] VAST XML received (length=".concat(vastXml.length, ")"));
1945
1945
  console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1946
+ trimmedXml = vastXml.trim();
1947
+ if (trimmedXml.length === 0) {
1948
+ console.warn("[HlsAdPlayer] VAST response body is empty (no fill)");
1949
+ return [
1950
+ 2,
1951
+ null
1952
+ ];
1953
+ }
1946
1954
  return [
1947
1955
  2,
1948
1956
  parseVastXml(vastXml)
@@ -3382,6 +3390,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3382
3390
  this.preloadPoolActive = false;
3383
3391
  this.preloadPoolLoopRunning = false;
3384
3392
  this.adDetectSentForCurrentBreak = false;
3393
+ this.latencyProfileApplied = false;
3385
3394
  this.continuousFetchLoopRunning = false;
3386
3395
  initializePolyfills();
3387
3396
  var browserOverrides = getBrowserConfigOverrides();
@@ -3498,24 +3507,21 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3498
3507
  2
3499
3508
  ];
3500
3509
  case 7:
3501
- this.hls = new import_hls2.default(_object_spread_props(_object_spread({
3510
+ this.hls = new import_hls2.default({
3502
3511
  enableWorker: true,
3503
3512
  backBufferLength: 30,
3504
3513
  liveDurationInfinity: true,
3505
3514
  lowLatencyMode: !!this.config.lowLatencyMode,
3506
- maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1
3507
- }, this.config.lowLatencyMode ? {
3508
- liveSyncDuration: 2
3509
- } : {}), {
3515
+ maxLiveSyncPlaybackRate: 1.1,
3510
3516
  maxBufferLength: 30,
3511
3517
  maxMaxBufferLength: 600,
3512
3518
  maxBufferSize: 60 * 1e3 * 1e3,
3513
- maxBufferHole: 0.5,
3519
+ maxBufferHole: 1,
3514
3520
  highBufferWatchdogPeriod: 2,
3515
- nudgeOffset: 0.1,
3516
- nudgeMaxRetry: 3,
3521
+ nudgeOffset: 0.2,
3522
+ nudgeMaxRetry: 5,
3517
3523
  startPosition: -1
3518
- }));
3524
+ });
3519
3525
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, function() {
3520
3526
  var _this_hls;
3521
3527
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.loadSource(_this.config.src);
@@ -3559,6 +3565,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3559
3565
  this.bufferedSegmentsCount = 0;
3560
3566
  this.hasInitialBufferCompleted = false;
3561
3567
  this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
3568
+ this.latencyProfileApplied = false;
3569
+ this.detectedLowLatencyStream = void 0;
3562
3570
  minSegments = (_this_config_minSegmentsBeforePlay = this.config.minSegmentsBeforePlay) !== null && _this_config_minSegmentsBeforePlay !== void 0 ? _this_config_minSegmentsBeforePlay : 2;
3563
3571
  if (this.config.debugAdTiming) {
3564
3572
  console.log("[StormcloudVideoPlayer] Waiting for", minSegments, "segments to buffer before playback");
@@ -3588,6 +3596,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3588
3596
  }).call(_this);
3589
3597
  });
3590
3598
  this.hls.on(import_hls2.default.Events.LEVEL_LOADED, function(_evt, data) {
3599
+ _this.applyStreamLatencyProfile(data === null || data === void 0 ? void 0 : data.details);
3591
3600
  if (_this.inAdBreak || _this.pendingAdBreak) {
3592
3601
  return;
3593
3602
  }
@@ -3867,6 +3876,64 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3867
3876
  }).call(this);
3868
3877
  }
3869
3878
  },
3879
+ {
3880
+ key: "applyStreamLatencyProfile",
3881
+ value: function applyStreamLatencyProfile(details) {
3882
+ if (this.latencyProfileApplied || !this.hls) {
3883
+ return;
3884
+ }
3885
+ if (!details) {
3886
+ return;
3887
+ }
3888
+ if (details.live !== true) {
3889
+ this.latencyProfileApplied = true;
3890
+ this.detectedLowLatencyStream = false;
3891
+ return;
3892
+ }
3893
+ var isLowLatencyManifest = this.isLowLatencyManifest(details);
3894
+ var useLowLatency = isLowLatencyManifest && !!this.config.lowLatencyMode;
3895
+ this.detectedLowLatencyStream = useLowLatency;
3896
+ this.latencyProfileApplied = true;
3897
+ var cfg = this.hls.config;
3898
+ if (useLowLatency) {
3899
+ cfg.maxLiveSyncPlaybackRate = 1.5;
3900
+ cfg.maxBufferHole = 0.5;
3901
+ delete cfg.liveSyncDuration;
3902
+ } else {
3903
+ cfg.maxLiveSyncPlaybackRate = 1.1;
3904
+ cfg.maxBufferHole = 1;
3905
+ delete cfg.liveSyncDuration;
3906
+ cfg.liveSyncDurationCount = 3;
3907
+ }
3908
+ if (this.config.debugAdTiming) {
3909
+ var _details_targetduration;
3910
+ console.log("[StormcloudVideoPlayer] Live latency profile: ".concat(useLowLatency ? "LL-HLS (low latency)" : "standard live (stability)"), {
3911
+ isLowLatencyManifest: isLowLatencyManifest,
3912
+ lowLatencyModeRequested: !!this.config.lowLatencyMode,
3913
+ canBlockReload: details.canBlockReload,
3914
+ partTarget: details.partTarget,
3915
+ partHoldBack: details.partHoldBack,
3916
+ partListLength: Array.isArray(details.partList) ? details.partList.length : 0,
3917
+ targetDuration: (_details_targetduration = details.targetduration) !== null && _details_targetduration !== void 0 ? _details_targetduration : details.targetDuration,
3918
+ maxLiveSyncPlaybackRate: cfg.maxLiveSyncPlaybackRate,
3919
+ maxBufferHole: cfg.maxBufferHole
3920
+ });
3921
+ }
3922
+ }
3923
+ },
3924
+ {
3925
+ key: "isLowLatencyManifest",
3926
+ value: function isLowLatencyManifest(details) {
3927
+ if (!details) {
3928
+ return false;
3929
+ }
3930
+ var hasParts = Array.isArray(details.partList) && details.partList.length > 0;
3931
+ var hasPartTarget = typeof details.partTarget === "number" && details.partTarget > 0;
3932
+ var hasPartHoldBack = typeof details.partHoldBack === "number" && details.partHoldBack > 0;
3933
+ var canBlockReload = details.canBlockReload === true;
3934
+ return hasParts || hasPartTarget || hasPartHoldBack || canBlockReload;
3935
+ }
3936
+ },
3870
3937
  {
3871
3938
  key: "attachImaEventListeners",
3872
3939
  value: function attachImaEventListeners() {
@@ -3923,10 +3990,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3923
3990
  console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3924
3991
  }
3925
3992
  }
3926
- var currentMuted = _this.video.muted;
3927
- var currentVolume = _this.video.volume;
3928
- var adVolume = currentMuted ? 0 : currentVolume;
3929
- _this.ima.setAdVolume(adVolume);
3993
+ _this.ima.setAdVolume(_this.getPreAdBreakAdVolume());
3930
3994
  if (_this.isShowingPlaceholder) {
3931
3995
  if (_this.config.debugAdTiming) {
3932
3996
  console.log("[StormcloudVideoPlayer] Hiding placeholder - new ads starting");
@@ -4680,6 +4744,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4680
4744
  {
4681
4745
  key: "startScte35AdBreak",
4682
4746
  value: function startScte35AdBreak(marker, cueKey, durationMs) {
4747
+ this.capturePreAdBreakAudio();
4683
4748
  if (!this.video.muted) {
4684
4749
  this.video.muted = true;
4685
4750
  this.video.volume = 0;
@@ -5857,6 +5922,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5857
5922
  return !!(this.config.allowNativeHls && !((_this_config_showCustomControls = this.config.showCustomControls) !== null && _this_config_showCustomControls !== void 0 ? _this_config_showCustomControls : false));
5858
5923
  }
5859
5924
  },
5925
+ {
5926
+ key: "isLowLatencyStream",
5927
+ value: function isLowLatencyStream() {
5928
+ return this.detectedLowLatencyStream;
5929
+ }
5930
+ },
5860
5931
  {
5861
5932
  key: "shouldContinueLiveStreamDuringAds",
5862
5933
  value: function shouldContinueLiveStreamDuringAds() {
@@ -6361,9 +6432,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6361
6432
  this.continuousFetchingActive = true;
6362
6433
  this.isShowingPlaceholder = false;
6363
6434
  this.totalAdRequestsInBreak = 0;
6364
- currentMuted = this.video.muted;
6365
- currentVolume = this.video.volume;
6366
- this.ima.updateOriginalMutedState(currentMuted, currentVolume);
6435
+ this.capturePreAdBreakAudio();
6436
+ currentMuted = this.preAdBreakAudio.muted;
6437
+ currentVolume = this.preAdBreakAudio.volume;
6367
6438
  if (!this.video.muted) {
6368
6439
  this.video.muted = true;
6369
6440
  this.video.volume = 0;
@@ -6838,7 +6909,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6838
6909
  value: function tryNextAvailableAd() {
6839
6910
  var retryCount = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 0;
6840
6911
  return _async_to_generator(function() {
6841
- var remaining, preloaded, currentMuted, currentVolume, adVolume, error, nextAdUrl, currentMuted1, currentVolume1, error1, errorMessage, maxRetries;
6912
+ var remaining, preloaded, error, _ref, _ref1, _this_preAdBreakAudio, _this_preAdBreakAudio1, nextAdUrl, error1, errorMessage, maxRetries;
6842
6913
  return _ts_generator(this, function(_state) {
6843
6914
  switch(_state.label){
6844
6915
  case 0:
@@ -6910,10 +6981,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6910
6981
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6911
6982
  this.scheduleAdStopAtBreakBoundary();
6912
6983
  }
6913
- currentMuted = this.video.muted;
6914
- currentVolume = this.video.volume;
6915
- adVolume = currentMuted ? 0 : currentVolume;
6916
- this.ima.setAdVolume(adVolume);
6984
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
6917
6985
  this.consecutiveFailures = 0;
6918
6986
  return [
6919
6987
  2
@@ -6960,9 +7028,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6960
7028
  if (this.config.debugAdTiming) {
6961
7029
  console.log("[CONTINUOUS-FETCH] \uD83C\uDFAC Requesting next ad via IMA SDK (".concat(this.currentAdIndex + 1, "/").concat(this.totalAdsInBreak, ", ").concat(this.adRequestQueue.length, " remaining in queue)"));
6962
7030
  }
6963
- currentMuted1 = this.video.muted;
6964
- currentVolume1 = this.video.volume;
6965
- this.ima.updateOriginalMutedState(currentMuted1, currentVolume1);
7031
+ this.ima.updateOriginalMutedState((_ref = (_this_preAdBreakAudio = this.preAdBreakAudio) === null || _this_preAdBreakAudio === void 0 ? void 0 : _this_preAdBreakAudio.muted) !== null && _ref !== void 0 ? _ref : this.video.muted, (_ref1 = (_this_preAdBreakAudio1 = this.preAdBreakAudio) === null || _this_preAdBreakAudio1 === void 0 ? void 0 : _this_preAdBreakAudio1.volume) !== null && _ref1 !== void 0 ? _ref1 : this.video.volume);
6966
7032
  this.currentAdIndex++;
6967
7033
  this.totalAdRequestsInBreak++;
6968
7034
  this.lastAdRequestTime = Date.now();
@@ -7055,7 +7121,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7055
7121
  key: "showPlaceholderAndWaitForAds",
7056
7122
  value: function showPlaceholderAndWaitForAds() {
7057
7123
  return _async_to_generator(function() {
7058
- var remaining, waitTime, checkInterval, maxChecks, i, nextAdUrl, currentMuted, currentVolume, error, errorMessage;
7124
+ var remaining, waitTime, checkInterval, maxChecks, i, _ref, _ref1, _this_preAdBreakAudio, _this_preAdBreakAudio1, nextAdUrl, error, errorMessage;
7059
7125
  return _ts_generator(this, function(_state) {
7060
7126
  switch(_state.label){
7061
7127
  case 0:
@@ -7151,9 +7217,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7151
7217
  }
7152
7218
  this.isShowingPlaceholder = false;
7153
7219
  this.ima.hidePlaceholder();
7154
- currentMuted = this.video.muted;
7155
- currentVolume = this.video.volume;
7156
- this.ima.updateOriginalMutedState(currentMuted, currentVolume);
7220
+ this.ima.updateOriginalMutedState((_ref = (_this_preAdBreakAudio = this.preAdBreakAudio) === null || _this_preAdBreakAudio === void 0 ? void 0 : _this_preAdBreakAudio.muted) !== null && _ref !== void 0 ? _ref : this.video.muted, (_ref1 = (_this_preAdBreakAudio1 = this.preAdBreakAudio) === null || _this_preAdBreakAudio1 === void 0 ? void 0 : _this_preAdBreakAudio1.volume) !== null && _ref1 !== void 0 ? _ref1 : this.video.volume);
7157
7221
  this.currentAdIndex++;
7158
7222
  this.totalAdRequestsInBreak++;
7159
7223
  this.lastAdRequestTime = Date.now();
@@ -7335,7 +7399,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7335
7399
  first = tags[0];
7336
7400
  rest = tags.slice(1);
7337
7401
  this.adPodQueue = rest;
7338
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
7402
+ this.capturePreAdBreakAudio();
7339
7403
  this.showAds = true;
7340
7404
  this.inAdBreak = true;
7341
7405
  this.currentAdBreakStartWallClockMs = Date.now();
@@ -7362,12 +7426,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7362
7426
  ];
7363
7427
  case 3:
7364
7428
  error = _state.sent();
7365
- this.adPodQueue = [];
7366
- this.inAdBreak = false;
7367
- this.showAds = false;
7368
7429
  if (this.config.debugAdTiming) {
7369
7430
  console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7370
7431
  }
7432
+ this.handleAdPodComplete();
7371
7433
  return [
7372
7434
  3,
7373
7435
  4
@@ -7598,7 +7660,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7598
7660
  key: "playSingleAd",
7599
7661
  value: function playSingleAd(vastTagUrl) {
7600
7662
  return _async_to_generator(function() {
7601
- var requestToken, currentMuted, currentVolume, adVolume, playError, preloadedFallback, currentMuted1, currentVolume1, adVolume1, fallbackError, error, errorMessage, preloadedFallback1, currentMuted2, currentVolume2, adVolume2, fallbackError1;
7663
+ var requestToken, playError, preloadedFallback, fallbackError, error, errorMessage, preloadedFallback1, fallbackError1;
7602
7664
  return _ts_generator(this, function(_state) {
7603
7665
  switch(_state.label){
7604
7666
  case 0:
@@ -7685,10 +7747,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7685
7747
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7686
7748
  this.scheduleAdStopAtBreakBoundary();
7687
7749
  }
7688
- currentMuted = this.video.muted;
7689
- currentVolume = this.video.volume;
7690
- adVolume = currentMuted ? 0 : currentVolume;
7691
- this.ima.setAdVolume(adVolume);
7750
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
7692
7751
  this.consecutiveFailures = 0;
7693
7752
  this.temporaryFailureUrls.delete(vastTagUrl);
7694
7753
  return [
@@ -7735,10 +7794,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7735
7794
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7736
7795
  this.scheduleAdStopAtBreakBoundary();
7737
7796
  }
7738
- currentMuted1 = this.video.muted;
7739
- currentVolume1 = this.video.volume;
7740
- adVolume1 = currentMuted1 ? 0 : currentVolume1;
7741
- this.ima.setAdVolume(adVolume1);
7797
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
7742
7798
  return [
7743
7799
  2
7744
7800
  ];
@@ -7812,10 +7868,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7812
7868
  ];
7813
7869
  case 14:
7814
7870
  _state.sent();
7815
- currentMuted2 = this.video.muted;
7816
- currentVolume2 = this.video.volume;
7817
- adVolume2 = currentMuted2 ? 0 : currentVolume2;
7818
- this.ima.setAdVolume(adVolume2);
7871
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
7819
7872
  return [
7820
7873
  2
7821
7874
  ];
@@ -7855,6 +7908,33 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7855
7908
  }).call(this);
7856
7909
  }
7857
7910
  },
7911
+ {
7912
+ key: "capturePreAdBreakAudio",
7913
+ value: function capturePreAdBreakAudio() {
7914
+ if (this.preAdBreakAudio) {
7915
+ return;
7916
+ }
7917
+ var captured = {
7918
+ muted: this.video.muted,
7919
+ volume: typeof this.video.volume === "number" && !Number.isNaN(this.video.volume) ? Math.max(0, Math.min(1, this.video.volume)) : 1
7920
+ };
7921
+ this.preAdBreakAudio = captured;
7922
+ this.ima.updateOriginalMutedState(captured.muted, captured.volume);
7923
+ if (this.config.debugAdTiming) {
7924
+ console.log("[StormcloudVideoPlayer] Captured pre-ad-break audio state: muted=".concat(captured.muted, ", volume=").concat(captured.volume));
7925
+ }
7926
+ }
7927
+ },
7928
+ {
7929
+ key: "getPreAdBreakAdVolume",
7930
+ value: function getPreAdBreakAdVolume() {
7931
+ var state = this.preAdBreakAudio;
7932
+ if (state) {
7933
+ return state.muted ? 0 : state.volume;
7934
+ }
7935
+ return this.ima.getOriginalMutedState() ? 0 : this.ima.getOriginalVolume();
7936
+ }
7937
+ },
7858
7938
  {
7859
7939
  key: "handleAdPodComplete",
7860
7940
  value: function handleAdPodComplete() {
@@ -7888,14 +7968,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7888
7968
  this.consecutiveFailures = 0;
7889
7969
  this.globalConsecutiveNoFills = 0;
7890
7970
  this.ima.stop().catch(function() {});
7891
- var restoredMuted = this.ima.getOriginalMutedState();
7892
- var restoredVolume = this.ima.getOriginalVolume();
7971
+ var restoredMuted = this.preAdBreakAudio ? this.preAdBreakAudio.muted : this.ima.getOriginalMutedState();
7972
+ var restoredVolume = this.preAdBreakAudio ? this.preAdBreakAudio.volume : this.ima.getOriginalVolume();
7973
+ this.ima.updateOriginalMutedState(restoredMuted, restoredVolume);
7893
7974
  if (this.video.muted !== restoredMuted) {
7894
7975
  this.video.muted = restoredMuted;
7895
7976
  }
7896
7977
  if (Math.abs(this.video.volume - restoredVolume) > 0.01) {
7897
7978
  this.video.volume = restoredVolume;
7898
7979
  }
7980
+ this.preAdBreakAudio = void 0;
7981
+ if (this.config.debugAdTiming) {
7982
+ console.log("[StormcloudVideoPlayer] Restored post-ad-break audio state: muted=".concat(restoredMuted, ", volume=").concat(restoredVolume));
7983
+ }
7899
7984
  if (this.shouldContinueLiveStreamDuringAds()) {
7900
7985
  if (this.video.paused) {
7901
7986
  var _this_video_play;
@@ -8305,6 +8390,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8305
8390
  this.clearAdFailsafeTimer();
8306
8391
  this.clearAdRequestWatchdog();
8307
8392
  this.clearPendingAdBreak();
8393
+ this.preAdBreakAudio = void 0;
8308
8394
  if (this.placeholderContainer) {
8309
8395
  if (this.placeholderContainer.parentElement) {
8310
8396
  this.placeholderContainer.parentElement.removeChild(this.placeholderContainer);