stormcloud-video-player 0.8.46 → 0.8.47

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.
@@ -351,15 +351,19 @@ module.exports = __toCommonJS(StormcloudVideoPlayer_exports);
351
351
  var import_hls = __toESM(require("hls.js"), 1);
352
352
  var MAX_VAST_WRAPPER_DEPTH = 5;
353
353
  function createHlsAdPlayer(contentVideo, options) {
354
+ var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
354
355
  var adPlaying = false;
355
356
  var originalMutedState = false;
356
357
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
357
358
  var listeners = /* @__PURE__ */ new Map();
358
359
  var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
359
360
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
360
- var adVideoElement;
361
+ var AD_CONTAINER_PROP = "__stormcloudAdContainer";
362
+ var AD_VIDEO_PROP = "__stormcloudAdVideo";
363
+ var adVideoElement = (_contentVideo_AD_VIDEO_PROP = contentVideo[AD_VIDEO_PROP]) !== null && _contentVideo_AD_VIDEO_PROP !== void 0 ? _contentVideo_AD_VIDEO_PROP : void 0;
361
364
  var adHls;
362
- var adContainerEl;
365
+ var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
366
+ var adEventHandlers = [];
363
367
  var currentAd;
364
368
  var podAds = [];
365
369
  var podIndex = 0;
@@ -1003,7 +1007,8 @@ function createHlsAdPlayer(contentVideo, options) {
1003
1007
  }
1004
1008
  function setupAdEventListeners() {
1005
1009
  if (!adVideoElement || !currentAd) return;
1006
- adVideoElement.addEventListener("timeupdate", function() {
1010
+ if (adEventHandlers.length > 0) return;
1011
+ var onTimeUpdate = function onTimeUpdate() {
1007
1012
  if (!currentAd || !adVideoElement) return;
1008
1013
  noteAdProgress();
1009
1014
  var progress = adVideoElement.currentTime / currentAd.duration;
@@ -1019,15 +1024,15 @@ function createHlsAdPlayer(contentVideo, options) {
1019
1024
  trackingFired.thirdQuartile = true;
1020
1025
  fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
1021
1026
  }
1022
- });
1023
- adVideoElement.addEventListener("playing", function() {
1027
+ };
1028
+ var onPlaying = function onPlaying() {
1024
1029
  startStallWatchdog();
1025
1030
  if (!currentAd || trackingFired.start) return;
1026
1031
  trackingFired.start = true;
1027
1032
  fireTrackingPixels(currentAd.trackingUrls.start);
1028
1033
  console.log("[HlsAdPlayer] Ad started playing");
1029
- });
1030
- adVideoElement.addEventListener("ended", function() {
1034
+ };
1035
+ var onEnded = function onEnded() {
1031
1036
  if (!currentAd || trackingFired.complete) return;
1032
1037
  trackingFired.complete = true;
1033
1038
  fireTrackingPixels(currentAd.trackingUrls.complete);
@@ -1036,8 +1041,8 @@ function createHlsAdPlayer(contentVideo, options) {
1036
1041
  return;
1037
1042
  }
1038
1043
  handleAdComplete();
1039
- });
1040
- adVideoElement.addEventListener("error", function(e) {
1044
+ };
1045
+ var onError = function onError(e) {
1041
1046
  if (!adPlaying) return;
1042
1047
  console.error("[HlsAdPlayer] Ad video error:", e);
1043
1048
  if (currentAd) {
@@ -1047,25 +1052,100 @@ function createHlsAdPlayer(contentVideo, options) {
1047
1052
  return;
1048
1053
  }
1049
1054
  handleAdError();
1050
- });
1051
- adVideoElement.addEventListener("volumechange", function() {
1052
- if (!currentAd) return;
1055
+ };
1056
+ var onVolumeChange = function onVolumeChange() {
1057
+ if (!currentAd || !adVideoElement) return;
1053
1058
  if (adVideoElement.muted) {
1054
1059
  fireTrackingPixels(currentAd.trackingUrls.mute);
1055
1060
  } else {
1056
1061
  fireTrackingPixels(currentAd.trackingUrls.unmute);
1057
1062
  }
1058
- });
1059
- adVideoElement.addEventListener("pause", function() {
1060
- if (currentAd && !adVideoElement.ended) {
1063
+ };
1064
+ var onPause = function onPause() {
1065
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1061
1066
  fireTrackingPixels(currentAd.trackingUrls.pause);
1062
1067
  }
1063
- });
1064
- adVideoElement.addEventListener("play", function() {
1065
- if (currentAd && adVideoElement.currentTime > 0) {
1068
+ };
1069
+ var onPlay = function onPlay() {
1070
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1066
1071
  fireTrackingPixels(currentAd.trackingUrls.resume);
1067
1072
  }
1068
- });
1073
+ };
1074
+ adEventHandlers = [
1075
+ {
1076
+ type: "timeupdate",
1077
+ handler: onTimeUpdate
1078
+ },
1079
+ {
1080
+ type: "playing",
1081
+ handler: onPlaying
1082
+ },
1083
+ {
1084
+ type: "ended",
1085
+ handler: onEnded
1086
+ },
1087
+ {
1088
+ type: "error",
1089
+ handler: onError
1090
+ },
1091
+ {
1092
+ type: "volumechange",
1093
+ handler: onVolumeChange
1094
+ },
1095
+ {
1096
+ type: "pause",
1097
+ handler: onPause
1098
+ },
1099
+ {
1100
+ type: "play",
1101
+ handler: onPlay
1102
+ }
1103
+ ];
1104
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1105
+ try {
1106
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1107
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1108
+ adVideoElement.addEventListener(type, handler);
1109
+ }
1110
+ } catch (err) {
1111
+ _didIteratorError = true;
1112
+ _iteratorError = err;
1113
+ } finally{
1114
+ try {
1115
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1116
+ _iterator.return();
1117
+ }
1118
+ } finally{
1119
+ if (_didIteratorError) {
1120
+ throw _iteratorError;
1121
+ }
1122
+ }
1123
+ }
1124
+ }
1125
+ function teardownAdEventListeners() {
1126
+ if (adVideoElement) {
1127
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1128
+ try {
1129
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1130
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1131
+ adVideoElement.removeEventListener(type, handler);
1132
+ }
1133
+ } catch (err) {
1134
+ _didIteratorError = true;
1135
+ _iteratorError = err;
1136
+ } finally{
1137
+ try {
1138
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1139
+ _iterator.return();
1140
+ }
1141
+ } finally{
1142
+ if (_didIteratorError) {
1143
+ throw _iteratorError;
1144
+ }
1145
+ }
1146
+ }
1147
+ }
1148
+ adEventHandlers = [];
1069
1149
  }
1070
1150
  function setAdPlayingFlag(isPlaying) {
1071
1151
  if (isPlaying) {
@@ -1211,15 +1291,13 @@ function createHlsAdPlayer(contentVideo, options) {
1211
1291
  adHls = void 0;
1212
1292
  }
1213
1293
  if (adVideoElement) {
1214
- adVideoElement.pause();
1215
- adVideoElement.removeAttribute("src");
1216
1294
  try {
1295
+ adVideoElement.pause();
1296
+ adVideoElement.removeAttribute("src");
1217
1297
  adVideoElement.load();
1218
1298
  } catch (error) {
1219
- console.warn("[HlsAdPlayer] adVideoElement.load() threw after src removal:", error);
1299
+ console.warn("[HlsAdPlayer] Error releasing ad decoder:", error);
1220
1300
  }
1221
- adVideoElement.remove();
1222
- adVideoElement = void 0;
1223
1301
  }
1224
1302
  if (adContainerEl) {
1225
1303
  adContainerEl.style.display = "none";
@@ -1282,6 +1360,7 @@ function createHlsAdPlayer(contentVideo, options) {
1282
1360
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1283
1361
  adContainerEl = container;
1284
1362
  }
1363
+ contentVideo[AD_CONTAINER_PROP] = adContainerEl;
1285
1364
  },
1286
1365
  requestAds: function requestAds(vastTagUrl) {
1287
1366
  return _async_to_generator(function() {
@@ -1384,8 +1463,9 @@ function createHlsAdPlayer(contentVideo, options) {
1384
1463
  if (!adVideoElement) {
1385
1464
  adVideoElement = createAdVideoElement();
1386
1465
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1387
- setupAdEventListeners();
1466
+ contentVideo[AD_VIDEO_PROP] = adVideoElement;
1388
1467
  }
1468
+ setupAdEventListeners();
1389
1469
  resetQuartileTracking(true);
1390
1470
  contentVolume = contentVideo.volume;
1391
1471
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
@@ -1513,11 +1593,8 @@ function createHlsAdPlayer(contentVideo, options) {
1513
1593
  setAdPlayingFlag(false);
1514
1594
  contentVideo.muted = originalMutedState;
1515
1595
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
1596
+ teardownAdEventListeners();
1516
1597
  releaseAdDecoder();
1517
- if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
1518
- adContainerEl.parentElement.removeChild(adContainerEl);
1519
- }
1520
- adContainerEl = void 0;
1521
1598
  currentAd = void 0;
1522
1599
  podAds = [];
1523
1600
  podIndex = 0;
@@ -3930,6 +4007,11 @@ function detectBrowser() {
3930
4007
  chromeVersion: chromeVersionNum
3931
4008
  };
3932
4009
  }
4010
+ function requiresMediaPipelineResetAfterAds() {
4011
+ var _browser_tizenVersion;
4012
+ var browser = detectBrowser();
4013
+ return browser.name === "Samsung Tizen" && ((_browser_tizenVersion = browser.tizenVersion) !== null && _browser_tizenVersion !== void 0 ? _browser_tizenVersion : 0) >= 5;
4014
+ }
3933
4015
  function getBrowserConfigOverrides() {
3934
4016
  var browser = detectBrowser();
3935
4017
  var overrides = {};
@@ -6691,30 +6773,49 @@ var HlsEngine = /*#__PURE__*/ function() {
6691
6773
  {
6692
6774
  key: "reloadLiveStream",
6693
6775
  value: function reloadLiveStream() {
6776
+ var _this = this;
6694
6777
  var hls = this.hls;
6695
6778
  if (!hls) {
6696
6779
  return;
6697
6780
  }
6698
6781
  if (this.debug) {
6699
- console.log("[StormcloudVideoPlayer] Hard-reloading live stream (detach \u2192 reset video \u2192 re-attach)");
6782
+ console.log("[StormcloudVideoPlayer] Hard-reloading live stream (destroy hls \u2192 reset video \u2192 fresh setupHls)");
6700
6783
  }
6701
6784
  try {
6702
6785
  this.reloadingLiveStream = true;
6703
6786
  hls.stopLoad();
6704
6787
  hls.detachMedia();
6788
+ hls.destroy();
6789
+ this.hls = void 0;
6705
6790
  try {
6706
6791
  this.video.removeAttribute("src");
6707
6792
  this.video.load();
6708
6793
  } catch (error) {
6709
6794
  console.warn("[StormcloudVideoPlayer] video.load() threw after src removal:", error);
6710
6795
  }
6711
- hls.attachMedia(this.video);
6712
6796
  } catch (error) {
6713
6797
  this.reloadingLiveStream = false;
6798
+ this.hls = void 0;
6714
6799
  if (this.debug) {
6715
- console.warn("[StormcloudVideoPlayer] Failed to hard-reload live stream:", error);
6800
+ console.warn("[StormcloudVideoPlayer] Failed to tear down during hard-reload:", error);
6716
6801
  }
6802
+ return;
6717
6803
  }
6804
+ var recreateDelayMs = 600;
6805
+ window.setTimeout(function() {
6806
+ if (_this.hls) {
6807
+ _this.reloadingLiveStream = false;
6808
+ return;
6809
+ }
6810
+ try {
6811
+ _this.setupHls();
6812
+ } catch (error) {
6813
+ _this.reloadingLiveStream = false;
6814
+ if (_this.debug) {
6815
+ console.warn("[StormcloudVideoPlayer] Failed to rebuild pipeline during hard-reload:", error);
6816
+ }
6817
+ }
6818
+ }, recreateDelayMs);
6718
6819
  }
6719
6820
  },
6720
6821
  {
@@ -8027,6 +8128,14 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8027
8128
  this.host.video.style.visibility = "visible";
8028
8129
  this.host.video.style.opacity = "1";
8029
8130
  if (this.host.isLiveStream()) {
8131
+ if (this.host.requiresMediaPipelineResetAfterAds()) {
8132
+ if (this.debug) {
8133
+ console.log("[StormcloudVideoPlayer] Live break end \u2014 hard-reloading stream to reacquire decoder (single-decoder platform)");
8134
+ }
8135
+ this.host.reloadLiveStream();
8136
+ this.monitorLiveResumeStall(this.host.video.currentTime);
8137
+ return;
8138
+ }
8030
8139
  var liveSyncPos = this.host.getLiveSyncPosition();
8031
8140
  if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8032
8141
  if (this.debug) {
@@ -8088,9 +8197,10 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8088
8197
  key: "monitorLiveResumeStall",
8089
8198
  value: function monitorLiveResumeStall(resumeBaseline) {
8090
8199
  var _this = this;
8200
+ var needsReset = this.host.requiresMediaPipelineResetAfterAds();
8091
8201
  var pollIntervalMs = 1e3;
8092
- var graceMs = 5e3;
8093
- var recoveryCooldownMs = 5e3;
8202
+ var graceMs = needsReset ? 8e3 : 5e3;
8203
+ var recoveryCooldownMs = needsReset ? 7e3 : 5e3;
8094
8204
  var maxRecoveries = 3;
8095
8205
  var maxMonitorMs = 45e3;
8096
8206
  var startTime = Date.now();
@@ -8204,7 +8314,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8204
8314
  if (canRecover) {
8205
8315
  recoveries++;
8206
8316
  lastRecoveryAt = Date.now();
8207
- if (recoveries === 1) {
8317
+ if (needsReset) {
8318
+ if (_this.debug) {
8319
+ console.warn("[StormcloudVideoPlayer] Content still wedged after ad break — hard-reloading live stream (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8320
+ }
8321
+ _this.host.reloadLiveStream();
8322
+ } else if (recoveries === 1) {
8208
8323
  if (_this.debug) {
8209
8324
  console.warn("[StormcloudVideoPlayer] Content wedged after ad break — calling recoverMediaError() (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8210
8325
  }
@@ -8417,6 +8532,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8417
8532
  recoverMediaError: function recoverMediaError() {
8418
8533
  return _this.hlsEngine.recoverMediaError();
8419
8534
  },
8535
+ requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
8536
+ return requiresMediaPipelineResetAfterAds();
8537
+ },
8420
8538
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8421
8539
  return _this.generatePodVastUrl(base, breakDurationMs);
8422
8540
  }