stormcloud-video-player 0.3.58 → 0.3.60

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.
package/lib/index.js CHANGED
@@ -1760,6 +1760,16 @@ function createHlsAdPlayer(contentVideo, options) {
1760
1760
  });
1761
1761
  return bestMatch.file;
1762
1762
  }
1763
+ function isHlsMediaFile(mediaFile) {
1764
+ var type = mediaFile.type.toLowerCase();
1765
+ var url = mediaFile.url.toLowerCase();
1766
+ return type === "application/x-mpegurl" || type === "application/vnd.apple.mpegurl" || type.includes("mpegurl") || url.includes(".m3u8");
1767
+ }
1768
+ function isProgressiveMediaFile(mediaFile) {
1769
+ var type = mediaFile.type.toLowerCase();
1770
+ var url = mediaFile.url.toLowerCase();
1771
+ return type.startsWith("video/") || url.endsWith(".mp4") || url.includes(".mp4?");
1772
+ }
1763
1773
  function parseVastXml(xmlString) {
1764
1774
  try {
1765
1775
  var _xmlDoc_querySelector, _xmlDoc_querySelector1, _xmlDoc_querySelector_textContent, _xmlDoc_querySelector2;
@@ -1791,30 +1801,32 @@ function createHlsAdPlayer(contentVideo, options) {
1791
1801
  var width = mf.getAttribute("width") || "";
1792
1802
  var height = mf.getAttribute("height") || "";
1793
1803
  console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
1794
- if (type === "application/x-mpegURL" || type.includes("m3u8")) {
1795
- if (!url) {
1796
- console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has HLS type but empty URL"));
1797
- return;
1798
- }
1799
- var bitrateAttr = mf.getAttribute("bitrate");
1800
- var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
1801
- mediaFiles.push({
1802
- url: url,
1803
- type: type,
1804
- width: parseInt(width || "1920", 10),
1805
- height: parseInt(height || "1080", 10),
1806
- bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
1807
- });
1808
- console.log("[HlsAdPlayer] Added HLS MediaFile: ".concat(url));
1804
+ var mediaFile = {
1805
+ url: url,
1806
+ type: type,
1807
+ width: parseInt(width || "1920", 10),
1808
+ height: parseInt(height || "1080", 10),
1809
+ bitrate: void 0
1810
+ };
1811
+ if (!url) {
1812
+ console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
1813
+ return;
1814
+ }
1815
+ var bitrateAttr = mf.getAttribute("bitrate");
1816
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
1817
+ mediaFile.bitrate = bitrateValue && bitrateValue > 0 ? bitrateValue : void 0;
1818
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
1819
+ mediaFiles.push(mediaFile);
1820
+ console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
1809
1821
  } else {
1810
- console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not HLS)'));
1822
+ console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
1811
1823
  }
1812
1824
  });
1813
1825
  if (mediaFiles.length === 0) {
1814
1826
  if (isNoAdAvailable) {
1815
1827
  console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
1816
1828
  } else {
1817
- console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
1829
+ console.warn("[HlsAdPlayer] No supported media files found in VAST XML");
1818
1830
  }
1819
1831
  return null;
1820
1832
  }
@@ -2111,7 +2123,7 @@ function createHlsAdPlayer(contentVideo, options) {
2111
2123
  },
2112
2124
  play: function play() {
2113
2125
  return _async_to_generator(function() {
2114
- var contentVolume, adVolume, mediaFile;
2126
+ var contentVolume, adVolume, mediaFile, isHlsAd;
2115
2127
  return _ts_generator(this, function(_state) {
2116
2128
  if (!currentAd) {
2117
2129
  console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
@@ -2163,8 +2175,9 @@ function createHlsAdPlayer(contentVideo, options) {
2163
2175
  if (!mediaFile) {
2164
2176
  throw new Error("No media file available for ad");
2165
2177
  }
2166
- console.log("[HlsAdPlayer] Loading ad from: ".concat(mediaFile.url));
2167
- if (Hls.isSupported()) {
2178
+ isHlsAd = isHlsMediaFile(mediaFile);
2179
+ console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad from: ").concat(mediaFile.url));
2180
+ if (isHlsAd && Hls.isSupported()) {
2168
2181
  if (adHls) {
2169
2182
  adHls.destroy();
2170
2183
  }
@@ -2187,14 +2200,25 @@ function createHlsAdPlayer(contentVideo, options) {
2187
2200
  handleAdError();
2188
2201
  }
2189
2202
  });
2190
- } else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
2203
+ } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
2191
2204
  adVideoElement.src = mediaFile.url;
2192
2205
  adVideoElement.play().catch(function(error) {
2193
2206
  console.error("[HlsAdPlayer] Error starting ad playback:", error);
2194
2207
  handleAdError();
2195
2208
  });
2209
+ } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
2210
+ if (adHls) {
2211
+ adHls.destroy();
2212
+ adHls = void 0;
2213
+ }
2214
+ adVideoElement.src = mediaFile.url;
2215
+ adVideoElement.load();
2216
+ adVideoElement.play().catch(function(error) {
2217
+ console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
2218
+ handleAdError();
2219
+ });
2196
2220
  } else {
2197
- throw new Error("HLS not supported");
2221
+ throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
2198
2222
  }
2199
2223
  return [
2200
2224
  2,
@@ -3278,6 +3302,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3278
3302
  this.adRequestQueue = [];
3279
3303
  this.maxPlaceholderDurationMs = 5e3;
3280
3304
  this.isShowingPlaceholder = false;
3305
+ this.tsScte35Pids = /* @__PURE__ */ new Set();
3306
+ this.pmtPids = /* @__PURE__ */ new Set();
3307
+ this.processedTsScte35Sections = /* @__PURE__ */ new Set();
3308
+ this.pendingScte35Cues = /* @__PURE__ */ new Map();
3309
+ this.recentScte35CueKeys = /* @__PURE__ */ new Map();
3310
+ this.recentScte35CueLimit = 200;
3281
3311
  this.totalAdRequestsInBreak = 0;
3282
3312
  this.maxTotalAdRequestsPerBreak = 10;
3283
3313
  this.pendingAdBreak = null;
@@ -3547,7 +3577,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3547
3577
  if (_this.config.debugAdTiming) {
3548
3578
  console.log("[StormcloudVideoPlayer] \uD83C\uDFAF EARLY SCTE-35 DETECTION: Ad break marker found in fragment", i, "- starting pre-fetch (NOT playing yet)");
3549
3579
  }
3550
- _this.startAdPrefetch(marker, frag === null || frag === void 0 ? void 0 : frag.sn);
3580
+ _this.onScte35Cue(marker, _object_spread({}, _this.createScte35CueContext("manifest", "early", frag)));
3551
3581
  return;
3552
3582
  }
3553
3583
  }
@@ -3628,10 +3658,21 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3628
3658
  return _this.onId3Tag(tag);
3629
3659
  });
3630
3660
  });
3661
+ this.hls.on(Hls2.Events.FRAG_LOADED, function(_evt, data) {
3662
+ var _data_frag;
3663
+ _this.processFragmentScte35Payload(data === null || data === void 0 ? void 0 : data.payload, typeof (data === null || data === void 0 ? void 0 : (_data_frag = data.frag) === null || _data_frag === void 0 ? void 0 : _data_frag.sn) === "number" ? data.frag.sn : void 0, _this.getFragmentStartSeconds(data === null || data === void 0 ? void 0 : data.frag));
3664
+ });
3665
+ this.hls.on(Hls2.Events.FRAG_DECRYPTED, function(_evt, data) {
3666
+ var _data_frag;
3667
+ _this.processFragmentScte35Payload(data === null || data === void 0 ? void 0 : data.payload, typeof (data === null || data === void 0 ? void 0 : (_data_frag = data.frag) === null || _data_frag === void 0 ? void 0 : _data_frag.sn) === "number" ? data.frag.sn : void 0, _this.getFragmentStartSeconds(data === null || data === void 0 ? void 0 : data.frag));
3668
+ });
3631
3669
  this.hls.on(Hls2.Events.FRAG_CHANGED, function(_evt, data) {
3632
3670
  var frag = data === null || data === void 0 ? void 0 : data.frag;
3633
3671
  var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3634
- if (!Array.isArray(tagList)) return;
3672
+ if (!Array.isArray(tagList)) {
3673
+ _this.activatePendingScte35CuesForFragment(frag);
3674
+ return;
3675
+ }
3635
3676
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3636
3677
  try {
3637
3678
  for(var _iterator = tagList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -3667,7 +3708,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3667
3708
  value: value
3668
3709
  }
3669
3710
  });
3670
- _this.onScte35Marker(marker);
3711
+ _this.onScte35Cue(marker, _object_spread({}, _this.createScte35CueContext("manifest", "playback", frag)));
3671
3712
  } else if (tag.includes("EXT-X-CUE-OUT")) {
3672
3713
  var durationSeconds = _this.parseCueOutDuration(value);
3673
3714
  var marker1 = _object_spread_props(_object_spread({
@@ -3680,15 +3721,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3680
3721
  value: value
3681
3722
  }
3682
3723
  });
3683
- _this.onScte35Marker(marker1);
3724
+ _this.onScte35Cue(marker1, _object_spread({}, _this.createScte35CueContext("manifest", "playback", frag)));
3684
3725
  } else if (tag.includes("EXT-X-CUE-IN")) {
3685
- _this.onScte35Marker({
3726
+ _this.onScte35Cue({
3686
3727
  type: "end",
3687
3728
  raw: {
3688
3729
  tag: tag,
3689
3730
  value: value
3690
3731
  }
3691
- });
3732
+ }, _object_spread({}, _this.createScte35CueContext("manifest", "playback", frag)));
3692
3733
  } else if (tag.includes("EXT-X-DATERANGE")) {
3693
3734
  var _attrs_CLASS;
3694
3735
  var attrs = _this.parseAttributeList(value);
@@ -3708,17 +3749,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3708
3749
  attrs: attrs
3709
3750
  }
3710
3751
  });
3711
- _this.onScte35Marker(marker2);
3752
+ _this.onScte35Cue(marker2, _object_spread({}, _this.createScte35CueContext("manifest", "playback", frag)));
3712
3753
  }
3713
3754
  if (hasScteIn) {
3714
- _this.onScte35Marker({
3755
+ _this.onScte35Cue({
3715
3756
  type: "end",
3716
3757
  raw: {
3717
3758
  tag: tag,
3718
3759
  value: value,
3719
3760
  attrs: attrs
3720
3761
  }
3721
- });
3762
+ }, _object_spread({}, _this.createScte35CueContext("manifest", "playback", frag)));
3722
3763
  }
3723
3764
  }
3724
3765
  }
@@ -3736,6 +3777,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3736
3777
  }
3737
3778
  }
3738
3779
  }
3780
+ _this.activatePendingScte35CuesForFragment(frag);
3739
3781
  });
3740
3782
  this.hls.on(Hls2.Events.ERROR, function(_evt, data) {
3741
3783
  if (data === null || data === void 0 ? void 0 : data.fatal) {
@@ -4041,7 +4083,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4041
4083
  }
4042
4084
  var marker = this.parseScte35FromId3(tag);
4043
4085
  if (marker) {
4044
- this.onScte35Marker(marker);
4086
+ this.onScte35Cue(marker, {
4087
+ source: "id3",
4088
+ readiness: "playback"
4089
+ });
4045
4090
  }
4046
4091
  }
4047
4092
  },
@@ -4185,9 +4230,251 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4185
4230
  }
4186
4231
  }
4187
4232
  },
4233
+ {
4234
+ key: "createScte35CueContext",
4235
+ value: function createScte35CueContext(source, readiness, frag) {
4236
+ var context = {
4237
+ source: source,
4238
+ readiness: readiness
4239
+ };
4240
+ if (typeof (frag === null || frag === void 0 ? void 0 : frag.sn) === "number") {
4241
+ context.fragmentSn = frag.sn;
4242
+ }
4243
+ var fragmentStartSeconds = this.getFragmentStartSeconds(frag);
4244
+ if (fragmentStartSeconds !== void 0) {
4245
+ context.fragmentStartSeconds = fragmentStartSeconds;
4246
+ }
4247
+ return context;
4248
+ }
4249
+ },
4250
+ {
4251
+ key: "getFragmentStartSeconds",
4252
+ value: function getFragmentStartSeconds(frag) {
4253
+ var candidates = [
4254
+ frag === null || frag === void 0 ? void 0 : frag.start,
4255
+ frag === null || frag === void 0 ? void 0 : frag.startPTS
4256
+ ];
4257
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
4258
+ try {
4259
+ for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4260
+ var candidate = _step.value;
4261
+ if (typeof candidate === "number" && Number.isFinite(candidate)) {
4262
+ return candidate;
4263
+ }
4264
+ }
4265
+ } catch (err) {
4266
+ _didIteratorError = true;
4267
+ _iteratorError = err;
4268
+ } finally{
4269
+ try {
4270
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
4271
+ _iterator.return();
4272
+ }
4273
+ } finally{
4274
+ if (_didIteratorError) {
4275
+ throw _iteratorError;
4276
+ }
4277
+ }
4278
+ }
4279
+ return void 0;
4280
+ }
4281
+ },
4282
+ {
4283
+ key: "onScte35Cue",
4284
+ value: function onScte35Cue(marker, context) {
4285
+ var cue = this.createScte35Cue(marker, context);
4286
+ var pendingKey = this.getPendingScte35CueKey(cue);
4287
+ if (context.readiness === "early") {
4288
+ this.pendingScte35Cues.set(pendingKey, cue);
4289
+ this.trimRecentScte35CueMaps();
4290
+ if (marker.type === "start") {
4291
+ this.startAdPrefetch(marker, context.fragmentSn, cue.key);
4292
+ }
4293
+ return;
4294
+ }
4295
+ if (marker.type === "end" && !this.shouldAcceptScte35EndCue(cue)) {
4296
+ if (this.config.debugAdTiming) {
4297
+ console.log("[StormcloudVideoPlayer] Ignoring SCTE-35 end cue", {
4298
+ key: cue.key,
4299
+ activeScte35BreakKey: this.activeScte35BreakKey,
4300
+ inAdBreak: this.inAdBreak,
4301
+ source: cue.source
4302
+ });
4303
+ }
4304
+ return;
4305
+ }
4306
+ if (marker.type === "start" && this.hasRecentlyHandledScte35Cue(cue)) {
4307
+ if (this.config.debugAdTiming) {
4308
+ console.log("[StormcloudVideoPlayer] Ignoring duplicate SCTE-35 start cue", {
4309
+ key: cue.key,
4310
+ source: cue.source
4311
+ });
4312
+ }
4313
+ return;
4314
+ }
4315
+ this.pendingScte35Cues.delete(pendingKey);
4316
+ this.markScte35CueHandled(cue);
4317
+ this.onScte35Marker(marker, cue.key);
4318
+ }
4319
+ },
4320
+ {
4321
+ key: "createScte35Cue",
4322
+ value: function createScte35Cue(marker, context) {
4323
+ var cue = {
4324
+ marker: marker,
4325
+ source: context.source,
4326
+ readiness: context.readiness,
4327
+ key: this.getScte35CueKey(marker, context)
4328
+ };
4329
+ if (context.fragmentSn !== void 0) {
4330
+ cue.fragmentSn = context.fragmentSn;
4331
+ }
4332
+ if (context.fragmentStartSeconds !== void 0) {
4333
+ cue.fragmentStartSeconds = context.fragmentStartSeconds;
4334
+ }
4335
+ return cue;
4336
+ }
4337
+ },
4338
+ {
4339
+ key: "getScte35CueKey",
4340
+ value: function getScte35CueKey(marker, context) {
4341
+ var _raw_attrs, _raw_attrs1, _raw_attrs2;
4342
+ var raw = this.getScte35MarkerRaw(marker);
4343
+ var spliceEventId = this.toIdentityString(raw === null || raw === void 0 ? void 0 : raw.splice_event_id);
4344
+ if (spliceEventId) {
4345
+ return "splice:".concat(spliceEventId);
4346
+ }
4347
+ var segmentationEventId = this.toIdentityString(raw === null || raw === void 0 ? void 0 : raw.segmentation_event_id);
4348
+ if (segmentationEventId) {
4349
+ return "segmentation:".concat(segmentationEventId);
4350
+ }
4351
+ var daterangeId = this.toIdentityString(raw === null || raw === void 0 ? void 0 : (_raw_attrs = raw.attrs) === null || _raw_attrs === void 0 ? void 0 : _raw_attrs.ID);
4352
+ if (daterangeId) {
4353
+ return "daterange:".concat(daterangeId);
4354
+ }
4355
+ var scteValue = this.toIdentityString(raw === null || raw === void 0 ? void 0 : (_raw_attrs1 = raw.attrs) === null || _raw_attrs1 === void 0 ? void 0 : _raw_attrs1["SCTE35-OUT"]) || this.toIdentityString(raw === null || raw === void 0 ? void 0 : (_raw_attrs2 = raw.attrs) === null || _raw_attrs2 === void 0 ? void 0 : _raw_attrs2["SCTE35-IN"]);
4356
+ if (scteValue) {
4357
+ return "daterange-scte:".concat(scteValue);
4358
+ }
4359
+ if (typeof marker.ptsSeconds === "number" && Number.isFinite(marker.ptsSeconds)) {
4360
+ return "pts:".concat(Math.round(marker.ptsSeconds * 2) / 2);
4361
+ }
4362
+ if (context.fragmentSn !== void 0) {
4363
+ return "fragment:".concat(context.fragmentSn);
4364
+ }
4365
+ return "".concat(context.source, ":wallclock:").concat(Math.floor(Date.now() / 1e3));
4366
+ }
4367
+ },
4368
+ {
4369
+ key: "getPendingScte35CueKey",
4370
+ value: function getPendingScte35CueKey(cue) {
4371
+ return "".concat(cue.marker.type, ":").concat(cue.key, ":").concat(cue.fragmentSn !== void 0 ? cue.fragmentSn : "unknown");
4372
+ }
4373
+ },
4374
+ {
4375
+ key: "getScte35MarkerRaw",
4376
+ value: function getScte35MarkerRaw(marker) {
4377
+ return _type_of(marker.raw) === "object" && marker.raw !== null ? marker.raw : {};
4378
+ }
4379
+ },
4380
+ {
4381
+ key: "toIdentityString",
4382
+ value: function toIdentityString(value) {
4383
+ if (typeof value === "number" && Number.isFinite(value)) {
4384
+ return String(value);
4385
+ }
4386
+ if (typeof value === "string" && value.trim().length > 0) {
4387
+ return value.trim();
4388
+ }
4389
+ return void 0;
4390
+ }
4391
+ },
4392
+ {
4393
+ key: "isStrongScte35CueKey",
4394
+ value: function isStrongScte35CueKey(key) {
4395
+ return !!(key && (key.startsWith("splice:") || key.startsWith("segmentation:") || key.startsWith("daterange:") || key.startsWith("daterange-scte:")));
4396
+ }
4397
+ },
4398
+ {
4399
+ key: "hasRecentlyHandledScte35Cue",
4400
+ value: function hasRecentlyHandledScte35Cue(cue) {
4401
+ if (this.activeScte35BreakKey === cue.key || this.scheduledScte35BreakKey === cue.key) {
4402
+ return true;
4403
+ }
4404
+ var recentKey = "".concat(cue.marker.type, ":").concat(cue.key);
4405
+ return this.recentScte35CueKeys.has(recentKey);
4406
+ }
4407
+ },
4408
+ {
4409
+ key: "markScte35CueHandled",
4410
+ value: function markScte35CueHandled(cue) {
4411
+ this.recentScte35CueKeys.set("".concat(cue.marker.type, ":").concat(cue.key), Date.now());
4412
+ this.trimRecentScte35CueMaps();
4413
+ }
4414
+ },
4415
+ {
4416
+ key: "trimRecentScte35CueMaps",
4417
+ value: function trimRecentScte35CueMaps() {
4418
+ while(this.recentScte35CueKeys.size > this.recentScte35CueLimit){
4419
+ var firstKey = this.recentScte35CueKeys.keys().next().value;
4420
+ if (!firstKey) {
4421
+ break;
4422
+ }
4423
+ this.recentScte35CueKeys.delete(firstKey);
4424
+ }
4425
+ while(this.pendingScte35Cues.size > this.recentScte35CueLimit){
4426
+ var firstKey1 = this.pendingScte35Cues.keys().next().value;
4427
+ if (!firstKey1) {
4428
+ break;
4429
+ }
4430
+ this.pendingScte35Cues.delete(firstKey1);
4431
+ }
4432
+ }
4433
+ },
4434
+ {
4435
+ key: "shouldAcceptScte35EndCue",
4436
+ value: function shouldAcceptScte35EndCue(cue) {
4437
+ if (!this.inAdBreak) {
4438
+ return false;
4439
+ }
4440
+ if (this.isStrongScte35CueKey(this.activeScte35BreakKey) && this.isStrongScte35CueKey(cue.key) && this.activeScte35BreakKey !== cue.key) {
4441
+ return false;
4442
+ }
4443
+ return true;
4444
+ }
4445
+ },
4446
+ {
4447
+ key: "activatePendingScte35CuesForFragment",
4448
+ value: function activatePendingScte35CuesForFragment(frag) {
4449
+ var _this = this;
4450
+ var fragmentSn = typeof (frag === null || frag === void 0 ? void 0 : frag.sn) === "number" ? frag.sn : void 0;
4451
+ if (fragmentSn === void 0) {
4452
+ return;
4453
+ }
4454
+ var matchingCues = Array.from(this.pendingScte35Cues.entries()).filter(function(param) {
4455
+ var _param = _sliced_to_array(param, 2), cue = _param[1];
4456
+ return cue.fragmentSn === fragmentSn;
4457
+ });
4458
+ matchingCues.forEach(function(param) {
4459
+ var _param = _sliced_to_array(param, 2), pendingKey = _param[0], cue = _param[1];
4460
+ var _cue_fragmentStartSeconds;
4461
+ _this.pendingScte35Cues.delete(pendingKey);
4462
+ var context = {
4463
+ source: cue.source,
4464
+ readiness: "playback"
4465
+ };
4466
+ context.fragmentSn = fragmentSn;
4467
+ var fragmentStartSeconds = (_cue_fragmentStartSeconds = cue.fragmentStartSeconds) !== null && _cue_fragmentStartSeconds !== void 0 ? _cue_fragmentStartSeconds : _this.getFragmentStartSeconds(frag);
4468
+ if (fragmentStartSeconds !== void 0) {
4469
+ context.fragmentStartSeconds = fragmentStartSeconds;
4470
+ }
4471
+ _this.onScte35Cue(cue.marker, context);
4472
+ });
4473
+ }
4474
+ },
4188
4475
  {
4189
4476
  key: "onScte35Marker",
4190
- value: function onScte35Marker(marker) {
4477
+ value: function onScte35Marker(marker, cueKey) {
4191
4478
  if (this.config.debugAdTiming) {
4192
4479
  console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
4193
4480
  type: marker.type,
@@ -4201,13 +4488,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4201
4488
  if (marker.type === "start") {
4202
4489
  var _this_config_immediateManifestAds;
4203
4490
  var _this_pendingAdBreak;
4204
- if (!this.video.muted) {
4205
- this.video.muted = true;
4206
- this.video.volume = 0;
4207
- if (this.config.debugAdTiming) {
4208
- console.log("[StormcloudVideoPlayer] Muted video on SCTE start marker");
4209
- }
4210
- }
4211
4491
  if (this.inAdBreak) {
4212
4492
  if (marker.durationSeconds != null) {
4213
4493
  var newDurationMs = marker.durationSeconds * 1e3;
@@ -4231,10 +4511,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4231
4511
  sendAdDetectTracking(this.config.licenseKey, detectPayload).catch(function() {});
4232
4512
  }
4233
4513
  var hasPrefetchedAds = this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0;
4234
- this.inAdBreak = true;
4235
4514
  var durationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : ((_this_pendingAdBreak = this.pendingAdBreak) === null || _this_pendingAdBreak === void 0 ? void 0 : _this_pendingAdBreak.marker.durationSeconds) != null ? this.pendingAdBreak.marker.durationSeconds * 1e3 : void 0;
4236
- this.expectedAdBreakDurationMs = durationMs;
4237
- this.currentAdBreakStartWallClockMs = Date.now();
4238
4515
  var isManifestMarker = this.isManifestBasedMarker(marker);
4239
4516
  var forceImmediate = (_this_config_immediateManifestAds = this.config.immediateManifestAds) !== null && _this_config_immediateManifestAds !== void 0 ? _this_config_immediateManifestAds : true;
4240
4517
  if (this.config.debugAdTiming) {
@@ -4250,7 +4527,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4250
4527
  console.log("[StormcloudVideoPlayer] Starting ad immediately (manifest-based)".concat(hasPrefetchedAds ? " with prefetched ads" : ""));
4251
4528
  }
4252
4529
  this.clearAdStartTimer();
4253
- this.handleAdStart(marker);
4530
+ this.startScte35AdBreak(marker, cueKey, durationMs);
4254
4531
  } else if (typeof marker.ptsSeconds === "number") {
4255
4532
  var _this_config_driftToleranceMs;
4256
4533
  var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
@@ -4270,23 +4547,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4270
4547
  if (this.config.debugAdTiming) {
4271
4548
  console.log("[StormcloudVideoPlayer] Scheduling ad start in ".concat(deltaMs, "ms"));
4272
4549
  }
4273
- this.scheduleAdStartIn(deltaMs);
4550
+ this.expectedAdBreakDurationMs = durationMs;
4551
+ this.scheduledScte35BreakKey = cueKey;
4552
+ this.scheduleAdStartIn(deltaMs, marker, cueKey);
4274
4553
  } else {
4275
4554
  if (this.config.debugAdTiming) {
4276
4555
  console.log("[StormcloudVideoPlayer] Starting ad immediately (within tolerance)");
4277
4556
  }
4278
4557
  this.clearAdStartTimer();
4279
- this.handleAdStart(marker);
4558
+ this.startScte35AdBreak(marker, cueKey, durationMs);
4280
4559
  }
4281
4560
  } else {
4282
4561
  if (this.config.debugAdTiming) {
4283
4562
  console.log("[StormcloudVideoPlayer] Starting ad immediately (fallback)");
4284
4563
  }
4285
4564
  this.clearAdStartTimer();
4286
- this.handleAdStart(marker);
4287
- }
4288
- if (this.expectedAdBreakDurationMs != null) {
4289
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4565
+ this.startScte35AdBreak(marker, cueKey, durationMs);
4290
4566
  }
4291
4567
  return;
4292
4568
  }
@@ -4342,6 +4618,27 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4342
4618
  }
4343
4619
  }
4344
4620
  },
4621
+ {
4622
+ key: "startScte35AdBreak",
4623
+ value: function startScte35AdBreak(marker, cueKey, durationMs) {
4624
+ if (!this.video.muted) {
4625
+ this.video.muted = true;
4626
+ this.video.volume = 0;
4627
+ if (this.config.debugAdTiming) {
4628
+ console.log("[StormcloudVideoPlayer] Muted video on SCTE start marker");
4629
+ }
4630
+ }
4631
+ this.inAdBreak = true;
4632
+ this.activeScte35BreakKey = cueKey !== null && cueKey !== void 0 ? cueKey : this.pendingScte35CueKey;
4633
+ this.scheduledScte35BreakKey = void 0;
4634
+ this.expectedAdBreakDurationMs = durationMs;
4635
+ this.currentAdBreakStartWallClockMs = Date.now();
4636
+ this.handleAdStart(marker);
4637
+ if (this.expectedAdBreakDurationMs != null) {
4638
+ this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4639
+ }
4640
+ }
4641
+ },
4345
4642
  {
4346
4643
  key: "parseCueOutDuration",
4347
4644
  value: function parseCueOutDuration(value) {
@@ -4425,6 +4722,336 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4425
4722
  return false;
4426
4723
  }
4427
4724
  },
4725
+ {
4726
+ key: "normalizeFragmentPayload",
4727
+ value: function normalizeFragmentPayload(payload) {
4728
+ if (_instanceof(payload, Uint8Array)) {
4729
+ return payload;
4730
+ }
4731
+ if (_instanceof(payload, ArrayBuffer)) {
4732
+ return new Uint8Array(payload);
4733
+ }
4734
+ if (ArrayBuffer.isView(payload)) {
4735
+ var view = payload;
4736
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
4737
+ }
4738
+ return void 0;
4739
+ }
4740
+ },
4741
+ {
4742
+ key: "processFragmentScte35Payload",
4743
+ value: function processFragmentScte35Payload(payloadData, fragmentSn, fragmentStartSeconds) {
4744
+ var _this = this;
4745
+ var payload = this.normalizeFragmentPayload(payloadData);
4746
+ if (!payload) {
4747
+ return;
4748
+ }
4749
+ var markers = this.parseScte35FromTsPackets(payload);
4750
+ markers.forEach(function(marker) {
4751
+ var context = {
4752
+ source: "ts",
4753
+ readiness: "early"
4754
+ };
4755
+ if (fragmentSn !== void 0) {
4756
+ context.fragmentSn = fragmentSn;
4757
+ }
4758
+ if (fragmentStartSeconds !== void 0) {
4759
+ context.fragmentStartSeconds = fragmentStartSeconds;
4760
+ }
4761
+ _this.onScte35Cue(marker, context);
4762
+ });
4763
+ }
4764
+ },
4765
+ {
4766
+ key: "parseScte35FromTsPackets",
4767
+ value: function parseScte35FromTsPackets(data) {
4768
+ var packetInfo = this.detectTsPacketFormat(data);
4769
+ if (!packetInfo) {
4770
+ return [];
4771
+ }
4772
+ var markers = [];
4773
+ var sectionAssemblers = /* @__PURE__ */ new Map();
4774
+ for(var packetStart = packetInfo.offset; packetStart + packetInfo.packetSize <= data.length; packetStart += packetInfo.packetSize){
4775
+ var tsStart = packetStart + packetInfo.tsPayloadOffset;
4776
+ if (data[tsStart] !== 71) {
4777
+ continue;
4778
+ }
4779
+ var secondByte = data[tsStart + 1];
4780
+ var thirdByte = data[tsStart + 2];
4781
+ var fourthByte = data[tsStart + 3];
4782
+ if (secondByte == null || thirdByte == null || fourthByte == null || (secondByte & 128) !== 0) {
4783
+ continue;
4784
+ }
4785
+ var payloadUnitStart = (secondByte & 64) !== 0;
4786
+ var pid = (secondByte & 31) << 8 | thirdByte;
4787
+ var adaptationFieldControl = fourthByte >> 4 & 3;
4788
+ var hasPayload = adaptationFieldControl === 1 || adaptationFieldControl === 3;
4789
+ if (!hasPayload) {
4790
+ continue;
4791
+ }
4792
+ var payloadStart = tsStart + 4;
4793
+ if (adaptationFieldControl === 3) {
4794
+ var adaptationLength = data[payloadStart];
4795
+ if (adaptationLength == null) {
4796
+ continue;
4797
+ }
4798
+ payloadStart += 1 + adaptationLength;
4799
+ }
4800
+ var payloadEnd = Math.min(tsStart + 188, data.length);
4801
+ if (payloadStart >= payloadEnd || payloadStart >= data.length) {
4802
+ continue;
4803
+ }
4804
+ var payload = data.subarray(payloadStart, payloadEnd);
4805
+ if (pid === 0) {
4806
+ this.parsePatSection(payload, payloadUnitStart);
4807
+ } else if (this.pmtPids.has(pid)) {
4808
+ this.parsePmtSection(payload, payloadUnitStart);
4809
+ } else if (this.tsScte35Pids.has(pid)) {
4810
+ this.collectScte35SectionsFromPayload(pid, payload, payloadUnitStart, sectionAssemblers, markers);
4811
+ }
4812
+ }
4813
+ return markers;
4814
+ }
4815
+ },
4816
+ {
4817
+ key: "detectTsPacketFormat",
4818
+ value: function detectTsPacketFormat(data) {
4819
+ var packetSizes = [
4820
+ 188,
4821
+ 192,
4822
+ 204
4823
+ ];
4824
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
4825
+ try {
4826
+ for(var _iterator = packetSizes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4827
+ var packetSize = _step.value;
4828
+ var tsPayloadOffset = packetSize === 192 ? 4 : 0;
4829
+ for(var offset = 0; offset < packetSize; offset++){
4830
+ var matchedPackets = 0;
4831
+ for(var packetStart = offset; packetStart + tsPayloadOffset < data.length && matchedPackets < 5; packetStart += packetSize){
4832
+ if (data[packetStart + tsPayloadOffset] !== 71) {
4833
+ break;
4834
+ }
4835
+ matchedPackets++;
4836
+ }
4837
+ if (matchedPackets >= 2) {
4838
+ return {
4839
+ offset: offset,
4840
+ packetSize: packetSize,
4841
+ tsPayloadOffset: tsPayloadOffset
4842
+ };
4843
+ }
4844
+ }
4845
+ }
4846
+ } catch (err) {
4847
+ _didIteratorError = true;
4848
+ _iteratorError = err;
4849
+ } finally{
4850
+ try {
4851
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
4852
+ _iterator.return();
4853
+ }
4854
+ } finally{
4855
+ if (_didIteratorError) {
4856
+ throw _iteratorError;
4857
+ }
4858
+ }
4859
+ }
4860
+ return void 0;
4861
+ }
4862
+ },
4863
+ {
4864
+ key: "parsePatSection",
4865
+ value: function parsePatSection(payload, payloadUnitStart) {
4866
+ var sectionStart = this.getPsiSectionStart(payload, payloadUnitStart);
4867
+ if (sectionStart == null || sectionStart + 8 >= payload.length) {
4868
+ return;
4869
+ }
4870
+ if (payload[sectionStart] !== 0) {
4871
+ return;
4872
+ }
4873
+ var sectionLength = this.getPsiSectionLength(payload, sectionStart);
4874
+ var sectionEnd = Math.min(payload.length, sectionStart + 3 + sectionLength);
4875
+ for(var offset = sectionStart + 8; offset + 4 <= sectionEnd - 4; offset += 4){
4876
+ var _payload_offset, _payload_, _payload_1, _payload_2;
4877
+ var programNumber = ((_payload_offset = payload[offset]) !== null && _payload_offset !== void 0 ? _payload_offset : 0) << 8 | ((_payload_ = payload[offset + 1]) !== null && _payload_ !== void 0 ? _payload_ : 0);
4878
+ var pid = (((_payload_1 = payload[offset + 2]) !== null && _payload_1 !== void 0 ? _payload_1 : 0) & 31) << 8 | ((_payload_2 = payload[offset + 3]) !== null && _payload_2 !== void 0 ? _payload_2 : 0);
4879
+ if (programNumber !== 0) {
4880
+ this.pmtPids.add(pid);
4881
+ }
4882
+ }
4883
+ }
4884
+ },
4885
+ {
4886
+ key: "parsePmtSection",
4887
+ value: function parsePmtSection(payload, payloadUnitStart) {
4888
+ var _payload_, _payload_1;
4889
+ var sectionStart = this.getPsiSectionStart(payload, payloadUnitStart);
4890
+ if (sectionStart == null || sectionStart + 12 >= payload.length) {
4891
+ return;
4892
+ }
4893
+ if (payload[sectionStart] !== 2) {
4894
+ return;
4895
+ }
4896
+ var sectionLength = this.getPsiSectionLength(payload, sectionStart);
4897
+ var sectionEnd = Math.min(payload.length, sectionStart + 3 + sectionLength);
4898
+ var programInfoLength = (((_payload_ = payload[sectionStart + 10]) !== null && _payload_ !== void 0 ? _payload_ : 0) & 15) << 8 | ((_payload_1 = payload[sectionStart + 11]) !== null && _payload_1 !== void 0 ? _payload_1 : 0);
4899
+ var offset = sectionStart + 12 + programInfoLength;
4900
+ while(offset + 5 <= sectionEnd - 4){
4901
+ var _payload_offset, _payload_2, _payload_3, _payload_4, _payload_5;
4902
+ var streamType = (_payload_offset = payload[offset]) !== null && _payload_offset !== void 0 ? _payload_offset : 0;
4903
+ var elementaryPid = (((_payload_2 = payload[offset + 1]) !== null && _payload_2 !== void 0 ? _payload_2 : 0) & 31) << 8 | ((_payload_3 = payload[offset + 2]) !== null && _payload_3 !== void 0 ? _payload_3 : 0);
4904
+ var esInfoLength = (((_payload_4 = payload[offset + 3]) !== null && _payload_4 !== void 0 ? _payload_4 : 0) & 15) << 8 | ((_payload_5 = payload[offset + 4]) !== null && _payload_5 !== void 0 ? _payload_5 : 0);
4905
+ var descriptorStart = offset + 5;
4906
+ var descriptorEnd = Math.min(descriptorStart + esInfoLength, sectionEnd - 4);
4907
+ if (streamType === 134 || streamType === 6 && this.descriptorsIdentifyScte35(payload, descriptorStart, descriptorEnd)) {
4908
+ this.tsScte35Pids.add(elementaryPid);
4909
+ }
4910
+ offset = descriptorStart + esInfoLength;
4911
+ }
4912
+ }
4913
+ },
4914
+ {
4915
+ key: "descriptorsIdentifyScte35",
4916
+ value: function descriptorsIdentifyScte35(data, start, end) {
4917
+ var offset = start;
4918
+ while(offset + 2 <= end){
4919
+ var _data_offset, _data_, _data_descriptorStart, _data_1, _data_2, _data_3;
4920
+ var tag = (_data_offset = data[offset]) !== null && _data_offset !== void 0 ? _data_offset : 0;
4921
+ var length = (_data_ = data[offset + 1]) !== null && _data_ !== void 0 ? _data_ : 0;
4922
+ var descriptorStart = offset + 2;
4923
+ var descriptorEnd = descriptorStart + length;
4924
+ if (descriptorEnd > end) {
4925
+ return false;
4926
+ }
4927
+ var registration = length >= 4 ? String.fromCharCode((_data_descriptorStart = data[descriptorStart]) !== null && _data_descriptorStart !== void 0 ? _data_descriptorStart : 0, (_data_1 = data[descriptorStart + 1]) !== null && _data_1 !== void 0 ? _data_1 : 0, (_data_2 = data[descriptorStart + 2]) !== null && _data_2 !== void 0 ? _data_2 : 0, (_data_3 = data[descriptorStart + 3]) !== null && _data_3 !== void 0 ? _data_3 : 0) : "";
4928
+ if (tag === 138 || registration === "CUEI" || registration === "SCTE") {
4929
+ return true;
4930
+ }
4931
+ offset = descriptorEnd;
4932
+ }
4933
+ return false;
4934
+ }
4935
+ },
4936
+ {
4937
+ key: "collectScte35SectionsFromPayload",
4938
+ value: function collectScte35SectionsFromPayload(pid, payload, payloadUnitStart, assemblers, markers) {
4939
+ if (payload.length === 0) {
4940
+ return;
4941
+ }
4942
+ var offset = 0;
4943
+ if (payloadUnitStart) {
4944
+ var _payload_;
4945
+ var pointerField = (_payload_ = payload[0]) !== null && _payload_ !== void 0 ? _payload_ : 0;
4946
+ var previousAssembler = assemblers.get(pid);
4947
+ if (previousAssembler && pointerField > 0) {
4948
+ this.appendScte35Bytes(pid, payload.subarray(1, Math.min(1 + pointerField, payload.length)), assemblers, markers);
4949
+ }
4950
+ assemblers.delete(pid);
4951
+ offset = 1 + pointerField;
4952
+ } else {
4953
+ this.appendScte35Bytes(pid, payload, assemblers, markers);
4954
+ return;
4955
+ }
4956
+ while(offset + 3 <= payload.length){
4957
+ var tableId = payload[offset];
4958
+ if (tableId == null || tableId === 255) {
4959
+ return;
4960
+ }
4961
+ var sectionLength = this.getPsiSectionLength(payload, offset);
4962
+ var totalLength = 3 + sectionLength;
4963
+ if (sectionLength <= 0 || totalLength <= 3) {
4964
+ return;
4965
+ }
4966
+ if (offset + totalLength <= payload.length) {
4967
+ this.addScte35SectionMarker(payload.subarray(offset, offset + totalLength), markers);
4968
+ offset += totalLength;
4969
+ } else {
4970
+ assemblers.set(pid, {
4971
+ bytes: Array.from(payload.subarray(offset)),
4972
+ expectedLength: totalLength
4973
+ });
4974
+ return;
4975
+ }
4976
+ }
4977
+ }
4978
+ },
4979
+ {
4980
+ key: "appendScte35Bytes",
4981
+ value: function appendScte35Bytes(pid, bytes, assemblers, markers) {
4982
+ var assembler = assemblers.get(pid);
4983
+ if (!assembler) {
4984
+ return;
4985
+ }
4986
+ for(var i = 0; i < bytes.length && assembler.bytes.length < assembler.expectedLength; i++){
4987
+ var _bytes_i;
4988
+ assembler.bytes.push((_bytes_i = bytes[i]) !== null && _bytes_i !== void 0 ? _bytes_i : 0);
4989
+ }
4990
+ if (assembler.bytes.length >= assembler.expectedLength) {
4991
+ assemblers.delete(pid);
4992
+ this.addScte35SectionMarker(new Uint8Array(assembler.bytes), markers);
4993
+ }
4994
+ }
4995
+ },
4996
+ {
4997
+ key: "addScte35SectionMarker",
4998
+ value: function addScte35SectionMarker(section, markers) {
4999
+ if (section[0] !== 252 || this.hasProcessedTsScte35Section(section)) {
5000
+ return;
5001
+ }
5002
+ var marker = this.parseScte35Binary(section);
5003
+ if (!marker) {
5004
+ return;
5005
+ }
5006
+ marker.raw = _object_spread_props(_object_spread({}, _type_of(marker.raw) === "object" && marker.raw ? marker.raw : {}), {
5007
+ source: "ts-packet"
5008
+ });
5009
+ markers.push(marker);
5010
+ }
5011
+ },
5012
+ {
5013
+ key: "hasProcessedTsScte35Section",
5014
+ value: function hasProcessedTsScte35Section(section) {
5015
+ var checksum = 0;
5016
+ for(var i = 0; i < section.length; i++){
5017
+ var _section_i;
5018
+ checksum = checksum * 31 + ((_section_i = section[i]) !== null && _section_i !== void 0 ? _section_i : 0) >>> 0;
5019
+ }
5020
+ var key = "".concat(section.length, ":").concat(checksum);
5021
+ if (this.processedTsScte35Sections.has(key)) {
5022
+ return true;
5023
+ }
5024
+ this.processedTsScte35Sections.add(key);
5025
+ if (this.processedTsScte35Sections.size > 200) {
5026
+ var firstKey = this.processedTsScte35Sections.values().next().value;
5027
+ if (firstKey) {
5028
+ this.processedTsScte35Sections.delete(firstKey);
5029
+ }
5030
+ }
5031
+ return false;
5032
+ }
5033
+ },
5034
+ {
5035
+ key: "getPsiSectionStart",
5036
+ value: function getPsiSectionStart(payload, payloadUnitStart) {
5037
+ if (!payloadUnitStart) {
5038
+ return void 0;
5039
+ }
5040
+ var pointerField = payload[0];
5041
+ if (pointerField == null) {
5042
+ return void 0;
5043
+ }
5044
+ var sectionStart = 1 + pointerField;
5045
+ return sectionStart < payload.length ? sectionStart : void 0;
5046
+ }
5047
+ },
5048
+ {
5049
+ key: "getPsiSectionLength",
5050
+ value: function getPsiSectionLength(data, offset) {
5051
+ var _data_, _data_1;
5052
+ return (((_data_ = data[offset + 1]) !== null && _data_ !== void 0 ? _data_ : 0) & 15) << 8 | ((_data_1 = data[offset + 2]) !== null && _data_1 !== void 0 ? _data_1 : 0);
5053
+ }
5054
+ },
4428
5055
  {
4429
5056
  key: "parseScte35Binary",
4430
5057
  value: function parseScte35Binary(data) {
@@ -4464,10 +5091,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4464
5091
  value: function skipBits(n) {
4465
5092
  this.readBits(n);
4466
5093
  }
5094
+ },
5095
+ {
5096
+ key: "bytePosition",
5097
+ get: function get() {
5098
+ return this.bitPos === 0 ? this.bytePos : this.bytePos + 1;
5099
+ }
4467
5100
  }
4468
5101
  ]);
4469
5102
  return BitReader;
4470
5103
  }();
5104
+ var readSpliceTime = function readSpliceTime(r2, ptsAdjustmentTicks2) {
5105
+ var timeSpecifiedFlag = r2.readBits(1) === 1;
5106
+ if (!timeSpecifiedFlag) {
5107
+ r2.readBits(7);
5108
+ return void 0;
5109
+ }
5110
+ r2.readBits(6);
5111
+ var high = r2.readBits(1);
5112
+ var low = r2.readBits(32);
5113
+ var ptsTicks = (high * 4294967296 + low + ptsAdjustmentTicks2) % 8589934592;
5114
+ return ptsTicks / 9e4;
5115
+ };
4471
5116
  var r = new BitReader(data);
4472
5117
  var tableId = r.readBits(8);
4473
5118
  if (tableId !== 252) return void 0;
@@ -4475,77 +5120,206 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4475
5120
  r.readBits(1);
4476
5121
  r.readBits(2);
4477
5122
  var sectionLength = r.readBits(12);
5123
+ if (sectionLength <= 0 || data.length < 3 + sectionLength) {
5124
+ return void 0;
5125
+ }
4478
5126
  r.readBits(8);
4479
5127
  r.readBits(1);
4480
5128
  r.readBits(6);
4481
5129
  var ptsAdjHigh = r.readBits(1);
4482
5130
  var ptsAdjLow = r.readBits(32);
4483
- void ptsAdjHigh;
4484
- void ptsAdjLow;
5131
+ var ptsAdjustmentTicks = ptsAdjHigh * 4294967296 + ptsAdjLow;
4485
5132
  r.readBits(8);
4486
5133
  r.readBits(12);
4487
5134
  var spliceCommandLength = r.readBits(12);
4488
5135
  var spliceCommandType = r.readBits(8);
4489
- if (spliceCommandType !== 5) {
5136
+ var markerType;
5137
+ var durationSeconds = void 0;
5138
+ var ptsSeconds = void 0;
5139
+ var spliceEventId = void 0;
5140
+ var commandBodyStart = r.bytePosition;
5141
+ if (spliceCommandType === 5) {
5142
+ spliceEventId = r.readBits(32);
5143
+ var cancel = r.readBits(1) === 1;
5144
+ r.readBits(7);
5145
+ if (cancel) return void 0;
5146
+ var outOfNetwork = r.readBits(1) === 1;
5147
+ var programSpliceFlag = r.readBits(1) === 1;
5148
+ var durationFlag = r.readBits(1) === 1;
5149
+ var spliceImmediateFlag = r.readBits(1) === 1;
5150
+ r.readBits(4);
5151
+ markerType = outOfNetwork ? "start" : "end";
5152
+ if (programSpliceFlag && !spliceImmediateFlag) {
5153
+ ptsSeconds = readSpliceTime(r, ptsAdjustmentTicks);
5154
+ } else if (!programSpliceFlag) {
5155
+ var componentCount = r.readBits(8);
5156
+ for(var i = 0; i < componentCount; i++){
5157
+ r.readBits(8);
5158
+ if (!spliceImmediateFlag) {
5159
+ var componentPtsSeconds = readSpliceTime(r, ptsAdjustmentTicks);
5160
+ if (ptsSeconds === void 0) {
5161
+ ptsSeconds = componentPtsSeconds;
5162
+ }
5163
+ }
5164
+ }
5165
+ }
5166
+ if (durationFlag) {
5167
+ r.readBits(6);
5168
+ r.readBits(1);
5169
+ var high = r.readBits(1);
5170
+ var low = r.readBits(32);
5171
+ var durationTicks = high * 4294967296 + low;
5172
+ durationSeconds = durationTicks / 9e4;
5173
+ }
5174
+ r.readBits(16);
5175
+ r.readBits(8);
5176
+ r.readBits(8);
5177
+ } else if (spliceCommandType === 6) {
5178
+ ptsSeconds = readSpliceTime(r, ptsAdjustmentTicks);
5179
+ } else {
4490
5180
  return void 0;
4491
5181
  }
4492
- r.readBits(32);
4493
- var cancel = r.readBits(1) === 1;
4494
- r.readBits(7);
4495
- if (cancel) return void 0;
4496
- var outOfNetwork = r.readBits(1) === 1;
4497
- var programSpliceFlag = r.readBits(1) === 1;
4498
- var durationFlag = r.readBits(1) === 1;
4499
- var spliceImmediateFlag = r.readBits(1) === 1;
4500
- r.readBits(4);
4501
- if (programSpliceFlag && !spliceImmediateFlag) {
4502
- var timeSpecifiedFlag = r.readBits(1) === 1;
4503
- if (timeSpecifiedFlag) {
4504
- r.readBits(6);
4505
- r.readBits(33);
4506
- } else {
4507
- r.readBits(7);
4508
- }
4509
- } else if (!programSpliceFlag) {
4510
- var componentCount = r.readBits(8);
4511
- for(var i = 0; i < componentCount; i++){
4512
- r.readBits(8);
4513
- if (!spliceImmediateFlag) {
4514
- var timeSpecifiedFlag1 = r.readBits(1) === 1;
4515
- if (timeSpecifiedFlag1) {
4516
- r.readBits(6);
4517
- r.readBits(33);
4518
- } else {
4519
- r.readBits(7);
4520
- }
5182
+ var expectedDescriptorOffset = spliceCommandLength === 4095 ? r.bytePosition : commandBodyStart + spliceCommandLength;
5183
+ var descriptorMarker = this.parseScte35SegmentationDescriptors(data, expectedDescriptorOffset);
5184
+ if (descriptorMarker) {
5185
+ markerType = descriptorMarker.type;
5186
+ if (durationSeconds === void 0) {
5187
+ durationSeconds = descriptorMarker.durationSeconds;
5188
+ }
5189
+ }
5190
+ if (!markerType) {
5191
+ return void 0;
5192
+ }
5193
+ var marker = _object_spread_props(_object_spread({
5194
+ type: markerType
5195
+ }, ptsSeconds !== void 0 ? {
5196
+ ptsSeconds: ptsSeconds
5197
+ } : {}, durationSeconds !== void 0 ? {
5198
+ durationSeconds: durationSeconds
5199
+ } : {}), {
5200
+ raw: _object_spread({
5201
+ splice_command_type: spliceCommandType
5202
+ }, spliceEventId !== void 0 ? {
5203
+ splice_event_id: spliceEventId
5204
+ } : {}, (descriptorMarker === null || descriptorMarker === void 0 ? void 0 : descriptorMarker.segmentationEventId) !== void 0 ? {
5205
+ segmentation_event_id: descriptorMarker.segmentationEventId
5206
+ } : {})
5207
+ });
5208
+ return marker;
5209
+ }
5210
+ },
5211
+ {
5212
+ key: "parseScte35SegmentationDescriptors",
5213
+ value: function parseScte35SegmentationDescriptors(data, offset) {
5214
+ var _data_offset, _data_;
5215
+ if (offset + 2 > data.length) {
5216
+ return void 0;
5217
+ }
5218
+ var descriptorLoopLength = ((_data_offset = data[offset]) !== null && _data_offset !== void 0 ? _data_offset : 0) << 8 | ((_data_ = data[offset + 1]) !== null && _data_ !== void 0 ? _data_ : 0);
5219
+ var descriptorOffset = offset + 2;
5220
+ var descriptorEnd = Math.min(data.length, descriptorOffset + descriptorLoopLength);
5221
+ while(descriptorOffset + 2 <= descriptorEnd){
5222
+ var _data_descriptorOffset, _data_1;
5223
+ var descriptorTag = (_data_descriptorOffset = data[descriptorOffset]) !== null && _data_descriptorOffset !== void 0 ? _data_descriptorOffset : 0;
5224
+ var descriptorLength = (_data_1 = data[descriptorOffset + 1]) !== null && _data_1 !== void 0 ? _data_1 : 0;
5225
+ var descriptorDataStart = descriptorOffset + 2;
5226
+ var descriptorDataEnd = descriptorDataStart + descriptorLength;
5227
+ if (descriptorDataEnd > descriptorEnd) {
5228
+ return void 0;
5229
+ }
5230
+ if (descriptorTag === 2) {
5231
+ var descriptorMarker = this.parseScte35SegmentationDescriptor(data.subarray(descriptorDataStart, descriptorDataEnd));
5232
+ if (descriptorMarker) {
5233
+ return descriptorMarker;
4521
5234
  }
4522
5235
  }
5236
+ descriptorOffset = descriptorDataEnd;
5237
+ }
5238
+ return void 0;
5239
+ }
5240
+ },
5241
+ {
5242
+ key: "parseScte35SegmentationDescriptor",
5243
+ value: function parseScte35SegmentationDescriptor(descriptor) {
5244
+ var _descriptor_, _descriptor_1, _descriptor_2, _descriptor_3, _descriptor_4, _descriptor_5, _descriptor_6, _descriptor_7, _descriptor_8, _descriptor_9, _descriptor_offset, _descriptor_offset1;
5245
+ if (descriptor.length < 11) {
5246
+ return void 0;
5247
+ }
5248
+ var identifier = String.fromCharCode((_descriptor_ = descriptor[0]) !== null && _descriptor_ !== void 0 ? _descriptor_ : 0, (_descriptor_1 = descriptor[1]) !== null && _descriptor_1 !== void 0 ? _descriptor_1 : 0, (_descriptor_2 = descriptor[2]) !== null && _descriptor_2 !== void 0 ? _descriptor_2 : 0, (_descriptor_3 = descriptor[3]) !== null && _descriptor_3 !== void 0 ? _descriptor_3 : 0);
5249
+ if (identifier !== "CUEI") {
5250
+ return void 0;
5251
+ }
5252
+ var segmentationEventId = ((_descriptor_4 = descriptor[4]) !== null && _descriptor_4 !== void 0 ? _descriptor_4 : 0) * 16777216 + (((_descriptor_5 = descriptor[5]) !== null && _descriptor_5 !== void 0 ? _descriptor_5 : 0) << 16) + (((_descriptor_6 = descriptor[6]) !== null && _descriptor_6 !== void 0 ? _descriptor_6 : 0) << 8) + ((_descriptor_7 = descriptor[7]) !== null && _descriptor_7 !== void 0 ? _descriptor_7 : 0);
5253
+ var cancelIndicator = (((_descriptor_8 = descriptor[8]) !== null && _descriptor_8 !== void 0 ? _descriptor_8 : 0) & 128) !== 0;
5254
+ if (cancelIndicator) {
5255
+ return void 0;
5256
+ }
5257
+ var flags = (_descriptor_9 = descriptor[9]) !== null && _descriptor_9 !== void 0 ? _descriptor_9 : 0;
5258
+ var programSegmentationFlag = (flags & 128) !== 0;
5259
+ var segmentationDurationFlag = (flags & 64) !== 0;
5260
+ var offset = 10;
5261
+ if (!programSegmentationFlag) {
5262
+ var _descriptor_offset2;
5263
+ var componentCount = (_descriptor_offset2 = descriptor[offset]) !== null && _descriptor_offset2 !== void 0 ? _descriptor_offset2 : 0;
5264
+ offset += 1 + componentCount * 6;
5265
+ if (offset > descriptor.length) {
5266
+ return void 0;
5267
+ }
4523
5268
  }
4524
5269
  var durationSeconds = void 0;
4525
- if (durationFlag) {
4526
- r.readBits(6);
4527
- r.readBits(1);
4528
- var high = r.readBits(1);
4529
- var low = r.readBits(32);
4530
- var durationTicks = high * 4294967296 + low;
5270
+ if (segmentationDurationFlag) {
5271
+ var _descriptor_offset3, _descriptor_10, _descriptor_11, _descriptor_12, _descriptor_13;
5272
+ if (offset + 5 > descriptor.length) {
5273
+ return void 0;
5274
+ }
5275
+ var durationTicks = ((_descriptor_offset3 = descriptor[offset]) !== null && _descriptor_offset3 !== void 0 ? _descriptor_offset3 : 0) * 4294967296 + ((_descriptor_10 = descriptor[offset + 1]) !== null && _descriptor_10 !== void 0 ? _descriptor_10 : 0) * 16777216 + (((_descriptor_11 = descriptor[offset + 2]) !== null && _descriptor_11 !== void 0 ? _descriptor_11 : 0) << 16) + (((_descriptor_12 = descriptor[offset + 3]) !== null && _descriptor_12 !== void 0 ? _descriptor_12 : 0) << 8) + ((_descriptor_13 = descriptor[offset + 4]) !== null && _descriptor_13 !== void 0 ? _descriptor_13 : 0);
4531
5276
  durationSeconds = durationTicks / 9e4;
5277
+ offset += 5;
4532
5278
  }
4533
- r.readBits(16);
4534
- r.readBits(8);
4535
- r.readBits(8);
4536
- if (outOfNetwork) {
4537
- var marker = _object_spread_props(_object_spread({
4538
- type: "start"
4539
- }, durationSeconds !== void 0 ? {
4540
- durationSeconds: durationSeconds
4541
- } : {}), {
4542
- raw: {
4543
- splice_command_type: 5
4544
- }
4545
- });
4546
- return marker;
5279
+ if (offset + 2 > descriptor.length) {
5280
+ return void 0;
5281
+ }
5282
+ offset += 1;
5283
+ var segmentationUpidLength = (_descriptor_offset = descriptor[offset]) !== null && _descriptor_offset !== void 0 ? _descriptor_offset : 0;
5284
+ offset += 1 + segmentationUpidLength;
5285
+ if (offset >= descriptor.length) {
5286
+ return void 0;
5287
+ }
5288
+ var segmentationTypeId = (_descriptor_offset1 = descriptor[offset]) !== null && _descriptor_offset1 !== void 0 ? _descriptor_offset1 : 0;
5289
+ var markerType = this.markerTypeFromSegmentationTypeId(segmentationTypeId);
5290
+ if (!markerType) {
5291
+ return void 0;
5292
+ }
5293
+ return _object_spread_props(_object_spread({
5294
+ type: markerType
5295
+ }, durationSeconds !== void 0 ? {
5296
+ durationSeconds: durationSeconds
5297
+ } : {}), {
5298
+ segmentationEventId: segmentationEventId
5299
+ });
5300
+ }
5301
+ },
5302
+ {
5303
+ key: "markerTypeFromSegmentationTypeId",
5304
+ value: function markerTypeFromSegmentationTypeId(segmentationTypeId) {
5305
+ switch(segmentationTypeId){
5306
+ case 16:
5307
+ case 34:
5308
+ case 48:
5309
+ case 50:
5310
+ case 52:
5311
+ case 54:
5312
+ return "start";
5313
+ case 17:
5314
+ case 35:
5315
+ case 49:
5316
+ case 51:
5317
+ case 53:
5318
+ case 55:
5319
+ return "end";
5320
+ default:
5321
+ return void 0;
4547
5322
  }
4548
- return void 0;
4549
5323
  }
4550
5324
  },
4551
5325
  {
@@ -4942,7 +5716,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4942
5716
  },
4943
5717
  {
4944
5718
  key: "startAdPrefetch",
4945
- value: function startAdPrefetch(marker, fragmentSn) {
5719
+ value: function startAdPrefetch(marker, fragmentSn, cueKey) {
4946
5720
  if (this.pendingAdBreak || this.inAdBreak) {
4947
5721
  return;
4948
5722
  }
@@ -4970,6 +5744,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4970
5744
  isFetching: false,
4971
5745
  fetchStartTime: Date.now()
4972
5746
  });
5747
+ this.pendingScte35CueKey = cueKey;
4973
5748
  this.adDetectSentForCurrentBreak = true;
4974
5749
  var detectPayload = {};
4975
5750
  if (marker.durationSeconds != null) detectPayload.durationSeconds = marker.durationSeconds;
@@ -4991,6 +5766,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4991
5766
  this.prefetchTimerId = void 0;
4992
5767
  }
4993
5768
  this.pendingAdBreak = null;
5769
+ this.pendingScte35CueKey = void 0;
4994
5770
  }
4995
5771
  },
4996
5772
  {
@@ -6474,18 +7250,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6474
7250
  key: "scheduleAdStartIn",
6475
7251
  value: function scheduleAdStartIn(delayMs) {
6476
7252
  var _this = this;
7253
+ var marker = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {
7254
+ type: "start"
7255
+ }, cueKey = arguments.length > 2 ? arguments[2] : void 0;
6477
7256
  this.clearAdStartTimer();
6478
7257
  var ms = Math.max(0, Math.floor(delayMs));
6479
7258
  if (ms === 0) {
6480
- this.handleAdStart({
6481
- type: "start"
6482
- }).catch(function() {});
7259
+ this.startScte35AdBreak(marker, cueKey, marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0);
6483
7260
  return;
6484
7261
  }
6485
7262
  this.adStartTimerId = window.setTimeout(function() {
6486
- _this.handleAdStart({
6487
- type: "start"
6488
- }).catch(function() {});
7263
+ _this.startScte35AdBreak(marker, cueKey, marker.durationSeconds != null ? marker.durationSeconds * 1e3 : _this.expectedAdBreakDurationMs);
6489
7264
  }, ms);
6490
7265
  }
6491
7266
  },
@@ -6916,6 +7691,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6916
7691
  this.adRequestQueue = [];
6917
7692
  this.inAdBreak = false;
6918
7693
  this.adDetectSentForCurrentBreak = false;
7694
+ this.activeScte35BreakKey = void 0;
7695
+ this.scheduledScte35BreakKey = void 0;
6919
7696
  this.expectedAdBreakDurationMs = void 0;
6920
7697
  this.currentAdBreakStartWallClockMs = void 0;
6921
7698
  this.clearAdStartTimer();