stormcloud-video-player 0.8.46 → 0.8.48

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.d.cts CHANGED
@@ -4001,6 +4001,7 @@ interface BrowserInfo {
4001
4001
  chromeVersion?: number | undefined;
4002
4002
  }
4003
4003
  declare function detectBrowser(): BrowserInfo;
4004
+ declare function requiresMediaPipelineResetAfterAds(): boolean;
4004
4005
  declare function getBrowserConfigOverrides(): {
4005
4006
  allowNativeHls?: boolean;
4006
4007
  pauseContentDuringAds?: boolean;
@@ -4043,4 +4044,4 @@ interface PalNonceManager {
4043
4044
  }
4044
4045
  declare function createPalNonceManager(): PalNonceManager;
4045
4046
 
4046
- export { type AdBreak, type AdController, type AdControllerOptions, type AdDetectInfo, type AdImpressionInfo, type AdLoadedInfo, type AdSchedule, type BaseStormcloudPlayerProps, type BrowserInfo, type ClientInfo, DEFAULT_MQTT_CONFIG, type HeartbeatData, IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, type ImaController, type ImaControllerOptions, type LateJoinPolicy, type MQTTConfig, type MQTTStatus, MQTT_CA_CERT_FILE, type OnProgressProps, type PalNonceManager, type PalNonceOptions, type PlayerAnalyticsContext, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, type StormcloudVideoPlayerConfig, type StormcloudVideoPlayerProps, type TrackingData, applyMQTTConfig, buildAnalyticsContext, buildMQTTBrokerUrl, buildPlayerTopic, canPlay, configureMQTT, createHlsAdPlayer, createPalNonceManager, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, disconnectMQTT, ensureMQTTClient, getBrowserConfigOverrides, getBrowserID, getClientInfo, getMQTTStatus, initMQTTClient, initializePolyfills, isMQTTConfigured, isMQTTConnected, isMQTTEnabled, isMediaStream, lazy, logBrowserInfo, merge, mqttConfig, omit, parseQuery, players, publishMQTT, randomString, sendAdDetectTracking, sendAdImpressionTracking, sendAdLoadedTracking, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode };
4047
+ export { type AdBreak, type AdController, type AdControllerOptions, type AdDetectInfo, type AdImpressionInfo, type AdLoadedInfo, type AdSchedule, type BaseStormcloudPlayerProps, type BrowserInfo, type ClientInfo, DEFAULT_MQTT_CONFIG, type HeartbeatData, IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, type ImaController, type ImaControllerOptions, type LateJoinPolicy, type MQTTConfig, type MQTTStatus, MQTT_CA_CERT_FILE, type OnProgressProps, type PalNonceManager, type PalNonceOptions, type PlayerAnalyticsContext, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, type StormcloudVideoPlayerConfig, type StormcloudVideoPlayerProps, type TrackingData, applyMQTTConfig, buildAnalyticsContext, buildMQTTBrokerUrl, buildPlayerTopic, canPlay, configureMQTT, createHlsAdPlayer, createPalNonceManager, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, disconnectMQTT, ensureMQTTClient, getBrowserConfigOverrides, getBrowserID, getClientInfo, getMQTTStatus, initMQTTClient, initializePolyfills, isMQTTConfigured, isMQTTConnected, isMQTTEnabled, isMediaStream, lazy, logBrowserInfo, merge, mqttConfig, omit, parseQuery, players, publishMQTT, randomString, requiresMediaPipelineResetAfterAds, sendAdDetectTracking, sendAdImpressionTracking, sendAdLoadedTracking, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode };
package/lib/index.d.ts CHANGED
@@ -4001,6 +4001,7 @@ interface BrowserInfo {
4001
4001
  chromeVersion?: number | undefined;
4002
4002
  }
4003
4003
  declare function detectBrowser(): BrowserInfo;
4004
+ declare function requiresMediaPipelineResetAfterAds(): boolean;
4004
4005
  declare function getBrowserConfigOverrides(): {
4005
4006
  allowNativeHls?: boolean;
4006
4007
  pauseContentDuringAds?: boolean;
@@ -4043,4 +4044,4 @@ interface PalNonceManager {
4043
4044
  }
4044
4045
  declare function createPalNonceManager(): PalNonceManager;
4045
4046
 
4046
- export { type AdBreak, type AdController, type AdControllerOptions, type AdDetectInfo, type AdImpressionInfo, type AdLoadedInfo, type AdSchedule, type BaseStormcloudPlayerProps, type BrowserInfo, type ClientInfo, DEFAULT_MQTT_CONFIG, type HeartbeatData, IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, type ImaController, type ImaControllerOptions, type LateJoinPolicy, type MQTTConfig, type MQTTStatus, MQTT_CA_CERT_FILE, type OnProgressProps, type PalNonceManager, type PalNonceOptions, type PlayerAnalyticsContext, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, type StormcloudVideoPlayerConfig, type StormcloudVideoPlayerProps, type TrackingData, applyMQTTConfig, buildAnalyticsContext, buildMQTTBrokerUrl, buildPlayerTopic, canPlay, configureMQTT, createHlsAdPlayer, createPalNonceManager, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, disconnectMQTT, ensureMQTTClient, getBrowserConfigOverrides, getBrowserID, getClientInfo, getMQTTStatus, initMQTTClient, initializePolyfills, isMQTTConfigured, isMQTTConnected, isMQTTEnabled, isMediaStream, lazy, logBrowserInfo, merge, mqttConfig, omit, parseQuery, players, publishMQTT, randomString, sendAdDetectTracking, sendAdImpressionTracking, sendAdLoadedTracking, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode };
4047
+ export { type AdBreak, type AdController, type AdControllerOptions, type AdDetectInfo, type AdImpressionInfo, type AdLoadedInfo, type AdSchedule, type BaseStormcloudPlayerProps, type BrowserInfo, type ClientInfo, DEFAULT_MQTT_CONFIG, type HeartbeatData, IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, type ImaController, type ImaControllerOptions, type LateJoinPolicy, type MQTTConfig, type MQTTStatus, MQTT_CA_CERT_FILE, type OnProgressProps, type PalNonceManager, type PalNonceOptions, type PlayerAnalyticsContext, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, type StormcloudVideoPlayerConfig, type StormcloudVideoPlayerProps, type TrackingData, applyMQTTConfig, buildAnalyticsContext, buildMQTTBrokerUrl, buildPlayerTopic, canPlay, configureMQTT, createHlsAdPlayer, createPalNonceManager, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, disconnectMQTT, ensureMQTTClient, getBrowserConfigOverrides, getBrowserID, getClientInfo, getMQTTStatus, initMQTTClient, initializePolyfills, isMQTTConfigured, isMQTTConnected, isMQTTEnabled, isMediaStream, lazy, logBrowserInfo, merge, mqttConfig, omit, parseQuery, players, publishMQTT, randomString, requiresMediaPipelineResetAfterAds, sendAdDetectTracking, sendAdImpressionTracking, sendAdLoadedTracking, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode };
package/lib/index.js CHANGED
@@ -372,15 +372,19 @@ import React, { useEffect, useRef, useMemo, useCallback } from "react";
372
372
  import Hls from "hls.js";
373
373
  var MAX_VAST_WRAPPER_DEPTH = 5;
374
374
  function createHlsAdPlayer(contentVideo, options) {
375
+ var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
375
376
  var adPlaying = false;
376
377
  var originalMutedState = false;
377
378
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
378
379
  var listeners = /* @__PURE__ */ new Map();
379
380
  var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
380
381
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
381
- var adVideoElement;
382
+ var AD_CONTAINER_PROP = "__stormcloudAdContainer";
383
+ var AD_VIDEO_PROP = "__stormcloudAdVideo";
384
+ var adVideoElement = (_contentVideo_AD_VIDEO_PROP = contentVideo[AD_VIDEO_PROP]) !== null && _contentVideo_AD_VIDEO_PROP !== void 0 ? _contentVideo_AD_VIDEO_PROP : void 0;
382
385
  var adHls;
383
- var adContainerEl;
386
+ var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
387
+ var adEventHandlers = [];
384
388
  var currentAd;
385
389
  var podAds = [];
386
390
  var podIndex = 0;
@@ -535,6 +539,56 @@ function createHlsAdPlayer(contentVideo, options) {
535
539
  var url = mediaFile.url.toLowerCase();
536
540
  return type.startsWith("video/") || url.endsWith(".mp4") || url.includes(".mp4?");
537
541
  }
542
+ function isAudioMediaFile(mediaFile) {
543
+ var type = mediaFile.type.toLowerCase();
544
+ var url = (mediaFile.url.toLowerCase().split("?")[0] || "").trim();
545
+ return type.startsWith("audio/") || url.endsWith(".mp3") || url.endsWith(".aac") || url.endsWith(".m4a") || url.endsWith(".ogg") || url.endsWith(".oga") || url.endsWith(".opus") || url.endsWith(".wav") || url.endsWith(".weba");
546
+ }
547
+ function collectVideoMediaFiles(scope, verbose) {
548
+ var mediaFileElements = scope.querySelectorAll("MediaFile");
549
+ var mediaFiles = [];
550
+ if (verbose) {
551
+ console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
552
+ }
553
+ mediaFileElements.forEach(function(mf, index) {
554
+ var _mf_textContent;
555
+ var type = mf.getAttribute("type") || "";
556
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
557
+ var width = mf.getAttribute("width") || "";
558
+ var height = mf.getAttribute("height") || "";
559
+ if (verbose) {
560
+ console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
561
+ }
562
+ if (!url) {
563
+ if (verbose) {
564
+ console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
565
+ }
566
+ return;
567
+ }
568
+ var bitrateAttr = mf.getAttribute("bitrate");
569
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
570
+ var mediaFile = {
571
+ url: url,
572
+ type: type,
573
+ width: parseInt(width || "1920", 10),
574
+ height: parseInt(height || "1080", 10),
575
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
576
+ };
577
+ if (isAudioMediaFile(mediaFile)) {
578
+ console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
579
+ return;
580
+ }
581
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
582
+ mediaFiles.push(mediaFile);
583
+ if (verbose) {
584
+ console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
585
+ }
586
+ } else if (verbose) {
587
+ console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
588
+ }
589
+ });
590
+ return mediaFiles;
591
+ }
538
592
  function createEmptyTrackingUrls() {
539
593
  return {
540
594
  impression: [],
@@ -622,37 +676,7 @@ function createHlsAdPlayer(contentVideo, options) {
622
676
  var durationText = ((_xmlDoc_querySelector3 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector3 === void 0 ? void 0 : _xmlDoc_querySelector3.textContent) || "00:00:30";
623
677
  var durationParts = durationText.split(":");
624
678
  var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
625
- var mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
626
- var mediaFiles = [];
627
- console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
628
- mediaFileElements.forEach(function(mf, index) {
629
- var _mf_textContent;
630
- var type = mf.getAttribute("type") || "";
631
- var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
632
- var width = mf.getAttribute("width") || "";
633
- var height = mf.getAttribute("height") || "";
634
- console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
635
- var mediaFile = {
636
- url: url,
637
- type: type,
638
- width: parseInt(width || "1920", 10),
639
- height: parseInt(height || "1080", 10),
640
- bitrate: void 0
641
- };
642
- if (!url) {
643
- console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
644
- return;
645
- }
646
- var bitrateAttr = mf.getAttribute("bitrate");
647
- var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
648
- mediaFile.bitrate = bitrateValue && bitrateValue > 0 ? bitrateValue : void 0;
649
- if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
650
- mediaFiles.push(mediaFile);
651
- console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
652
- } else {
653
- console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
654
- }
655
- });
679
+ var mediaFiles = collectVideoMediaFiles(xmlDoc, true);
656
680
  if (mediaFiles.length === 0) {
657
681
  if (isNoAdAvailable) {
658
682
  console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
@@ -700,28 +724,7 @@ function createHlsAdPlayer(contentVideo, options) {
700
724
  var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
701
725
  var durationParts = durationText.split(":");
702
726
  var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
703
- var mediaFileElements = adElement.querySelectorAll("MediaFile");
704
- var mediaFiles = [];
705
- mediaFileElements.forEach(function(mf) {
706
- var _mf_textContent;
707
- var type = mf.getAttribute("type") || "";
708
- var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
709
- var width = mf.getAttribute("width") || "";
710
- var height = mf.getAttribute("height") || "";
711
- if (!url) return;
712
- var bitrateAttr = mf.getAttribute("bitrate");
713
- var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
714
- var mediaFile = {
715
- url: url,
716
- type: type,
717
- width: parseInt(width || "1920", 10),
718
- height: parseInt(height || "1080", 10),
719
- bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
720
- };
721
- if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
722
- mediaFiles.push(mediaFile);
723
- }
724
- });
727
+ var mediaFiles = collectVideoMediaFiles(adElement, false);
725
728
  if (mediaFiles.length === 0) {
726
729
  if (isNoAdAvailable) {
727
730
  console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
@@ -1024,7 +1027,8 @@ function createHlsAdPlayer(contentVideo, options) {
1024
1027
  }
1025
1028
  function setupAdEventListeners() {
1026
1029
  if (!adVideoElement || !currentAd) return;
1027
- adVideoElement.addEventListener("timeupdate", function() {
1030
+ if (adEventHandlers.length > 0) return;
1031
+ var onTimeUpdate = function onTimeUpdate() {
1028
1032
  if (!currentAd || !adVideoElement) return;
1029
1033
  noteAdProgress();
1030
1034
  var progress = adVideoElement.currentTime / currentAd.duration;
@@ -1040,15 +1044,15 @@ function createHlsAdPlayer(contentVideo, options) {
1040
1044
  trackingFired.thirdQuartile = true;
1041
1045
  fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
1042
1046
  }
1043
- });
1044
- adVideoElement.addEventListener("playing", function() {
1047
+ };
1048
+ var onPlaying = function onPlaying() {
1045
1049
  startStallWatchdog();
1046
1050
  if (!currentAd || trackingFired.start) return;
1047
1051
  trackingFired.start = true;
1048
1052
  fireTrackingPixels(currentAd.trackingUrls.start);
1049
1053
  console.log("[HlsAdPlayer] Ad started playing");
1050
- });
1051
- adVideoElement.addEventListener("ended", function() {
1054
+ };
1055
+ var onEnded = function onEnded() {
1052
1056
  if (!currentAd || trackingFired.complete) return;
1053
1057
  trackingFired.complete = true;
1054
1058
  fireTrackingPixels(currentAd.trackingUrls.complete);
@@ -1057,8 +1061,8 @@ function createHlsAdPlayer(contentVideo, options) {
1057
1061
  return;
1058
1062
  }
1059
1063
  handleAdComplete();
1060
- });
1061
- adVideoElement.addEventListener("error", function(e) {
1064
+ };
1065
+ var onError = function onError(e) {
1062
1066
  if (!adPlaying) return;
1063
1067
  console.error("[HlsAdPlayer] Ad video error:", e);
1064
1068
  if (currentAd) {
@@ -1068,25 +1072,100 @@ function createHlsAdPlayer(contentVideo, options) {
1068
1072
  return;
1069
1073
  }
1070
1074
  handleAdError();
1071
- });
1072
- adVideoElement.addEventListener("volumechange", function() {
1073
- if (!currentAd) return;
1075
+ };
1076
+ var onVolumeChange = function onVolumeChange() {
1077
+ if (!currentAd || !adVideoElement) return;
1074
1078
  if (adVideoElement.muted) {
1075
1079
  fireTrackingPixels(currentAd.trackingUrls.mute);
1076
1080
  } else {
1077
1081
  fireTrackingPixels(currentAd.trackingUrls.unmute);
1078
1082
  }
1079
- });
1080
- adVideoElement.addEventListener("pause", function() {
1081
- if (currentAd && !adVideoElement.ended) {
1083
+ };
1084
+ var onPause = function onPause() {
1085
+ if (currentAd && adVideoElement && !adVideoElement.ended) {
1082
1086
  fireTrackingPixels(currentAd.trackingUrls.pause);
1083
1087
  }
1084
- });
1085
- adVideoElement.addEventListener("play", function() {
1086
- if (currentAd && adVideoElement.currentTime > 0) {
1088
+ };
1089
+ var onPlay = function onPlay() {
1090
+ if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1087
1091
  fireTrackingPixels(currentAd.trackingUrls.resume);
1088
1092
  }
1089
- });
1093
+ };
1094
+ adEventHandlers = [
1095
+ {
1096
+ type: "timeupdate",
1097
+ handler: onTimeUpdate
1098
+ },
1099
+ {
1100
+ type: "playing",
1101
+ handler: onPlaying
1102
+ },
1103
+ {
1104
+ type: "ended",
1105
+ handler: onEnded
1106
+ },
1107
+ {
1108
+ type: "error",
1109
+ handler: onError
1110
+ },
1111
+ {
1112
+ type: "volumechange",
1113
+ handler: onVolumeChange
1114
+ },
1115
+ {
1116
+ type: "pause",
1117
+ handler: onPause
1118
+ },
1119
+ {
1120
+ type: "play",
1121
+ handler: onPlay
1122
+ }
1123
+ ];
1124
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1125
+ try {
1126
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1127
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1128
+ adVideoElement.addEventListener(type, handler);
1129
+ }
1130
+ } catch (err) {
1131
+ _didIteratorError = true;
1132
+ _iteratorError = err;
1133
+ } finally{
1134
+ try {
1135
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1136
+ _iterator.return();
1137
+ }
1138
+ } finally{
1139
+ if (_didIteratorError) {
1140
+ throw _iteratorError;
1141
+ }
1142
+ }
1143
+ }
1144
+ }
1145
+ function teardownAdEventListeners() {
1146
+ if (adVideoElement) {
1147
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1148
+ try {
1149
+ for(var _iterator = adEventHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1150
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
1151
+ adVideoElement.removeEventListener(type, handler);
1152
+ }
1153
+ } catch (err) {
1154
+ _didIteratorError = true;
1155
+ _iteratorError = err;
1156
+ } finally{
1157
+ try {
1158
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1159
+ _iterator.return();
1160
+ }
1161
+ } finally{
1162
+ if (_didIteratorError) {
1163
+ throw _iteratorError;
1164
+ }
1165
+ }
1166
+ }
1167
+ }
1168
+ adEventHandlers = [];
1090
1169
  }
1091
1170
  function setAdPlayingFlag(isPlaying) {
1092
1171
  if (isPlaying) {
@@ -1232,15 +1311,13 @@ function createHlsAdPlayer(contentVideo, options) {
1232
1311
  adHls = void 0;
1233
1312
  }
1234
1313
  if (adVideoElement) {
1235
- adVideoElement.pause();
1236
- adVideoElement.removeAttribute("src");
1237
1314
  try {
1315
+ adVideoElement.pause();
1316
+ adVideoElement.removeAttribute("src");
1238
1317
  adVideoElement.load();
1239
1318
  } catch (error) {
1240
- console.warn("[HlsAdPlayer] adVideoElement.load() threw after src removal:", error);
1319
+ console.warn("[HlsAdPlayer] Error releasing ad decoder:", error);
1241
1320
  }
1242
- adVideoElement.remove();
1243
- adVideoElement = void 0;
1244
1321
  }
1245
1322
  if (adContainerEl) {
1246
1323
  adContainerEl.style.display = "none";
@@ -1303,6 +1380,7 @@ function createHlsAdPlayer(contentVideo, options) {
1303
1380
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1304
1381
  adContainerEl = container;
1305
1382
  }
1383
+ contentVideo[AD_CONTAINER_PROP] = adContainerEl;
1306
1384
  },
1307
1385
  requestAds: function requestAds(vastTagUrl) {
1308
1386
  return _async_to_generator(function() {
@@ -1405,8 +1483,9 @@ function createHlsAdPlayer(contentVideo, options) {
1405
1483
  if (!adVideoElement) {
1406
1484
  adVideoElement = createAdVideoElement();
1407
1485
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1408
- setupAdEventListeners();
1486
+ contentVideo[AD_VIDEO_PROP] = adVideoElement;
1409
1487
  }
1488
+ setupAdEventListeners();
1410
1489
  resetQuartileTracking(true);
1411
1490
  contentVolume = contentVideo.volume;
1412
1491
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
@@ -1534,11 +1613,8 @@ function createHlsAdPlayer(contentVideo, options) {
1534
1613
  setAdPlayingFlag(false);
1535
1614
  contentVideo.muted = originalMutedState;
1536
1615
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
1616
+ teardownAdEventListeners();
1537
1617
  releaseAdDecoder();
1538
- if (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.parentElement) {
1539
- adContainerEl.parentElement.removeChild(adContainerEl);
1540
- }
1541
- adContainerEl = void 0;
1542
1618
  currentAd = void 0;
1543
1619
  podAds = [];
1544
1620
  podIndex = 0;
@@ -3974,6 +4050,11 @@ function detectBrowser() {
3974
4050
  chromeVersion: chromeVersionNum
3975
4051
  };
3976
4052
  }
4053
+ function requiresMediaPipelineResetAfterAds() {
4054
+ var _browser_tizenVersion;
4055
+ var browser = detectBrowser();
4056
+ return browser.name === "Samsung Tizen" && ((_browser_tizenVersion = browser.tizenVersion) !== null && _browser_tizenVersion !== void 0 ? _browser_tizenVersion : 0) >= 5;
4057
+ }
3977
4058
  function getBrowserConfigOverrides() {
3978
4059
  var browser = detectBrowser();
3979
4060
  var overrides = {};
@@ -6764,30 +6845,49 @@ var HlsEngine = /*#__PURE__*/ function() {
6764
6845
  {
6765
6846
  key: "reloadLiveStream",
6766
6847
  value: function reloadLiveStream() {
6848
+ var _this = this;
6767
6849
  var hls = this.hls;
6768
6850
  if (!hls) {
6769
6851
  return;
6770
6852
  }
6771
6853
  if (this.debug) {
6772
- console.log("[StormcloudVideoPlayer] Hard-reloading live stream (detach \u2192 reset video \u2192 re-attach)");
6854
+ console.log("[StormcloudVideoPlayer] Hard-reloading live stream (destroy hls \u2192 reset video \u2192 fresh setupHls)");
6773
6855
  }
6774
6856
  try {
6775
6857
  this.reloadingLiveStream = true;
6776
6858
  hls.stopLoad();
6777
6859
  hls.detachMedia();
6860
+ hls.destroy();
6861
+ this.hls = void 0;
6778
6862
  try {
6779
6863
  this.video.removeAttribute("src");
6780
6864
  this.video.load();
6781
6865
  } catch (error) {
6782
6866
  console.warn("[StormcloudVideoPlayer] video.load() threw after src removal:", error);
6783
6867
  }
6784
- hls.attachMedia(this.video);
6785
6868
  } catch (error) {
6786
6869
  this.reloadingLiveStream = false;
6870
+ this.hls = void 0;
6787
6871
  if (this.debug) {
6788
- console.warn("[StormcloudVideoPlayer] Failed to hard-reload live stream:", error);
6872
+ console.warn("[StormcloudVideoPlayer] Failed to tear down during hard-reload:", error);
6789
6873
  }
6874
+ return;
6790
6875
  }
6876
+ var recreateDelayMs = 600;
6877
+ window.setTimeout(function() {
6878
+ if (_this.hls) {
6879
+ _this.reloadingLiveStream = false;
6880
+ return;
6881
+ }
6882
+ try {
6883
+ _this.setupHls();
6884
+ } catch (error) {
6885
+ _this.reloadingLiveStream = false;
6886
+ if (_this.debug) {
6887
+ console.warn("[StormcloudVideoPlayer] Failed to rebuild pipeline during hard-reload:", error);
6888
+ }
6889
+ }
6890
+ }, recreateDelayMs);
6791
6891
  }
6792
6892
  },
6793
6893
  {
@@ -8101,6 +8201,14 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8101
8201
  this.host.video.style.visibility = "visible";
8102
8202
  this.host.video.style.opacity = "1";
8103
8203
  if (this.host.isLiveStream()) {
8204
+ if (this.host.requiresMediaPipelineResetAfterAds()) {
8205
+ if (this.debug) {
8206
+ console.log("[StormcloudVideoPlayer] Live break end \u2014 hard-reloading stream to reacquire decoder (single-decoder platform)");
8207
+ }
8208
+ this.host.reloadLiveStream();
8209
+ this.monitorLiveResumeStall(this.host.video.currentTime);
8210
+ return;
8211
+ }
8104
8212
  var liveSyncPos = this.host.getLiveSyncPosition();
8105
8213
  if (liveSyncPos != null && liveSyncPos > this.host.video.currentTime) {
8106
8214
  if (this.debug) {
@@ -8162,9 +8270,10 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8162
8270
  key: "monitorLiveResumeStall",
8163
8271
  value: function monitorLiveResumeStall(resumeBaseline) {
8164
8272
  var _this = this;
8273
+ var needsReset = this.host.requiresMediaPipelineResetAfterAds();
8165
8274
  var pollIntervalMs = 1e3;
8166
- var graceMs = 5e3;
8167
- var recoveryCooldownMs = 5e3;
8275
+ var graceMs = needsReset ? 8e3 : 5e3;
8276
+ var recoveryCooldownMs = needsReset ? 7e3 : 5e3;
8168
8277
  var maxRecoveries = 3;
8169
8278
  var maxMonitorMs = 45e3;
8170
8279
  var startTime = Date.now();
@@ -8278,7 +8387,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8278
8387
  if (canRecover) {
8279
8388
  recoveries++;
8280
8389
  lastRecoveryAt = Date.now();
8281
- if (recoveries === 1) {
8390
+ if (needsReset) {
8391
+ if (_this.debug) {
8392
+ console.warn("[StormcloudVideoPlayer] Content still wedged after ad break — hard-reloading live stream (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8393
+ }
8394
+ _this.host.reloadLiveStream();
8395
+ } else if (recoveries === 1) {
8282
8396
  if (_this.debug) {
8283
8397
  console.warn("[StormcloudVideoPlayer] Content wedged after ad break — calling recoverMediaError() (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8284
8398
  }
@@ -8492,6 +8606,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8492
8606
  recoverMediaError: function recoverMediaError() {
8493
8607
  return _this.hlsEngine.recoverMediaError();
8494
8608
  },
8609
+ requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
8610
+ return requiresMediaPipelineResetAfterAds();
8611
+ },
8495
8612
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8496
8613
  return _this.generatePodVastUrl(base, breakDurationMs);
8497
8614
  }
@@ -11804,5 +11921,5 @@ var createStormcloudPlayer = function createStormcloudPlayer(playerList, fallbac
11804
11921
  };
11805
11922
  var StormcloudPlayer = createStormcloudPlayer(players_default, players_default[players_default.length - 1]);
11806
11923
  var StormcloudPlayer_default = StormcloudPlayer;
11807
- export { DEFAULT_MQTT_CONFIG, IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, MQTT_CA_CERT_FILE, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer_default as StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, applyMQTTConfig, buildAnalyticsContext, buildMQTTBrokerUrl, buildPlayerTopic, canPlay, configureMQTT, createHlsAdPlayer, createPalNonceManager, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, disconnectMQTT, ensureMQTTClient, getBrowserConfigOverrides, getBrowserID, getClientInfo, getMQTTStatus, initMQTTClient, initializePolyfills, isMQTTConfigured, isMQTTConnected, isMQTTEnabled, isMediaStream, lazy, logBrowserInfo, merge, mqttConfig, omit, parseQuery, players_default as players, publishMQTT, randomString, sendAdDetectTracking, sendAdImpressionTracking, sendAdLoadedTracking, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode };
11924
+ export { DEFAULT_MQTT_CONFIG, IS_BROWSER, IS_GLOBAL, IS_IOS, IS_SAFARI, MQTT_CA_CERT_FILE, SUPPORTS_DASH, SUPPORTS_HLS, StormcloudPlayer_default as StormcloudPlayer, StormcloudVideoPlayer, StormcloudVideoPlayerComponent, applyMQTTConfig, buildAnalyticsContext, buildMQTTBrokerUrl, buildPlayerTopic, canPlay, configureMQTT, createHlsAdPlayer, createPalNonceManager, createStormcloudPlayer, StormcloudVideoPlayerComponent as default, detectBrowser, disconnectMQTT, ensureMQTTClient, getBrowserConfigOverrides, getBrowserID, getClientInfo, getMQTTStatus, initMQTTClient, initializePolyfills, isMQTTConfigured, isMQTTConnected, isMQTTEnabled, isMediaStream, lazy, logBrowserInfo, merge, mqttConfig, omit, parseQuery, players_default as players, publishMQTT, randomString, requiresMediaPipelineResetAfterAds, sendAdDetectTracking, sendAdImpressionTracking, sendAdLoadedTracking, sendHeartbeat, sendInitialTracking, supportsFeature, supportsModernJS, supportsWebKitPresentationMode };
11808
11925
  //# sourceMappingURL=index.js.map