stormcloud-video-player 0.2.17 → 0.2.18

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.
@@ -1,5 +1,5 @@
1
1
  import { Component } from 'react';
2
- import { S as StormcloudVideoPlayerConfig } from '../types-mVgmKmzM.cjs';
2
+ import { S as StormcloudVideoPlayerConfig } from '../types-J6-Dpcvw.cjs';
3
3
 
4
4
  interface HlsPlayerProps extends StormcloudVideoPlayerConfig {
5
5
  onMount?: (player: any) => void;
@@ -242,6 +242,13 @@ function createImaController(video, options) {
242
242
  let adPlaying = false;
243
243
  let originalMutedState = false;
244
244
  const listeners = /* @__PURE__ */ new Map();
245
+ function setAdPlayingFlag(isPlaying) {
246
+ if (isPlaying) {
247
+ video.dataset.stormcloudAdPlaying = "true";
248
+ } else {
249
+ delete video.dataset.stormcloudAdPlaying;
250
+ }
251
+ }
245
252
  function emit(event, payload) {
246
253
  const set = listeners.get(event);
247
254
  if (!set) return;
@@ -484,7 +491,12 @@ function createImaController(video, options) {
484
491
  console.error("[IMA] Ad error:", errorEvent.getError());
485
492
  destroyAdsManager();
486
493
  adPlaying = false;
494
+ const previousMutedState = video.muted;
487
495
  video.muted = originalMutedState;
496
+ setAdPlayingFlag(false);
497
+ console.log(
498
+ `[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
499
+ );
488
500
  if (adContainerEl) {
489
501
  adContainerEl.style.pointerEvents = "none";
490
502
  adContainerEl.style.display = "none";
@@ -537,11 +549,13 @@ function createImaController(video, options) {
537
549
  }
538
550
  video.muted = true;
539
551
  adPlaying = true;
552
+ setAdPlayingFlag(true);
540
553
  emit("content_pause");
541
554
  }
542
555
  );
543
556
  adsManager.addEventListener(AdEvent.STARTED, () => {
544
557
  console.log("[IMA] Ad started playing");
558
+ setAdPlayingFlag(true);
545
559
  if (adContainerEl) {
546
560
  adContainerEl.style.pointerEvents = "auto";
547
561
  adContainerEl.style.display = "flex";
@@ -557,6 +571,7 @@ function createImaController(video, options) {
557
571
  console.log("[IMA] Content resume requested");
558
572
  adPlaying = false;
559
573
  video.muted = originalMutedState;
574
+ setAdPlayingFlag(false);
560
575
  if (adContainerEl) {
561
576
  adContainerEl.style.pointerEvents = "none";
562
577
  adContainerEl.style.display = "none";
@@ -580,6 +595,7 @@ function createImaController(video, options) {
580
595
  console.log("[IMA] All ads completed");
581
596
  adPlaying = false;
582
597
  video.muted = originalMutedState;
598
+ setAdPlayingFlag(false);
583
599
  if (adContainerEl) {
584
600
  adContainerEl.style.pointerEvents = "none";
585
601
  adContainerEl.style.display = "none";
@@ -610,6 +626,7 @@ function createImaController(video, options) {
610
626
  console.error("[IMA] Error setting up ads manager:", e);
611
627
  adPlaying = false;
612
628
  video.muted = originalMutedState;
629
+ setAdPlayingFlag(false);
613
630
  if (adContainerEl) {
614
631
  adContainerEl.style.pointerEvents = "none";
615
632
  adContainerEl.style.display = "none";
@@ -639,7 +656,12 @@ function createImaController(video, options) {
639
656
  (adErrorEvent) => {
640
657
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
641
658
  adPlaying = false;
659
+ const previousMutedState = video.muted;
642
660
  video.muted = originalMutedState;
661
+ setAdPlayingFlag(false);
662
+ console.log(
663
+ `[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
664
+ );
643
665
  if (adContainerEl) {
644
666
  adContainerEl.style.pointerEvents = "none";
645
667
  adContainerEl.style.display = "none";
@@ -691,12 +713,20 @@ function createImaController(video, options) {
691
713
  console.log(`[IMA] Initializing ads manager (${width}x${height})`);
692
714
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
693
715
  adPlaying = true;
716
+ const adVolume = originalMutedState ? 0 : video.volume;
717
+ try {
718
+ adsManager.setVolume(adVolume);
719
+ console.log(`[IMA] Set ad volume to ${adVolume}`);
720
+ } catch (error) {
721
+ console.warn("[IMA] Failed to set ad volume:", error);
722
+ }
694
723
  console.log("[IMA] Starting ad playback");
695
724
  adsManager.start();
696
725
  return Promise.resolve();
697
726
  } catch (error) {
698
727
  console.error("[IMA] Error starting ad playback:", error);
699
728
  adPlaying = false;
729
+ setAdPlayingFlag(false);
700
730
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
701
731
  (_b = video.play()) == null ? void 0 : _b.catch(() => {
702
732
  });
@@ -708,6 +738,7 @@ function createImaController(video, options) {
708
738
  var _a;
709
739
  adPlaying = false;
710
740
  video.muted = originalMutedState;
741
+ setAdPlayingFlag(false);
711
742
  if (adContainerEl) {
712
743
  adContainerEl.style.pointerEvents = "none";
713
744
  adContainerEl.style.display = "none";
@@ -731,6 +762,7 @@ function createImaController(video, options) {
731
762
  destroyAdsManager();
732
763
  adPlaying = false;
733
764
  video.muted = originalMutedState;
765
+ setAdPlayingFlag(false);
734
766
  if (adContainerEl) {
735
767
  adContainerEl.style.pointerEvents = "none";
736
768
  adContainerEl.style.display = "none";
@@ -773,6 +805,9 @@ function createImaController(video, options) {
773
805
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
774
806
  },
775
807
  updateOriginalMutedState(muted) {
808
+ console.log(
809
+ `[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
810
+ );
776
811
  originalMutedState = muted;
777
812
  },
778
813
  getOriginalMutedState() {
@@ -829,7 +864,10 @@ function createHlsAdPlayer(contentVideo, options) {
829
864
  try {
830
865
  fn(payload);
831
866
  } catch (error) {
832
- console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
867
+ console.warn(
868
+ `[HlsAdPlayer] Error in event listener for ${event}:`,
869
+ error
870
+ );
833
871
  }
834
872
  }
835
873
  }
@@ -892,7 +930,9 @@ function createHlsAdPlayer(contentVideo, options) {
892
930
  }
893
931
  const mainQuality = getMainStreamQuality();
894
932
  if (!mainQuality) {
895
- console.log("[HlsAdPlayer] No main stream quality info, using first media file");
933
+ console.log(
934
+ "[HlsAdPlayer] No main stream quality info, using first media file"
935
+ );
896
936
  return firstFile;
897
937
  }
898
938
  console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
@@ -928,7 +968,10 @@ function createHlsAdPlayer(contentVideo, options) {
928
968
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
929
969
  const parserError = xmlDoc.querySelector("parsererror");
930
970
  if (parserError) {
931
- console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
971
+ console.error(
972
+ "[HlsAdPlayer] XML parsing error (malformed VAST XML):",
973
+ parserError.textContent
974
+ );
932
975
  return null;
933
976
  }
934
977
  const adElement = xmlDoc.querySelector("Ad");
@@ -944,17 +987,23 @@ function createHlsAdPlayer(contentVideo, options) {
944
987
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
945
988
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
946
989
  const mediaFiles = [];
947
- console.log(`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`);
990
+ console.log(
991
+ `[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`
992
+ );
948
993
  mediaFileElements.forEach((mf, index) => {
949
994
  var _a2;
950
995
  const type = mf.getAttribute("type") || "";
951
996
  const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
952
997
  const width = mf.getAttribute("width") || "";
953
998
  const height = mf.getAttribute("height") || "";
954
- console.log(`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`);
999
+ console.log(
1000
+ `[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`
1001
+ );
955
1002
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
956
1003
  if (!url) {
957
- console.warn(`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`);
1004
+ console.warn(
1005
+ `[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`
1006
+ );
958
1007
  return;
959
1008
  }
960
1009
  const bitrateAttr = mf.getAttribute("bitrate");
@@ -968,12 +1017,16 @@ function createHlsAdPlayer(contentVideo, options) {
968
1017
  });
969
1018
  console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
970
1019
  } else {
971
- console.log(`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`);
1020
+ console.log(
1021
+ `[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`
1022
+ );
972
1023
  }
973
1024
  });
974
1025
  if (mediaFiles.length === 0) {
975
1026
  if (isNoAdAvailable) {
976
- console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
1027
+ console.warn(
1028
+ "[HlsAdPlayer] No ads available (VAST response indicates no ads)"
1029
+ );
977
1030
  } else {
978
1031
  console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
979
1032
  }
@@ -1036,6 +1089,10 @@ function createHlsAdPlayer(contentVideo, options) {
1036
1089
  video.style.backgroundColor = "#000";
1037
1090
  video.playsInline = true;
1038
1091
  video.muted = false;
1092
+ video.volume = 1;
1093
+ console.log(
1094
+ `[HlsAdPlayer] Created ad video element with volume ${video.volume}`
1095
+ );
1039
1096
  return video;
1040
1097
  }
1041
1098
  function setupAdEventListeners() {
@@ -1095,10 +1152,22 @@ function createHlsAdPlayer(contentVideo, options) {
1095
1152
  }
1096
1153
  });
1097
1154
  }
1155
+ function setAdPlayingFlag(isPlaying) {
1156
+ if (isPlaying) {
1157
+ contentVideo.dataset.stormcloudAdPlaying = "true";
1158
+ } else {
1159
+ delete contentVideo.dataset.stormcloudAdPlaying;
1160
+ }
1161
+ }
1098
1162
  function handleAdComplete() {
1099
1163
  console.log("[HlsAdPlayer] Handling ad completion");
1100
1164
  adPlaying = false;
1165
+ setAdPlayingFlag(false);
1166
+ const previousMutedState = contentVideo.muted;
1101
1167
  contentVideo.muted = originalMutedState;
1168
+ console.log(
1169
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1170
+ );
1102
1171
  if (adContainerEl) {
1103
1172
  adContainerEl.style.display = "none";
1104
1173
  adContainerEl.style.pointerEvents = "none";
@@ -1116,7 +1185,12 @@ function createHlsAdPlayer(contentVideo, options) {
1116
1185
  function handleAdError() {
1117
1186
  console.log("[HlsAdPlayer] Handling ad error");
1118
1187
  adPlaying = false;
1188
+ setAdPlayingFlag(false);
1189
+ const previousMutedState = contentVideo.muted;
1119
1190
  contentVideo.muted = originalMutedState;
1191
+ console.log(
1192
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1193
+ );
1120
1194
  if (adContainerEl) {
1121
1195
  adContainerEl.style.display = "none";
1122
1196
  adContainerEl.style.pointerEvents = "none";
@@ -1153,7 +1227,9 @@ function createHlsAdPlayer(contentVideo, options) {
1153
1227
  async requestAds(vastTagUrl) {
1154
1228
  console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
1155
1229
  if (adPlaying) {
1156
- console.warn("[HlsAdPlayer] Cannot request new ads while an ad is playing");
1230
+ console.warn(
1231
+ "[HlsAdPlayer] Cannot request new ads while an ad is playing"
1232
+ );
1157
1233
  return Promise.reject(new Error("Ad already playing"));
1158
1234
  }
1159
1235
  try {
@@ -1164,14 +1240,20 @@ function createHlsAdPlayer(contentVideo, options) {
1164
1240
  }
1165
1241
  const vastXml = await response.text();
1166
1242
  console.log("[HlsAdPlayer] VAST XML received");
1167
- console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1243
+ console.log(
1244
+ "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1245
+ vastXml.substring(0, 2e3)
1246
+ );
1168
1247
  const ad = parseVastXml(vastXml);
1169
1248
  if (!ad) {
1170
1249
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1250
+ emit("ad_error");
1171
1251
  return Promise.resolve();
1172
1252
  }
1173
1253
  currentAd = ad;
1174
- console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
1254
+ console.log(
1255
+ `[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`
1256
+ );
1175
1257
  fireTrackingPixels(ad.trackingUrls.impression);
1176
1258
  trackingFired.impression = true;
1177
1259
  return Promise.resolve();
@@ -1183,7 +1265,9 @@ function createHlsAdPlayer(contentVideo, options) {
1183
1265
  },
1184
1266
  async play() {
1185
1267
  if (!currentAd) {
1186
- console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
1268
+ console.warn(
1269
+ "[HlsAdPlayer] Cannot play: No ad loaded (no ads available)"
1270
+ );
1187
1271
  return Promise.reject(new Error("No ad loaded"));
1188
1272
  }
1189
1273
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1201,6 +1285,7 @@ function createHlsAdPlayer(contentVideo, options) {
1201
1285
  thirdQuartile: false,
1202
1286
  complete: false
1203
1287
  };
1288
+ const contentVolume = contentVideo.volume;
1204
1289
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1205
1290
  contentVideo.pause();
1206
1291
  console.log("[HlsAdPlayer] Content paused (VOD mode)");
@@ -1209,6 +1294,15 @@ function createHlsAdPlayer(contentVideo, options) {
1209
1294
  }
1210
1295
  contentVideo.muted = true;
1211
1296
  adPlaying = true;
1297
+ setAdPlayingFlag(true);
1298
+ if (adVideoElement) {
1299
+ const adVolume = originalMutedState ? 0 : contentVolume;
1300
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1301
+ adVideoElement.muted = false;
1302
+ console.log(
1303
+ `[HlsAdPlayer] Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}, originalMutedState: ${originalMutedState}, contentVolume: ${contentVolume}`
1304
+ );
1305
+ }
1212
1306
  if (adContainerEl) {
1213
1307
  adContainerEl.style.display = "flex";
1214
1308
  adContainerEl.style.pointerEvents = "auto";
@@ -1261,6 +1355,7 @@ function createHlsAdPlayer(contentVideo, options) {
1261
1355
  async stop() {
1262
1356
  console.log("[HlsAdPlayer] Stopping ad");
1263
1357
  adPlaying = false;
1358
+ setAdPlayingFlag(false);
1264
1359
  contentVideo.muted = originalMutedState;
1265
1360
  if (adContainerEl) {
1266
1361
  adContainerEl.style.display = "none";
@@ -1283,6 +1378,7 @@ function createHlsAdPlayer(contentVideo, options) {
1283
1378
  destroy() {
1284
1379
  console.log("[HlsAdPlayer] Destroying");
1285
1380
  adPlaying = false;
1381
+ setAdPlayingFlag(false);
1286
1382
  contentVideo.muted = originalMutedState;
1287
1383
  if (adHls) {
1288
1384
  adHls.destroy();
@@ -1324,6 +1420,9 @@ function createHlsAdPlayer(contentVideo, options) {
1324
1420
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
1325
1421
  },
1326
1422
  updateOriginalMutedState(muted) {
1423
+ console.log(
1424
+ `[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
1425
+ );
1327
1426
  originalMutedState = muted;
1328
1427
  },
1329
1428
  getOriginalMutedState() {
@@ -1816,6 +1915,9 @@ var StormcloudVideoPlayer = class {
1816
1915
  this.isLiveStream = false;
1817
1916
  this.nativeHlsMode = false;
1818
1917
  this.videoSrcProtection = null;
1918
+ this.bufferedSegmentsCount = 0;
1919
+ this.shouldAutoplayAfterBuffering = false;
1920
+ this.hasInitialBufferCompleted = false;
1819
1921
  initializePolyfills();
1820
1922
  const browserOverrides = getBrowserConfigOverrides();
1821
1923
  this.config = { ...config, ...browserOverrides };
@@ -1902,14 +2004,22 @@ var StormcloudVideoPlayer = class {
1902
2004
  liveDurationInfinity: true,
1903
2005
  lowLatencyMode: !!this.config.lowLatencyMode,
1904
2006
  maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
1905
- ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}
2007
+ ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {},
2008
+ maxBufferLength: 30,
2009
+ maxMaxBufferLength: 600,
2010
+ maxBufferSize: 60 * 1e3 * 1e3,
2011
+ maxBufferHole: 0.5,
2012
+ highBufferWatchdogPeriod: 2,
2013
+ nudgeOffset: 0.1,
2014
+ nudgeMaxRetry: 3,
2015
+ startPosition: -1
1906
2016
  });
1907
2017
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
1908
2018
  var _a2;
1909
2019
  (_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
1910
2020
  });
1911
2021
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
1912
- var _a2, _b2, _c, _d;
2022
+ var _a2, _b2, _c, _d, _e;
1913
2023
  this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
1914
2024
  (level) => {
1915
2025
  var _a3, _b3;
@@ -1927,9 +2037,51 @@ var StormcloudVideoPlayer = class {
1927
2037
  this.ima.destroy();
1928
2038
  this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
1929
2039
  this.ima.initialize();
1930
- if (this.config.autoplay) {
1931
- await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
1932
- }));
2040
+ this.bufferedSegmentsCount = 0;
2041
+ this.hasInitialBufferCompleted = false;
2042
+ this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
2043
+ const minSegments = (_d = this.config.minSegmentsBeforePlay) != null ? _d : 2;
2044
+ if (this.config.debugAdTiming) {
2045
+ console.log(
2046
+ "[StormcloudVideoPlayer] Waiting for",
2047
+ minSegments,
2048
+ "segments to buffer before playback"
2049
+ );
2050
+ }
2051
+ if (minSegments === 0 || !this.config.autoplay) {
2052
+ this.hasInitialBufferCompleted = true;
2053
+ if (this.config.autoplay) {
2054
+ await ((_e = this.video.play()) == null ? void 0 : _e.catch(() => {
2055
+ }));
2056
+ }
2057
+ }
2058
+ });
2059
+ this.hls.on(import_hls2.default.Events.FRAG_BUFFERED, async (_evt, data) => {
2060
+ var _a2, _b2;
2061
+ if (this.hasInitialBufferCompleted) {
2062
+ return;
2063
+ }
2064
+ this.bufferedSegmentsCount++;
2065
+ const minSegments = (_a2 = this.config.minSegmentsBeforePlay) != null ? _a2 : 2;
2066
+ if (this.config.debugAdTiming) {
2067
+ console.log(
2068
+ `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`
2069
+ );
2070
+ }
2071
+ if (this.bufferedSegmentsCount >= minSegments) {
2072
+ this.hasInitialBufferCompleted = true;
2073
+ if (this.shouldAutoplayAfterBuffering) {
2074
+ if (this.config.debugAdTiming) {
2075
+ console.log(
2076
+ `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`
2077
+ );
2078
+ }
2079
+ await ((_b2 = this.video.play()) == null ? void 0 : _b2.catch((err) => {
2080
+ if (this.config.debugAdTiming) {
2081
+ console.warn("[StormcloudVideoPlayer] Autoplay failed:", err);
2082
+ }
2083
+ }));
2084
+ }
1933
2085
  }
1934
2086
  });
1935
2087
  this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
@@ -2025,6 +2177,7 @@ var StormcloudVideoPlayer = class {
2025
2177
  this.video.autoplay = !!this.config.autoplay;
2026
2178
  this.video.muted = !!this.config.muted;
2027
2179
  this.ima.initialize();
2180
+ this.ima.updateOriginalMutedState(this.video.muted);
2028
2181
  this.ima.on("all_ads_completed", () => {
2029
2182
  if (this.config.debugAdTiming) {
2030
2183
  console.log(
@@ -2809,7 +2962,23 @@ var StormcloudVideoPlayer = class {
2809
2962
  }
2810
2963
  return;
2811
2964
  }
2812
- this.ima.updateOriginalMutedState(this.video.muted);
2965
+ if (!this.showAds) {
2966
+ if (this.config.debugAdTiming) {
2967
+ console.log(
2968
+ `[StormcloudVideoPlayer] Capturing original state before ad request:`,
2969
+ {
2970
+ videoMuted: this.video.muted,
2971
+ videoVolume: this.video.volume,
2972
+ showAds: this.showAds
2973
+ }
2974
+ );
2975
+ }
2976
+ this.ima.updateOriginalMutedState(this.video.muted);
2977
+ } else if (this.config.debugAdTiming) {
2978
+ console.log(
2979
+ `[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
2980
+ );
2981
+ }
2813
2982
  this.startAdFailsafeTimer();
2814
2983
  try {
2815
2984
  await this.ima.requestAds(vastTagUrl);
@@ -2864,11 +3033,12 @@ var StormcloudVideoPlayer = class {
2864
3033
  this.showAds = false;
2865
3034
  this.currentAdIndex = 0;
2866
3035
  this.totalAdsInBreak = 0;
3036
+ const currentMutedState = this.video.muted;
2867
3037
  const originalMutedState = this.ima.getOriginalMutedState();
2868
3038
  this.video.muted = originalMutedState;
2869
3039
  if (this.config.debugAdTiming) {
2870
3040
  console.log(
2871
- `[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
3041
+ `[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
2872
3042
  );
2873
3043
  }
2874
3044
  if (this.video.paused) {
@@ -2960,6 +3130,7 @@ var StormcloudVideoPlayer = class {
2960
3130
  }
2961
3131
  } else {
2962
3132
  this.video.muted = !this.video.muted;
3133
+ this.ima.updateOriginalMutedState(this.video.muted);
2963
3134
  if (this.config.debugAdTiming) {
2964
3135
  console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
2965
3136
  }
@@ -3004,11 +3175,47 @@ var StormcloudVideoPlayer = class {
3004
3175
  }
3005
3176
  isMuted() {
3006
3177
  if (this.ima.isAdPlaying()) {
3007
- const adVolume = this.ima.getAdVolume();
3008
- return adVolume === 0;
3178
+ if (this.config.debugAdTiming) {
3179
+ console.log(
3180
+ "[StormcloudVideoPlayer] isMuted() override during ad playback -> false"
3181
+ );
3182
+ }
3183
+ return false;
3184
+ }
3185
+ if (this.config.debugAdTiming) {
3186
+ console.log(
3187
+ `[StormcloudVideoPlayer] isMuted() no ad playing: video.muted=${this.video.muted}`
3188
+ );
3009
3189
  }
3010
3190
  return this.video.muted;
3011
3191
  }
3192
+ setMuted(muted) {
3193
+ const adPlaying = this.ima.isAdPlaying();
3194
+ if (adPlaying && muted === this.video.muted) {
3195
+ if (this.config.debugAdTiming) {
3196
+ console.log(
3197
+ "[StormcloudVideoPlayer] setMuted reflective update during ad ignored",
3198
+ { muted }
3199
+ );
3200
+ }
3201
+ return;
3202
+ }
3203
+ this.video.muted = muted;
3204
+ if (adPlaying) {
3205
+ this.ima.updateOriginalMutedState(muted);
3206
+ this.ima.setAdVolume(muted ? 0 : 1);
3207
+ if (this.config.debugAdTiming) {
3208
+ console.log("[StormcloudVideoPlayer] setMuted applied during ad", {
3209
+ muted
3210
+ });
3211
+ }
3212
+ return;
3213
+ }
3214
+ this.ima.updateOriginalMutedState(muted);
3215
+ if (this.config.debugAdTiming) {
3216
+ console.log("[StormcloudVideoPlayer] setMuted called:", muted);
3217
+ }
3218
+ }
3012
3219
  isFullscreen() {
3013
3220
  return !!document.fullscreenElement;
3014
3221
  }
@@ -3090,6 +3297,8 @@ var HlsPlayer = class extends import_react2.Component {
3090
3297
  config.licenseKey = this.props.licenseKey;
3091
3298
  if (this.props.adFailsafeTimeoutMs !== void 0)
3092
3299
  config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
3300
+ if (this.props.minSegmentsBeforePlay !== void 0)
3301
+ config.minSegmentsBeforePlay = this.props.minSegmentsBeforePlay;
3093
3302
  this.player = new StormcloudVideoPlayer(config);
3094
3303
  (_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
3095
3304
  await this.player.load();