stormcloud-video-player 0.8.53 → 0.8.55

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.
Files changed (70) hide show
  1. package/dist/stormcloud-vp.min.js +1 -1
  2. package/lib/index.cjs +204 -110
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +2 -0
  5. package/lib/index.d.ts +2 -0
  6. package/lib/index.js +204 -110
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/AdBreakOrchestrator.cjs +69 -66
  9. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  10. package/lib/player/AdBreakOrchestrator.d.cts +1 -1
  11. package/lib/player/AdConfigManager.cjs +38 -33
  12. package/lib/player/AdConfigManager.cjs.map +1 -1
  13. package/lib/player/AdConfigManager.d.cts +1 -1
  14. package/lib/player/AdTimingService.cjs +18 -25
  15. package/lib/player/AdTimingService.cjs.map +1 -1
  16. package/lib/player/AdTimingService.d.cts +1 -1
  17. package/lib/player/HlsEngine.cjs +86 -30
  18. package/lib/player/HlsEngine.cjs.map +1 -1
  19. package/lib/player/HlsEngine.d.cts +6 -1
  20. package/lib/player/PlaceholderLayer.cjs +1 -3
  21. package/lib/player/PlaceholderLayer.cjs.map +1 -1
  22. package/lib/player/PlayerControls.cjs.map +1 -1
  23. package/lib/player/PlayerControls.d.cts +1 -1
  24. package/lib/player/Scte35CueManager.cjs +2 -4
  25. package/lib/player/Scte35CueManager.cjs.map +1 -1
  26. package/lib/player/Scte35CueManager.d.cts +1 -1
  27. package/lib/player/Scte35Parser.cjs +6 -12
  28. package/lib/player/Scte35Parser.cjs.map +1 -1
  29. package/lib/player/Scte35Parser.d.cts +1 -1
  30. package/lib/player/StormcloudVideoPlayer.cjs +194 -96
  31. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  32. package/lib/player/StormcloudVideoPlayer.d.cts +2 -1
  33. package/lib/player/playerTypes.cjs.map +1 -1
  34. package/lib/player/playerTypes.d.cts +1 -1
  35. package/lib/players/FilePlayer.cjs +17 -26
  36. package/lib/players/FilePlayer.cjs.map +1 -1
  37. package/lib/players/HlsPlayer.cjs +204 -110
  38. package/lib/players/HlsPlayer.cjs.map +1 -1
  39. package/lib/players/HlsPlayer.d.cts +1 -1
  40. package/lib/players/index.cjs +204 -110
  41. package/lib/players/index.cjs.map +1 -1
  42. package/lib/sdk/hlsAdPlayer.cjs +42 -19
  43. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  44. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  45. package/lib/sdk/pal.cjs +6 -9
  46. package/lib/sdk/pal.cjs.map +1 -1
  47. package/lib/{types-cTqIKw_D.d.cts → types-DpbgEvSH.d.cts} +1 -0
  48. package/lib/ui/StormcloudVideoPlayer.cjs +194 -96
  49. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  50. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  51. package/lib/utils/browserCompat.cjs +3 -6
  52. package/lib/utils/browserCompat.cjs.map +1 -1
  53. package/lib/utils/ctvVastSignals.cjs +3 -6
  54. package/lib/utils/ctvVastSignals.cjs.map +1 -1
  55. package/lib/utils/devUrl.cjs.map +1 -1
  56. package/lib/utils/mqttClient.cjs +1 -3
  57. package/lib/utils/mqttClient.cjs.map +1 -1
  58. package/lib/utils/mqttConfig.cjs +1 -3
  59. package/lib/utils/mqttConfig.cjs.map +1 -1
  60. package/lib/utils/polyfills.cjs +4 -7
  61. package/lib/utils/polyfills.cjs.map +1 -1
  62. package/lib/utils/tracking.cjs +27 -20
  63. package/lib/utils/tracking.cjs.map +1 -1
  64. package/lib/utils/tracking.d.cts +1 -1
  65. package/lib/utils/vastEnvironmentSignals.cjs +7 -6
  66. package/lib/utils/vastEnvironmentSignals.cjs.map +1 -1
  67. package/lib/utils/vastEnvironmentSignals.d.cts +2 -1
  68. package/lib/utils/vastMacros.cjs +4 -2
  69. package/lib/utils/vastMacros.cjs.map +1 -1
  70. package/package.json +1 -1
package/lib/index.d.cts CHANGED
@@ -163,6 +163,7 @@ interface AdLoadedInfo {
163
163
  interface AdImpressionInfo {
164
164
  source: "vast" | "hls";
165
165
  adIndex: number;
166
+ adId?: string;
166
167
  adUrl?: string;
167
168
  durationSeconds?: number;
168
169
  timestamp: string;
@@ -207,6 +208,7 @@ declare class StormcloudVideoPlayer {
207
208
  getStreamType(): "hls" | "other";
208
209
  shouldShowNativeControls(): boolean;
209
210
  isLive(): boolean;
211
+ isLowLatencyStream(): boolean | undefined;
210
212
  get videoElement(): HTMLVideoElement;
211
213
  toggleMute(): void;
212
214
  toggleFullscreen(): Promise<void>;
package/lib/index.d.ts CHANGED
@@ -163,6 +163,7 @@ interface AdLoadedInfo {
163
163
  interface AdImpressionInfo {
164
164
  source: "vast" | "hls";
165
165
  adIndex: number;
166
+ adId?: string;
166
167
  adUrl?: string;
167
168
  durationSeconds?: number;
168
169
  timestamp: string;
@@ -207,6 +208,7 @@ declare class StormcloudVideoPlayer {
207
208
  getStreamType(): "hls" | "other";
208
209
  shouldShowNativeControls(): boolean;
209
210
  isLive(): boolean;
211
+ isLowLatencyStream(): boolean | undefined;
210
212
  get videoElement(): HTMLVideoElement;
211
213
  toggleMute(): void;
212
214
  toggleFullscreen(): Promise<void>;
package/lib/index.js CHANGED
@@ -10,9 +10,7 @@ function _array_without_holes(arr) {
10
10
  if (Array.isArray(arr)) return _array_like_to_array(arr);
11
11
  }
12
12
  function _assert_this_initialized(self) {
13
- if (self === void 0) {
14
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
15
- }
13
+ if (self === void 0) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
16
14
  return self;
17
15
  }
18
16
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
@@ -23,11 +21,8 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
23
21
  reject(error);
24
22
  return;
25
23
  }
26
- if (info.done) {
27
- resolve(value);
28
- } else {
29
- Promise.resolve(value).then(_next, _throw);
30
- }
24
+ if (info.done) resolve(value);
25
+ else Promise.resolve(value).then(_next, _throw);
31
26
  }
32
27
  function _async_to_generator(fn) {
33
28
  return function() {
@@ -49,9 +44,7 @@ function _call_super(_this, derived, args) {
49
44
  return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
50
45
  }
51
46
  function _class_call_check(instance, Constructor) {
52
- if (!(instance instanceof Constructor)) {
53
- throw new TypeError("Cannot call a class as a function");
54
- }
47
+ if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
55
48
  }
56
49
  function _defineProperties(target, props) {
57
50
  for(var i = 0; i < props.length; i++){
@@ -75,9 +68,7 @@ function _define_property(obj, key, value) {
75
68
  configurable: true,
76
69
  writable: true
77
70
  });
78
- } else {
79
- obj[key] = value;
80
- }
71
+ } else obj[key] = value;
81
72
  return obj;
82
73
  }
83
74
  function _get_prototype_of(o) {
@@ -100,14 +91,23 @@ function _inherits(subClass, superClass) {
100
91
  if (superClass) _set_prototype_of(subClass, superClass);
101
92
  }
102
93
  function _instanceof(left, right) {
94
+ "@swc/helpers - instanceof";
103
95
  if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
104
96
  return !!right[Symbol.hasInstance](left);
105
- } else {
106
- return left instanceof right;
107
- }
97
+ } else return left instanceof right;
98
+ }
99
+ function _is_native_reflect_construct() {
100
+ try {
101
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
102
+ } catch (_) {}
103
+ return (_is_native_reflect_construct = function() {
104
+ return !!result;
105
+ })();
108
106
  }
109
107
  function _iterable_to_array(iter) {
110
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
108
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
109
+ return Array.from(iter);
110
+ }
111
111
  }
112
112
  function _iterable_to_array_limit(arr, i) {
113
113
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
@@ -134,10 +134,10 @@ function _iterable_to_array_limit(arr, i) {
134
134
  return _arr;
135
135
  }
136
136
  function _non_iterable_rest() {
137
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
137
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
138
138
  }
139
139
  function _non_iterable_spread() {
140
- throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
140
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
141
141
  }
142
142
  function _object_spread(target) {
143
143
  for(var i = 1; i < arguments.length; i++){
@@ -169,9 +169,8 @@ function ownKeys(object, enumerableOnly) {
169
169
  }
170
170
  function _object_spread_props(target, source) {
171
171
  source = source != null ? source : {};
172
- if (Object.getOwnPropertyDescriptors) {
173
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
174
- } else {
172
+ if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
173
+ else {
175
174
  ownKeys(Object(source)).forEach(function(key) {
176
175
  Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
177
176
  });
@@ -215,9 +214,7 @@ function _object_without_properties_loose(source, excluded) {
215
214
  return target;
216
215
  }
217
216
  function _possible_constructor_return(self, call) {
218
- if (call && (_type_of(call) === "object" || typeof call === "function")) {
219
- return call;
220
- }
217
+ if (call && (_type_of(call) === "object" || typeof call === "function")) return call;
221
218
  return _assert_this_initialized(self);
222
219
  }
223
220
  function _set_prototype_of(o, p) {
@@ -233,26 +230,6 @@ function _sliced_to_array(arr, i) {
233
230
  function _to_consumable_array(arr) {
234
231
  return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
235
232
  }
236
- function _type_of(obj) {
237
- "@swc/helpers - typeof";
238
- return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
239
- }
240
- function _unsupported_iterable_to_array(o, minLen) {
241
- if (!o) return;
242
- if (typeof o === "string") return _array_like_to_array(o, minLen);
243
- var n = Object.prototype.toString.call(o).slice(8, -1);
244
- if (n === "Object" && o.constructor) n = o.constructor.name;
245
- if (n === "Map" || n === "Set") return Array.from(n);
246
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
247
- }
248
- function _is_native_reflect_construct() {
249
- try {
250
- var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
251
- } catch (_) {}
252
- return (_is_native_reflect_construct = function() {
253
- return !!result;
254
- })();
255
- }
256
233
  function _ts_generator(thisArg, body) {
257
234
  var f, y, t, _ = {
258
235
  label: 0,
@@ -354,18 +331,36 @@ function _ts_generator(thisArg, body) {
354
331
  }
355
332
  function _ts_values(o) {
356
333
  var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
357
- if (m) return m.call(o);
358
- if (o && typeof o.length === "number") return {
359
- next: function() {
360
- if (o && i >= o.length) o = void 0;
361
- return {
362
- value: o && o[i++],
363
- done: !o
364
- };
365
- }
366
- };
334
+ if (m) {
335
+ return m.call(o);
336
+ }
337
+ if (o && typeof o.length === "number") {
338
+ return {
339
+ next: function() {
340
+ if (o && i >= o.length) {
341
+ o = void 0;
342
+ }
343
+ return {
344
+ value: o && o[i++],
345
+ done: !o
346
+ };
347
+ }
348
+ };
349
+ }
367
350
  throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
368
351
  }
352
+ function _type_of(obj) {
353
+ "@swc/helpers - typeof";
354
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
355
+ }
356
+ function _unsupported_iterable_to_array(o, minLen) {
357
+ if (!o) return;
358
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
359
+ var n = Object.prototype.toString.call(o).slice(8, -1);
360
+ if (n === "Object" && o.constructor) n = o.constructor.name;
361
+ if (n === "Map" || n === "Set") return Array.from(n);
362
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
363
+ }
369
364
  // src/ui/StormcloudVideoPlayer.tsx
370
365
  import React, { useEffect, useRef, useMemo, useCallback } from "react";
371
366
  // src/sdk/hlsAdPlayer.ts
@@ -584,6 +579,7 @@ function createHlsAdPlayer(contentVideo, options) {
584
579
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
585
580
  var adEventHandlers = [];
586
581
  var currentAd;
582
+ var currentAdMediaUrl;
587
583
  var podAds = [];
588
584
  var podIndex = 0;
589
585
  var sessionId;
@@ -1401,9 +1397,9 @@ function createHlsAdPlayer(contentVideo, options) {
1401
1397
  delete contentVideo.dataset.stormcloudAdPlaying;
1402
1398
  }
1403
1399
  }
1404
- function resetQuartileTracking(preserveImpression) {
1400
+ function resetQuartileTracking() {
1405
1401
  trackingFired = {
1406
- impression: preserveImpression ? trackingFired.impression : false,
1402
+ impression: false,
1407
1403
  start: false,
1408
1404
  firstQuartile: false,
1409
1405
  midpoint: false,
@@ -1411,6 +1407,27 @@ function createHlsAdPlayer(contentVideo, options) {
1411
1407
  complete: false
1412
1408
  };
1413
1409
  }
1410
+ function markCreativeRendered(reason) {
1411
+ if (!currentAd || trackingFired.impression) return;
1412
+ trackingFired.impression = true;
1413
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1414
+ console.log("[HlsAdPlayer] Impression (pod ".concat(podIndex + 1, "/").concat(podAds.length || 1, ", reason: ").concat(reason, "): ").concat(currentAd.title));
1415
+ emit("ad_impression", {
1416
+ adId: currentAd.id,
1417
+ title: currentAd.title,
1418
+ durationSeconds: currentAd.duration,
1419
+ mediaUrl: currentAdMediaUrl,
1420
+ podIndex: podIndex,
1421
+ podSize: podAds.length || 1,
1422
+ reason: reason
1423
+ });
1424
+ }
1425
+ function canDetectBlackFrames() {
1426
+ if (!adVideoElement) return false;
1427
+ if (requiresMediaPipelineResetAfterAds()) return false;
1428
+ if (isRvfcSupported(adVideoElement)) return true;
1429
+ return getDecodedVideoFrameCount(adVideoElement) !== void 0;
1430
+ }
1414
1431
  function isRvfcSupported(video) {
1415
1432
  return typeof video.requestVideoFrameCallback === "function";
1416
1433
  }
@@ -1473,6 +1490,7 @@ function createHlsAdPlayer(contentVideo, options) {
1473
1490
  if (!mediaFile) {
1474
1491
  throw new Error("No media file available for ad");
1475
1492
  }
1493
+ currentAdMediaUrl = mediaFile.url;
1476
1494
  var isHlsAd = isHlsMediaFile(mediaFile);
1477
1495
  console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1478
1496
  if (isHlsAd && Hls.isSupported()) {
@@ -1516,10 +1534,9 @@ function createHlsAdPlayer(contentVideo, options) {
1516
1534
  }
1517
1535
  podIndex++;
1518
1536
  currentAd = podAds[podIndex];
1519
- resetQuartileTracking(false);
1537
+ currentAdMediaUrl = void 0;
1538
+ resetQuartileTracking();
1520
1539
  if (currentAd) {
1521
- fireTrackingPixels(currentAd.trackingUrls.impression);
1522
- trackingFired.impression = true;
1523
1540
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1524
1541
  }
1525
1542
  clearStallWatchdog();
@@ -1614,6 +1631,7 @@ function createHlsAdPlayer(contentVideo, options) {
1614
1631
  if (!adPlaying) return;
1615
1632
  sawDecodedVideoFrame = true;
1616
1633
  markRvfcReliable();
1634
+ markCreativeRendered("first_presented_frame");
1617
1635
  };
1618
1636
  try {
1619
1637
  videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
@@ -1648,6 +1666,7 @@ function createHlsAdPlayer(contentVideo, options) {
1648
1666
  if (decodedFrames !== void 0 && decodedFrames > 0) {
1649
1667
  sawDecodedVideoFrame = true;
1650
1668
  markFrameCounterReliable();
1669
+ markCreativeRendered("decoded_frames");
1651
1670
  } else if (adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1652
1671
  var timeAdvancing = adVideoElement.currentTime > lastAdProgressPosition + 0.05;
1653
1672
  if (isRvfcSupported(adVideoElement) && timeAdvancing && isRvfcReliable()) {
@@ -1660,6 +1679,9 @@ function createHlsAdPlayer(contentVideo, options) {
1660
1679
  }
1661
1680
  }
1662
1681
  }
1682
+ if (!trackingFired.impression && !adVideoElement.paused && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && (sawDecodedVideoFrame || !canDetectBlackFrames())) {
1683
+ markCreativeRendered(sawDecodedVideoFrame ? "decoded_frames" : "sustained_playback");
1684
+ }
1663
1685
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1664
1686
  noteAdProgress();
1665
1687
  return;
@@ -1798,11 +1820,9 @@ function createHlsAdPlayer(contentVideo, options) {
1798
1820
  podAds = ads;
1799
1821
  podIndex = 0;
1800
1822
  currentAd = ads[0];
1823
+ currentAdMediaUrl = void 0;
1824
+ resetQuartileTracking();
1801
1825
  console.log("[HlsAdPlayer] Pod parsed: ".concat(ads.length, ' ad(s), first="').concat(currentAd === null || currentAd === void 0 ? void 0 : currentAd.title, '", duration=').concat(currentAd === null || currentAd === void 0 ? void 0 : currentAd.duration, "s"));
1802
- if (currentAd) {
1803
- fireTrackingPixels(currentAd.trackingUrls.impression);
1804
- trackingFired.impression = true;
1805
- }
1806
1826
  return [
1807
1827
  2,
1808
1828
  Promise.resolve()
@@ -1842,7 +1862,7 @@ function createHlsAdPlayer(contentVideo, options) {
1842
1862
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
1843
1863
  }
1844
1864
  setupAdEventListeners();
1845
- resetQuartileTracking(true);
1865
+ resetQuartileTracking();
1846
1866
  contentVolume = contentVideo.volume;
1847
1867
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1848
1868
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1932,6 +1952,7 @@ function createHlsAdPlayer(contentVideo, options) {
1932
1952
  }
1933
1953
  }
1934
1954
  currentAd = void 0;
1955
+ currentAdMediaUrl = void 0;
1935
1956
  podAds = [];
1936
1957
  podIndex = 0;
1937
1958
  return [
@@ -3267,7 +3288,7 @@ function buildPlayerMetricEvent() {
3267
3288
  if (debugAdTiming) {
3268
3289
  console.log("[StormcloudVideoPlayer] playerId: ", playerId);
3269
3290
  }
3270
- captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
3291
+ captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : (/* @__PURE__ */ new Date()).toISOString();
3271
3292
  return [
3272
3293
  2,
3273
3294
  _object_spread({
@@ -3286,8 +3307,19 @@ function buildPlayerMetricEvent() {
3286
3307
  }).apply(this, arguments);
3287
3308
  }
3288
3309
  function publishTracking(licenseKey, channel, body) {
3310
+ var debug = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : false;
3289
3311
  ensureMQTTClient();
3290
- publishMQTT(buildPlayerTopic(licenseKey, channel), body);
3312
+ var topic = buildPlayerTopic(licenseKey, channel);
3313
+ var published = publishMQTT(topic, body);
3314
+ if (debug) {
3315
+ console.log("[StormcloudVideoPlayer] publishTracking:", JSON.stringify({
3316
+ licenseKey: licenseKey,
3317
+ channel: channel,
3318
+ topic: topic,
3319
+ body: body,
3320
+ published: published
3321
+ }, null, 2));
3322
+ }
3291
3323
  }
3292
3324
  function sendInitialTracking(_0) {
3293
3325
  return _async_to_generator(function(licenseKey) {
@@ -3321,7 +3353,7 @@ function sendInitialTracking(_0) {
3321
3353
  events: [
3322
3354
  metricEvent
3323
3355
  ]
3324
- });
3356
+ }, !!context.debugAdTiming);
3325
3357
  return [
3326
3358
  3,
3327
3359
  4
@@ -3431,7 +3463,7 @@ function sendAdLoadedTracking(_0, _1) {
3431
3463
  }
3432
3464
  function sendAdImpressionTracking(_0, _1) {
3433
3465
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
3434
- var context, metricEvent, error;
3466
+ var context, _adImpressionInfo_adUrl, metricEvent, error;
3435
3467
  var _arguments = arguments;
3436
3468
  return _ts_generator(this, function(_state) {
3437
3469
  switch(_state.label){
@@ -3456,17 +3488,18 @@ function sendAdImpressionTracking(_0, _1) {
3456
3488
  ];
3457
3489
  case 2:
3458
3490
  metricEvent = _state.sent();
3459
- publishTracking(licenseKey, "heartbeat", metricEvent);
3491
+ publishTracking(licenseKey, "heartbeat", metricEvent, !!context.debugAdTiming);
3460
3492
  publishTracking(licenseKey, "impressions", {
3461
3493
  events: [
3462
3494
  {
3495
+ event_id: createUuid(),
3463
3496
  player_id: metricEvent.player_id,
3464
3497
  ad_played_count: 1,
3465
- ad_url: adImpressionInfo.adUrl,
3498
+ ad_url: (_adImpressionInfo_adUrl = adImpressionInfo.adUrl) !== null && _adImpressionInfo_adUrl !== void 0 ? _adImpressionInfo_adUrl : adImpressionInfo.adId,
3466
3499
  capture_at: adImpressionInfo.timestamp
3467
3500
  }
3468
3501
  ]
3469
- });
3502
+ }, !!context.debugAdTiming);
3470
3503
  return [
3471
3504
  3,
3472
3505
  4
@@ -3511,7 +3544,7 @@ function sendHeartbeat(_0) {
3511
3544
  ];
3512
3545
  case 2:
3513
3546
  heartbeatData = _state.sent();
3514
- publishTracking(licenseKey, "heartbeat", heartbeatData);
3547
+ publishTracking(licenseKey, "heartbeat", heartbeatData, !!context.debugAdTiming);
3515
3548
  return [
3516
3549
  3,
3517
3550
  4
@@ -6350,7 +6383,7 @@ var AdTimingService = /*#__PURE__*/ function() {
6350
6383
  var _this_callbacks_getAdState = this.callbacks.getAdState(), inAdBreak = _this_callbacks_getAdState.inAdBreak, showAds = _this_callbacks_getAdState.showAds, adPlaying = _this_callbacks_getAdState.adPlaying;
6351
6384
  console.log("[StormcloudVideoPlayer][AdState]", _object_spread({
6352
6385
  event: event,
6353
- timestamp: /* @__PURE__ */ new Date().toISOString(),
6386
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6354
6387
  showAds: showAds,
6355
6388
  adPlaying: adPlaying,
6356
6389
  inAdBreak: inAdBreak,
@@ -6513,6 +6546,7 @@ var HlsEngine = /*#__PURE__*/ function() {
6513
6546
  this.bufferedSegmentsCount = 0;
6514
6547
  this.shouldAutoplayAfterBuffering = false;
6515
6548
  this.hasInitialBufferCompleted = false;
6549
+ this.latencyProfileApplied = false;
6516
6550
  this.config = config;
6517
6551
  this.video = video;
6518
6552
  this.cueManager = cueManager;
@@ -6581,24 +6615,21 @@ var HlsEngine = /*#__PURE__*/ function() {
6581
6615
  key: "setupHls",
6582
6616
  value: function setupHls() {
6583
6617
  var _this = this;
6584
- this.hls = new Hls2(_object_spread_props(_object_spread({
6618
+ this.hls = new Hls2({
6585
6619
  enableWorker: true,
6586
6620
  backBufferLength: 30,
6587
6621
  liveDurationInfinity: true,
6588
6622
  lowLatencyMode: !!this.config.lowLatencyMode,
6589
- maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1
6590
- }, this.config.lowLatencyMode ? {
6591
- liveSyncDuration: 2
6592
- } : {}), {
6623
+ maxLiveSyncPlaybackRate: 1.1,
6593
6624
  maxBufferLength: 30,
6594
6625
  maxMaxBufferLength: 600,
6595
6626
  maxBufferSize: 60 * 1e3 * 1e3,
6596
- maxBufferHole: 0.5,
6627
+ maxBufferHole: 1,
6597
6628
  highBufferWatchdogPeriod: 2,
6598
- nudgeOffset: 0.1,
6599
- nudgeMaxRetry: 3,
6629
+ nudgeOffset: 0.2,
6630
+ nudgeMaxRetry: 5,
6600
6631
  startPosition: -1
6601
- }));
6632
+ });
6602
6633
  this.hls.on(Hls2.Events.MEDIA_ATTACHED, function() {
6603
6634
  var _this_hls;
6604
6635
  (_this_hls = _this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.loadSource(_this.config.src);
@@ -6622,6 +6653,8 @@ var HlsEngine = /*#__PURE__*/ function() {
6622
6653
  this.bufferedSegmentsCount = 0;
6623
6654
  this.hasInitialBufferCompleted = false;
6624
6655
  this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
6656
+ this.latencyProfileApplied = false;
6657
+ this.detectedLowLatencyStream = void 0;
6625
6658
  minSegments = (_this_config_minSegmentsBeforePlay = this.config.minSegmentsBeforePlay) !== null && _this_config_minSegmentsBeforePlay !== void 0 ? _this_config_minSegmentsBeforePlay : 2;
6626
6659
  if (this.debug) {
6627
6660
  console.log("[StormcloudVideoPlayer] Waiting for", minSegments, "segments to buffer before playback");
@@ -6652,6 +6685,7 @@ var HlsEngine = /*#__PURE__*/ function() {
6652
6685
  }).call(_this);
6653
6686
  });
6654
6687
  this.hls.on(Hls2.Events.LEVEL_LOADED, function(_evt, data) {
6688
+ _this.applyStreamLatencyProfile(data === null || data === void 0 ? void 0 : data.details);
6655
6689
  if (_this.callbacks.isInAdBreak() || _this.callbacks.hasPendingAdBreak()) {
6656
6690
  return;
6657
6691
  }
@@ -6925,6 +6959,70 @@ var HlsEngine = /*#__PURE__*/ function() {
6925
6959
  this.hls.attachMedia(this.video);
6926
6960
  }
6927
6961
  },
6962
+ {
6963
+ key: "isLowLatencyStream",
6964
+ value: function isLowLatencyStream() {
6965
+ return this.detectedLowLatencyStream;
6966
+ }
6967
+ },
6968
+ {
6969
+ key: "applyStreamLatencyProfile",
6970
+ value: function applyStreamLatencyProfile(details) {
6971
+ if (this.latencyProfileApplied || !this.hls) {
6972
+ return;
6973
+ }
6974
+ if (!details) {
6975
+ return;
6976
+ }
6977
+ if (details.live !== true) {
6978
+ this.latencyProfileApplied = true;
6979
+ this.detectedLowLatencyStream = false;
6980
+ return;
6981
+ }
6982
+ var isLowLatencyManifest = this.isLowLatencyManifest(details);
6983
+ var useLowLatency = isLowLatencyManifest && !!this.config.lowLatencyMode;
6984
+ this.detectedLowLatencyStream = useLowLatency;
6985
+ this.latencyProfileApplied = true;
6986
+ var cfg = this.hls.config;
6987
+ if (useLowLatency) {
6988
+ cfg.maxLiveSyncPlaybackRate = 1.5;
6989
+ cfg.maxBufferHole = 0.5;
6990
+ delete cfg.liveSyncDuration;
6991
+ } else {
6992
+ cfg.maxLiveSyncPlaybackRate = 1.1;
6993
+ cfg.maxBufferHole = 1;
6994
+ delete cfg.liveSyncDuration;
6995
+ cfg.liveSyncDurationCount = 3;
6996
+ }
6997
+ if (this.debug) {
6998
+ var _details_targetduration;
6999
+ console.log("[StormcloudVideoPlayer] Live latency profile: ".concat(useLowLatency ? "LL-HLS (low latency)" : "standard live (stability)"), {
7000
+ isLowLatencyManifest: isLowLatencyManifest,
7001
+ lowLatencyModeRequested: !!this.config.lowLatencyMode,
7002
+ canBlockReload: details.canBlockReload,
7003
+ partTarget: details.partTarget,
7004
+ partHoldBack: details.partHoldBack,
7005
+ partListLength: Array.isArray(details.partList) ? details.partList.length : 0,
7006
+ targetDuration: (_details_targetduration = details.targetduration) !== null && _details_targetduration !== void 0 ? _details_targetduration : details.targetDuration,
7007
+ maxLiveSyncPlaybackRate: cfg.maxLiveSyncPlaybackRate,
7008
+ maxBufferHole: cfg.maxBufferHole
7009
+ });
7010
+ }
7011
+ }
7012
+ },
7013
+ {
7014
+ key: "isLowLatencyManifest",
7015
+ value: function isLowLatencyManifest(details) {
7016
+ if (!details) {
7017
+ return false;
7018
+ }
7019
+ var hasParts = Array.isArray(details.partList) && details.partList.length > 0;
7020
+ var hasPartTarget = typeof details.partTarget === "number" && details.partTarget > 0;
7021
+ var hasPartHoldBack = typeof details.partHoldBack === "number" && details.partHoldBack > 0;
7022
+ var canBlockReload = details.canBlockReload === true;
7023
+ return hasParts || hasPartTarget || hasPartHoldBack || canBlockReload;
7024
+ }
7025
+ },
6928
7026
  {
6929
7027
  key: "onId3Tag",
6930
7028
  value: function onId3Tag(tag) {
@@ -7249,27 +7347,22 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7249
7347
  console.log("[POD] Playing pod ad ".concat((payload === null || payload === void 0 ? void 0 : payload.index) != null ? payload.index + 1 : "?", "/").concat((_ref = payload === null || payload === void 0 ? void 0 : payload.total) !== null && _ref !== void 0 ? _ref : "?"));
7250
7348
  }
7251
7349
  });
7252
- adPlayer.on("all_ads_completed", function() {
7253
- sendAdImpressionTracking(_this.host.config.licenseKey, {
7350
+ adPlayer.on("ad_impression", function(payload) {
7351
+ var impressionInfo = {
7254
7352
  source: "hls",
7255
7353
  adIndex: _this.timing.currentAdIndex,
7256
- timestamp: /* @__PURE__ */ new Date().toISOString()
7257
- }, _this.analyticsContext).catch(function() {});
7258
- _this.timing.recordPlayedAdDuration(_this.host.getAdPlayer());
7259
- var remaining = _this.timing.getRemainingAdMs();
7260
- _this.timing.consecutiveFailures = 0;
7261
- if (_this.debug) {
7262
- console.log("[StormcloudVideoPlayer] all_ads_completed event received - remaining=".concat(remaining, "ms, queued ads=").concat(_this.adRequestQueue.length), _this.adRequestQueue.length > 0 ? {
7263
- queuedUrls: _to_consumable_array(_this.adRequestQueue)
7264
- } : {});
7354
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7355
+ };
7356
+ if (payload === null || payload === void 0 ? void 0 : payload.adId) impressionInfo.adId = payload.adId;
7357
+ if (payload === null || payload === void 0 ? void 0 : payload.mediaUrl) impressionInfo.adUrl = payload.mediaUrl;
7358
+ if ((payload === null || payload === void 0 ? void 0 : payload.durationSeconds) != null) {
7359
+ impressionInfo.durationSeconds = payload.durationSeconds;
7265
7360
  }
7266
- if (_this.inAdBreak) {
7267
- if (_this.timing.hasTimeToStartAnotherAd()) {
7268
- _this.tryNextAvailableAdWithRateLimit();
7269
- } else {
7270
- _this.handleAdPodComplete();
7361
+ sendAdImpressionTracking(_this.host.config.licenseKey, impressionInfo, _this.analyticsContext).catch(function(error) {
7362
+ if (_this.debug) {
7363
+ console.warn("[AdBreakOrchestrator] Failed to send ad impression tracking:", error);
7271
7364
  }
7272
- }
7365
+ });
7273
7366
  });
7274
7367
  adPlayer.on("ad_error", function(errorPayload) {
7275
7368
  var errorMessage = "Ad playback failed";
@@ -7312,11 +7405,6 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7312
7405
  }
7313
7406
  });
7314
7407
  adPlayer.on("content_resume", function() {
7315
- sendAdImpressionTracking(_this.host.config.licenseKey, {
7316
- source: "hls",
7317
- adIndex: _this.timing.currentAdIndex,
7318
- timestamp: /* @__PURE__ */ new Date().toISOString()
7319
- }, _this.analyticsContext).catch(function() {});
7320
7408
  if (!_this.host.video.muted) {
7321
7409
  _this.host.video.muted = true;
7322
7410
  if (_this.debug) {
@@ -7554,7 +7642,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7554
7642
  sendAdLoadedTracking(this.host.config.licenseKey, {
7555
7643
  source: "hls",
7556
7644
  vastUrl: podUrl,
7557
- timestamp: /* @__PURE__ */ new Date().toISOString()
7645
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7558
7646
  }, this.analyticsContext).catch(function() {});
7559
7647
  this.timing.startAdFailsafeTimer(requestToken);
7560
7648
  return [
@@ -8074,7 +8162,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8074
8162
  sendAdLoadedTracking(this.host.config.licenseKey, {
8075
8163
  source: "hls",
8076
8164
  vastUrl: vastTagUrl,
8077
- timestamp: /* @__PURE__ */ new Date().toISOString()
8165
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
8078
8166
  }, this.analyticsContext).catch(function() {});
8079
8167
  this.timing.clearAdRequestWatchdog();
8080
8168
  if (this.timing.activeAdRequestToken !== requestToken) return [
@@ -9056,7 +9144,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
9056
9144
  if (marker.ptsSeconds != null) detectPayload.ptsSeconds = marker.ptsSeconds;
9057
9145
  sendAdDetectTracking(this.config.licenseKey, _object_spread({
9058
9146
  source: "scte35",
9059
- timestamp: /* @__PURE__ */ new Date().toISOString()
9147
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
9060
9148
  }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
9061
9149
  }
9062
9150
  var hasPrefetchedAds = this.adBreak.pendingAdBreak && this.adBreak.pendingAdBreak.vastUrls.length > 0;
@@ -9232,7 +9320,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
9232
9320
  if (fragmentSn !== void 0) detectPayload.detectedAtFragmentSn = fragmentSn;
9233
9321
  sendAdDetectTracking(this.config.licenseKey, _object_spread({
9234
9322
  source: "scte35",
9235
- timestamp: /* @__PURE__ */ new Date().toISOString()
9323
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
9236
9324
  }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
9237
9325
  if (this.debug) {
9238
9326
  console.log("[PREFETCH] Starting ad prefetch for upcoming ad break");
@@ -9412,6 +9500,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
9412
9500
  return this.hlsEngine.isLiveStream;
9413
9501
  }
9414
9502
  },
9503
+ {
9504
+ key: "isLowLatencyStream",
9505
+ value: function isLowLatencyStream() {
9506
+ return this.hlsEngine.isLowLatencyStream();
9507
+ }
9508
+ },
9415
9509
  {
9416
9510
  key: "videoElement",
9417
9511
  get: function get() {