stormcloud-video-player 0.3.64 → 0.3.66

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.d.cts CHANGED
@@ -2,6 +2,25 @@ import React, { CSSProperties, lazy as lazy$1 } from 'react';
2
2
  import * as csstype from 'csstype';
3
3
  import Hls from 'hls.js';
4
4
 
5
+ declare const MQTT_CA_CERT_FILE = "src/certs/emqxsl-ca.crt";
6
+ type MQTTConfig = {
7
+ enabled: boolean;
8
+ brokerAddress: string;
9
+ brokerPort: number;
10
+ wsPort: number;
11
+ username: string;
12
+ password: string;
13
+ topicPrefix: string;
14
+ qos: 0 | 1 | 2;
15
+ brokerUrl?: string;
16
+ };
17
+ declare const DEFAULT_MQTT_CONFIG: MQTTConfig;
18
+ declare const mqttConfig: MQTTConfig;
19
+ declare function applyMQTTConfig(overrides: Partial<MQTTConfig>): void;
20
+ declare function isMQTTEnabled(): boolean;
21
+ declare function buildMQTTBrokerUrl(): string;
22
+ declare function buildPlayerTopic(licenseKey: string, channel: "metrics" | "impressions" | "heartbeat"): string;
23
+
5
24
  type LateJoinPolicy = "play_remaining" | "skip_to_content";
6
25
  interface AdBreak {
7
26
  id?: string;
@@ -145,6 +164,7 @@ declare class StormcloudVideoPlayer {
145
164
  private inAdBreak;
146
165
  private currentAdBreakStartWallClockMs;
147
166
  private expectedAdBreakDurationMs;
167
+ private scteAdBreakEndWallClockMs;
148
168
  private adStopTimerId;
149
169
  private adStartTimerId;
150
170
  private adFailsafeTimerId;
@@ -241,6 +261,9 @@ declare class StormcloudVideoPlayer {
241
261
  private activatePendingScte35CuesForFragment;
242
262
  private onScte35Marker;
243
263
  private startScte35AdBreak;
264
+ private resolveScteBreakStartWallClockMs;
265
+ private setAdBreakDurationBoundary;
266
+ private scheduleAdStopAtBreakBoundary;
244
267
  private parseCueOutDuration;
245
268
  private parseCueOutCont;
246
269
  private parseAttributeList;
@@ -266,6 +289,7 @@ declare class StormcloudVideoPlayer {
266
289
  private initializeTracking;
267
290
  private sendHeartbeatIfNeeded;
268
291
  private isVmapEnabled;
292
+ private applyMqttConfigFromResponse;
269
293
  private fetchAdConfiguration;
270
294
  private fetchAndParseVmap;
271
295
  private parseVmapToBreaks;
@@ -324,6 +348,7 @@ declare class StormcloudVideoPlayer {
324
348
  private selectVastTagsForBreak;
325
349
  private logAdState;
326
350
  private getRemainingAdMs;
351
+ private getAdBreakEndWallClockMs;
327
352
  private findBreakForTime;
328
353
  toggleMute(): void;
329
354
  toggleFullscreen(): Promise<void>;
@@ -4079,25 +4104,6 @@ declare function sendAdLoadedTracking(licenseKey: string | undefined, adLoadedIn
4079
4104
  declare function sendAdImpressionTracking(licenseKey: string | undefined, adImpressionInfo: AdImpressionInfo, context?: PlayerAnalyticsContext): Promise<void>;
4080
4105
  declare function sendHeartbeat(licenseKey?: string, context?: PlayerAnalyticsContext, flags?: PlayerMetricFlags): Promise<void>;
4081
4106
 
4082
- declare const MQTT_CA_CERT_FILE = "src/certs/emqxsl-ca.crt";
4083
- type MQTTConfig = {
4084
- enabled: boolean;
4085
- brokerAddress: string;
4086
- brokerPort: number;
4087
- wsPort: number;
4088
- username: string;
4089
- password: string;
4090
- topicPrefix: string;
4091
- qos: 0 | 1 | 2;
4092
- brokerUrl?: string;
4093
- };
4094
- declare const DEFAULT_MQTT_CONFIG: MQTTConfig;
4095
- declare const mqttConfig: MQTTConfig;
4096
- declare function applyMQTTConfig(overrides: Partial<MQTTConfig>): void;
4097
- declare function isMQTTEnabled(): boolean;
4098
- declare function buildMQTTBrokerUrl(): string;
4099
- declare function buildPlayerTopic(licenseKey: string, channel: "metrics" | "impressions" | "heartbeat"): string;
4100
-
4101
4107
  type MQTTStatus = "disconnected" | "connecting" | "connected" | "error";
4102
4108
  declare function getMQTTStatus(): MQTTStatus;
4103
4109
  declare function isMQTTConnected(): boolean;
package/lib/index.d.ts CHANGED
@@ -2,6 +2,25 @@ import React, { CSSProperties, lazy as lazy$1 } from 'react';
2
2
  import * as csstype from 'csstype';
3
3
  import Hls from 'hls.js';
4
4
 
5
+ declare const MQTT_CA_CERT_FILE = "src/certs/emqxsl-ca.crt";
6
+ type MQTTConfig = {
7
+ enabled: boolean;
8
+ brokerAddress: string;
9
+ brokerPort: number;
10
+ wsPort: number;
11
+ username: string;
12
+ password: string;
13
+ topicPrefix: string;
14
+ qos: 0 | 1 | 2;
15
+ brokerUrl?: string;
16
+ };
17
+ declare const DEFAULT_MQTT_CONFIG: MQTTConfig;
18
+ declare const mqttConfig: MQTTConfig;
19
+ declare function applyMQTTConfig(overrides: Partial<MQTTConfig>): void;
20
+ declare function isMQTTEnabled(): boolean;
21
+ declare function buildMQTTBrokerUrl(): string;
22
+ declare function buildPlayerTopic(licenseKey: string, channel: "metrics" | "impressions" | "heartbeat"): string;
23
+
5
24
  type LateJoinPolicy = "play_remaining" | "skip_to_content";
6
25
  interface AdBreak {
7
26
  id?: string;
@@ -145,6 +164,7 @@ declare class StormcloudVideoPlayer {
145
164
  private inAdBreak;
146
165
  private currentAdBreakStartWallClockMs;
147
166
  private expectedAdBreakDurationMs;
167
+ private scteAdBreakEndWallClockMs;
148
168
  private adStopTimerId;
149
169
  private adStartTimerId;
150
170
  private adFailsafeTimerId;
@@ -241,6 +261,9 @@ declare class StormcloudVideoPlayer {
241
261
  private activatePendingScte35CuesForFragment;
242
262
  private onScte35Marker;
243
263
  private startScte35AdBreak;
264
+ private resolveScteBreakStartWallClockMs;
265
+ private setAdBreakDurationBoundary;
266
+ private scheduleAdStopAtBreakBoundary;
244
267
  private parseCueOutDuration;
245
268
  private parseCueOutCont;
246
269
  private parseAttributeList;
@@ -266,6 +289,7 @@ declare class StormcloudVideoPlayer {
266
289
  private initializeTracking;
267
290
  private sendHeartbeatIfNeeded;
268
291
  private isVmapEnabled;
292
+ private applyMqttConfigFromResponse;
269
293
  private fetchAdConfiguration;
270
294
  private fetchAndParseVmap;
271
295
  private parseVmapToBreaks;
@@ -324,6 +348,7 @@ declare class StormcloudVideoPlayer {
324
348
  private selectVastTagsForBreak;
325
349
  private logAdState;
326
350
  private getRemainingAdMs;
351
+ private getAdBreakEndWallClockMs;
327
352
  private findBreakForTime;
328
353
  toggleMute(): void;
329
354
  toggleFullscreen(): Promise<void>;
@@ -4079,25 +4104,6 @@ declare function sendAdLoadedTracking(licenseKey: string | undefined, adLoadedIn
4079
4104
  declare function sendAdImpressionTracking(licenseKey: string | undefined, adImpressionInfo: AdImpressionInfo, context?: PlayerAnalyticsContext): Promise<void>;
4080
4105
  declare function sendHeartbeat(licenseKey?: string, context?: PlayerAnalyticsContext, flags?: PlayerMetricFlags): Promise<void>;
4081
4106
 
4082
- declare const MQTT_CA_CERT_FILE = "src/certs/emqxsl-ca.crt";
4083
- type MQTTConfig = {
4084
- enabled: boolean;
4085
- brokerAddress: string;
4086
- brokerPort: number;
4087
- wsPort: number;
4088
- username: string;
4089
- password: string;
4090
- topicPrefix: string;
4091
- qos: 0 | 1 | 2;
4092
- brokerUrl?: string;
4093
- };
4094
- declare const DEFAULT_MQTT_CONFIG: MQTTConfig;
4095
- declare const mqttConfig: MQTTConfig;
4096
- declare function applyMQTTConfig(overrides: Partial<MQTTConfig>): void;
4097
- declare function isMQTTEnabled(): boolean;
4098
- declare function buildMQTTBrokerUrl(): string;
4099
- declare function buildPlayerTopic(licenseKey: string, channel: "metrics" | "impressions" | "heartbeat"): string;
4100
-
4101
4107
  type MQTTStatus = "disconnected" | "connecting" | "connected" | "error";
4102
4108
  declare function getMQTTStatus(): MQTTStatus;
4103
4109
  declare function isMQTTConnected(): boolean;
package/lib/index.js CHANGED
@@ -3905,7 +3905,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3905
3905
  _this.showAds = true;
3906
3906
  _this.resetGamNoFillCounter();
3907
3907
  if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3908
- _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3908
+ _this.scheduleAdStopAtBreakBoundary();
3909
3909
  if (_this.config.debugAdTiming) {
3910
3910
  console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3911
3911
  }
@@ -4549,12 +4549,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4549
4549
  if (marker.durationSeconds != null) {
4550
4550
  var newDurationMs = marker.durationSeconds * 1e3;
4551
4551
  if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4552
- this.expectedAdBreakDurationMs = newDurationMs;
4553
- var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4554
- var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4555
- this.scheduleAdStopCountdown(remainingMs);
4552
+ this.setAdBreakDurationBoundary(newDurationMs);
4553
+ this.scheduleAdStopAtBreakBoundary();
4556
4554
  if (this.config.debugAdTiming) {
4557
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4555
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(this.getRemainingAdMs(), "ms"));
4558
4556
  }
4559
4557
  }
4560
4558
  }
@@ -4628,13 +4626,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4628
4626
  }
4629
4627
  if (marker.type === "progress" && this.inAdBreak) {
4630
4628
  if (marker.durationSeconds != null) {
4631
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4632
- }
4633
- if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4634
- var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4635
- var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4636
- this.scheduleAdStopCountdown(remainingMs1);
4629
+ this.setAdBreakDurationBoundary(marker.durationSeconds * 1e3);
4637
4630
  }
4631
+ this.scheduleAdStopAtBreakBoundary();
4638
4632
  if (!this.ima.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0) {
4639
4633
  this.tryNextAvailableAdWithRateLimit();
4640
4634
  }
@@ -4659,15 +4653,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4659
4653
  activeAdRequest: this.activeAdRequestToken !== null
4660
4654
  });
4661
4655
  }
4662
- if (adPlaying || remaining > 1e3 && hasQueuedAds) {
4663
- if (this.config.debugAdTiming) {
4664
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active");
4665
- }
4666
- return;
4667
- }
4668
- this.inAdBreak = false;
4669
- this.expectedAdBreakDurationMs = void 0;
4670
- this.currentAdBreakStartWallClockMs = void 0;
4656
+ this.scteAdBreakEndWallClockMs = Date.now();
4671
4657
  this.clearAdStartTimer();
4672
4658
  this.clearAdStopTimer();
4673
4659
  if (adPlaying) {
@@ -4691,12 +4677,46 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4691
4677
  this.inAdBreak = true;
4692
4678
  this.activeScte35BreakKey = cueKey !== null && cueKey !== void 0 ? cueKey : this.pendingScte35CueKey;
4693
4679
  this.scheduledScte35BreakKey = void 0;
4694
- this.expectedAdBreakDurationMs = durationMs;
4695
- this.currentAdBreakStartWallClockMs = Date.now();
4680
+ this.currentAdBreakStartWallClockMs = this.resolveScteBreakStartWallClockMs(marker);
4681
+ this.setAdBreakDurationBoundary(durationMs);
4696
4682
  this.handleAdStart(marker);
4697
- if (this.expectedAdBreakDurationMs != null) {
4698
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4683
+ this.scheduleAdStopAtBreakBoundary();
4684
+ }
4685
+ },
4686
+ {
4687
+ key: "resolveScteBreakStartWallClockMs",
4688
+ value: function resolveScteBreakStartWallClockMs(marker) {
4689
+ var nowWallClockMs = Date.now();
4690
+ if (typeof marker.ptsSeconds !== "number") {
4691
+ return nowWallClockMs;
4692
+ }
4693
+ var nowMs = this.video.currentTime * 1e3;
4694
+ var estimatedCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
4695
+ var deltaMs = marker.ptsSeconds * 1e3 - estimatedCurrentPtsMs;
4696
+ if (!Number.isFinite(deltaMs)) {
4697
+ return nowWallClockMs;
4698
+ }
4699
+ return nowWallClockMs + Math.floor(deltaMs);
4700
+ }
4701
+ },
4702
+ {
4703
+ key: "setAdBreakDurationBoundary",
4704
+ value: function setAdBreakDurationBoundary(durationMs) {
4705
+ this.expectedAdBreakDurationMs = durationMs;
4706
+ if (durationMs != null && this.currentAdBreakStartWallClockMs != null) {
4707
+ this.scteAdBreakEndWallClockMs = this.currentAdBreakStartWallClockMs + durationMs;
4708
+ } else {
4709
+ this.scteAdBreakEndWallClockMs = void 0;
4710
+ }
4711
+ }
4712
+ },
4713
+ {
4714
+ key: "scheduleAdStopAtBreakBoundary",
4715
+ value: function scheduleAdStopAtBreakBoundary() {
4716
+ if (this.expectedAdBreakDurationMs == null) {
4717
+ return;
4699
4718
  }
4719
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
4700
4720
  }
4701
4721
  },
4702
4722
  {
@@ -5422,6 +5442,20 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5422
5442
  return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
5423
5443
  }
5424
5444
  },
5445
+ {
5446
+ key: "applyMqttConfigFromResponse",
5447
+ value: function applyMqttConfigFromResponse(data) {
5448
+ var _data_response;
5449
+ var mqttConfig2 = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : _data_response.mqtt_config;
5450
+ if (!mqttConfig2 || (typeof mqttConfig2 === "undefined" ? "undefined" : _type_of(mqttConfig2)) !== "object") {
5451
+ return;
5452
+ }
5453
+ applyMQTTConfig(mqttConfig2);
5454
+ if (this.config.debugAdTiming) {
5455
+ console.log("[StormcloudVideoPlayer] Applied MQTT config from /ads/web:", mqttConfig2);
5456
+ }
5457
+ }
5458
+ },
5425
5459
  {
5426
5460
  key: "fetchAdConfiguration",
5427
5461
  value: function fetchAdConfiguration() {
@@ -5508,6 +5542,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5508
5542
  ];
5509
5543
  case 4:
5510
5544
  data = _state.sent();
5545
+ this.applyMqttConfigFromResponse(data);
5511
5546
  imaPayload = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
5512
5547
  if (imaPayload) {
5513
5548
  this.apiVastTagUrl = decodeURIComponent(imaPayload);
@@ -6324,7 +6359,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6324
6359
  }
6325
6360
  }
6326
6361
  this.inAdBreak = true;
6327
- this.currentAdBreakStartWallClockMs = Date.now();
6328
6362
  this.currentAdIndex = 0;
6329
6363
  this.totalAdsInBreak = 1;
6330
6364
  this.adPodQueue = [];
@@ -6411,7 +6445,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6411
6445
  case 2:
6412
6446
  _state.sent();
6413
6447
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6414
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6448
+ this.scheduleAdStopAtBreakBoundary();
6415
6449
  }
6416
6450
  adVolume = currentMuted ? 0 : currentVolume;
6417
6451
  this.ima.setAdVolume(adVolume);
@@ -6454,7 +6488,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6454
6488
  case 6:
6455
6489
  _state.sent();
6456
6490
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6457
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6491
+ this.scheduleAdStopAtBreakBoundary();
6458
6492
  }
6459
6493
  adVolume1 = currentMuted ? 0 : currentVolume;
6460
6494
  this.ima.setAdVolume(adVolume1);
@@ -6509,7 +6543,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6509
6543
  case 10:
6510
6544
  _state.sent();
6511
6545
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6512
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6546
+ this.scheduleAdStopAtBreakBoundary();
6513
6547
  }
6514
6548
  adVolume2 = currentMuted ? 0 : currentVolume;
6515
6549
  this.ima.setAdVolume(adVolume2);
@@ -6861,7 +6895,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6861
6895
  case 2:
6862
6896
  _state.sent();
6863
6897
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6864
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6898
+ this.scheduleAdStopAtBreakBoundary();
6865
6899
  }
6866
6900
  currentMuted = this.video.muted;
6867
6901
  currentVolume = this.video.volume;
@@ -7361,21 +7395,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7361
7395
  {
7362
7396
  key: "ensureAdStoppedByTimer",
7363
7397
  value: function ensureAdStoppedByTimer() {
7364
- var _this_config_adBreakCheckIntervalMs, _this_expectedAdBreakDurationMs;
7398
+ var _this_config_adBreakCheckIntervalMs, _this_getAdBreakEndWallClockMs;
7365
7399
  if (!this.inAdBreak) return;
7366
7400
  this.adStopTimerId = void 0;
7367
7401
  var adPlaying = this.ima.isAdPlaying();
7368
- var pendingAds = this.adPodQueue.length > 0;
7369
7402
  var checkIntervalMs = Math.max(250, Math.floor((_this_config_adBreakCheckIntervalMs = this.config.adBreakCheckIntervalMs) !== null && _this_config_adBreakCheckIntervalMs !== void 0 ? _this_config_adBreakCheckIntervalMs : 1e3));
7370
7403
  var maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;
7371
- var maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 6e4;
7372
- var elapsedSinceStartMs = 0;
7373
- if (this.currentAdBreakStartWallClockMs != null) {
7374
- elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;
7375
- }
7376
- var expectedDurationMs = (_this_expectedAdBreakDurationMs = this.expectedAdBreakDurationMs) !== null && _this_expectedAdBreakDurationMs !== void 0 ? _this_expectedAdBreakDurationMs : 0;
7377
- var overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);
7378
- var shouldExtendAdBreak = (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;
7404
+ var maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 0;
7405
+ var endWallClockMs = (_this_getAdBreakEndWallClockMs = this.getAdBreakEndWallClockMs()) !== null && _this_getAdBreakEndWallClockMs !== void 0 ? _this_getAdBreakEndWallClockMs : Date.now();
7406
+ var overrunMs = Math.max(0, Date.now() - endWallClockMs);
7407
+ var shouldExtendAdBreak = adPlaying && overrunMs < maxExtensionMs;
7379
7408
  if (shouldExtendAdBreak) {
7380
7409
  this.scheduleAdStopCountdown(checkIntervalMs);
7381
7410
  return;
@@ -7641,7 +7670,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7641
7670
  case 5:
7642
7671
  _state.sent();
7643
7672
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7644
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
7673
+ this.scheduleAdStopAtBreakBoundary();
7645
7674
  }
7646
7675
  currentMuted = this.video.muted;
7647
7676
  currentVolume = this.video.volume;
@@ -7691,7 +7720,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7691
7720
  case 8:
7692
7721
  _state.sent();
7693
7722
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7694
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
7723
+ this.scheduleAdStopAtBreakBoundary();
7695
7724
  }
7696
7725
  currentMuted1 = this.video.muted;
7697
7726
  currentVolume1 = this.video.volume;
@@ -7836,6 +7865,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7836
7865
  this.scheduledScte35BreakKey = void 0;
7837
7866
  this.expectedAdBreakDurationMs = void 0;
7838
7867
  this.currentAdBreakStartWallClockMs = void 0;
7868
+ this.scteAdBreakEndWallClockMs = void 0;
7839
7869
  this.clearAdStartTimer();
7840
7870
  this.clearAdStopTimer();
7841
7871
  this.adPodQueue = [];
@@ -8025,9 +8055,21 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8025
8055
  {
8026
8056
  key: "getRemainingAdMs",
8027
8057
  value: function getRemainingAdMs() {
8028
- if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null) return 0;
8029
- var elapsed = Date.now() - this.currentAdBreakStartWallClockMs;
8030
- return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
8058
+ var endWallClockMs = this.getAdBreakEndWallClockMs();
8059
+ if (endWallClockMs != null) {
8060
+ return Math.max(0, endWallClockMs - Date.now());
8061
+ }
8062
+ return 0;
8063
+ }
8064
+ },
8065
+ {
8066
+ key: "getAdBreakEndWallClockMs",
8067
+ value: function getAdBreakEndWallClockMs() {
8068
+ if (this.scteAdBreakEndWallClockMs != null) {
8069
+ return this.scteAdBreakEndWallClockMs;
8070
+ }
8071
+ if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null) return void 0;
8072
+ return this.currentAdBreakStartWallClockMs + this.expectedAdBreakDurationMs;
8031
8073
  }
8032
8074
  },
8033
8075
  {