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,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;
@@ -287,6 +294,14 @@ function createImaController(video, options) {
287
294
  function makeAdsRequest(google, vastTagUrl) {
288
295
  const adsRequest = new google.ima.AdsRequest();
289
296
  adsRequest.adTagUrl = vastTagUrl;
297
+ const videoWidth = video.offsetWidth || video.clientWidth || 640;
298
+ const videoHeight = video.offsetHeight || video.clientHeight || 360;
299
+ adsRequest.linearAdSlotWidth = videoWidth;
300
+ adsRequest.linearAdSlotHeight = videoHeight;
301
+ adsRequest.nonLinearAdSlotWidth = videoWidth;
302
+ adsRequest.nonLinearAdSlotHeight = videoHeight;
303
+ adsRequest.vastLoadTimeout = 5e3;
304
+ console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
290
305
  adsLoader.requestAds(adsRequest);
291
306
  }
292
307
  function destroyAdsManager() {
@@ -333,6 +348,18 @@ function createImaController(video, options) {
333
348
  },
334
349
  async requestAds(vastTagUrl) {
335
350
  console.log("[IMA] Requesting ads:", vastTagUrl);
351
+ if (!vastTagUrl || vastTagUrl.trim() === "") {
352
+ const error = new Error("VAST tag URL is empty or undefined");
353
+ console.warn("[IMA]", error.message);
354
+ return Promise.reject(error);
355
+ }
356
+ try {
357
+ new URL(vastTagUrl);
358
+ } catch (e) {
359
+ const error = new Error(`Invalid VAST tag URL format: ${vastTagUrl}`);
360
+ console.warn("[IMA]", error.message);
361
+ return Promise.reject(error);
362
+ }
336
363
  if (adPlaying) {
337
364
  console.warn(
338
365
  "[IMA] Cannot request new ads while an ad is playing. Call stop() first."
@@ -394,6 +421,18 @@ function createImaController(video, options) {
394
421
  );
395
422
  }
396
423
  }
424
+ const videoWidth = video.offsetWidth || video.clientWidth;
425
+ const videoHeight = video.offsetHeight || video.clientHeight;
426
+ if (!videoWidth || !videoHeight || videoWidth === 0 || videoHeight === 0) {
427
+ const error = new Error(
428
+ `Invalid video dimensions: ${videoWidth}x${videoHeight}. Cannot initialize ads.`
429
+ );
430
+ console.warn("[IMA]", error.message);
431
+ currentReject == null ? void 0 : currentReject(error);
432
+ adsLoadedReject = void 0;
433
+ adsLoadedResolve = void 0;
434
+ return Promise.reject(error);
435
+ }
397
436
  if (!adsLoader) {
398
437
  console.log("[IMA] Creating ads loader");
399
438
  const adsLoaderCls = new google.ima.AdsLoader(adDisplayContainer);
@@ -413,7 +452,12 @@ function createImaController(video, options) {
413
452
  console.error("[IMA] Ad error:", errorEvent.getError());
414
453
  destroyAdsManager();
415
454
  adPlaying = false;
455
+ const previousMutedState = video.muted;
416
456
  video.muted = originalMutedState;
457
+ setAdPlayingFlag(false);
458
+ console.log(
459
+ `[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
460
+ );
417
461
  if (adContainerEl) {
418
462
  adContainerEl.style.pointerEvents = "none";
419
463
  adContainerEl.style.display = "none";
@@ -442,7 +486,9 @@ function createImaController(video, options) {
442
486
  emit("ad_error");
443
487
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
444
488
  if (video.paused) {
445
- console.log("[IMA] Resuming paused video after ad error");
489
+ console.log(
490
+ "[IMA] Resuming paused video after ad error"
491
+ );
446
492
  (_a = video.play()) == null ? void 0 : _a.catch(() => {
447
493
  });
448
494
  }
@@ -464,11 +510,13 @@ function createImaController(video, options) {
464
510
  }
465
511
  video.muted = true;
466
512
  adPlaying = true;
513
+ setAdPlayingFlag(true);
467
514
  emit("content_pause");
468
515
  }
469
516
  );
470
517
  adsManager.addEventListener(AdEvent.STARTED, () => {
471
518
  console.log("[IMA] Ad started playing");
519
+ setAdPlayingFlag(true);
472
520
  if (adContainerEl) {
473
521
  adContainerEl.style.pointerEvents = "auto";
474
522
  adContainerEl.style.display = "flex";
@@ -484,6 +532,7 @@ function createImaController(video, options) {
484
532
  console.log("[IMA] Content resume requested");
485
533
  adPlaying = false;
486
534
  video.muted = originalMutedState;
535
+ setAdPlayingFlag(false);
487
536
  if (adContainerEl) {
488
537
  adContainerEl.style.pointerEvents = "none";
489
538
  adContainerEl.style.display = "none";
@@ -507,6 +556,7 @@ function createImaController(video, options) {
507
556
  console.log("[IMA] All ads completed");
508
557
  adPlaying = false;
509
558
  video.muted = originalMutedState;
559
+ setAdPlayingFlag(false);
510
560
  if (adContainerEl) {
511
561
  adContainerEl.style.pointerEvents = "none";
512
562
  adContainerEl.style.display = "none";
@@ -537,6 +587,7 @@ function createImaController(video, options) {
537
587
  console.error("[IMA] Error setting up ads manager:", e);
538
588
  adPlaying = false;
539
589
  video.muted = originalMutedState;
590
+ setAdPlayingFlag(false);
540
591
  if (adContainerEl) {
541
592
  adContainerEl.style.pointerEvents = "none";
542
593
  adContainerEl.style.display = "none";
@@ -544,7 +595,9 @@ function createImaController(video, options) {
544
595
  }
545
596
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
546
597
  if (video.paused) {
547
- console.log("[IMA] Resuming paused video after setup error");
598
+ console.log(
599
+ "[IMA] Resuming paused video after setup error"
600
+ );
548
601
  video.play().catch(() => {
549
602
  });
550
603
  }
@@ -564,7 +617,12 @@ function createImaController(video, options) {
564
617
  (adErrorEvent) => {
565
618
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
566
619
  adPlaying = false;
620
+ const previousMutedState = video.muted;
567
621
  video.muted = originalMutedState;
622
+ setAdPlayingFlag(false);
623
+ console.log(
624
+ `[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
625
+ );
568
626
  if (adContainerEl) {
569
627
  adContainerEl.style.pointerEvents = "none";
570
628
  adContainerEl.style.display = "none";
@@ -616,12 +674,20 @@ function createImaController(video, options) {
616
674
  console.log(`[IMA] Initializing ads manager (${width}x${height})`);
617
675
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
618
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
+ }
619
684
  console.log("[IMA] Starting ad playback");
620
685
  adsManager.start();
621
686
  return Promise.resolve();
622
687
  } catch (error) {
623
688
  console.error("[IMA] Error starting ad playback:", error);
624
689
  adPlaying = false;
690
+ setAdPlayingFlag(false);
625
691
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
626
692
  (_b = video.play()) == null ? void 0 : _b.catch(() => {
627
693
  });
@@ -633,6 +699,7 @@ function createImaController(video, options) {
633
699
  var _a;
634
700
  adPlaying = false;
635
701
  video.muted = originalMutedState;
702
+ setAdPlayingFlag(false);
636
703
  if (adContainerEl) {
637
704
  adContainerEl.style.pointerEvents = "none";
638
705
  adContainerEl.style.display = "none";
@@ -656,6 +723,7 @@ function createImaController(video, options) {
656
723
  destroyAdsManager();
657
724
  adPlaying = false;
658
725
  video.muted = originalMutedState;
726
+ setAdPlayingFlag(false);
659
727
  if (adContainerEl) {
660
728
  adContainerEl.style.pointerEvents = "none";
661
729
  adContainerEl.style.display = "none";
@@ -698,6 +766,9 @@ function createImaController(video, options) {
698
766
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
699
767
  },
700
768
  updateOriginalMutedState(muted) {
769
+ console.log(
770
+ `[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
771
+ );
701
772
  originalMutedState = muted;
702
773
  },
703
774
  getOriginalMutedState() {
@@ -754,7 +825,10 @@ function createHlsAdPlayer(contentVideo, options) {
754
825
  try {
755
826
  fn(payload);
756
827
  } catch (error) {
757
- console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
828
+ console.warn(
829
+ `[HlsAdPlayer] Error in event listener for ${event}:`,
830
+ error
831
+ );
758
832
  }
759
833
  }
760
834
  }
@@ -817,7 +891,9 @@ function createHlsAdPlayer(contentVideo, options) {
817
891
  }
818
892
  const mainQuality = getMainStreamQuality();
819
893
  if (!mainQuality) {
820
- 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
+ );
821
897
  return firstFile;
822
898
  }
823
899
  console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
@@ -853,7 +929,10 @@ function createHlsAdPlayer(contentVideo, options) {
853
929
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
854
930
  const parserError = xmlDoc.querySelector("parsererror");
855
931
  if (parserError) {
856
- 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
+ );
857
936
  return null;
858
937
  }
859
938
  const adElement = xmlDoc.querySelector("Ad");
@@ -869,17 +948,23 @@ function createHlsAdPlayer(contentVideo, options) {
869
948
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
870
949
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
871
950
  const mediaFiles = [];
872
- 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
+ );
873
954
  mediaFileElements.forEach((mf, index) => {
874
955
  var _a2;
875
956
  const type = mf.getAttribute("type") || "";
876
957
  const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
877
958
  const width = mf.getAttribute("width") || "";
878
959
  const height = mf.getAttribute("height") || "";
879
- 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
+ );
880
963
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
881
964
  if (!url) {
882
- 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
+ );
883
968
  return;
884
969
  }
885
970
  const bitrateAttr = mf.getAttribute("bitrate");
@@ -893,12 +978,16 @@ function createHlsAdPlayer(contentVideo, options) {
893
978
  });
894
979
  console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
895
980
  } else {
896
- 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
+ );
897
984
  }
898
985
  });
899
986
  if (mediaFiles.length === 0) {
900
987
  if (isNoAdAvailable) {
901
- 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
+ );
902
991
  } else {
903
992
  console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
904
993
  }
@@ -961,6 +1050,10 @@ function createHlsAdPlayer(contentVideo, options) {
961
1050
  video.style.backgroundColor = "#000";
962
1051
  video.playsInline = true;
963
1052
  video.muted = false;
1053
+ video.volume = 1;
1054
+ console.log(
1055
+ `[HlsAdPlayer] Created ad video element with volume ${video.volume}`
1056
+ );
964
1057
  return video;
965
1058
  }
966
1059
  function setupAdEventListeners() {
@@ -1020,10 +1113,22 @@ function createHlsAdPlayer(contentVideo, options) {
1020
1113
  }
1021
1114
  });
1022
1115
  }
1116
+ function setAdPlayingFlag(isPlaying) {
1117
+ if (isPlaying) {
1118
+ contentVideo.dataset.stormcloudAdPlaying = "true";
1119
+ } else {
1120
+ delete contentVideo.dataset.stormcloudAdPlaying;
1121
+ }
1122
+ }
1023
1123
  function handleAdComplete() {
1024
1124
  console.log("[HlsAdPlayer] Handling ad completion");
1025
1125
  adPlaying = false;
1126
+ setAdPlayingFlag(false);
1127
+ const previousMutedState = contentVideo.muted;
1026
1128
  contentVideo.muted = originalMutedState;
1129
+ console.log(
1130
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1131
+ );
1027
1132
  if (adContainerEl) {
1028
1133
  adContainerEl.style.display = "none";
1029
1134
  adContainerEl.style.pointerEvents = "none";
@@ -1041,7 +1146,12 @@ function createHlsAdPlayer(contentVideo, options) {
1041
1146
  function handleAdError() {
1042
1147
  console.log("[HlsAdPlayer] Handling ad error");
1043
1148
  adPlaying = false;
1149
+ setAdPlayingFlag(false);
1150
+ const previousMutedState = contentVideo.muted;
1044
1151
  contentVideo.muted = originalMutedState;
1152
+ console.log(
1153
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1154
+ );
1045
1155
  if (adContainerEl) {
1046
1156
  adContainerEl.style.display = "none";
1047
1157
  adContainerEl.style.pointerEvents = "none";
@@ -1078,7 +1188,9 @@ function createHlsAdPlayer(contentVideo, options) {
1078
1188
  async requestAds(vastTagUrl) {
1079
1189
  console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
1080
1190
  if (adPlaying) {
1081
- 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
+ );
1082
1194
  return Promise.reject(new Error("Ad already playing"));
1083
1195
  }
1084
1196
  try {
@@ -1089,14 +1201,20 @@ function createHlsAdPlayer(contentVideo, options) {
1089
1201
  }
1090
1202
  const vastXml = await response.text();
1091
1203
  console.log("[HlsAdPlayer] VAST XML received");
1092
- 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
+ );
1093
1208
  const ad = parseVastXml(vastXml);
1094
1209
  if (!ad) {
1095
1210
  console.warn("[HlsAdPlayer] No ads available from VAST response");
1211
+ emit("ad_error");
1096
1212
  return Promise.resolve();
1097
1213
  }
1098
1214
  currentAd = ad;
1099
- 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
+ );
1100
1218
  fireTrackingPixels(ad.trackingUrls.impression);
1101
1219
  trackingFired.impression = true;
1102
1220
  return Promise.resolve();
@@ -1108,7 +1226,9 @@ function createHlsAdPlayer(contentVideo, options) {
1108
1226
  },
1109
1227
  async play() {
1110
1228
  if (!currentAd) {
1111
- 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
+ );
1112
1232
  return Promise.reject(new Error("No ad loaded"));
1113
1233
  }
1114
1234
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1126,6 +1246,7 @@ function createHlsAdPlayer(contentVideo, options) {
1126
1246
  thirdQuartile: false,
1127
1247
  complete: false
1128
1248
  };
1249
+ const contentVolume = contentVideo.volume;
1129
1250
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1130
1251
  contentVideo.pause();
1131
1252
  console.log("[HlsAdPlayer] Content paused (VOD mode)");
@@ -1134,6 +1255,15 @@ function createHlsAdPlayer(contentVideo, options) {
1134
1255
  }
1135
1256
  contentVideo.muted = true;
1136
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
+ }
1137
1267
  if (adContainerEl) {
1138
1268
  adContainerEl.style.display = "flex";
1139
1269
  adContainerEl.style.pointerEvents = "auto";
@@ -1186,6 +1316,7 @@ function createHlsAdPlayer(contentVideo, options) {
1186
1316
  async stop() {
1187
1317
  console.log("[HlsAdPlayer] Stopping ad");
1188
1318
  adPlaying = false;
1319
+ setAdPlayingFlag(false);
1189
1320
  contentVideo.muted = originalMutedState;
1190
1321
  if (adContainerEl) {
1191
1322
  adContainerEl.style.display = "none";
@@ -1208,6 +1339,7 @@ function createHlsAdPlayer(contentVideo, options) {
1208
1339
  destroy() {
1209
1340
  console.log("[HlsAdPlayer] Destroying");
1210
1341
  adPlaying = false;
1342
+ setAdPlayingFlag(false);
1211
1343
  contentVideo.muted = originalMutedState;
1212
1344
  if (adHls) {
1213
1345
  adHls.destroy();
@@ -1249,6 +1381,9 @@ function createHlsAdPlayer(contentVideo, options) {
1249
1381
  (_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
1250
1382
  },
1251
1383
  updateOriginalMutedState(muted) {
1384
+ console.log(
1385
+ `[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
1386
+ );
1252
1387
  originalMutedState = muted;
1253
1388
  },
1254
1389
  getOriginalMutedState() {
@@ -1741,6 +1876,9 @@ var StormcloudVideoPlayer = class {
1741
1876
  this.isLiveStream = false;
1742
1877
  this.nativeHlsMode = false;
1743
1878
  this.videoSrcProtection = null;
1879
+ this.bufferedSegmentsCount = 0;
1880
+ this.shouldAutoplayAfterBuffering = false;
1881
+ this.hasInitialBufferCompleted = false;
1744
1882
  initializePolyfills();
1745
1883
  const browserOverrides = getBrowserConfigOverrides();
1746
1884
  this.config = { ...config, ...browserOverrides };
@@ -1827,14 +1965,22 @@ var StormcloudVideoPlayer = class {
1827
1965
  liveDurationInfinity: true,
1828
1966
  lowLatencyMode: !!this.config.lowLatencyMode,
1829
1967
  maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
1830
- ...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
1831
1977
  });
1832
1978
  this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
1833
1979
  var _a2;
1834
1980
  (_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
1835
1981
  });
1836
1982
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
1837
- var _a2, _b2, _c, _d;
1983
+ var _a2, _b2, _c, _d, _e;
1838
1984
  this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
1839
1985
  (level) => {
1840
1986
  var _a3, _b3;
@@ -1852,9 +1998,51 @@ var StormcloudVideoPlayer = class {
1852
1998
  this.ima.destroy();
1853
1999
  this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
1854
2000
  this.ima.initialize();
1855
- if (this.config.autoplay) {
1856
- await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
1857
- }));
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
+ }
1858
2046
  }
1859
2047
  });
1860
2048
  this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
@@ -1950,6 +2138,7 @@ var StormcloudVideoPlayer = class {
1950
2138
  this.video.autoplay = !!this.config.autoplay;
1951
2139
  this.video.muted = !!this.config.muted;
1952
2140
  this.ima.initialize();
2141
+ this.ima.updateOriginalMutedState(this.video.muted);
1953
2142
  this.ima.on("all_ads_completed", () => {
1954
2143
  if (this.config.debugAdTiming) {
1955
2144
  console.log(
@@ -2734,7 +2923,23 @@ var StormcloudVideoPlayer = class {
2734
2923
  }
2735
2924
  return;
2736
2925
  }
2737
- 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
+ }
2738
2943
  this.startAdFailsafeTimer();
2739
2944
  try {
2740
2945
  await this.ima.requestAds(vastTagUrl);
@@ -2789,11 +2994,12 @@ var StormcloudVideoPlayer = class {
2789
2994
  this.showAds = false;
2790
2995
  this.currentAdIndex = 0;
2791
2996
  this.totalAdsInBreak = 0;
2997
+ const currentMutedState = this.video.muted;
2792
2998
  const originalMutedState = this.ima.getOriginalMutedState();
2793
2999
  this.video.muted = originalMutedState;
2794
3000
  if (this.config.debugAdTiming) {
2795
3001
  console.log(
2796
- `[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
3002
+ `[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
2797
3003
  );
2798
3004
  }
2799
3005
  if (this.video.paused) {
@@ -2885,6 +3091,7 @@ var StormcloudVideoPlayer = class {
2885
3091
  }
2886
3092
  } else {
2887
3093
  this.video.muted = !this.video.muted;
3094
+ this.ima.updateOriginalMutedState(this.video.muted);
2888
3095
  if (this.config.debugAdTiming) {
2889
3096
  console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
2890
3097
  }
@@ -2929,11 +3136,47 @@ var StormcloudVideoPlayer = class {
2929
3136
  }
2930
3137
  isMuted() {
2931
3138
  if (this.ima.isAdPlaying()) {
2932
- const adVolume = this.ima.getAdVolume();
2933
- 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
+ );
2934
3150
  }
2935
3151
  return this.video.muted;
2936
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
+ }
2937
3180
  isFullscreen() {
2938
3181
  return !!document.fullscreenElement;
2939
3182
  }
@@ -3044,6 +3287,8 @@ var HlsPlayer = class extends import_react.Component {
3044
3287
  config.licenseKey = this.props.licenseKey;
3045
3288
  if (this.props.adFailsafeTimeoutMs !== void 0)
3046
3289
  config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
3290
+ if (this.props.minSegmentsBeforePlay !== void 0)
3291
+ config.minSegmentsBeforePlay = this.props.minSegmentsBeforePlay;
3047
3292
  this.player = new StormcloudVideoPlayer(config);
3048
3293
  (_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
3049
3294
  await this.player.load();