stormcloud-video-player 0.8.77 → 0.8.78
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/dist/stormcloud-vp.min.js +1 -1
- package/lib/Player.cjs +2 -0
- package/lib/Player.cjs.map +1 -1
- package/lib/Player.d.cts +1 -1
- package/lib/StormcloudPlayer.cjs +225 -6
- package/lib/StormcloudPlayer.cjs.map +1 -1
- package/lib/index.cjs +225 -6
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +226 -6
- package/lib/index.js.map +1 -1
- package/lib/player/ContentHealthWatchdog.cjs +255 -0
- package/lib/player/ContentHealthWatchdog.cjs.map +1 -0
- package/lib/player/ContentHealthWatchdog.d.cts +40 -0
- package/lib/player/StormcloudVideoPlayer.cjs +225 -6
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +1 -0
- package/lib/players/HlsPlayer.cjs +225 -6
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +225 -6
- package/lib/players/index.cjs.map +1 -1
- package/lib/props.cjs +2 -0
- package/lib/props.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +16 -6
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/types.d.cts +1 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +225 -6
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/utils/browserCompat.cjs +7 -0
- package/lib/utils/browserCompat.cjs.map +1 -1
- package/lib/utils/browserCompat.d.cts +2 -1
- package/package.json +2 -2
|
@@ -19,6 +19,7 @@ declare class StormcloudVideoPlayer {
|
|
|
19
19
|
private readonly hlsEngine;
|
|
20
20
|
private readonly adBreak;
|
|
21
21
|
private readonly floorLadder;
|
|
22
|
+
private readonly contentWatchdog;
|
|
22
23
|
private edgePodBaseUrl;
|
|
23
24
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
24
25
|
private get debug();
|
|
@@ -2299,6 +2299,9 @@ function requiresMediaPipelineResetAfterAds() {
|
|
|
2299
2299
|
var browser = detectBrowser();
|
|
2300
2300
|
return browser.name === "Samsung Tizen" && ((_browser_tizenVersion = browser.tizenVersion) !== null && _browser_tizenVersion !== void 0 ? _browser_tizenVersion : 0) >= 5;
|
|
2301
2301
|
}
|
|
2302
|
+
function prefersProgressiveAdMedia() {
|
|
2303
|
+
return detectBrowser().isSmartTV;
|
|
2304
|
+
}
|
|
2302
2305
|
function getBrowserConfigOverrides() {
|
|
2303
2306
|
var browser = detectBrowser();
|
|
2304
2307
|
var overrides = {};
|
|
@@ -3142,6 +3145,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
3142
3145
|
var probe = adVideoElement !== null && adVideoElement !== void 0 ? adVideoElement : document.createElement("video");
|
|
3143
3146
|
var pageIsHttps = typeof location !== "undefined" && location.protocol === "https:";
|
|
3144
3147
|
var target = getMediaTargetQuality();
|
|
3148
|
+
var deprioritizeHls = prefersProgressiveAdMedia();
|
|
3145
3149
|
var accepted = [];
|
|
3146
3150
|
mediaFiles.forEach(function(file, index) {
|
|
3147
3151
|
var isHls = isHlsMediaFile(file);
|
|
@@ -3172,19 +3176,24 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
3172
3176
|
var bitrateDiff = Math.abs((file.bitrate || 5e3) * 1e3 - target.bitrate);
|
|
3173
3177
|
score = resolutionDiff * 2 + bitrateDiff / 1e3;
|
|
3174
3178
|
}
|
|
3179
|
+
var deprioritizedHls = deprioritizeHls && isHls;
|
|
3175
3180
|
accepted.push({
|
|
3176
3181
|
file: file,
|
|
3177
3182
|
score: score,
|
|
3178
|
-
insecure: insecure
|
|
3183
|
+
insecure: insecure,
|
|
3184
|
+
deprioritizedHls: deprioritizedHls
|
|
3179
3185
|
});
|
|
3180
3186
|
logFunnel("media_candidate", _object_spread_props(_object_spread({}, details), {
|
|
3181
3187
|
reason: "accepted",
|
|
3182
|
-
why: insecure ? "insecure_http_deprioritized" : "playable",
|
|
3188
|
+
why: insecure ? "insecure_http_deprioritized" : deprioritizedHls ? "hls_deprioritized_on_tv" : "playable",
|
|
3183
3189
|
score: score
|
|
3184
3190
|
}));
|
|
3185
3191
|
});
|
|
3186
3192
|
accepted.sort(function(a, b) {
|
|
3187
3193
|
if (a.insecure !== b.insecure) return a.insecure ? 1 : -1;
|
|
3194
|
+
if (a.deprioritizedHls !== b.deprioritizedHls) {
|
|
3195
|
+
return a.deprioritizedHls ? 1 : -1;
|
|
3196
|
+
}
|
|
3188
3197
|
return a.score - b.score;
|
|
3189
3198
|
});
|
|
3190
3199
|
return accepted.map(function(entry) {
|
|
@@ -4857,8 +4866,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
4857
4866
|
console.warn("[HlsAdPlayer] Error preparing ad video for new source:", error);
|
|
4858
4867
|
}
|
|
4859
4868
|
}
|
|
4860
|
-
function recreateAdVideoElement() {
|
|
4861
|
-
console.log("[HlsAdPlayer] Recreating ad video element (
|
|
4869
|
+
function recreateAdVideoElement(reason) {
|
|
4870
|
+
console.log("[HlsAdPlayer] Recreating ad video element (".concat(reason, ")"));
|
|
4862
4871
|
teardownAdEventListeners();
|
|
4863
4872
|
prepareVideoElementForNewSource();
|
|
4864
4873
|
if (adVideoElement) {
|
|
@@ -4902,8 +4911,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
4902
4911
|
}
|
|
4903
4912
|
function resetVideoElementForNextSource() {
|
|
4904
4913
|
clearStallWatchdog();
|
|
4905
|
-
|
|
4906
|
-
|
|
4914
|
+
var previousSourceUsedHlsJs = adHls !== void 0;
|
|
4915
|
+
if (requiresMediaPipelineResetAfterAds() || previousSourceUsedHlsJs) {
|
|
4916
|
+
recreateAdVideoElement(previousSourceUsedHlsJs ? "after hls.js source" : "single-decoder platform");
|
|
4907
4917
|
setupAdEventListeners();
|
|
4908
4918
|
} else {
|
|
4909
4919
|
prepareVideoElementForNewSource();
|
|
@@ -12385,6 +12395,181 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
|
|
|
12385
12395
|
]);
|
|
12386
12396
|
return AdBreakOrchestrator;
|
|
12387
12397
|
}();
|
|
12398
|
+
// src/player/ContentHealthWatchdog.ts
|
|
12399
|
+
var POLL_INTERVAL_MS = 2e3;
|
|
12400
|
+
var STALL_THRESHOLD_MS = 12e3;
|
|
12401
|
+
var POST_BREAK_GRACE_MS = 5e4;
|
|
12402
|
+
var MAX_BREAK_SUPPRESSION_MS = 10 * 60 * 1e3;
|
|
12403
|
+
var SELF_INFLICTED_PAUSE_WINDOW_MS = 5e3;
|
|
12404
|
+
var HEALTHY_PLAYBACK_SECONDS = 5;
|
|
12405
|
+
var MAX_NORMAL_ADVANCE_PER_TICK_S = 4;
|
|
12406
|
+
var LIGHT_STEP_COOLDOWN_MS = 1e4;
|
|
12407
|
+
var RELOAD_BASE_COOLDOWN_MS = 15e3;
|
|
12408
|
+
var RELOAD_MAX_COOLDOWN_MS = 12e4;
|
|
12409
|
+
var ContentHealthWatchdog = /*#__PURE__*/ function() {
|
|
12410
|
+
function ContentHealthWatchdog(host) {
|
|
12411
|
+
var _this = this;
|
|
12412
|
+
_class_call_check(this, ContentHealthWatchdog);
|
|
12413
|
+
this.host = host;
|
|
12414
|
+
this.armed = false;
|
|
12415
|
+
this.userPaused = false;
|
|
12416
|
+
this.wasInBreak = false;
|
|
12417
|
+
this.breakStartedAt = 0;
|
|
12418
|
+
this.stuckBreakLogged = false;
|
|
12419
|
+
this.graceUntil = 0;
|
|
12420
|
+
this.lastPosition = 0;
|
|
12421
|
+
this.lastProgressAt = 0;
|
|
12422
|
+
this.lastRealPlaybackAt = 0;
|
|
12423
|
+
this.healthySeconds = 0;
|
|
12424
|
+
this.step = 0;
|
|
12425
|
+
this.nextActionAt = 0;
|
|
12426
|
+
this.lastActionAt = 0;
|
|
12427
|
+
this.onPlaying = function() {
|
|
12428
|
+
if (_this.host.isAdPlaying()) return;
|
|
12429
|
+
_this.armed = true;
|
|
12430
|
+
_this.userPaused = false;
|
|
12431
|
+
};
|
|
12432
|
+
this.onPause = function() {
|
|
12433
|
+
if (_this.host.isBreakActive() || _this.host.isAdPlaying() || Date.now() - _this.lastActionAt < SELF_INFLICTED_PAUSE_WINDOW_MS) {
|
|
12434
|
+
return;
|
|
12435
|
+
}
|
|
12436
|
+
_this.userPaused = true;
|
|
12437
|
+
};
|
|
12438
|
+
this.onPlay = function() {
|
|
12439
|
+
_this.userPaused = false;
|
|
12440
|
+
};
|
|
12441
|
+
}
|
|
12442
|
+
_create_class(ContentHealthWatchdog, [
|
|
12443
|
+
{
|
|
12444
|
+
key: "start",
|
|
12445
|
+
value: function start() {
|
|
12446
|
+
var _this = this;
|
|
12447
|
+
if (this.intervalId !== void 0) return;
|
|
12448
|
+
var video = this.host.video;
|
|
12449
|
+
video.addEventListener("playing", this.onPlaying);
|
|
12450
|
+
video.addEventListener("pause", this.onPause);
|
|
12451
|
+
video.addEventListener("play", this.onPlay);
|
|
12452
|
+
this.resetProgress(Date.now());
|
|
12453
|
+
this.intervalId = window.setInterval(function() {
|
|
12454
|
+
return _this.tick();
|
|
12455
|
+
}, POLL_INTERVAL_MS);
|
|
12456
|
+
}
|
|
12457
|
+
},
|
|
12458
|
+
{
|
|
12459
|
+
key: "stop",
|
|
12460
|
+
value: function stop() {
|
|
12461
|
+
if (this.intervalId !== void 0) {
|
|
12462
|
+
clearInterval(this.intervalId);
|
|
12463
|
+
this.intervalId = void 0;
|
|
12464
|
+
}
|
|
12465
|
+
var video = this.host.video;
|
|
12466
|
+
video.removeEventListener("playing", this.onPlaying);
|
|
12467
|
+
video.removeEventListener("pause", this.onPause);
|
|
12468
|
+
video.removeEventListener("play", this.onPlay);
|
|
12469
|
+
this.armed = false;
|
|
12470
|
+
this.step = 0;
|
|
12471
|
+
}
|
|
12472
|
+
},
|
|
12473
|
+
{
|
|
12474
|
+
key: "resetProgress",
|
|
12475
|
+
value: function resetProgress(now) {
|
|
12476
|
+
this.lastPosition = this.host.video.currentTime;
|
|
12477
|
+
this.lastProgressAt = now;
|
|
12478
|
+
}
|
|
12479
|
+
},
|
|
12480
|
+
{
|
|
12481
|
+
key: "tick",
|
|
12482
|
+
value: function tick() {
|
|
12483
|
+
var now = Date.now();
|
|
12484
|
+
var video = this.host.video;
|
|
12485
|
+
var hidden = typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
12486
|
+
if (!this.armed || this.userPaused || hidden || video.ended || !this.host.isLiveStream() || !this.host.hasHlsInstance()) {
|
|
12487
|
+
this.resetProgress(now);
|
|
12488
|
+
return;
|
|
12489
|
+
}
|
|
12490
|
+
var breakActive = this.host.isBreakActive() || this.host.isAdPlaying();
|
|
12491
|
+
if (breakActive && !this.wasInBreak) {
|
|
12492
|
+
this.wasInBreak = true;
|
|
12493
|
+
this.breakStartedAt = now;
|
|
12494
|
+
this.stuckBreakLogged = false;
|
|
12495
|
+
}
|
|
12496
|
+
if (breakActive && now - this.breakStartedAt < MAX_BREAK_SUPPRESSION_MS) {
|
|
12497
|
+
this.resetProgress(now);
|
|
12498
|
+
return;
|
|
12499
|
+
}
|
|
12500
|
+
if (breakActive && !this.stuckBreakLogged) {
|
|
12501
|
+
this.stuckBreakLogged = true;
|
|
12502
|
+
console.warn("[ContentWatchdog] Ad break state active for over ".concat(MAX_BREAK_SUPPRESSION_MS / 6e4, " min — monitoring content anyway"));
|
|
12503
|
+
}
|
|
12504
|
+
if (!breakActive && this.wasInBreak) {
|
|
12505
|
+
this.wasInBreak = false;
|
|
12506
|
+
this.graceUntil = now + POST_BREAK_GRACE_MS;
|
|
12507
|
+
this.resetProgress(now);
|
|
12508
|
+
return;
|
|
12509
|
+
}
|
|
12510
|
+
var currentTime = video.currentTime;
|
|
12511
|
+
var delta = currentTime - this.lastPosition;
|
|
12512
|
+
this.lastPosition = currentTime;
|
|
12513
|
+
if (delta > 0.25 && delta <= MAX_NORMAL_ADVANCE_PER_TICK_S && !video.paused) {
|
|
12514
|
+
this.lastProgressAt = now;
|
|
12515
|
+
this.lastRealPlaybackAt = now;
|
|
12516
|
+
this.healthySeconds += delta;
|
|
12517
|
+
if (this.step > 0 && this.healthySeconds >= HEALTHY_PLAYBACK_SECONDS) {
|
|
12518
|
+
console.log("[ContentWatchdog] Content playback recovered after ".concat(this.step, " recovery step(s)"));
|
|
12519
|
+
this.step = 0;
|
|
12520
|
+
this.nextActionAt = 0;
|
|
12521
|
+
}
|
|
12522
|
+
return;
|
|
12523
|
+
}
|
|
12524
|
+
if (now < this.graceUntil) {
|
|
12525
|
+
this.lastProgressAt = now;
|
|
12526
|
+
return;
|
|
12527
|
+
}
|
|
12528
|
+
if (now - this.lastProgressAt < STALL_THRESHOLD_MS || now < this.nextActionAt) {
|
|
12529
|
+
return;
|
|
12530
|
+
}
|
|
12531
|
+
this.recover(now);
|
|
12532
|
+
}
|
|
12533
|
+
},
|
|
12534
|
+
{
|
|
12535
|
+
key: "recover",
|
|
12536
|
+
value: function recover(now) {
|
|
12537
|
+
var video = this.host.video;
|
|
12538
|
+
var state = "t=".concat(video.currentTime.toFixed(2), " paused=").concat(video.paused, " readyState=").concat(video.readyState, " networkState=").concat(video.networkState, " error=").concat(video.error ? video.error.code : "none");
|
|
12539
|
+
var stalledForS = ((now - (this.lastRealPlaybackAt || this.lastProgressAt)) / 1e3).toFixed(0);
|
|
12540
|
+
var fullReloadOnly = this.host.requiresMediaPipelineResetAfterAds();
|
|
12541
|
+
var action = fullReloadOnly || this.step >= 2 ? "reload" : this.step === 0 ? "recover_media_error" : "restart_load";
|
|
12542
|
+
console.warn("[ContentWatchdog] Content stalled for ".concat(stalledForS, "s — ").concat(action, " (step ").concat(this.step + 1, ") — ").concat(state));
|
|
12543
|
+
this.lastActionAt = now;
|
|
12544
|
+
this.healthySeconds = 0;
|
|
12545
|
+
if (action === "recover_media_error") {
|
|
12546
|
+
this.host.recoverMediaError();
|
|
12547
|
+
this.nextActionAt = now + LIGHT_STEP_COOLDOWN_MS;
|
|
12548
|
+
} else if (action === "restart_load") {
|
|
12549
|
+
var liveSyncPos = this.host.getLiveSyncPosition();
|
|
12550
|
+
var position = liveSyncPos != null && liveSyncPos > video.currentTime ? liveSyncPos : video.currentTime;
|
|
12551
|
+
if (position !== video.currentTime) {
|
|
12552
|
+
video.currentTime = position;
|
|
12553
|
+
}
|
|
12554
|
+
this.host.restartHlsLoad(position);
|
|
12555
|
+
this.nextActionAt = now + LIGHT_STEP_COOLDOWN_MS;
|
|
12556
|
+
} else {
|
|
12557
|
+
var reloadIndex = fullReloadOnly ? this.step : this.step - 2;
|
|
12558
|
+
var cooldown = Math.min(RELOAD_BASE_COOLDOWN_MS * Math.pow(2, reloadIndex), RELOAD_MAX_COOLDOWN_MS);
|
|
12559
|
+
this.host.reloadLiveStream();
|
|
12560
|
+
this.nextActionAt = now + cooldown;
|
|
12561
|
+
}
|
|
12562
|
+
this.step++;
|
|
12563
|
+
this.resetProgress(now);
|
|
12564
|
+
if (video.paused) {
|
|
12565
|
+
var _video_play;
|
|
12566
|
+
(_video_play = video.play()) === null || _video_play === void 0 ? void 0 : _video_play.catch(function() {});
|
|
12567
|
+
}
|
|
12568
|
+
}
|
|
12569
|
+
}
|
|
12570
|
+
]);
|
|
12571
|
+
return ContentHealthWatchdog;
|
|
12572
|
+
}();
|
|
12388
12573
|
// src/player/StormcloudVideoPlayer.ts
|
|
12389
12574
|
var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
12390
12575
|
function StormcloudVideoPlayer(config) {
|
|
@@ -12515,6 +12700,36 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
12515
12700
|
return _this.palNonce.sendAdTouch(event);
|
|
12516
12701
|
}
|
|
12517
12702
|
}, this.timing, this.adConfig, this.cueManager, this.placeholder);
|
|
12703
|
+
this.contentWatchdog = new ContentHealthWatchdog({
|
|
12704
|
+
video: this.video,
|
|
12705
|
+
isLiveStream: function isLiveStream() {
|
|
12706
|
+
return _this.hlsEngine.isLiveStream;
|
|
12707
|
+
},
|
|
12708
|
+
hasHlsInstance: function hasHlsInstance() {
|
|
12709
|
+
return !!_this.hlsEngine.hls;
|
|
12710
|
+
},
|
|
12711
|
+
isBreakActive: function isBreakActive() {
|
|
12712
|
+
return _this.adBreak.inAdBreak || _this.adBreak.isBreakActive();
|
|
12713
|
+
},
|
|
12714
|
+
isAdPlaying: function isAdPlaying() {
|
|
12715
|
+
return _this.adPlayer.isAdPlaying();
|
|
12716
|
+
},
|
|
12717
|
+
requiresMediaPipelineResetAfterAds: function requiresMediaPipelineResetAfterAds1() {
|
|
12718
|
+
return requiresMediaPipelineResetAfterAds();
|
|
12719
|
+
},
|
|
12720
|
+
getLiveSyncPosition: function getLiveSyncPosition() {
|
|
12721
|
+
return _this.hlsEngine.getLiveSyncPosition();
|
|
12722
|
+
},
|
|
12723
|
+
recoverMediaError: function recoverMediaError() {
|
|
12724
|
+
return _this.hlsEngine.recoverMediaError();
|
|
12725
|
+
},
|
|
12726
|
+
restartHlsLoad: function restartHlsLoad(position) {
|
|
12727
|
+
return _this.hlsEngine.restartLoadAt(position);
|
|
12728
|
+
},
|
|
12729
|
+
reloadLiveStream: function reloadLiveStream() {
|
|
12730
|
+
return _this.hlsEngine.reloadLiveStream();
|
|
12731
|
+
}
|
|
12732
|
+
});
|
|
12518
12733
|
}
|
|
12519
12734
|
_create_class(StormcloudVideoPlayer, [
|
|
12520
12735
|
{
|
|
@@ -12835,6 +13050,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
12835
13050
|
}
|
|
12836
13051
|
};
|
|
12837
13052
|
this.video.addEventListener("emptied", this.emptiedHandler);
|
|
13053
|
+
if (this.config.contentStallWatchdog !== false) {
|
|
13054
|
+
this.contentWatchdog.start();
|
|
13055
|
+
}
|
|
12838
13056
|
}
|
|
12839
13057
|
},
|
|
12840
13058
|
{
|
|
@@ -13319,6 +13537,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
13319
13537
|
key: "destroy",
|
|
13320
13538
|
value: function destroy() {
|
|
13321
13539
|
var _this_adPlayer;
|
|
13540
|
+
this.contentWatchdog.stop();
|
|
13322
13541
|
this.adBreak.cancelScheduledRequest();
|
|
13323
13542
|
this.timing.destroy();
|
|
13324
13543
|
this.adBreak.clearPendingAdBreak();
|