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.
@@ -200,6 +200,13 @@ function createImaController(video, options) {
200
200
  let adPlaying = false;
201
201
  let originalMutedState = false;
202
202
  const listeners = /* @__PURE__ */ new Map();
203
+ function setAdPlayingFlag(isPlaying) {
204
+ if (isPlaying) {
205
+ video.dataset.stormcloudAdPlaying = "true";
206
+ } else {
207
+ delete video.dataset.stormcloudAdPlaying;
208
+ }
209
+ }
203
210
  function emit(event, payload) {
204
211
  const set = listeners.get(event);
205
212
  if (!set) return;
@@ -442,7 +449,12 @@ function createImaController(video, options) {
442
449
  console.error("[IMA] Ad error:", errorEvent.getError());
443
450
  destroyAdsManager();
444
451
  adPlaying = false;
452
+ const previousMutedState = video.muted;
445
453
  video.muted = originalMutedState;
454
+ setAdPlayingFlag(false);
455
+ console.log(
456
+ `[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
457
+ );
446
458
  if (adContainerEl) {
447
459
  adContainerEl.style.pointerEvents = "none";
448
460
  adContainerEl.style.display = "none";
@@ -495,11 +507,13 @@ function createImaController(video, options) {
495
507
  }
496
508
  video.muted = true;
497
509
  adPlaying = true;
510
+ setAdPlayingFlag(true);
498
511
  emit("content_pause");
499
512
  }
500
513
  );
501
514
  adsManager.addEventListener(AdEvent.STARTED, () => {
502
515
  console.log("[IMA] Ad started playing");
516
+ setAdPlayingFlag(true);
503
517
  if (adContainerEl) {
504
518
  adContainerEl.style.pointerEvents = "auto";
505
519
  adContainerEl.style.display = "flex";
@@ -515,6 +529,7 @@ function createImaController(video, options) {
515
529
  console.log("[IMA] Content resume requested");
516
530
  adPlaying = false;
517
531
  video.muted = originalMutedState;
532
+ setAdPlayingFlag(false);
518
533
  if (adContainerEl) {
519
534
  adContainerEl.style.pointerEvents = "none";
520
535
  adContainerEl.style.display = "none";
@@ -538,6 +553,7 @@ function createImaController(video, options) {
538
553
  console.log("[IMA] All ads completed");
539
554
  adPlaying = false;
540
555
  video.muted = originalMutedState;
556
+ setAdPlayingFlag(false);
541
557
  if (adContainerEl) {
542
558
  adContainerEl.style.pointerEvents = "none";
543
559
  adContainerEl.style.display = "none";
@@ -568,6 +584,7 @@ function createImaController(video, options) {
568
584
  console.error("[IMA] Error setting up ads manager:", e);
569
585
  adPlaying = false;
570
586
  video.muted = originalMutedState;
587
+ setAdPlayingFlag(false);
571
588
  if (adContainerEl) {
572
589
  adContainerEl.style.pointerEvents = "none";
573
590
  adContainerEl.style.display = "none";
@@ -597,7 +614,12 @@ function createImaController(video, options) {
597
614
  (adErrorEvent) => {
598
615
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
599
616
  adPlaying = false;
617
+ const previousMutedState = video.muted;
600
618
  video.muted = originalMutedState;
619
+ setAdPlayingFlag(false);
620
+ console.log(
621
+ `[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
622
+ );
601
623
  if (adContainerEl) {
602
624
  adContainerEl.style.pointerEvents = "none";
603
625
  adContainerEl.style.display = "none";
@@ -649,12 +671,20 @@ function createImaController(video, options) {
649
671
  console.log(`[IMA] Initializing ads manager (${width}x${height})`);
650
672
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
651
673
  adPlaying = true;
674
+ const adVolume = originalMutedState ? 0 : video.volume;
675
+ try {
676
+ adsManager.setVolume(adVolume);
677
+ console.log(`[IMA] Set ad volume to ${adVolume}`);
678
+ } catch (error) {
679
+ console.warn("[IMA] Failed to set ad volume:", error);
680
+ }
652
681
  console.log("[IMA] Starting ad playback");
653
682
  adsManager.start();
654
683
  return Promise.resolve();
655
684
  } catch (error) {
656
685
  console.error("[IMA] Error starting ad playback:", error);
657
686
  adPlaying = false;
687
+ setAdPlayingFlag(false);
658
688
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
659
689
  (_b = video.play()) == null ? void 0 : _b.catch(() => {
660
690
  });
@@ -666,6 +696,7 @@ function createImaController(video, options) {
666
696
  var _a;
667
697
  adPlaying = false;
668
698
  video.muted = originalMutedState;
699
+ setAdPlayingFlag(false);
669
700
  if (adContainerEl) {
670
701
  adContainerEl.style.pointerEvents = "none";
671
702
  adContainerEl.style.display = "none";
@@ -689,6 +720,7 @@ function createImaController(video, options) {
689
720
  destroyAdsManager();
690
721
  adPlaying = false;
691
722
  video.muted = originalMutedState;
723
+ setAdPlayingFlag(false);
692
724
  if (adContainerEl) {
693
725
  adContainerEl.style.pointerEvents = "none";
694
726
  adContainerEl.style.display = "none";
@@ -731,6 +763,9 @@ function createImaController(video, options) {
731
763
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
732
764
  },
733
765
  updateOriginalMutedState(muted) {
766
+ console.log(
767
+ `[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
768
+ );
734
769
  originalMutedState = muted;
735
770
  },
736
771
  getOriginalMutedState() {
@@ -787,7 +822,10 @@ function createHlsAdPlayer(contentVideo, options) {
787
822
  try {
788
823
  fn(payload);
789
824
  } catch (error) {
790
- console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
825
+ console.warn(
826
+ `[HlsAdPlayer] Error in event listener for ${event}:`,
827
+ error
828
+ );
791
829
  }
792
830
  }
793
831
  }
@@ -850,7 +888,9 @@ function createHlsAdPlayer(contentVideo, options) {
850
888
  }
851
889
  const mainQuality = getMainStreamQuality();
852
890
  if (!mainQuality) {
853
- console.log("[HlsAdPlayer] No main stream quality info, using first media file");
891
+ console.log(
892
+ "[HlsAdPlayer] No main stream quality info, using first media file"
893
+ );
854
894
  return firstFile;
855
895
  }
856
896
  console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
@@ -886,7 +926,10 @@ function createHlsAdPlayer(contentVideo, options) {
886
926
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
887
927
  const parserError = xmlDoc.querySelector("parsererror");
888
928
  if (parserError) {
889
- console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
929
+ console.error(
930
+ "[HlsAdPlayer] XML parsing error (malformed VAST XML):",
931
+ parserError.textContent
932
+ );
890
933
  return null;
891
934
  }
892
935
  const adElement = xmlDoc.querySelector("Ad");
@@ -902,17 +945,23 @@ function createHlsAdPlayer(contentVideo, options) {
902
945
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
903
946
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
904
947
  const mediaFiles = [];
905
- console.log(`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`);
948
+ console.log(
949
+ `[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`
950
+ );
906
951
  mediaFileElements.forEach((mf, index) => {
907
952
  var _a2;
908
953
  const type = mf.getAttribute("type") || "";
909
954
  const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
910
955
  const width = mf.getAttribute("width") || "";
911
956
  const height = mf.getAttribute("height") || "";
912
- console.log(`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`);
957
+ console.log(
958
+ `[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`
959
+ );
913
960
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
914
961
  if (!url) {
915
- console.warn(`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`);
962
+ console.warn(
963
+ `[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`
964
+ );
916
965
  return;
917
966
  }
918
967
  const bitrateAttr = mf.getAttribute("bitrate");
@@ -926,12 +975,16 @@ function createHlsAdPlayer(contentVideo, options) {
926
975
  });
927
976
  console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
928
977
  } else {
929
- console.log(`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`);
978
+ console.log(
979
+ `[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`
980
+ );
930
981
  }
931
982
  });
932
983
  if (mediaFiles.length === 0) {
933
984
  if (isNoAdAvailable) {
934
- console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
985
+ console.warn(
986
+ "[HlsAdPlayer] No ads available (VAST response indicates no ads)"
987
+ );
935
988
  } else {
936
989
  console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
937
990
  }
@@ -994,6 +1047,10 @@ function createHlsAdPlayer(contentVideo, options) {
994
1047
  video.style.backgroundColor = "#000";
995
1048
  video.playsInline = true;
996
1049
  video.muted = false;
1050
+ video.volume = 1;
1051
+ console.log(
1052
+ `[HlsAdPlayer] Created ad video element with volume ${video.volume}`
1053
+ );
997
1054
  return video;
998
1055
  }
999
1056
  function setupAdEventListeners() {
@@ -1053,10 +1110,22 @@ function createHlsAdPlayer(contentVideo, options) {
1053
1110
  }
1054
1111
  });
1055
1112
  }
1113
+ function setAdPlayingFlag(isPlaying) {
1114
+ if (isPlaying) {
1115
+ contentVideo.dataset.stormcloudAdPlaying = "true";
1116
+ } else {
1117
+ delete contentVideo.dataset.stormcloudAdPlaying;
1118
+ }
1119
+ }
1056
1120
  function handleAdComplete() {
1057
1121
  console.log("[HlsAdPlayer] Handling ad completion");
1058
1122
  adPlaying = false;
1123
+ setAdPlayingFlag(false);
1124
+ const previousMutedState = contentVideo.muted;
1059
1125
  contentVideo.muted = originalMutedState;
1126
+ console.log(
1127
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1128
+ );
1060
1129
  if (adContainerEl) {
1061
1130
  adContainerEl.style.display = "none";
1062
1131
  adContainerEl.style.pointerEvents = "none";
@@ -1074,7 +1143,12 @@ function createHlsAdPlayer(contentVideo, options) {
1074
1143
  function handleAdError() {
1075
1144
  console.log("[HlsAdPlayer] Handling ad error");
1076
1145
  adPlaying = false;
1146
+ setAdPlayingFlag(false);
1147
+ const previousMutedState = contentVideo.muted;
1077
1148
  contentVideo.muted = originalMutedState;
1149
+ console.log(
1150
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1151
+ );
1078
1152
  if (adContainerEl) {
1079
1153
  adContainerEl.style.display = "none";
1080
1154
  adContainerEl.style.pointerEvents = "none";
@@ -1111,7 +1185,9 @@ function createHlsAdPlayer(contentVideo, options) {
1111
1185
  async requestAds(vastTagUrl) {
1112
1186
  console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
1113
1187
  if (adPlaying) {
1114
- console.warn("[HlsAdPlayer] Cannot request new ads while an ad is playing");
1188
+ console.warn(
1189
+ "[HlsAdPlayer] Cannot request new ads while an ad is playing"
1190
+ );
1115
1191
  return Promise.reject(new Error("Ad already playing"));
1116
1192
  }
1117
1193
  try {
@@ -1122,14 +1198,20 @@ function createHlsAdPlayer(contentVideo, options) {
1122
1198
  }
1123
1199
  const vastXml = await response.text();
1124
1200
  console.log("[HlsAdPlayer] VAST XML received");
1125
- console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1201
+ console.log(
1202
+ "[HlsAdPlayer] VAST XML content (first 2000 chars):",
1203
+ vastXml.substring(0, 2e3)
1204
+ );
1126
1205
  const ad = parseVastXml(vastXml);
1127
1206
  if (!ad) {
1128
1207
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1208
+ emit("ad_error");
1129
1209
  return Promise.resolve();
1130
1210
  }
1131
1211
  currentAd = ad;
1132
- console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
1212
+ console.log(
1213
+ `[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`
1214
+ );
1133
1215
  fireTrackingPixels(ad.trackingUrls.impression);
1134
1216
  trackingFired.impression = true;
1135
1217
  return Promise.resolve();
@@ -1141,7 +1223,9 @@ function createHlsAdPlayer(contentVideo, options) {
1141
1223
  },
1142
1224
  async play() {
1143
1225
  if (!currentAd) {
1144
- console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
1226
+ console.warn(
1227
+ "[HlsAdPlayer] Cannot play: No ad loaded (no ads available)"
1228
+ );
1145
1229
  return Promise.reject(new Error("No ad loaded"));
1146
1230
  }
1147
1231
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1159,6 +1243,7 @@ function createHlsAdPlayer(contentVideo, options) {
1159
1243
  thirdQuartile: false,
1160
1244
  complete: false
1161
1245
  };
1246
+ const contentVolume = contentVideo.volume;
1162
1247
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1163
1248
  contentVideo.pause();
1164
1249
  console.log("[HlsAdPlayer] Content paused (VOD mode)");
@@ -1167,6 +1252,15 @@ function createHlsAdPlayer(contentVideo, options) {
1167
1252
  }
1168
1253
  contentVideo.muted = true;
1169
1254
  adPlaying = true;
1255
+ setAdPlayingFlag(true);
1256
+ if (adVideoElement) {
1257
+ const adVolume = originalMutedState ? 0 : contentVolume;
1258
+ adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
1259
+ adVideoElement.muted = false;
1260
+ console.log(
1261
+ `[HlsAdPlayer] Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}, originalMutedState: ${originalMutedState}, contentVolume: ${contentVolume}`
1262
+ );
1263
+ }
1170
1264
  if (adContainerEl) {
1171
1265
  adContainerEl.style.display = "flex";
1172
1266
  adContainerEl.style.pointerEvents = "auto";
@@ -1219,6 +1313,7 @@ function createHlsAdPlayer(contentVideo, options) {
1219
1313
  async stop() {
1220
1314
  console.log("[HlsAdPlayer] Stopping ad");
1221
1315
  adPlaying = false;
1316
+ setAdPlayingFlag(false);
1222
1317
  contentVideo.muted = originalMutedState;
1223
1318
  if (adContainerEl) {
1224
1319
  adContainerEl.style.display = "none";
@@ -1241,6 +1336,7 @@ function createHlsAdPlayer(contentVideo, options) {
1241
1336
  destroy() {
1242
1337
  console.log("[HlsAdPlayer] Destroying");
1243
1338
  adPlaying = false;
1339
+ setAdPlayingFlag(false);
1244
1340
  contentVideo.muted = originalMutedState;
1245
1341
  if (adHls) {
1246
1342
  adHls.destroy();
@@ -1282,6 +1378,9 @@ function createHlsAdPlayer(contentVideo, options) {
1282
1378
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
1283
1379
  },
1284
1380
  updateOriginalMutedState(muted) {
1381
+ console.log(
1382
+ `[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
1383
+ );
1285
1384
  originalMutedState = muted;
1286
1385
  },
1287
1386
  getOriginalMutedState() {
@@ -1774,6 +1873,9 @@ var StormcloudVideoPlayer = class {
1774
1873
  this.isLiveStream = false;
1775
1874
  this.nativeHlsMode = false;
1776
1875
  this.videoSrcProtection = null;
1876
+ this.bufferedSegmentsCount = 0;
1877
+ this.shouldAutoplayAfterBuffering = false;
1878
+ this.hasInitialBufferCompleted = false;
1777
1879
  initializePolyfills();
1778
1880
  const browserOverrides = getBrowserConfigOverrides();
1779
1881
  this.config = { ...config, ...browserOverrides };
@@ -1860,14 +1962,22 @@ var StormcloudVideoPlayer = class {
1860
1962
  liveDurationInfinity: true,
1861
1963
  lowLatencyMode: !!this.config.lowLatencyMode,
1862
1964
  maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
1863
- ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}
1965
+ ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {},
1966
+ maxBufferLength: 30,
1967
+ maxMaxBufferLength: 600,
1968
+ maxBufferSize: 60 * 1e3 * 1e3,
1969
+ maxBufferHole: 0.5,
1970
+ highBufferWatchdogPeriod: 2,
1971
+ nudgeOffset: 0.1,
1972
+ nudgeMaxRetry: 3,
1973
+ startPosition: -1
1864
1974
  });
1865
1975
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
1866
1976
  var _a2;
1867
1977
  (_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
1868
1978
  });
1869
1979
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
1870
- var _a2, _b2, _c, _d;
1980
+ var _a2, _b2, _c, _d, _e;
1871
1981
  this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
1872
1982
  (level) => {
1873
1983
  var _a3, _b3;
@@ -1885,9 +1995,51 @@ var StormcloudVideoPlayer = class {
1885
1995
  this.ima.destroy();
1886
1996
  this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
1887
1997
  this.ima.initialize();
1888
- if (this.config.autoplay) {
1889
- await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
1890
- }));
1998
+ this.bufferedSegmentsCount = 0;
1999
+ this.hasInitialBufferCompleted = false;
2000
+ this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
2001
+ const minSegments = (_d = this.config.minSegmentsBeforePlay) != null ? _d : 2;
2002
+ if (this.config.debugAdTiming) {
2003
+ console.log(
2004
+ "[StormcloudVideoPlayer] Waiting for",
2005
+ minSegments,
2006
+ "segments to buffer before playback"
2007
+ );
2008
+ }
2009
+ if (minSegments === 0 || !this.config.autoplay) {
2010
+ this.hasInitialBufferCompleted = true;
2011
+ if (this.config.autoplay) {
2012
+ await ((_e = this.video.play()) == null ? void 0 : _e.catch(() => {
2013
+ }));
2014
+ }
2015
+ }
2016
+ });
2017
+ this.hls.on(import_hls2.default.Events.FRAG_BUFFERED, async (_evt, data) => {
2018
+ var _a2, _b2;
2019
+ if (this.hasInitialBufferCompleted) {
2020
+ return;
2021
+ }
2022
+ this.bufferedSegmentsCount++;
2023
+ const minSegments = (_a2 = this.config.minSegmentsBeforePlay) != null ? _a2 : 2;
2024
+ if (this.config.debugAdTiming) {
2025
+ console.log(
2026
+ `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`
2027
+ );
2028
+ }
2029
+ if (this.bufferedSegmentsCount >= minSegments) {
2030
+ this.hasInitialBufferCompleted = true;
2031
+ if (this.shouldAutoplayAfterBuffering) {
2032
+ if (this.config.debugAdTiming) {
2033
+ console.log(
2034
+ `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`
2035
+ );
2036
+ }
2037
+ await ((_b2 = this.video.play()) == null ? void 0 : _b2.catch((err) => {
2038
+ if (this.config.debugAdTiming) {
2039
+ console.warn("[StormcloudVideoPlayer] Autoplay failed:", err);
2040
+ }
2041
+ }));
2042
+ }
1891
2043
  }
1892
2044
  });
1893
2045
  this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
@@ -1983,6 +2135,7 @@ var StormcloudVideoPlayer = class {
1983
2135
  this.video.autoplay = !!this.config.autoplay;
1984
2136
  this.video.muted = !!this.config.muted;
1985
2137
  this.ima.initialize();
2138
+ this.ima.updateOriginalMutedState(this.video.muted);
1986
2139
  this.ima.on("all_ads_completed", () => {
1987
2140
  if (this.config.debugAdTiming) {
1988
2141
  console.log(
@@ -2767,7 +2920,23 @@ var StormcloudVideoPlayer = class {
2767
2920
  }
2768
2921
  return;
2769
2922
  }
2770
- this.ima.updateOriginalMutedState(this.video.muted);
2923
+ if (!this.showAds) {
2924
+ if (this.config.debugAdTiming) {
2925
+ console.log(
2926
+ `[StormcloudVideoPlayer] Capturing original state before ad request:`,
2927
+ {
2928
+ videoMuted: this.video.muted,
2929
+ videoVolume: this.video.volume,
2930
+ showAds: this.showAds
2931
+ }
2932
+ );
2933
+ }
2934
+ this.ima.updateOriginalMutedState(this.video.muted);
2935
+ } else if (this.config.debugAdTiming) {
2936
+ console.log(
2937
+ `[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
2938
+ );
2939
+ }
2771
2940
  this.startAdFailsafeTimer();
2772
2941
  try {
2773
2942
  await this.ima.requestAds(vastTagUrl);
@@ -2822,11 +2991,12 @@ var StormcloudVideoPlayer = class {
2822
2991
  this.showAds = false;
2823
2992
  this.currentAdIndex = 0;
2824
2993
  this.totalAdsInBreak = 0;
2994
+ const currentMutedState = this.video.muted;
2825
2995
  const originalMutedState = this.ima.getOriginalMutedState();
2826
2996
  this.video.muted = originalMutedState;
2827
2997
  if (this.config.debugAdTiming) {
2828
2998
  console.log(
2829
- `[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
2999
+ `[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
2830
3000
  );
2831
3001
  }
2832
3002
  if (this.video.paused) {
@@ -2918,6 +3088,7 @@ var StormcloudVideoPlayer = class {
2918
3088
  }
2919
3089
  } else {
2920
3090
  this.video.muted = !this.video.muted;
3091
+ this.ima.updateOriginalMutedState(this.video.muted);
2921
3092
  if (this.config.debugAdTiming) {
2922
3093
  console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
2923
3094
  }
@@ -2962,11 +3133,47 @@ var StormcloudVideoPlayer = class {
2962
3133
  }
2963
3134
  isMuted() {
2964
3135
  if (this.ima.isAdPlaying()) {
2965
- const adVolume = this.ima.getAdVolume();
2966
- return adVolume === 0;
3136
+ if (this.config.debugAdTiming) {
3137
+ console.log(
3138
+ "[StormcloudVideoPlayer] isMuted() override during ad playback -> false"
3139
+ );
3140
+ }
3141
+ return false;
3142
+ }
3143
+ if (this.config.debugAdTiming) {
3144
+ console.log(
3145
+ `[StormcloudVideoPlayer] isMuted() no ad playing: video.muted=${this.video.muted}`
3146
+ );
2967
3147
  }
2968
3148
  return this.video.muted;
2969
3149
  }
3150
+ setMuted(muted) {
3151
+ const adPlaying = this.ima.isAdPlaying();
3152
+ if (adPlaying && muted === this.video.muted) {
3153
+ if (this.config.debugAdTiming) {
3154
+ console.log(
3155
+ "[StormcloudVideoPlayer] setMuted reflective update during ad ignored",
3156
+ { muted }
3157
+ );
3158
+ }
3159
+ return;
3160
+ }
3161
+ this.video.muted = muted;
3162
+ if (adPlaying) {
3163
+ this.ima.updateOriginalMutedState(muted);
3164
+ this.ima.setAdVolume(muted ? 0 : 1);
3165
+ if (this.config.debugAdTiming) {
3166
+ console.log("[StormcloudVideoPlayer] setMuted applied during ad", {
3167
+ muted
3168
+ });
3169
+ }
3170
+ return;
3171
+ }
3172
+ this.ima.updateOriginalMutedState(muted);
3173
+ if (this.config.debugAdTiming) {
3174
+ console.log("[StormcloudVideoPlayer] setMuted called:", muted);
3175
+ }
3176
+ }
2970
3177
  isFullscreen() {
2971
3178
  return !!document.fullscreenElement;
2972
3179
  }