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.
@@ -1731,7 +1731,7 @@ function createHlsAdPlayer(contentVideo, options) {
1731
1731
  }
1732
1732
  var adElement = xmlDoc.querySelector("Ad");
1733
1733
  if (!adElement) {
1734
- console.warn("[HlsAdPlayer] No Ad element found in VAST XML");
1734
+ console.warn("[HlsAdPlayer] No Ad element found in VAST XML (no fill). Content (first 2000 chars):", xmlString.substring(0, 2e3));
1735
1735
  return null;
1736
1736
  }
1737
1737
  var adId = adElement.getAttribute("id") || "unknown";
@@ -1827,7 +1827,7 @@ function createHlsAdPlayer(contentVideo, options) {
1827
1827
  }
1828
1828
  function fetchAndParseVastAd(vastTagUrl) {
1829
1829
  return _async_to_generator(function() {
1830
- var response, vastXml;
1830
+ var response, vastXml, trimmedXml;
1831
1831
  return _ts_generator(this, function(_state) {
1832
1832
  switch(_state.label){
1833
1833
  case 0:
@@ -1853,8 +1853,16 @@ function createHlsAdPlayer(contentVideo, options) {
1853
1853
  ];
1854
1854
  case 2:
1855
1855
  vastXml = _state.sent();
1856
- console.log("[HlsAdPlayer] VAST XML received");
1856
+ console.log("[HlsAdPlayer] VAST XML received (length=".concat(vastXml.length, ")"));
1857
1857
  console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1858
+ trimmedXml = vastXml.trim();
1859
+ if (trimmedXml.length === 0) {
1860
+ console.warn("[HlsAdPlayer] VAST response body is empty (no fill)");
1861
+ return [
1862
+ 2,
1863
+ null
1864
+ ];
1865
+ }
1858
1866
  return [
1859
1867
  2,
1860
1868
  parseVastXml(vastXml)
@@ -3294,6 +3302,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3294
3302
  this.preloadPoolActive = false;
3295
3303
  this.preloadPoolLoopRunning = false;
3296
3304
  this.adDetectSentForCurrentBreak = false;
3305
+ this.latencyProfileApplied = false;
3297
3306
  this.continuousFetchLoopRunning = false;
3298
3307
  initializePolyfills();
3299
3308
  var browserOverrides = getBrowserConfigOverrides();
@@ -3410,24 +3419,21 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3410
3419
  2
3411
3420
  ];
3412
3421
  case 7:
3413
- this.hls = new import_hls2.default(_object_spread_props(_object_spread({
3422
+ this.hls = new import_hls2.default({
3414
3423
  enableWorker: true,
3415
3424
  backBufferLength: 30,
3416
3425
  liveDurationInfinity: true,
3417
3426
  lowLatencyMode: !!this.config.lowLatencyMode,
3418
- maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1
3419
- }, this.config.lowLatencyMode ? {
3420
- liveSyncDuration: 2
3421
- } : {}), {
3427
+ maxLiveSyncPlaybackRate: 1.1,
3422
3428
  maxBufferLength: 30,
3423
3429
  maxMaxBufferLength: 600,
3424
3430
  maxBufferSize: 60 * 1e3 * 1e3,
3425
- maxBufferHole: 0.5,
3431
+ maxBufferHole: 1,
3426
3432
  highBufferWatchdogPeriod: 2,
3427
- nudgeOffset: 0.1,
3428
- nudgeMaxRetry: 3,
3433
+ nudgeOffset: 0.2,
3434
+ nudgeMaxRetry: 5,
3429
3435
  startPosition: -1
3430
- }));
3436
+ });
3431
3437
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, function() {
3432
3438
  var _this_hls;
3433
3439
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.loadSource(_this.config.src);
@@ -3471,6 +3477,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3471
3477
  this.bufferedSegmentsCount = 0;
3472
3478
  this.hasInitialBufferCompleted = false;
3473
3479
  this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
3480
+ this.latencyProfileApplied = false;
3481
+ this.detectedLowLatencyStream = void 0;
3474
3482
  minSegments = (_this_config_minSegmentsBeforePlay = this.config.minSegmentsBeforePlay) !== null && _this_config_minSegmentsBeforePlay !== void 0 ? _this_config_minSegmentsBeforePlay : 2;
3475
3483
  if (this.config.debugAdTiming) {
3476
3484
  console.log("[StormcloudVideoPlayer] Waiting for", minSegments, "segments to buffer before playback");
@@ -3500,6 +3508,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3500
3508
  }).call(_this);
3501
3509
  });
3502
3510
  this.hls.on(import_hls2.default.Events.LEVEL_LOADED, function(_evt, data) {
3511
+ _this.applyStreamLatencyProfile(data === null || data === void 0 ? void 0 : data.details);
3503
3512
  if (_this.inAdBreak || _this.pendingAdBreak) {
3504
3513
  return;
3505
3514
  }
@@ -3779,6 +3788,64 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3779
3788
  }).call(this);
3780
3789
  }
3781
3790
  },
3791
+ {
3792
+ key: "applyStreamLatencyProfile",
3793
+ value: function applyStreamLatencyProfile(details) {
3794
+ if (this.latencyProfileApplied || !this.hls) {
3795
+ return;
3796
+ }
3797
+ if (!details) {
3798
+ return;
3799
+ }
3800
+ if (details.live !== true) {
3801
+ this.latencyProfileApplied = true;
3802
+ this.detectedLowLatencyStream = false;
3803
+ return;
3804
+ }
3805
+ var isLowLatencyManifest = this.isLowLatencyManifest(details);
3806
+ var useLowLatency = isLowLatencyManifest && !!this.config.lowLatencyMode;
3807
+ this.detectedLowLatencyStream = useLowLatency;
3808
+ this.latencyProfileApplied = true;
3809
+ var cfg = this.hls.config;
3810
+ if (useLowLatency) {
3811
+ cfg.maxLiveSyncPlaybackRate = 1.5;
3812
+ cfg.maxBufferHole = 0.5;
3813
+ delete cfg.liveSyncDuration;
3814
+ } else {
3815
+ cfg.maxLiveSyncPlaybackRate = 1.1;
3816
+ cfg.maxBufferHole = 1;
3817
+ delete cfg.liveSyncDuration;
3818
+ cfg.liveSyncDurationCount = 3;
3819
+ }
3820
+ if (this.config.debugAdTiming) {
3821
+ var _details_targetduration;
3822
+ console.log("[StormcloudVideoPlayer] Live latency profile: ".concat(useLowLatency ? "LL-HLS (low latency)" : "standard live (stability)"), {
3823
+ isLowLatencyManifest: isLowLatencyManifest,
3824
+ lowLatencyModeRequested: !!this.config.lowLatencyMode,
3825
+ canBlockReload: details.canBlockReload,
3826
+ partTarget: details.partTarget,
3827
+ partHoldBack: details.partHoldBack,
3828
+ partListLength: Array.isArray(details.partList) ? details.partList.length : 0,
3829
+ targetDuration: (_details_targetduration = details.targetduration) !== null && _details_targetduration !== void 0 ? _details_targetduration : details.targetDuration,
3830
+ maxLiveSyncPlaybackRate: cfg.maxLiveSyncPlaybackRate,
3831
+ maxBufferHole: cfg.maxBufferHole
3832
+ });
3833
+ }
3834
+ }
3835
+ },
3836
+ {
3837
+ key: "isLowLatencyManifest",
3838
+ value: function isLowLatencyManifest(details) {
3839
+ if (!details) {
3840
+ return false;
3841
+ }
3842
+ var hasParts = Array.isArray(details.partList) && details.partList.length > 0;
3843
+ var hasPartTarget = typeof details.partTarget === "number" && details.partTarget > 0;
3844
+ var hasPartHoldBack = typeof details.partHoldBack === "number" && details.partHoldBack > 0;
3845
+ var canBlockReload = details.canBlockReload === true;
3846
+ return hasParts || hasPartTarget || hasPartHoldBack || canBlockReload;
3847
+ }
3848
+ },
3782
3849
  {
3783
3850
  key: "attachImaEventListeners",
3784
3851
  value: function attachImaEventListeners() {
@@ -3835,10 +3902,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3835
3902
  console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3836
3903
  }
3837
3904
  }
3838
- var currentMuted = _this.video.muted;
3839
- var currentVolume = _this.video.volume;
3840
- var adVolume = currentMuted ? 0 : currentVolume;
3841
- _this.ima.setAdVolume(adVolume);
3905
+ _this.ima.setAdVolume(_this.getPreAdBreakAdVolume());
3842
3906
  if (_this.isShowingPlaceholder) {
3843
3907
  if (_this.config.debugAdTiming) {
3844
3908
  console.log("[StormcloudVideoPlayer] Hiding placeholder - new ads starting");
@@ -4592,6 +4656,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4592
4656
  {
4593
4657
  key: "startScte35AdBreak",
4594
4658
  value: function startScte35AdBreak(marker, cueKey, durationMs) {
4659
+ this.capturePreAdBreakAudio();
4595
4660
  if (!this.video.muted) {
4596
4661
  this.video.muted = true;
4597
4662
  this.video.volume = 0;
@@ -5769,6 +5834,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5769
5834
  return !!(this.config.allowNativeHls && !((_this_config_showCustomControls = this.config.showCustomControls) !== null && _this_config_showCustomControls !== void 0 ? _this_config_showCustomControls : false));
5770
5835
  }
5771
5836
  },
5837
+ {
5838
+ key: "isLowLatencyStream",
5839
+ value: function isLowLatencyStream() {
5840
+ return this.detectedLowLatencyStream;
5841
+ }
5842
+ },
5772
5843
  {
5773
5844
  key: "shouldContinueLiveStreamDuringAds",
5774
5845
  value: function shouldContinueLiveStreamDuringAds() {
@@ -6273,9 +6344,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6273
6344
  this.continuousFetchingActive = true;
6274
6345
  this.isShowingPlaceholder = false;
6275
6346
  this.totalAdRequestsInBreak = 0;
6276
- currentMuted = this.video.muted;
6277
- currentVolume = this.video.volume;
6278
- this.ima.updateOriginalMutedState(currentMuted, currentVolume);
6347
+ this.capturePreAdBreakAudio();
6348
+ currentMuted = this.preAdBreakAudio.muted;
6349
+ currentVolume = this.preAdBreakAudio.volume;
6279
6350
  if (!this.video.muted) {
6280
6351
  this.video.muted = true;
6281
6352
  this.video.volume = 0;
@@ -6750,7 +6821,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6750
6821
  value: function tryNextAvailableAd() {
6751
6822
  var retryCount = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 0;
6752
6823
  return _async_to_generator(function() {
6753
- var remaining, preloaded, currentMuted, currentVolume, adVolume, error, nextAdUrl, currentMuted1, currentVolume1, error1, errorMessage, maxRetries;
6824
+ var remaining, preloaded, error, _ref, _ref1, _this_preAdBreakAudio, _this_preAdBreakAudio1, nextAdUrl, error1, errorMessage, maxRetries;
6754
6825
  return _ts_generator(this, function(_state) {
6755
6826
  switch(_state.label){
6756
6827
  case 0:
@@ -6822,10 +6893,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6822
6893
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6823
6894
  this.scheduleAdStopAtBreakBoundary();
6824
6895
  }
6825
- currentMuted = this.video.muted;
6826
- currentVolume = this.video.volume;
6827
- adVolume = currentMuted ? 0 : currentVolume;
6828
- this.ima.setAdVolume(adVolume);
6896
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
6829
6897
  this.consecutiveFailures = 0;
6830
6898
  return [
6831
6899
  2
@@ -6872,9 +6940,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6872
6940
  if (this.config.debugAdTiming) {
6873
6941
  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)"));
6874
6942
  }
6875
- currentMuted1 = this.video.muted;
6876
- currentVolume1 = this.video.volume;
6877
- this.ima.updateOriginalMutedState(currentMuted1, currentVolume1);
6943
+ 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);
6878
6944
  this.currentAdIndex++;
6879
6945
  this.totalAdRequestsInBreak++;
6880
6946
  this.lastAdRequestTime = Date.now();
@@ -6967,7 +7033,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6967
7033
  key: "showPlaceholderAndWaitForAds",
6968
7034
  value: function showPlaceholderAndWaitForAds() {
6969
7035
  return _async_to_generator(function() {
6970
- var remaining, waitTime, checkInterval, maxChecks, i, nextAdUrl, currentMuted, currentVolume, error, errorMessage;
7036
+ var remaining, waitTime, checkInterval, maxChecks, i, _ref, _ref1, _this_preAdBreakAudio, _this_preAdBreakAudio1, nextAdUrl, error, errorMessage;
6971
7037
  return _ts_generator(this, function(_state) {
6972
7038
  switch(_state.label){
6973
7039
  case 0:
@@ -7063,9 +7129,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7063
7129
  }
7064
7130
  this.isShowingPlaceholder = false;
7065
7131
  this.ima.hidePlaceholder();
7066
- currentMuted = this.video.muted;
7067
- currentVolume = this.video.volume;
7068
- this.ima.updateOriginalMutedState(currentMuted, currentVolume);
7132
+ 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);
7069
7133
  this.currentAdIndex++;
7070
7134
  this.totalAdRequestsInBreak++;
7071
7135
  this.lastAdRequestTime = Date.now();
@@ -7247,7 +7311,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7247
7311
  first = tags[0];
7248
7312
  rest = tags.slice(1);
7249
7313
  this.adPodQueue = rest;
7250
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
7314
+ this.capturePreAdBreakAudio();
7251
7315
  this.showAds = true;
7252
7316
  this.inAdBreak = true;
7253
7317
  this.currentAdBreakStartWallClockMs = Date.now();
@@ -7274,12 +7338,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7274
7338
  ];
7275
7339
  case 3:
7276
7340
  error = _state.sent();
7277
- this.adPodQueue = [];
7278
- this.inAdBreak = false;
7279
- this.showAds = false;
7280
7341
  if (this.config.debugAdTiming) {
7281
7342
  console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7282
7343
  }
7344
+ this.handleAdPodComplete();
7283
7345
  return [
7284
7346
  3,
7285
7347
  4
@@ -7510,7 +7572,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7510
7572
  key: "playSingleAd",
7511
7573
  value: function playSingleAd(vastTagUrl) {
7512
7574
  return _async_to_generator(function() {
7513
- var requestToken, currentMuted, currentVolume, adVolume, playError, preloadedFallback, currentMuted1, currentVolume1, adVolume1, fallbackError, error, errorMessage, preloadedFallback1, currentMuted2, currentVolume2, adVolume2, fallbackError1;
7575
+ var requestToken, playError, preloadedFallback, fallbackError, error, errorMessage, preloadedFallback1, fallbackError1;
7514
7576
  return _ts_generator(this, function(_state) {
7515
7577
  switch(_state.label){
7516
7578
  case 0:
@@ -7597,10 +7659,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7597
7659
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7598
7660
  this.scheduleAdStopAtBreakBoundary();
7599
7661
  }
7600
- currentMuted = this.video.muted;
7601
- currentVolume = this.video.volume;
7602
- adVolume = currentMuted ? 0 : currentVolume;
7603
- this.ima.setAdVolume(adVolume);
7662
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
7604
7663
  this.consecutiveFailures = 0;
7605
7664
  this.temporaryFailureUrls.delete(vastTagUrl);
7606
7665
  return [
@@ -7647,10 +7706,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7647
7706
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7648
7707
  this.scheduleAdStopAtBreakBoundary();
7649
7708
  }
7650
- currentMuted1 = this.video.muted;
7651
- currentVolume1 = this.video.volume;
7652
- adVolume1 = currentMuted1 ? 0 : currentVolume1;
7653
- this.ima.setAdVolume(adVolume1);
7709
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
7654
7710
  return [
7655
7711
  2
7656
7712
  ];
@@ -7724,10 +7780,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7724
7780
  ];
7725
7781
  case 14:
7726
7782
  _state.sent();
7727
- currentMuted2 = this.video.muted;
7728
- currentVolume2 = this.video.volume;
7729
- adVolume2 = currentMuted2 ? 0 : currentVolume2;
7730
- this.ima.setAdVolume(adVolume2);
7783
+ this.ima.setAdVolume(this.getPreAdBreakAdVolume());
7731
7784
  return [
7732
7785
  2
7733
7786
  ];
@@ -7767,6 +7820,33 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7767
7820
  }).call(this);
7768
7821
  }
7769
7822
  },
7823
+ {
7824
+ key: "capturePreAdBreakAudio",
7825
+ value: function capturePreAdBreakAudio() {
7826
+ if (this.preAdBreakAudio) {
7827
+ return;
7828
+ }
7829
+ var captured = {
7830
+ muted: this.video.muted,
7831
+ volume: typeof this.video.volume === "number" && !Number.isNaN(this.video.volume) ? Math.max(0, Math.min(1, this.video.volume)) : 1
7832
+ };
7833
+ this.preAdBreakAudio = captured;
7834
+ this.ima.updateOriginalMutedState(captured.muted, captured.volume);
7835
+ if (this.config.debugAdTiming) {
7836
+ console.log("[StormcloudVideoPlayer] Captured pre-ad-break audio state: muted=".concat(captured.muted, ", volume=").concat(captured.volume));
7837
+ }
7838
+ }
7839
+ },
7840
+ {
7841
+ key: "getPreAdBreakAdVolume",
7842
+ value: function getPreAdBreakAdVolume() {
7843
+ var state = this.preAdBreakAudio;
7844
+ if (state) {
7845
+ return state.muted ? 0 : state.volume;
7846
+ }
7847
+ return this.ima.getOriginalMutedState() ? 0 : this.ima.getOriginalVolume();
7848
+ }
7849
+ },
7770
7850
  {
7771
7851
  key: "handleAdPodComplete",
7772
7852
  value: function handleAdPodComplete() {
@@ -7800,14 +7880,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7800
7880
  this.consecutiveFailures = 0;
7801
7881
  this.globalConsecutiveNoFills = 0;
7802
7882
  this.ima.stop().catch(function() {});
7803
- var restoredMuted = this.ima.getOriginalMutedState();
7804
- var restoredVolume = this.ima.getOriginalVolume();
7883
+ var restoredMuted = this.preAdBreakAudio ? this.preAdBreakAudio.muted : this.ima.getOriginalMutedState();
7884
+ var restoredVolume = this.preAdBreakAudio ? this.preAdBreakAudio.volume : this.ima.getOriginalVolume();
7885
+ this.ima.updateOriginalMutedState(restoredMuted, restoredVolume);
7805
7886
  if (this.video.muted !== restoredMuted) {
7806
7887
  this.video.muted = restoredMuted;
7807
7888
  }
7808
7889
  if (Math.abs(this.video.volume - restoredVolume) > 0.01) {
7809
7890
  this.video.volume = restoredVolume;
7810
7891
  }
7892
+ this.preAdBreakAudio = void 0;
7893
+ if (this.config.debugAdTiming) {
7894
+ console.log("[StormcloudVideoPlayer] Restored post-ad-break audio state: muted=".concat(restoredMuted, ", volume=").concat(restoredVolume));
7895
+ }
7811
7896
  if (this.shouldContinueLiveStreamDuringAds()) {
7812
7897
  if (this.video.paused) {
7813
7898
  var _this_video_play;
@@ -8217,6 +8302,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8217
8302
  this.clearAdFailsafeTimer();
8218
8303
  this.clearAdRequestWatchdog();
8219
8304
  this.clearPendingAdBreak();
8305
+ this.preAdBreakAudio = void 0;
8220
8306
  if (this.placeholderContainer) {
8221
8307
  if (this.placeholderContainer.parentElement) {
8222
8308
  this.placeholderContainer.parentElement.removeChild(this.placeholderContainer);