stormcloud-video-player 0.8.45 → 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.
@@ -438,15 +438,19 @@ var import_react2 = require("react");
438
438
  var import_hls = __toESM(require("hls.js"), 1);
439
439
  var MAX_VAST_WRAPPER_DEPTH = 5;
440
440
  function createHlsAdPlayer(contentVideo, options) {
441
+ var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
441
442
  var adPlaying = false;
442
443
  var originalMutedState = false;
443
444
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
444
445
  var listeners = /* @__PURE__ */ new Map();
445
446
  var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
446
447
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
447
- var adVideoElement;
448
+ var AD_CONTAINER_PROP = "__stormcloudAdContainer";
449
+ var AD_VIDEO_PROP = "__stormcloudAdVideo";
450
+ var adVideoElement = (_contentVideo_AD_VIDEO_PROP = contentVideo[AD_VIDEO_PROP]) !== null && _contentVideo_AD_VIDEO_PROP !== void 0 ? _contentVideo_AD_VIDEO_PROP : void 0;
448
451
  var adHls;
449
- var adContainerEl;
452
+ var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
453
+ var adEventHandlers = [];
450
454
  var currentAd;
451
455
  var podAds = [];
452
456
  var podIndex = 0;
@@ -1090,7 +1094,8 @@ function createHlsAdPlayer(contentVideo, options) {
1090
1094
  }
1091
1095
  function setupAdEventListeners() {
1092
1096
  if (!adVideoElement || !currentAd) return;
1093
- adVideoElement.addEventListener("timeupdate", function() {
1097
+ if (adEventHandlers.length > 0) return;
1098
+ var onTimeUpdate = function onTimeUpdate() {
1094
1099
  if (!currentAd || !adVideoElement) return;
1095
1100
  noteAdProgress();
1096
1101
  var progress = adVideoElement.currentTime / currentAd.duration;
@@ -1106,15 +1111,15 @@ function createHlsAdPlayer(contentVideo, options) {
1106
1111
  trackingFired.thirdQuartile = true;
1107
1112
  fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
1108
1113
  }
1109
- });
1110
- adVideoElement.addEventListener("playing", function() {
1114
+ };
1115
+ var onPlaying = function onPlaying() {
1111
1116
  startStallWatchdog();
1112
1117
  if (!currentAd || trackingFired.start) return;
1113
1118
  trackingFired.start = true;
1114
1119
  fireTrackingPixels(currentAd.trackingUrls.start);
1115
1120
  console.log("[HlsAdPlayer] Ad started playing");
1116
- });
1117
- adVideoElement.addEventListener("ended", function() {
1121
+ };
1122
+ var onEnded = function onEnded() {
1118
1123
  if (!currentAd || trackingFired.complete) return;
1119
1124
  trackingFired.complete = true;
1120
1125
  fireTrackingPixels(currentAd.trackingUrls.complete);
@@ -1123,8 +1128,8 @@ function createHlsAdPlayer(contentVideo, options) {
1123
1128
  return;
1124
1129
  }
1125
1130
  handleAdComplete();
1126
- });
1127
- adVideoElement.addEventListener("error", function(e) {
1131
+ };
1132
+ var onError = function onError(e) {
1128
1133
  if (!adPlaying) return;
1129
1134
  console.error("[HlsAdPlayer] Ad video error:", e);
1130
1135
  if (currentAd) {
@@ -1134,25 +1139,100 @@ function createHlsAdPlayer(contentVideo, options) {
1134
1139
  return;
1135
1140
  }
1136
1141
  handleAdError();
1137
- });
1138
- adVideoElement.addEventListener("volumechange", function() {
1139
- if (!currentAd) return;
1142
+ };
1143
+ var onVolumeChange = function onVolumeChange() {
1144
+ if (!currentAd || !adVideoElement) return;
1140
1145
  if (adVideoElement.muted) {
1141
1146
  fireTrackingPixels(currentAd.trackingUrls.mute);
1142
1147
  } else {
1143
1148
  fireTrackingPixels(currentAd.trackingUrls.unmute);
1144
1149
  }
1145
- });
1146
- adVideoElement.addEventListener("pause", function() {
1147
- if (currentAd && !adVideoElement.ended) {
1150
+ };
1151
+ var onPause = function onPause() {
1152
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1148
1153
  fireTrackingPixels(currentAd.trackingUrls.pause);
1149
1154
  }
1150
- });
1151
- adVideoElement.addEventListener("play", function() {
1152
- if (currentAd && adVideoElement.currentTime > 0) {
1155
+ };
1156
+ var onPlay = function onPlay() {
1157
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1153
1158
  fireTrackingPixels(currentAd.trackingUrls.resume);
1154
1159
  }
1155
- });
1160
+ };
1161
+ adEventHandlers = [
1162
+ {
1163
+ type: "timeupdate",
1164
+ handler: onTimeUpdate
1165
+ },
1166
+ {
1167
+ type: "playing",
1168
+ handler: onPlaying
1169
+ },
1170
+ {
1171
+ type: "ended",
1172
+ handler: onEnded
1173
+ },
1174
+ {
1175
+ type: "error",
1176
+ handler: onError
1177
+ },
1178
+ {
1179
+ type: "volumechange",
1180
+ handler: onVolumeChange
1181
+ },
1182
+ {
1183
+ type: "pause",
1184
+ handler: onPause
1185
+ },
1186
+ {
1187
+ type: "play",
1188
+ handler: onPlay
1189
+ }
1190
+ ];
1191
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1192
+ try {
1193
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1194
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1195
+ adVideoElement.addEventListener(type, handler);
1196
+ }
1197
+ } catch (err) {
1198
+ _didIteratorError = true;
1199
+ _iteratorError = err;
1200
+ } finally{
1201
+ try {
1202
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1203
+ _iterator.return();
1204
+ }
1205
+ } finally{
1206
+ if (_didIteratorError) {
1207
+ throw _iteratorError;
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ function teardownAdEventListeners() {
1213
+ if (adVideoElement) {
1214
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1215
+ try {
1216
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1217
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1218
+ adVideoElement.removeEventListener(type, handler);
1219
+ }
1220
+ } catch (err) {
1221
+ _didIteratorError = true;
1222
+ _iteratorError = err;
1223
+ } finally{
1224
+ try {
1225
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1226
+ _iterator.return();
1227
+ }
1228
+ } finally{
1229
+ if (_didIteratorError) {
1230
+ throw _iteratorError;
1231
+ }
1232
+ }
1233
+ }
1234
+ }
1235
+ adEventHandlers = [];
1156
1236
  }
1157
1237
  function setAdPlayingFlag(isPlaying) {
1158
1238
  if (isPlaying) {
@@ -1292,16 +1372,32 @@ function createHlsAdPlayer(contentVideo, options) {
1292
1372
  }
1293
1373
  }, STALL_CHECK_INTERVAL_MS);
1294
1374
  }
1375
+ function releaseAdDecoder() {
1376
+ if (adHls) {
1377
+ adHls.destroy();
1378
+ adHls = void 0;
1379
+ }
1380
+ if (adVideoElement) {
1381
+ try {
1382
+ adVideoElement.pause();
1383
+ adVideoElement.removeAttribute("src");
1384
+ adVideoElement.load();
1385
+ } catch (error) {
1386
+ console.warn("[HlsAdPlayer] Error releasing ad decoder:", error);
1387
+ }
1388
+ }
1389
+ if (adContainerEl) {
1390
+ adContainerEl.style.display = "none";
1391
+ adContainerEl.style.pointerEvents = "none";
1392
+ }
1393
+ }
1295
1394
  function handleAdComplete() {
1296
1395
  console.log("[HlsAdPlayer] Handling ad completion");
1297
1396
  clearStallWatchdog();
1298
1397
  adPlaying = false;
1299
1398
  setAdPlayingFlag(false);
1300
1399
  contentVideo.muted = true;
1301
- if (adContainerEl) {
1302
- adContainerEl.style.display = "none";
1303
- adContainerEl.style.pointerEvents = "none";
1304
- }
1400
+ releaseAdDecoder();
1305
1401
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
1306
1402
  contentVideo.style.visibility = "visible";
1307
1403
  contentVideo.style.opacity = "1";
@@ -1324,10 +1420,7 @@ function createHlsAdPlayer(contentVideo, options) {
1324
1420
  adPlaying = false;
1325
1421
  setAdPlayingFlag(false);
1326
1422
  contentVideo.muted = true;
1327
- if (adContainerEl) {
1328
- adContainerEl.style.display = "none";
1329
- adContainerEl.style.pointerEvents = "none";
1330
- }
1423
+ releaseAdDecoder();
1331
1424
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
1332
1425
  contentVideo.style.visibility = "visible";
1333
1426
  contentVideo.style.opacity = "1";
@@ -1354,6 +1447,7 @@ function createHlsAdPlayer(contentVideo, options) {
1354
1447
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1355
1448
  adContainerEl = container;
1356
1449
  }
1450
+ contentVideo[AD_CONTAINER_PROP] = adContainerEl;
1357
1451
  },
1358
1452
  requestAds: function requestAds(vastTagUrl) {
1359
1453
  return _async_to_generator(function() {
@@ -1456,8 +1550,9 @@ function createHlsAdPlayer(contentVideo, options) {
1456
1550
  if (!adVideoElement) {
1457
1551
  adVideoElement = createAdVideoElement();
1458
1552
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1459
- setupAdEventListeners();
1553
+ contentVideo[AD_VIDEO_PROP] = adVideoElement;
1460
1554
  }
1555
+ setupAdEventListeners();
1461
1556
  resetQuartileTracking(true);
1462
1557
  contentVolume = contentVideo.volume;
1463
1558
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
@@ -1536,10 +1631,7 @@ function createHlsAdPlayer(contentVideo, options) {
1536
1631
  contentVideo.muted = originalMutedState;
1537
1632
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
1538
1633
  console.log("[HlsAdPlayer] Restored mute state on stop: ".concat(previousMutedState, " -> ").concat(originalMutedState, ", volume: ").concat(contentVideo.volume));
1539
- if (adContainerEl) {
1540
- adContainerEl.style.display = "none";
1541
- adContainerEl.style.pointerEvents = "none";
1542
- }
1634
+ releaseAdDecoder();
1543
1635
  contentVideo.style.visibility = "visible";
1544
1636
  contentVideo.style.opacity = "1";
1545
1637
  if (options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) {
@@ -1550,17 +1642,6 @@ function createHlsAdPlayer(contentVideo, options) {
1550
1642
  });
1551
1643
  }
1552
1644
  }
1553
- if (adHls) {
1554
- adHls.destroy();
1555
- adHls = void 0;
1556
- }
1557
- if (adVideoElement) {
1558
- adVideoElement.pause();
1559
- adVideoElement.removeAttribute("src");
1560
- try {
1561
- adVideoElement.load();
1562
- } catch (unused) {}
1563
- }
1564
1645
  currentAd = void 0;
1565
1646
  podAds = [];
1566
1647
  podIndex = 0;
@@ -1599,23 +1680,8 @@ function createHlsAdPlayer(contentVideo, options) {
1599
1680
  setAdPlayingFlag(false);
1600
1681
  contentVideo.muted = originalMutedState;
1601
1682
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
1602
- if (adHls) {
1603
- adHls.destroy();
1604
- adHls = void 0;
1605
- }
1606
- if (adVideoElement) {
1607
- adVideoElement.pause();
1608
- adVideoElement.removeAttribute("src");
1609
- try {
1610
- adVideoElement.load();
1611
- } catch (unused) {}
1612
- adVideoElement.remove();
1613
- adVideoElement = void 0;
1614
- }
1615
- if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
1616
- adContainerEl.parentElement.removeChild(adContainerEl);
1617
- }
1618
- adContainerEl = void 0;
1683
+ teardownAdEventListeners();
1684
+ releaseAdDecoder();
1619
1685
  currentAd = void 0;
1620
1686
  podAds = [];
1621
1687
  podIndex = 0;
@@ -4028,6 +4094,11 @@ function detectBrowser() {
4028
4094
  chromeVersion: chromeVersionNum
4029
4095
  };
4030
4096
  }
4097
+ function requiresMediaPipelineResetAfterAds() {
4098
+ var _browser_tizenVersion;
4099
+ var browser = detectBrowser();
4100
+ return browser.name === "Samsung Tizen" && ((_browser_tizenVersion = browser.tizenVersion) !== null && _browser_tizenVersion !== void 0 ? _browser_tizenVersion : 0) >= 5;
4101
+ }
4031
4102
  function getBrowserConfigOverrides() {
4032
4103
  var browser = detectBrowser();
4033
4104
  var overrides = {};
@@ -6771,31 +6842,67 @@ var HlsEngine = /*#__PURE__*/ function() {
6771
6842
  }
6772
6843
  }
6773
6844
  },
6845
+ {
6846
+ key: "recoverMediaError",
6847
+ value: function recoverMediaError() {
6848
+ if (!this.hls) {
6849
+ return;
6850
+ }
6851
+ try {
6852
+ this.hls.recoverMediaError();
6853
+ } catch (error) {
6854
+ if (this.debug) {
6855
+ console.warn("[StormcloudVideoPlayer] recoverMediaError() failed:", error);
6856
+ }
6857
+ }
6858
+ }
6859
+ },
6774
6860
  {
6775
6861
  key: "reloadLiveStream",
6776
6862
  value: function reloadLiveStream() {
6863
+ var _this = this;
6777
6864
  var hls = this.hls;
6778
6865
  if (!hls) {
6779
6866
  return;
6780
6867
  }
6781
6868
  if (this.debug) {
6782
- console.log("[StormcloudVideoPlayer] Hard-reloading live stream (detach \u2192 reset video \u2192 re-attach)");
6869
+ console.log("[StormcloudVideoPlayer] Hard-reloading live stream (destroy hls \u2192 reset video \u2192 fresh setupHls)");
6783
6870
  }
6784
6871
  try {
6785
6872
  this.reloadingLiveStream = true;
6786
6873
  hls.stopLoad();
6787
6874
  hls.detachMedia();
6875
+ hls.destroy();
6876
+ this.hls = void 0;
6788
6877
  try {
6789
6878
  this.video.removeAttribute("src");
6790
6879
  this.video.load();
6791
- } catch (unused) {}
6792
- hls.attachMedia(this.video);
6880
+ } catch (error) {
6881
+ console.warn("[StormcloudVideoPlayer] video.load() threw after src removal:", error);
6882
+ }
6793
6883
  } catch (error) {
6794
6884
  this.reloadingLiveStream = false;
6885
+ this.hls = void 0;
6795
6886
  if (this.debug) {
6796
- console.warn("[StormcloudVideoPlayer] Failed to hard-reload live stream:", error);
6887
+ console.warn("[StormcloudVideoPlayer] Failed to tear down during hard-reload:", error);
6797
6888
  }
6889
+ return;
6798
6890
  }
6891
+ var recreateDelayMs = 600;
6892
+ window.setTimeout(function() {
6893
+ if (_this.hls) {
6894
+ _this.reloadingLiveStream = false;
6895
+ return;
6896
+ }
6897
+ try {
6898
+ _this.setupHls();
6899
+ } catch (error) {
6900
+ _this.reloadingLiveStream = false;
6901
+ if (_this.debug) {
6902
+ console.warn("[StormcloudVideoPlayer] Failed to rebuild pipeline during hard-reload:", error);
6903
+ }
6904
+ }
6905
+ }, recreateDelayMs);
6799
6906
  }
6800
6907
  },
6801
6908
  {
@@ -8108,6 +8215,14 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8108
8215
  this.host.video.style.visibility = "visible";
8109
8216
  this.host.video.style.opacity = "1";
8110
8217
  if (this.host.isLiveStream()) {
8218
+ if (this.host.requiresMediaPipelineResetAfterAds()) {
8219
+ if (this.debug) {
8220
+ console.log("[StormcloudVideoPlayer] Live break end \u2014 hard-reloading stream to reacquire decoder (single-decoder platform)");
8221
+ }
8222
+ this.host.reloadLiveStream();
8223
+ this.monitorLiveResumeStall(this.host.video.currentTime);
8224
+ return;
8225
+ }
8111
8226
  var liveSyncPos = this.host.getLiveSyncPosition();
8112
8227
  if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8113
8228
  if (this.debug) {
@@ -8169,11 +8284,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8169
8284
  key: "monitorLiveResumeStall",
8170
8285
  value: function monitorLiveResumeStall(resumeBaseline) {
8171
8286
  var _this = this;
8287
+ var needsReset = this.host.requiresMediaPipelineResetAfterAds();
8172
8288
  var pollIntervalMs = 1e3;
8173
- var graceMs = 5e3;
8174
- var recoveryCooldownMs = 5e3;
8175
- var maxRecoveries = 2;
8176
- var maxMonitorMs = 3e4;
8289
+ var graceMs = needsReset ? 8e3 : 5e3;
8290
+ var recoveryCooldownMs = needsReset ? 7e3 : 5e3;
8291
+ var maxRecoveries = 3;
8292
+ var maxMonitorMs = 45e3;
8177
8293
  var startTime = Date.now();
8178
8294
  var baseline = resumeBaseline;
8179
8295
  var recoveries = 0;
@@ -8285,8 +8401,17 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8285
8401
  if (canRecover) {
8286
8402
  recoveries++;
8287
8403
  lastRecoveryAt = Date.now();
8288
- var isFinalAttempt = recoveries >= maxRecoveries;
8289
- if (!isFinalAttempt) {
8404
+ if (needsReset) {
8405
+ if (_this.debug) {
8406
+ console.warn("[StormcloudVideoPlayer] Content still wedged after ad break — hard-reloading live stream (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8407
+ }
8408
+ _this.host.reloadLiveStream();
8409
+ } else if (recoveries === 1) {
8410
+ if (_this.debug) {
8411
+ console.warn("[StormcloudVideoPlayer] Content wedged after ad break — calling recoverMediaError() (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8412
+ }
8413
+ _this.host.recoverMediaError();
8414
+ } else if (recoveries === 2) {
8290
8415
  var liveSyncPos = _this.host.getLiveSyncPosition();
8291
8416
  var reloadPos = liveSyncPos != null && liveSyncPos > currentTime ? liveSyncPos : currentTime;
8292
8417
  if (_this.debug) {
@@ -8318,17 +8443,41 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8318
8443
  value: function resumeContentPlayback() {
8319
8444
  var _this = this;
8320
8445
  var attempt = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 0;
8321
- var maxAttempts = 3;
8322
- if (!this.host.video.paused) {
8446
+ var maxAttempts = 5;
8447
+ var video = this.host.video;
8448
+ if (!video.paused) {
8323
8449
  if (this.debug && attempt === 0) {
8324
8450
  console.log("[StormcloudVideoPlayer] Content video already playing after ads");
8325
8451
  }
8326
8452
  return;
8327
8453
  }
8328
8454
  if (this.debug) {
8329
- console.log("[StormcloudVideoPlayer] Resuming content playback after ads (attempt ".concat(attempt + 1, "/").concat(maxAttempts, ")"));
8455
+ console.log("[StormcloudVideoPlayer] Resuming content playback after ads (attempt ".concat(attempt + 1, "/").concat(maxAttempts, ", readyState=").concat(video.readyState, ")"));
8330
8456
  }
8331
- var playResult = this.host.video.play();
8457
+ if (video.readyState < 3) {
8458
+ if (attempt + 1 >= maxAttempts) {
8459
+ var _video_play;
8460
+ if (this.debug) {
8461
+ console.warn("[StormcloudVideoPlayer] readyState never reached HAVE_FUTURE_DATA, forcing play()");
8462
+ }
8463
+ (_video_play = video.play()) === null || _video_play === void 0 ? void 0 : _video_play.catch(function() {});
8464
+ return;
8465
+ }
8466
+ var onReady = function onReady1() {
8467
+ video.removeEventListener("canplay", onReady);
8468
+ _this.resumeContentPlayback(attempt + 1);
8469
+ };
8470
+ video.addEventListener("canplay", onReady);
8471
+ var backoffMs = 500 * (attempt + 1);
8472
+ window.setTimeout(function() {
8473
+ video.removeEventListener("canplay", onReady);
8474
+ if (video.paused) {
8475
+ _this.resumeContentPlayback(attempt + 1);
8476
+ }
8477
+ }, backoffMs);
8478
+ return;
8479
+ }
8480
+ var playResult = video.play();
8332
8481
  if (playResult && typeof playResult.catch === "function") {
8333
8482
  playResult.catch(function(error) {
8334
8483
  if (attempt + 1 >= maxAttempts) {
@@ -8467,6 +8616,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8467
8616
  reloadLiveStream: function reloadLiveStream() {
8468
8617
  return _this.hlsEngine.reloadLiveStream();
8469
8618
  },
8619
+ recoverMediaError: function recoverMediaError() {
8620
+ return _this.hlsEngine.recoverMediaError();
8621
+ },
8622
+ requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
8623
+ return requiresMediaPipelineResetAfterAds();
8624
+ },
8470
8625
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8471
8626
  return _this.generatePodVastUrl(base, breakDurationMs);
8472
8627
  }