stormcloud-video-player 0.2.16 → 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;
@@ -326,6 +333,14 @@ function createImaController(video, options) {
326
333
  function makeAdsRequest(google, vastTagUrl) {
327
334
  const adsRequest = new google.ima.AdsRequest();
328
335
  adsRequest.adTagUrl = vastTagUrl;
336
+ const videoWidth = video.offsetWidth || video.clientWidth || 640;
337
+ const videoHeight = video.offsetHeight || video.clientHeight || 360;
338
+ adsRequest.linearAdSlotWidth = videoWidth;
339
+ adsRequest.linearAdSlotHeight = videoHeight;
340
+ adsRequest.nonLinearAdSlotWidth = videoWidth;
341
+ adsRequest.nonLinearAdSlotHeight = videoHeight;
342
+ adsRequest.vastLoadTimeout = 5e3;
343
+ console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
329
344
  adsLoader.requestAds(adsRequest);
330
345
  }
331
346
  function destroyAdsManager() {
@@ -372,6 +387,18 @@ function createImaController(video, options) {
372
387
  },
373
388
  async requestAds(vastTagUrl) {
374
389
  console.log("[IMA] Requesting ads:", vastTagUrl);
390
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
391
+ const error = new Error("VAST tag URL is empty or undefined");
392
+ console.warn("[IMA]", error.message);
393
+ return Promise.reject(error);
394
+ }
395
+ try {
396
+ new URL(vastTagUrl);
397
+ } catch (e) {
398
+ const error = new Error(`Invalid VAST tag URL format: ${vastTagUrl}`);
399
+ console.warn("[IMA]", error.message);
400
+ return Promise.reject(error);
401
+ }
375
402
  if (adPlaying) {
376
403
  console.warn(
377
404
  "[IMA] Cannot request new ads while an ad is playing. Call stop() first."
@@ -433,6 +460,18 @@ function createImaController(video, options) {
433
460
  );
434
461
  }
435
462
  }
463
+ const videoWidth = video.offsetWidth || video.clientWidth;
464
+ const videoHeight = video.offsetHeight || video.clientHeight;
465
+ if (!videoWidth || !videoHeight || videoWidth === 0 || videoHeight === 0) {
466
+ const error = new Error(
467
+ `Invalid video dimensions: ${videoWidth}x${videoHeight}. Cannot initialize ads.`
468
+ );
469
+ console.warn("[IMA]", error.message);
470
+ currentReject == null ? void 0 : currentReject(error);
471
+ adsLoadedReject = void 0;
472
+ adsLoadedResolve = void 0;
473
+ return Promise.reject(error);
474
+ }
436
475
  if (!adsLoader) {
437
476
  console.log("[IMA] Creating ads loader");
438
477
  const adsLoaderCls = new google.ima.AdsLoader(adDisplayContainer);
@@ -452,7 +491,12 @@ function createImaController(video, options) {
452
491
  console.error("[IMA] Ad error:", errorEvent.getError());
453
492
  destroyAdsManager();
454
493
  adPlaying = false;
494
+ const previousMutedState = video.muted;
455
495
  video.muted = originalMutedState;
496
+ setAdPlayingFlag(false);
497
+ console.log(
498
+ `[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
499
+ );
456
500
  if (adContainerEl) {
457
501
  adContainerEl.style.pointerEvents = "none";
458
502
  adContainerEl.style.display = "none";
@@ -481,7 +525,9 @@ function createImaController(video, options) {
481
525
  emit("ad_error");
482
526
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
483
527
  if (video.paused) {
484
- console.log("[IMA] Resuming paused video after ad error");
528
+ console.log(
529
+ "[IMA] Resuming paused video after ad error"
530
+ );
485
531
  (_a = video.play()) == null ? void 0 : _a.catch(() => {
486
532
  });
487
533
  }
@@ -503,11 +549,13 @@ function createImaController(video, options) {
503
549
  }
504
550
  video.muted = true;
505
551
  adPlaying = true;
552
+ setAdPlayingFlag(true);
506
553
  emit("content_pause");
507
554
  }
508
555
  );
509
556
  adsManager.addEventListener(AdEvent.STARTED, () => {
510
557
  console.log("[IMA] Ad started playing");
558
+ setAdPlayingFlag(true);
511
559
  if (adContainerEl) {
512
560
  adContainerEl.style.pointerEvents = "auto";
513
561
  adContainerEl.style.display = "flex";
@@ -523,6 +571,7 @@ function createImaController(video, options) {
523
571
  console.log("[IMA] Content resume requested");
524
572
  adPlaying = false;
525
573
  video.muted = originalMutedState;
574
+ setAdPlayingFlag(false);
526
575
  if (adContainerEl) {
527
576
  adContainerEl.style.pointerEvents = "none";
528
577
  adContainerEl.style.display = "none";
@@ -546,6 +595,7 @@ function createImaController(video, options) {
546
595
  console.log("[IMA] All ads completed");
547
596
  adPlaying = false;
548
597
  video.muted = originalMutedState;
598
+ setAdPlayingFlag(false);
549
599
  if (adContainerEl) {
550
600
  adContainerEl.style.pointerEvents = "none";
551
601
  adContainerEl.style.display = "none";
@@ -576,6 +626,7 @@ function createImaController(video, options) {
576
626
  console.error("[IMA] Error setting up ads manager:", e);
577
627
  adPlaying = false;
578
628
  video.muted = originalMutedState;
629
+ setAdPlayingFlag(false);
579
630
  if (adContainerEl) {
580
631
  adContainerEl.style.pointerEvents = "none";
581
632
  adContainerEl.style.display = "none";
@@ -583,7 +634,9 @@ function createImaController(video, options) {
583
634
  }
584
635
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
585
636
  if (video.paused) {
586
- console.log("[IMA] Resuming paused video after setup error");
637
+ console.log(
638
+ "[IMA] Resuming paused video after setup error"
639
+ );
587
640
  video.play().catch(() => {
588
641
  });
589
642
  }
@@ -603,7 +656,12 @@ function createImaController(video, options) {
603
656
  (adErrorEvent) => {
604
657
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
605
658
  adPlaying = false;
659
+ const previousMutedState = video.muted;
606
660
  video.muted = originalMutedState;
661
+ setAdPlayingFlag(false);
662
+ console.log(
663
+ `[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
664
+ );
607
665
  if (adContainerEl) {
608
666
  adContainerEl.style.pointerEvents = "none";
609
667
  adContainerEl.style.display = "none";
@@ -655,12 +713,20 @@ function createImaController(video, options) {
655
713
  console.log(`[IMA] Initializing ads manager (${width}x${height})`);
656
714
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
657
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
+ }
658
723
  console.log("[IMA] Starting ad playback");
659
724
  adsManager.start();
660
725
  return Promise.resolve();
661
726
  } catch (error) {
662
727
  console.error("[IMA] Error starting ad playback:", error);
663
728
  adPlaying = false;
729
+ setAdPlayingFlag(false);
664
730
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
665
731
  (_b = video.play()) == null ? void 0 : _b.catch(() => {
666
732
  });
@@ -672,6 +738,7 @@ function createImaController(video, options) {
672
738
  var _a;
673
739
  adPlaying = false;
674
740
  video.muted = originalMutedState;
741
+ setAdPlayingFlag(false);
675
742
  if (adContainerEl) {
676
743
  adContainerEl.style.pointerEvents = "none";
677
744
  adContainerEl.style.display = "none";
@@ -695,6 +762,7 @@ function createImaController(video, options) {
695
762
  destroyAdsManager();
696
763
  adPlaying = false;
697
764
  video.muted = originalMutedState;
765
+ setAdPlayingFlag(false);
698
766
  if (adContainerEl) {
699
767
  adContainerEl.style.pointerEvents = "none";
700
768
  adContainerEl.style.display = "none";
@@ -737,6 +805,9 @@ function createImaController(video, options) {
737
805
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
738
806
  },
739
807
  updateOriginalMutedState(muted) {
808
+ console.log(
809
+ `[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
810
+ );
740
811
  originalMutedState = muted;
741
812
  },
742
813
  getOriginalMutedState() {
@@ -793,7 +864,10 @@ function createHlsAdPlayer(contentVideo, options) {
793
864
  try {
794
865
  fn(payload);
795
866
  } catch (error) {
796
- console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
867
+ console.warn(
868
+ `[HlsAdPlayer] Error in event listener for ${event}:`,
869
+ error
870
+ );
797
871
  }
798
872
  }
799
873
  }
@@ -856,7 +930,9 @@ function createHlsAdPlayer(contentVideo, options) {
856
930
  }
857
931
  const mainQuality = getMainStreamQuality();
858
932
  if (!mainQuality) {
859
- 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
+ );
860
936
  return firstFile;
861
937
  }
862
938
  console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
@@ -892,7 +968,10 @@ function createHlsAdPlayer(contentVideo, options) {
892
968
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
893
969
  const parserError = xmlDoc.querySelector("parsererror");
894
970
  if (parserError) {
895
- 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
+ );
896
975
  return null;
897
976
  }
898
977
  const adElement = xmlDoc.querySelector("Ad");
@@ -908,17 +987,23 @@ function createHlsAdPlayer(contentVideo, options) {
908
987
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
909
988
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
910
989
  const mediaFiles = [];
911
- 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
+ );
912
993
  mediaFileElements.forEach((mf, index) => {
913
994
  var _a2;
914
995
  const type = mf.getAttribute("type") || "";
915
996
  const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
916
997
  const width = mf.getAttribute("width") || "";
917
998
  const height = mf.getAttribute("height") || "";
918
- 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
+ );
919
1002
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
920
1003
  if (!url) {
921
- 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
+ );
922
1007
  return;
923
1008
  }
924
1009
  const bitrateAttr = mf.getAttribute("bitrate");
@@ -932,12 +1017,16 @@ function createHlsAdPlayer(contentVideo, options) {
932
1017
  });
933
1018
  console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
934
1019
  } else {
935
- 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
+ );
936
1023
  }
937
1024
  });
938
1025
  if (mediaFiles.length === 0) {
939
1026
  if (isNoAdAvailable) {
940
- 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
+ );
941
1030
  } else {
942
1031
  console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
943
1032
  }
@@ -1000,6 +1089,10 @@ function createHlsAdPlayer(contentVideo, options) {
1000
1089
  video.style.backgroundColor = "#000";
1001
1090
  video.playsInline = true;
1002
1091
  video.muted = false;
1092
+ video.volume = 1;
1093
+ console.log(
1094
+ `[HlsAdPlayer] Created ad video element with volume ${video.volume}`
1095
+ );
1003
1096
  return video;
1004
1097
  }
1005
1098
  function setupAdEventListeners() {
@@ -1059,10 +1152,22 @@ function createHlsAdPlayer(contentVideo, options) {
1059
1152
  }
1060
1153
  });
1061
1154
  }
1155
+ function setAdPlayingFlag(isPlaying) {
1156
+ if (isPlaying) {
1157
+ contentVideo.dataset.stormcloudAdPlaying = "true";
1158
+ } else {
1159
+ delete contentVideo.dataset.stormcloudAdPlaying;
1160
+ }
1161
+ }
1062
1162
  function handleAdComplete() {
1063
1163
  console.log("[HlsAdPlayer] Handling ad completion");
1064
1164
  adPlaying = false;
1165
+ setAdPlayingFlag(false);
1166
+ const previousMutedState = contentVideo.muted;
1065
1167
  contentVideo.muted = originalMutedState;
1168
+ console.log(
1169
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1170
+ );
1066
1171
  if (adContainerEl) {
1067
1172
  adContainerEl.style.display = "none";
1068
1173
  adContainerEl.style.pointerEvents = "none";
@@ -1080,7 +1185,12 @@ function createHlsAdPlayer(contentVideo, options) {
1080
1185
  function handleAdError() {
1081
1186
  console.log("[HlsAdPlayer] Handling ad error");
1082
1187
  adPlaying = false;
1188
+ setAdPlayingFlag(false);
1189
+ const previousMutedState = contentVideo.muted;
1083
1190
  contentVideo.muted = originalMutedState;
1191
+ console.log(
1192
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1193
+ );
1084
1194
  if (adContainerEl) {
1085
1195
  adContainerEl.style.display = "none";
1086
1196
  adContainerEl.style.pointerEvents = "none";
@@ -1117,7 +1227,9 @@ function createHlsAdPlayer(contentVideo, options) {
1117
1227
  async requestAds(vastTagUrl) {
1118
1228
  console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
1119
1229
  if (adPlaying) {
1120
- 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
+ );
1121
1233
  return Promise.reject(new Error("Ad already playing"));
1122
1234
  }
1123
1235
  try {
@@ -1128,14 +1240,20 @@ function createHlsAdPlayer(contentVideo, options) {
1128
1240
  }
1129
1241
  const vastXml = await response.text();
1130
1242
  console.log("[HlsAdPlayer] VAST XML received");
1131
- 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
+ );
1132
1247
  const ad = parseVastXml(vastXml);
1133
1248
  if (!ad) {
1134
1249
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1250
+ emit("ad_error");
1135
1251
  return Promise.resolve();
1136
1252
  }
1137
1253
  currentAd = ad;
1138
- 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
+ );
1139
1257
  fireTrackingPixels(ad.trackingUrls.impression);
1140
1258
  trackingFired.impression = true;
1141
1259
  return Promise.resolve();
@@ -1147,7 +1265,9 @@ function createHlsAdPlayer(contentVideo, options) {
1147
1265
  },
1148
1266
  async play() {
1149
1267
  if (!currentAd) {
1150
- 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
+ );
1151
1271
  return Promise.reject(new Error("No ad loaded"));
1152
1272
  }
1153
1273
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1165,6 +1285,7 @@ function createHlsAdPlayer(contentVideo, options) {
1165
1285
  thirdQuartile: false,
1166
1286
  complete: false
1167
1287
  };
1288
+ const contentVolume = contentVideo.volume;
1168
1289
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1169
1290
  contentVideo.pause();
1170
1291
  console.log("[HlsAdPlayer] Content paused (VOD mode)");
@@ -1173,6 +1294,15 @@ function createHlsAdPlayer(contentVideo, options) {
1173
1294
  }
1174
1295
  contentVideo.muted = true;
1175
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
+ }
1176
1306
  if (adContainerEl) {
1177
1307
  adContainerEl.style.display = "flex";
1178
1308
  adContainerEl.style.pointerEvents = "auto";
@@ -1225,6 +1355,7 @@ function createHlsAdPlayer(contentVideo, options) {
1225
1355
  async stop() {
1226
1356
  console.log("[HlsAdPlayer] Stopping ad");
1227
1357
  adPlaying = false;
1358
+ setAdPlayingFlag(false);
1228
1359
  contentVideo.muted = originalMutedState;
1229
1360
  if (adContainerEl) {
1230
1361
  adContainerEl.style.display = "none";
@@ -1247,6 +1378,7 @@ function createHlsAdPlayer(contentVideo, options) {
1247
1378
  destroy() {
1248
1379
  console.log("[HlsAdPlayer] Destroying");
1249
1380
  adPlaying = false;
1381
+ setAdPlayingFlag(false);
1250
1382
  contentVideo.muted = originalMutedState;
1251
1383
  if (adHls) {
1252
1384
  adHls.destroy();
@@ -1288,6 +1420,9 @@ function createHlsAdPlayer(contentVideo, options) {
1288
1420
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
1289
1421
  },
1290
1422
  updateOriginalMutedState(muted) {
1423
+ console.log(
1424
+ `[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
1425
+ );
1291
1426
  originalMutedState = muted;
1292
1427
  },
1293
1428
  getOriginalMutedState() {
@@ -1780,6 +1915,9 @@ var StormcloudVideoPlayer = class {
1780
1915
  this.isLiveStream = false;
1781
1916
  this.nativeHlsMode = false;
1782
1917
  this.videoSrcProtection = null;
1918
+ this.bufferedSegmentsCount = 0;
1919
+ this.shouldAutoplayAfterBuffering = false;
1920
+ this.hasInitialBufferCompleted = false;
1783
1921
  initializePolyfills();
1784
1922
  const browserOverrides = getBrowserConfigOverrides();
1785
1923
  this.config = { ...config, ...browserOverrides };
@@ -1866,14 +2004,22 @@ var StormcloudVideoPlayer = class {
1866
2004
  liveDurationInfinity: true,
1867
2005
  lowLatencyMode: !!this.config.lowLatencyMode,
1868
2006
  maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
1869
- ...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
1870
2016
  });
1871
2017
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
1872
2018
  var _a2;
1873
2019
  (_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
1874
2020
  });
1875
2021
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
1876
- var _a2, _b2, _c, _d;
2022
+ var _a2, _b2, _c, _d, _e;
1877
2023
  this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
1878
2024
  (level) => {
1879
2025
  var _a3, _b3;
@@ -1891,9 +2037,51 @@ var StormcloudVideoPlayer = class {
1891
2037
  this.ima.destroy();
1892
2038
  this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
1893
2039
  this.ima.initialize();
1894
- if (this.config.autoplay) {
1895
- await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
1896
- }));
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
+ }
1897
2085
  }
1898
2086
  });
1899
2087
  this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
@@ -1989,6 +2177,7 @@ var StormcloudVideoPlayer = class {
1989
2177
  this.video.autoplay = !!this.config.autoplay;
1990
2178
  this.video.muted = !!this.config.muted;
1991
2179
  this.ima.initialize();
2180
+ this.ima.updateOriginalMutedState(this.video.muted);
1992
2181
  this.ima.on("all_ads_completed", () => {
1993
2182
  if (this.config.debugAdTiming) {
1994
2183
  console.log(
@@ -2773,7 +2962,23 @@ var StormcloudVideoPlayer = class {
2773
2962
  }
2774
2963
  return;
2775
2964
  }
2776
- 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
+ }
2777
2982
  this.startAdFailsafeTimer();
2778
2983
  try {
2779
2984
  await this.ima.requestAds(vastTagUrl);
@@ -2828,11 +3033,12 @@ var StormcloudVideoPlayer = class {
2828
3033
  this.showAds = false;
2829
3034
  this.currentAdIndex = 0;
2830
3035
  this.totalAdsInBreak = 0;
3036
+ const currentMutedState = this.video.muted;
2831
3037
  const originalMutedState = this.ima.getOriginalMutedState();
2832
3038
  this.video.muted = originalMutedState;
2833
3039
  if (this.config.debugAdTiming) {
2834
3040
  console.log(
2835
- `[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
3041
+ `[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
2836
3042
  );
2837
3043
  }
2838
3044
  if (this.video.paused) {
@@ -2924,6 +3130,7 @@ var StormcloudVideoPlayer = class {
2924
3130
  }
2925
3131
  } else {
2926
3132
  this.video.muted = !this.video.muted;
3133
+ this.ima.updateOriginalMutedState(this.video.muted);
2927
3134
  if (this.config.debugAdTiming) {
2928
3135
  console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
2929
3136
  }
@@ -2968,11 +3175,47 @@ var StormcloudVideoPlayer = class {
2968
3175
  }
2969
3176
  isMuted() {
2970
3177
  if (this.ima.isAdPlaying()) {
2971
- const adVolume = this.ima.getAdVolume();
2972
- 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
+ );
2973
3189
  }
2974
3190
  return this.video.muted;
2975
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
+ }
2976
3219
  isFullscreen() {
2977
3220
  return !!document.fullscreenElement;
2978
3221
  }
@@ -3054,6 +3297,8 @@ var HlsPlayer = class extends import_react2.Component {
3054
3297
  config.licenseKey = this.props.licenseKey;
3055
3298
  if (this.props.adFailsafeTimeoutMs !== void 0)
3056
3299
  config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
3300
+ if (this.props.minSegmentsBeforePlay !== void 0)
3301
+ config.minSegmentsBeforePlay = this.props.minSegmentsBeforePlay;
3057
3302
  this.player = new StormcloudVideoPlayer(config);
3058
3303
  (_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
3059
3304
  await this.player.load();