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.
package/lib/index.cjs CHANGED
@@ -557,6 +557,9 @@ __export(index_exports, {
557
557
  randomString: function randomString1() {
558
558
  return randomString;
559
559
  },
560
+ requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
561
+ return requiresMediaPipelineResetAfterAds;
562
+ },
560
563
  sendAdDetectTracking: function sendAdDetectTracking1() {
561
564
  return sendAdDetectTracking;
562
565
  },
@@ -589,15 +592,19 @@ var import_react = __toESM(require("react"), 1);
589
592
  var import_hls = __toESM(require("hls.js"), 1);
590
593
  var MAX_VAST_WRAPPER_DEPTH = 5;
591
594
  function createHlsAdPlayer(contentVideo, options) {
595
+ var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
592
596
  var adPlaying = false;
593
597
  var originalMutedState = false;
594
598
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
595
599
  var listeners = /* @__PURE__ */ new Map();
596
600
  var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
597
601
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
598
- var adVideoElement;
602
+ var AD_CONTAINER_PROP = "__stormcloudAdContainer";
603
+ var AD_VIDEO_PROP = "__stormcloudAdVideo";
604
+ var adVideoElement = (_contentVideo_AD_VIDEO_PROP = contentVideo[AD_VIDEO_PROP]) !== null && _contentVideo_AD_VIDEO_PROP !== void 0 ? _contentVideo_AD_VIDEO_PROP : void 0;
599
605
  var adHls;
600
- var adContainerEl;
606
+ var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
607
+ var adEventHandlers = [];
601
608
  var currentAd;
602
609
  var podAds = [];
603
610
  var podIndex = 0;
@@ -1241,7 +1248,8 @@ function createHlsAdPlayer(contentVideo, options) {
1241
1248
  }
1242
1249
  function setupAdEventListeners() {
1243
1250
  if (!adVideoElement || !currentAd) return;
1244
- adVideoElement.addEventListener("timeupdate", function() {
1251
+ if (adEventHandlers.length > 0) return;
1252
+ var onTimeUpdate = function onTimeUpdate() {
1245
1253
  if (!currentAd || !adVideoElement) return;
1246
1254
  noteAdProgress();
1247
1255
  var progress = adVideoElement.currentTime / currentAd.duration;
@@ -1257,15 +1265,15 @@ function createHlsAdPlayer(contentVideo, options) {
1257
1265
  trackingFired.thirdQuartile = true;
1258
1266
  fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
1259
1267
  }
1260
- });
1261
- adVideoElement.addEventListener("playing", function() {
1268
+ };
1269
+ var onPlaying = function onPlaying() {
1262
1270
  startStallWatchdog();
1263
1271
  if (!currentAd || trackingFired.start) return;
1264
1272
  trackingFired.start = true;
1265
1273
  fireTrackingPixels(currentAd.trackingUrls.start);
1266
1274
  console.log("[HlsAdPlayer] Ad started playing");
1267
- });
1268
- adVideoElement.addEventListener("ended", function() {
1275
+ };
1276
+ var onEnded = function onEnded() {
1269
1277
  if (!currentAd || trackingFired.complete) return;
1270
1278
  trackingFired.complete = true;
1271
1279
  fireTrackingPixels(currentAd.trackingUrls.complete);
@@ -1274,8 +1282,8 @@ function createHlsAdPlayer(contentVideo, options) {
1274
1282
  return;
1275
1283
  }
1276
1284
  handleAdComplete();
1277
- });
1278
- adVideoElement.addEventListener("error", function(e) {
1285
+ };
1286
+ var onError = function onError(e) {
1279
1287
  if (!adPlaying) return;
1280
1288
  console.error("[HlsAdPlayer] Ad video error:", e);
1281
1289
  if (currentAd) {
@@ -1285,25 +1293,100 @@ function createHlsAdPlayer(contentVideo, options) {
1285
1293
  return;
1286
1294
  }
1287
1295
  handleAdError();
1288
- });
1289
- adVideoElement.addEventListener("volumechange", function() {
1290
- if (!currentAd) return;
1296
+ };
1297
+ var onVolumeChange = function onVolumeChange() {
1298
+ if (!currentAd || !adVideoElement) return;
1291
1299
  if (adVideoElement.muted) {
1292
1300
  fireTrackingPixels(currentAd.trackingUrls.mute);
1293
1301
  } else {
1294
1302
  fireTrackingPixels(currentAd.trackingUrls.unmute);
1295
1303
  }
1296
- });
1297
- adVideoElement.addEventListener("pause", function() {
1298
- if (currentAd && !adVideoElement.ended) {
1304
+ };
1305
+ var onPause = function onPause() {
1306
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1299
1307
  fireTrackingPixels(currentAd.trackingUrls.pause);
1300
1308
  }
1301
- });
1302
- adVideoElement.addEventListener("play", function() {
1303
- if (currentAd && adVideoElement.currentTime > 0) {
1309
+ };
1310
+ var onPlay = function onPlay() {
1311
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1304
1312
  fireTrackingPixels(currentAd.trackingUrls.resume);
1305
1313
  }
1306
- });
1314
+ };
1315
+ adEventHandlers = [
1316
+ {
1317
+ type: "timeupdate",
1318
+ handler: onTimeUpdate
1319
+ },
1320
+ {
1321
+ type: "playing",
1322
+ handler: onPlaying
1323
+ },
1324
+ {
1325
+ type: "ended",
1326
+ handler: onEnded
1327
+ },
1328
+ {
1329
+ type: "error",
1330
+ handler: onError
1331
+ },
1332
+ {
1333
+ type: "volumechange",
1334
+ handler: onVolumeChange
1335
+ },
1336
+ {
1337
+ type: "pause",
1338
+ handler: onPause
1339
+ },
1340
+ {
1341
+ type: "play",
1342
+ handler: onPlay
1343
+ }
1344
+ ];
1345
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1346
+ try {
1347
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1348
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1349
+ adVideoElement.addEventListener(type, handler);
1350
+ }
1351
+ } catch (err) {
1352
+ _didIteratorError = true;
1353
+ _iteratorError = err;
1354
+ } finally{
1355
+ try {
1356
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1357
+ _iterator.return();
1358
+ }
1359
+ } finally{
1360
+ if (_didIteratorError) {
1361
+ throw _iteratorError;
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ function teardownAdEventListeners() {
1367
+ if (adVideoElement) {
1368
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1369
+ try {
1370
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1371
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1372
+ adVideoElement.removeEventListener(type, handler);
1373
+ }
1374
+ } catch (err) {
1375
+ _didIteratorError = true;
1376
+ _iteratorError = err;
1377
+ } finally{
1378
+ try {
1379
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1380
+ _iterator.return();
1381
+ }
1382
+ } finally{
1383
+ if (_didIteratorError) {
1384
+ throw _iteratorError;
1385
+ }
1386
+ }
1387
+ }
1388
+ }
1389
+ adEventHandlers = [];
1307
1390
  }
1308
1391
  function setAdPlayingFlag(isPlaying) {
1309
1392
  if (isPlaying) {
@@ -1449,15 +1532,13 @@ function createHlsAdPlayer(contentVideo, options) {
1449
1532
  adHls = void 0;
1450
1533
  }
1451
1534
  if (adVideoElement) {
1452
- adVideoElement.pause();
1453
- adVideoElement.removeAttribute("src");
1454
1535
  try {
1536
+ adVideoElement.pause();
1537
+ adVideoElement.removeAttribute("src");
1455
1538
  adVideoElement.load();
1456
1539
  } catch (error) {
1457
- console.warn("[HlsAdPlayer] adVideoElement.load() threw after src removal:", error);
1540
+ console.warn("[HlsAdPlayer] Error releasing ad decoder:", error);
1458
1541
  }
1459
- adVideoElement.remove();
1460
- adVideoElement = void 0;
1461
1542
  }
1462
1543
  if (adContainerEl) {
1463
1544
  adContainerEl.style.display = "none";
@@ -1520,6 +1601,7 @@ function createHlsAdPlayer(contentVideo, options) {
1520
1601
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1521
1602
  adContainerEl = container;
1522
1603
  }
1604
+ contentVideo[AD_CONTAINER_PROP] = adContainerEl;
1523
1605
  },
1524
1606
  requestAds: function requestAds(vastTagUrl) {
1525
1607
  return _async_to_generator(function() {
@@ -1622,8 +1704,9 @@ function createHlsAdPlayer(contentVideo, options) {
1622
1704
  if (!adVideoElement) {
1623
1705
  adVideoElement = createAdVideoElement();
1624
1706
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1625
- setupAdEventListeners();
1707
+ contentVideo[AD_VIDEO_PROP] = adVideoElement;
1626
1708
  }
1709
+ setupAdEventListeners();
1627
1710
  resetQuartileTracking(true);
1628
1711
  contentVolume = contentVideo.volume;
1629
1712
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
@@ -1751,11 +1834,8 @@ function createHlsAdPlayer(contentVideo, options) {
1751
1834
  setAdPlayingFlag(false);
1752
1835
  contentVideo.muted = originalMutedState;
1753
1836
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
1837
+ teardownAdEventListeners();
1754
1838
  releaseAdDecoder();
1755
- if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
1756
- adContainerEl.parentElement.removeChild(adContainerEl);
1757
- }
1758
- adContainerEl = void 0;
1759
1839
  currentAd = void 0;
1760
1840
  podAds = [];
1761
1841
  podIndex = 0;
@@ -4189,6 +4269,11 @@ function detectBrowser() {
4189
4269
  chromeVersion: chromeVersionNum
4190
4270
  };
4191
4271
  }
4272
+ function requiresMediaPipelineResetAfterAds() {
4273
+ var _browser_tizenVersion;
4274
+ var browser = detectBrowser();
4275
+ return browser.name === "Samsung Tizen" && ((_browser_tizenVersion = browser.tizenVersion) !== null && _browser_tizenVersion !== void 0 ? _browser_tizenVersion : 0) >= 5;
4276
+ }
4192
4277
  function getBrowserConfigOverrides() {
4193
4278
  var browser = detectBrowser();
4194
4279
  var overrides = {};
@@ -6973,30 +7058,49 @@ var HlsEngine = /*#__PURE__*/ function() {
6973
7058
  {
6974
7059
  key: "reloadLiveStream",
6975
7060
  value: function reloadLiveStream() {
7061
+ var _this = this;
6976
7062
  var hls = this.hls;
6977
7063
  if (!hls) {
6978
7064
  return;
6979
7065
  }
6980
7066
  if (this.debug) {
6981
- console.log("[StormcloudVideoPlayer] Hard-reloading live stream (detach \u2192 reset video \u2192 re-attach)");
7067
+ console.log("[StormcloudVideoPlayer] Hard-reloading live stream (destroy hls \u2192 reset video \u2192 fresh setupHls)");
6982
7068
  }
6983
7069
  try {
6984
7070
  this.reloadingLiveStream = true;
6985
7071
  hls.stopLoad();
6986
7072
  hls.detachMedia();
7073
+ hls.destroy();
7074
+ this.hls = void 0;
6987
7075
  try {
6988
7076
  this.video.removeAttribute("src");
6989
7077
  this.video.load();
6990
7078
  } catch (error) {
6991
7079
  console.warn("[StormcloudVideoPlayer] video.load() threw after src removal:", error);
6992
7080
  }
6993
- hls.attachMedia(this.video);
6994
7081
  } catch (error) {
6995
7082
  this.reloadingLiveStream = false;
7083
+ this.hls = void 0;
6996
7084
  if (this.debug) {
6997
- console.warn("[StormcloudVideoPlayer] Failed to hard-reload live stream:", error);
7085
+ console.warn("[StormcloudVideoPlayer] Failed to tear down during hard-reload:", error);
6998
7086
  }
7087
+ return;
6999
7088
  }
7089
+ var recreateDelayMs = 600;
7090
+ window.setTimeout(function() {
7091
+ if (_this.hls) {
7092
+ _this.reloadingLiveStream = false;
7093
+ return;
7094
+ }
7095
+ try {
7096
+ _this.setupHls();
7097
+ } catch (error) {
7098
+ _this.reloadingLiveStream = false;
7099
+ if (_this.debug) {
7100
+ console.warn("[StormcloudVideoPlayer] Failed to rebuild pipeline during hard-reload:", error);
7101
+ }
7102
+ }
7103
+ }, recreateDelayMs);
7000
7104
  }
7001
7105
  },
7002
7106
  {
@@ -8309,6 +8413,14 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8309
8413
  this.host.video.style.visibility = "visible";
8310
8414
  this.host.video.style.opacity = "1";
8311
8415
  if (this.host.isLiveStream()) {
8416
+ if (this.host.requiresMediaPipelineResetAfterAds()) {
8417
+ if (this.debug) {
8418
+ console.log("[StormcloudVideoPlayer] Live break end \u2014 hard-reloading stream to reacquire decoder (single-decoder platform)");
8419
+ }
8420
+ this.host.reloadLiveStream();
8421
+ this.monitorLiveResumeStall(this.host.video.currentTime);
8422
+ return;
8423
+ }
8312
8424
  var liveSyncPos = this.host.getLiveSyncPosition();
8313
8425
  if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8314
8426
  if (this.debug) {
@@ -8370,9 +8482,10 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8370
8482
  key: "monitorLiveResumeStall",
8371
8483
  value: function monitorLiveResumeStall(resumeBaseline) {
8372
8484
  var _this = this;
8485
+ var needsReset = this.host.requiresMediaPipelineResetAfterAds();
8373
8486
  var pollIntervalMs = 1e3;
8374
- var graceMs = 5e3;
8375
- var recoveryCooldownMs = 5e3;
8487
+ var graceMs = needsReset ? 8e3 : 5e3;
8488
+ var recoveryCooldownMs = needsReset ? 7e3 : 5e3;
8376
8489
  var maxRecoveries = 3;
8377
8490
  var maxMonitorMs = 45e3;
8378
8491
  var startTime = Date.now();
@@ -8486,7 +8599,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8486
8599
  if (canRecover) {
8487
8600
  recoveries++;
8488
8601
  lastRecoveryAt = Date.now();
8489
- if (recoveries === 1) {
8602
+ if (needsReset) {
8603
+ if (_this.debug) {
8604
+ console.warn("[StormcloudVideoPlayer] Content still wedged after ad break — hard-reloading live stream (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8605
+ }
8606
+ _this.host.reloadLiveStream();
8607
+ } else if (recoveries === 1) {
8490
8608
  if (_this.debug) {
8491
8609
  console.warn("[StormcloudVideoPlayer] Content wedged after ad break — calling recoverMediaError() (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8492
8610
  }
@@ -8699,6 +8817,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8699
8817
  recoverMediaError: function recoverMediaError() {
8700
8818
  return _this.hlsEngine.recoverMediaError();
8701
8819
  },
8820
+ requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
8821
+ return requiresMediaPipelineResetAfterAds();
8822
+ },
8702
8823
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8703
8824
  return _this.generatePodVastUrl(base, breakDurationMs);
8704
8825
  }
@@ -12051,6 +12172,7 @@ var StormcloudPlayer_default = StormcloudPlayer;
12051
12172
  players: players,
12052
12173
  publishMQTT: publishMQTT,
12053
12174
  randomString: randomString,
12175
+ requiresMediaPipelineResetAfterAds: requiresMediaPipelineResetAfterAds,
12054
12176
  sendAdDetectTracking: sendAdDetectTracking,
12055
12177
  sendAdImpressionTracking: sendAdImpressionTracking,
12056
12178
  sendAdLoadedTracking: sendAdLoadedTracking,