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,4 +1,4 @@
1
- import { S as StormcloudVideoPlayerConfig } from '../types-mVgmKmzM.cjs';
1
+ import { S as StormcloudVideoPlayerConfig } from '../types-J6-Dpcvw.cjs';
2
2
 
3
3
  declare class StormcloudVideoPlayer {
4
4
  private readonly video;
@@ -23,6 +23,9 @@ declare class StormcloudVideoPlayer {
23
23
  private isLiveStream;
24
24
  private nativeHlsMode;
25
25
  private videoSrcProtection;
26
+ private bufferedSegmentsCount;
27
+ private shouldAutoplayAfterBuffering;
28
+ private hasInitialBufferCompleted;
26
29
  constructor(config: StormcloudVideoPlayerConfig);
27
30
  private createAdPlayer;
28
31
  load(): Promise<void>;
@@ -68,6 +71,7 @@ declare class StormcloudVideoPlayer {
68
71
  toggleMute(): void;
69
72
  toggleFullscreen(): Promise<void>;
70
73
  isMuted(): boolean;
74
+ setMuted(muted: boolean): void;
71
75
  isFullscreen(): boolean;
72
76
  isLive(): boolean;
73
77
  get videoElement(): HTMLVideoElement;
@@ -203,6 +203,13 @@ function createImaController(video, options) {
203
203
  let adPlaying = false;
204
204
  let originalMutedState = false;
205
205
  const listeners = /* @__PURE__ */ new Map();
206
+ function setAdPlayingFlag(isPlaying) {
207
+ if (isPlaying) {
208
+ video.dataset.stormcloudAdPlaying = "true";
209
+ } else {
210
+ delete video.dataset.stormcloudAdPlaying;
211
+ }
212
+ }
206
213
  function emit(event, payload) {
207
214
  const set = listeners.get(event);
208
215
  if (!set) return;
@@ -445,7 +452,12 @@ function createImaController(video, options) {
445
452
  console.error("[IMA] Ad error:", errorEvent.getError());
446
453
  destroyAdsManager();
447
454
  adPlaying = false;
455
+ const previousMutedState = video.muted;
448
456
  video.muted = originalMutedState;
457
+ setAdPlayingFlag(false);
458
+ console.log(
459
+ `[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
460
+ );
449
461
  if (adContainerEl) {
450
462
  adContainerEl.style.pointerEvents = "none";
451
463
  adContainerEl.style.display = "none";
@@ -498,11 +510,13 @@ function createImaController(video, options) {
498
510
  }
499
511
  video.muted = true;
500
512
  adPlaying = true;
513
+ setAdPlayingFlag(true);
501
514
  emit("content_pause");
502
515
  }
503
516
  );
504
517
  adsManager.addEventListener(AdEvent.STARTED, () => {
505
518
  console.log("[IMA] Ad started playing");
519
+ setAdPlayingFlag(true);
506
520
  if (adContainerEl) {
507
521
  adContainerEl.style.pointerEvents = "auto";
508
522
  adContainerEl.style.display = "flex";
@@ -518,6 +532,7 @@ function createImaController(video, options) {
518
532
  console.log("[IMA] Content resume requested");
519
533
  adPlaying = false;
520
534
  video.muted = originalMutedState;
535
+ setAdPlayingFlag(false);
521
536
  if (adContainerEl) {
522
537
  adContainerEl.style.pointerEvents = "none";
523
538
  adContainerEl.style.display = "none";
@@ -541,6 +556,7 @@ function createImaController(video, options) {
541
556
  console.log("[IMA] All ads completed");
542
557
  adPlaying = false;
543
558
  video.muted = originalMutedState;
559
+ setAdPlayingFlag(false);
544
560
  if (adContainerEl) {
545
561
  adContainerEl.style.pointerEvents = "none";
546
562
  adContainerEl.style.display = "none";
@@ -571,6 +587,7 @@ function createImaController(video, options) {
571
587
  console.error("[IMA] Error setting up ads manager:", e);
572
588
  adPlaying = false;
573
589
  video.muted = originalMutedState;
590
+ setAdPlayingFlag(false);
574
591
  if (adContainerEl) {
575
592
  adContainerEl.style.pointerEvents = "none";
576
593
  adContainerEl.style.display = "none";
@@ -600,7 +617,12 @@ function createImaController(video, options) {
600
617
  (adErrorEvent) => {
601
618
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
602
619
  adPlaying = false;
620
+ const previousMutedState = video.muted;
603
621
  video.muted = originalMutedState;
622
+ setAdPlayingFlag(false);
623
+ console.log(
624
+ `[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
625
+ );
604
626
  if (adContainerEl) {
605
627
  adContainerEl.style.pointerEvents = "none";
606
628
  adContainerEl.style.display = "none";
@@ -652,12 +674,20 @@ function createImaController(video, options) {
652
674
  console.log(`[IMA] Initializing ads manager (${width}x${height})`);
653
675
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
654
676
  adPlaying = true;
677
+ const adVolume = originalMutedState ? 0 : video.volume;
678
+ try {
679
+ adsManager.setVolume(adVolume);
680
+ console.log(`[IMA] Set ad volume to ${adVolume}`);
681
+ } catch (error) {
682
+ console.warn("[IMA] Failed to set ad volume:", error);
683
+ }
655
684
  console.log("[IMA] Starting ad playback");
656
685
  adsManager.start();
657
686
  return Promise.resolve();
658
687
  } catch (error) {
659
688
  console.error("[IMA] Error starting ad playback:", error);
660
689
  adPlaying = false;
690
+ setAdPlayingFlag(false);
661
691
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
662
692
  (_b = video.play()) == null ? void 0 : _b.catch(() => {
663
693
  });
@@ -669,6 +699,7 @@ function createImaController(video, options) {
669
699
  var _a;
670
700
  adPlaying = false;
671
701
  video.muted = originalMutedState;
702
+ setAdPlayingFlag(false);
672
703
  if (adContainerEl) {
673
704
  adContainerEl.style.pointerEvents = "none";
674
705
  adContainerEl.style.display = "none";
@@ -692,6 +723,7 @@ function createImaController(video, options) {
692
723
  destroyAdsManager();
693
724
  adPlaying = false;
694
725
  video.muted = originalMutedState;
726
+ setAdPlayingFlag(false);
695
727
  if (adContainerEl) {
696
728
  adContainerEl.style.pointerEvents = "none";
697
729
  adContainerEl.style.display = "none";
@@ -734,6 +766,9 @@ function createImaController(video, options) {
734
766
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
735
767
  },
736
768
  updateOriginalMutedState(muted) {
769
+ console.log(
770
+ `[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
771
+ );
737
772
  originalMutedState = muted;
738
773
  },
739
774
  getOriginalMutedState() {
@@ -790,7 +825,10 @@ function createHlsAdPlayer(contentVideo, options) {
790
825
  try {
791
826
  fn(payload);
792
827
  } catch (error) {
793
- console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
828
+ console.warn(
829
+ `[HlsAdPlayer] Error in event listener for ${event}:`,
830
+ error
831
+ );
794
832
  }
795
833
  }
796
834
  }
@@ -853,7 +891,9 @@ function createHlsAdPlayer(contentVideo, options) {
853
891
  }
854
892
  const mainQuality = getMainStreamQuality();
855
893
  if (!mainQuality) {
856
- console.log("[HlsAdPlayer] No main stream quality info, using first media file");
894
+ console.log(
895
+ "[HlsAdPlayer] No main stream quality info, using first media file"
896
+ );
857
897
  return firstFile;
858
898
  }
859
899
  console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
@@ -889,7 +929,10 @@ function createHlsAdPlayer(contentVideo, options) {
889
929
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
890
930
  const parserError = xmlDoc.querySelector("parsererror");
891
931
  if (parserError) {
892
- console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
932
+ console.error(
933
+ "[HlsAdPlayer] XML parsing error (malformed VAST XML):",
934
+ parserError.textContent
935
+ );
893
936
  return null;
894
937
  }
895
938
  const adElement = xmlDoc.querySelector("Ad");
@@ -905,17 +948,23 @@ function createHlsAdPlayer(contentVideo, options) {
905
948
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
906
949
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
907
950
  const mediaFiles = [];
908
- console.log(`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`);
951
+ console.log(
952
+ `[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`
953
+ );
909
954
  mediaFileElements.forEach((mf, index) => {
910
955
  var _a2;
911
956
  const type = mf.getAttribute("type") || "";
912
957
  const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
913
958
  const width = mf.getAttribute("width") || "";
914
959
  const height = mf.getAttribute("height") || "";
915
- console.log(`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`);
960
+ console.log(
961
+ `[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`
962
+ );
916
963
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
917
964
  if (!url) {
918
- console.warn(`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`);
965
+ console.warn(
966
+ `[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`
967
+ );
919
968
  return;
920
969
  }
921
970
  const bitrateAttr = mf.getAttribute("bitrate");
@@ -929,12 +978,16 @@ function createHlsAdPlayer(contentVideo, options) {
929
978
  });
930
979
  console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
931
980
  } else {
932
- console.log(`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`);
981
+ console.log(
982
+ `[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`
983
+ );
933
984
  }
934
985
  });
935
986
  if (mediaFiles.length === 0) {
936
987
  if (isNoAdAvailable) {
937
- console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
988
+ console.warn(
989
+ "[HlsAdPlayer] No ads available (VAST response indicates no ads)"
990
+ );
938
991
  } else {
939
992
  console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
940
993
  }
@@ -997,6 +1050,10 @@ function createHlsAdPlayer(contentVideo, options) {
997
1050
  video.style.backgroundColor = "#000";
998
1051
  video.playsInline = true;
999
1052
  video.muted = false;
1053
+ video.volume = 1;
1054
+ console.log(
1055
+ `[HlsAdPlayer] Created ad video element with volume ${video.volume}`
1056
+ );
1000
1057
  return video;
1001
1058
  }
1002
1059
  function setupAdEventListeners() {
@@ -1056,10 +1113,22 @@ function createHlsAdPlayer(contentVideo, options) {
1056
1113
  }
1057
1114
  });
1058
1115
  }
1116
+ function setAdPlayingFlag(isPlaying) {
1117
+ if (isPlaying) {
1118
+ contentVideo.dataset.stormcloudAdPlaying = "true";
1119
+ } else {
1120
+ delete contentVideo.dataset.stormcloudAdPlaying;
1121
+ }
1122
+ }
1059
1123
  function handleAdComplete() {
1060
1124
  console.log("[HlsAdPlayer] Handling ad completion");
1061
1125
  adPlaying = false;
1126
+ setAdPlayingFlag(false);
1127
+ const previousMutedState = contentVideo.muted;
1062
1128
  contentVideo.muted = originalMutedState;
1129
+ console.log(
1130
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1131
+ );
1063
1132
  if (adContainerEl) {
1064
1133
  adContainerEl.style.display = "none";
1065
1134
  adContainerEl.style.pointerEvents = "none";
@@ -1077,7 +1146,12 @@ function createHlsAdPlayer(contentVideo, options) {
1077
1146
  function handleAdError() {
1078
1147
  console.log("[HlsAdPlayer] Handling ad error");
1079
1148
  adPlaying = false;
1149
+ setAdPlayingFlag(false);
1150
+ const previousMutedState = contentVideo.muted;
1080
1151
  contentVideo.muted = originalMutedState;
1152
+ console.log(
1153
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1154
+ );
1081
1155
  if (adContainerEl) {
1082
1156
  adContainerEl.style.display = "none";
1083
1157
  adContainerEl.style.pointerEvents = "none";
@@ -1114,7 +1188,9 @@ function createHlsAdPlayer(contentVideo, options) {
1114
1188
  async requestAds(vastTagUrl) {
1115
1189
  console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
1116
1190
  if (adPlaying) {
1117
- console.warn("[HlsAdPlayer] Cannot request new ads while an ad is playing");
1191
+ console.warn(
1192
+ "[HlsAdPlayer] Cannot request new ads while an ad is playing"
1193
+ );
1118
1194
  return Promise.reject(new Error("Ad already playing"));
1119
1195
  }
1120
1196
  try {
@@ -1125,14 +1201,20 @@ function createHlsAdPlayer(contentVideo, options) {
1125
1201
  }
1126
1202
  const vastXml = await response.text();
1127
1203
  console.log("[HlsAdPlayer] VAST XML received");
1128
- console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1204
+ console.log(
1205
+ "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1206
+ vastXml.substring(0, 2e3)
1207
+ );
1129
1208
  const ad = parseVastXml(vastXml);
1130
1209
  if (!ad) {
1131
1210
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1211
+ emit("ad_error");
1132
1212
  return Promise.resolve();
1133
1213
  }
1134
1214
  currentAd = ad;
1135
- console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
1215
+ console.log(
1216
+ `[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`
1217
+ );
1136
1218
  fireTrackingPixels(ad.trackingUrls.impression);
1137
1219
  trackingFired.impression = true;
1138
1220
  return Promise.resolve();
@@ -1144,7 +1226,9 @@ function createHlsAdPlayer(contentVideo, options) {
1144
1226
  },
1145
1227
  async play() {
1146
1228
  if (!currentAd) {
1147
- console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
1229
+ console.warn(
1230
+ "[HlsAdPlayer] Cannot play: No ad loaded (no ads available)"
1231
+ );
1148
1232
  return Promise.reject(new Error("No ad loaded"));
1149
1233
  }
1150
1234
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1162,6 +1246,7 @@ function createHlsAdPlayer(contentVideo, options) {
1162
1246
  thirdQuartile: false,
1163
1247
  complete: false
1164
1248
  };
1249
+ const contentVolume = contentVideo.volume;
1165
1250
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1166
1251
  contentVideo.pause();
1167
1252
  console.log("[HlsAdPlayer] Content paused (VOD mode)");
@@ -1170,6 +1255,15 @@ function createHlsAdPlayer(contentVideo, options) {
1170
1255
  }
1171
1256
  contentVideo.muted = true;
1172
1257
  adPlaying = true;
1258
+ setAdPlayingFlag(true);
1259
+ if (adVideoElement) {
1260
+ const adVolume = originalMutedState ? 0 : contentVolume;
1261
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1262
+ adVideoElement.muted = false;
1263
+ console.log(
1264
+ `[HlsAdPlayer] Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}, originalMutedState: ${originalMutedState}, contentVolume: ${contentVolume}`
1265
+ );
1266
+ }
1173
1267
  if (adContainerEl) {
1174
1268
  adContainerEl.style.display = "flex";
1175
1269
  adContainerEl.style.pointerEvents = "auto";
@@ -1222,6 +1316,7 @@ function createHlsAdPlayer(contentVideo, options) {
1222
1316
  async stop() {
1223
1317
  console.log("[HlsAdPlayer] Stopping ad");
1224
1318
  adPlaying = false;
1319
+ setAdPlayingFlag(false);
1225
1320
  contentVideo.muted = originalMutedState;
1226
1321
  if (adContainerEl) {
1227
1322
  adContainerEl.style.display = "none";
@@ -1244,6 +1339,7 @@ function createHlsAdPlayer(contentVideo, options) {
1244
1339
  destroy() {
1245
1340
  console.log("[HlsAdPlayer] Destroying");
1246
1341
  adPlaying = false;
1342
+ setAdPlayingFlag(false);
1247
1343
  contentVideo.muted = originalMutedState;
1248
1344
  if (adHls) {
1249
1345
  adHls.destroy();
@@ -1285,6 +1381,9 @@ function createHlsAdPlayer(contentVideo, options) {
1285
1381
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
1286
1382
  },
1287
1383
  updateOriginalMutedState(muted) {
1384
+ console.log(
1385
+ `[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
1386
+ );
1288
1387
  originalMutedState = muted;
1289
1388
  },
1290
1389
  getOriginalMutedState() {
@@ -1777,6 +1876,9 @@ var StormcloudVideoPlayer = class {
1777
1876
  this.isLiveStream = false;
1778
1877
  this.nativeHlsMode = false;
1779
1878
  this.videoSrcProtection = null;
1879
+ this.bufferedSegmentsCount = 0;
1880
+ this.shouldAutoplayAfterBuffering = false;
1881
+ this.hasInitialBufferCompleted = false;
1780
1882
  initializePolyfills();
1781
1883
  const browserOverrides = getBrowserConfigOverrides();
1782
1884
  this.config = { ...config, ...browserOverrides };
@@ -1863,14 +1965,22 @@ var StormcloudVideoPlayer = class {
1863
1965
  liveDurationInfinity: true,
1864
1966
  lowLatencyMode: !!this.config.lowLatencyMode,
1865
1967
  maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
1866
- ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}
1968
+ ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {},
1969
+ maxBufferLength: 30,
1970
+ maxMaxBufferLength: 600,
1971
+ maxBufferSize: 60 * 1e3 * 1e3,
1972
+ maxBufferHole: 0.5,
1973
+ highBufferWatchdogPeriod: 2,
1974
+ nudgeOffset: 0.1,
1975
+ nudgeMaxRetry: 3,
1976
+ startPosition: -1
1867
1977
  });
1868
1978
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
1869
1979
  var _a2;
1870
1980
  (_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
1871
1981
  });
1872
1982
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
1873
- var _a2, _b2, _c, _d;
1983
+ var _a2, _b2, _c, _d, _e;
1874
1984
  this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
1875
1985
  (level) => {
1876
1986
  var _a3, _b3;
@@ -1888,9 +1998,51 @@ var StormcloudVideoPlayer = class {
1888
1998
  this.ima.destroy();
1889
1999
  this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
1890
2000
  this.ima.initialize();
1891
- if (this.config.autoplay) {
1892
- await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
1893
- }));
2001
+ this.bufferedSegmentsCount = 0;
2002
+ this.hasInitialBufferCompleted = false;
2003
+ this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
2004
+ const minSegments = (_d = this.config.minSegmentsBeforePlay) != null ? _d : 2;
2005
+ if (this.config.debugAdTiming) {
2006
+ console.log(
2007
+ "[StormcloudVideoPlayer] Waiting for",
2008
+ minSegments,
2009
+ "segments to buffer before playback"
2010
+ );
2011
+ }
2012
+ if (minSegments === 0 || !this.config.autoplay) {
2013
+ this.hasInitialBufferCompleted = true;
2014
+ if (this.config.autoplay) {
2015
+ await ((_e = this.video.play()) == null ? void 0 : _e.catch(() => {
2016
+ }));
2017
+ }
2018
+ }
2019
+ });
2020
+ this.hls.on(import_hls2.default.Events.FRAG_BUFFERED, async (_evt, data) => {
2021
+ var _a2, _b2;
2022
+ if (this.hasInitialBufferCompleted) {
2023
+ return;
2024
+ }
2025
+ this.bufferedSegmentsCount++;
2026
+ const minSegments = (_a2 = this.config.minSegmentsBeforePlay) != null ? _a2 : 2;
2027
+ if (this.config.debugAdTiming) {
2028
+ console.log(
2029
+ `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`
2030
+ );
2031
+ }
2032
+ if (this.bufferedSegmentsCount >= minSegments) {
2033
+ this.hasInitialBufferCompleted = true;
2034
+ if (this.shouldAutoplayAfterBuffering) {
2035
+ if (this.config.debugAdTiming) {
2036
+ console.log(
2037
+ `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`
2038
+ );
2039
+ }
2040
+ await ((_b2 = this.video.play()) == null ? void 0 : _b2.catch((err) => {
2041
+ if (this.config.debugAdTiming) {
2042
+ console.warn("[StormcloudVideoPlayer] Autoplay failed:", err);
2043
+ }
2044
+ }));
2045
+ }
1894
2046
  }
1895
2047
  });
1896
2048
  this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
@@ -1986,6 +2138,7 @@ var StormcloudVideoPlayer = class {
1986
2138
  this.video.autoplay = !!this.config.autoplay;
1987
2139
  this.video.muted = !!this.config.muted;
1988
2140
  this.ima.initialize();
2141
+ this.ima.updateOriginalMutedState(this.video.muted);
1989
2142
  this.ima.on("all_ads_completed", () => {
1990
2143
  if (this.config.debugAdTiming) {
1991
2144
  console.log(
@@ -2770,7 +2923,23 @@ var StormcloudVideoPlayer = class {
2770
2923
  }
2771
2924
  return;
2772
2925
  }
2773
- this.ima.updateOriginalMutedState(this.video.muted);
2926
+ if (!this.showAds) {
2927
+ if (this.config.debugAdTiming) {
2928
+ console.log(
2929
+ `[StormcloudVideoPlayer] Capturing original state before ad request:`,
2930
+ {
2931
+ videoMuted: this.video.muted,
2932
+ videoVolume: this.video.volume,
2933
+ showAds: this.showAds
2934
+ }
2935
+ );
2936
+ }
2937
+ this.ima.updateOriginalMutedState(this.video.muted);
2938
+ } else if (this.config.debugAdTiming) {
2939
+ console.log(
2940
+ `[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
2941
+ );
2942
+ }
2774
2943
  this.startAdFailsafeTimer();
2775
2944
  try {
2776
2945
  await this.ima.requestAds(vastTagUrl);
@@ -2825,11 +2994,12 @@ var StormcloudVideoPlayer = class {
2825
2994
  this.showAds = false;
2826
2995
  this.currentAdIndex = 0;
2827
2996
  this.totalAdsInBreak = 0;
2997
+ const currentMutedState = this.video.muted;
2828
2998
  const originalMutedState = this.ima.getOriginalMutedState();
2829
2999
  this.video.muted = originalMutedState;
2830
3000
  if (this.config.debugAdTiming) {
2831
3001
  console.log(
2832
- `[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
3002
+ `[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
2833
3003
  );
2834
3004
  }
2835
3005
  if (this.video.paused) {
@@ -2921,6 +3091,7 @@ var StormcloudVideoPlayer = class {
2921
3091
  }
2922
3092
  } else {
2923
3093
  this.video.muted = !this.video.muted;
3094
+ this.ima.updateOriginalMutedState(this.video.muted);
2924
3095
  if (this.config.debugAdTiming) {
2925
3096
  console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
2926
3097
  }
@@ -2965,11 +3136,47 @@ var StormcloudVideoPlayer = class {
2965
3136
  }
2966
3137
  isMuted() {
2967
3138
  if (this.ima.isAdPlaying()) {
2968
- const adVolume = this.ima.getAdVolume();
2969
- return adVolume === 0;
3139
+ if (this.config.debugAdTiming) {
3140
+ console.log(
3141
+ "[StormcloudVideoPlayer] isMuted() override during ad playback -> false"
3142
+ );
3143
+ }
3144
+ return false;
3145
+ }
3146
+ if (this.config.debugAdTiming) {
3147
+ console.log(
3148
+ `[StormcloudVideoPlayer] isMuted() no ad playing: video.muted=${this.video.muted}`
3149
+ );
2970
3150
  }
2971
3151
  return this.video.muted;
2972
3152
  }
3153
+ setMuted(muted) {
3154
+ const adPlaying = this.ima.isAdPlaying();
3155
+ if (adPlaying && muted === this.video.muted) {
3156
+ if (this.config.debugAdTiming) {
3157
+ console.log(
3158
+ "[StormcloudVideoPlayer] setMuted reflective update during ad ignored",
3159
+ { muted }
3160
+ );
3161
+ }
3162
+ return;
3163
+ }
3164
+ this.video.muted = muted;
3165
+ if (adPlaying) {
3166
+ this.ima.updateOriginalMutedState(muted);
3167
+ this.ima.setAdVolume(muted ? 0 : 1);
3168
+ if (this.config.debugAdTiming) {
3169
+ console.log("[StormcloudVideoPlayer] setMuted applied during ad", {
3170
+ muted
3171
+ });
3172
+ }
3173
+ return;
3174
+ }
3175
+ this.ima.updateOriginalMutedState(muted);
3176
+ if (this.config.debugAdTiming) {
3177
+ console.log("[StormcloudVideoPlayer] setMuted called:", muted);
3178
+ }
3179
+ }
2973
3180
  isFullscreen() {
2974
3181
  return !!document.fullscreenElement;
2975
3182
  }
@@ -3080,6 +3287,8 @@ var HlsPlayer = class extends import_react.Component {
3080
3287
  config.licenseKey = this.props.licenseKey;
3081
3288
  if (this.props.adFailsafeTimeoutMs !== void 0)
3082
3289
  config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
3290
+ if (this.props.minSegmentsBeforePlay !== void 0)
3291
+ config.minSegmentsBeforePlay = this.props.minSegmentsBeforePlay;
3083
3292
  this.player = new StormcloudVideoPlayer(config);
3084
3293
  (_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
3085
3294
  await this.player.load();