eb-player 2.1.1 → 2.1.2
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/build/ebplayer.bundle.js +82 -3
- package/dist/build/ebplayer.bundle.js.map +1 -1
- package/dist/build/types/src/core/event-bus.d.ts +3 -0
- package/dist/build/types/src/core/event-bus.d.ts.map +1 -1
- package/dist/build/types/src/eb-player.d.ts.map +1 -1
- package/dist/build/types/src/engines/hls.d.ts +24 -0
- package/dist/build/types/src/engines/hls.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.EBPlayer = {}));
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
|
-
var __EB_PLAYER_VERSION__ = "2.1.
|
|
7
|
+
var __EB_PLAYER_VERSION__ = "2.1.2";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Finite State Machine for player playback state transitions.
|
|
@@ -5937,6 +5937,17 @@
|
|
|
5937
5937
|
* CRITICAL: Call applyDiscontinuityWorkaround BEFORE driver.attachMedia/loadSource (Pitfall 4).
|
|
5938
5938
|
* CRITICAL: Never call driver.startLoad() from video 'play' event handler (Pitfall 3).
|
|
5939
5939
|
*/
|
|
5940
|
+
/**
|
|
5941
|
+
* Bound for the "load never started" watchdog: hls.js's own manifest-loading
|
|
5942
|
+
* budget (default manifestLoadingTimeOut 10 000 ms with one retry plus
|
|
5943
|
+
* backoff) tops out around 21s before hls.js surfaces its own fatal network
|
|
5944
|
+
* error, so 30s guarantees hls.js's own error path always wins first and
|
|
5945
|
+
* this watchdog only ever sees the case hls.js is silent about — a
|
|
5946
|
+
* StreamController parked in STOPPED with no error and no event. 30s also
|
|
5947
|
+
* matches the existing MAIN_OPEN_FALLBACK_MS precedent in src/eb-player.ts
|
|
5948
|
+
* and sits well below INTRO_MAX_DURATION_MS (90 000).
|
|
5949
|
+
*/
|
|
5950
|
+
const LOAD_NEVER_STARTED_TIMEOUT_MS = 30000;
|
|
5940
5951
|
// ---------------------------------------------------------------------------
|
|
5941
5952
|
// HlsEngine
|
|
5942
5953
|
// ---------------------------------------------------------------------------
|
|
@@ -5949,6 +5960,9 @@
|
|
|
5949
5960
|
this.autoQuality = true;
|
|
5950
5961
|
// Holds state reference for named driver event handlers
|
|
5951
5962
|
this.eventState = null;
|
|
5963
|
+
// Bound "load never started" watchdog timer — 0-initialized (not null) so
|
|
5964
|
+
// clearTimeout(0) is a no-op, eliminating a null-guard phantom V8 branch.
|
|
5965
|
+
this.loadNeverStartedTimer = 0;
|
|
5952
5966
|
this.liveSyncDisabled = false;
|
|
5953
5967
|
}
|
|
5954
5968
|
getDriver() {
|
|
@@ -5982,6 +5996,7 @@
|
|
|
5982
5996
|
}
|
|
5983
5997
|
onDetach() {
|
|
5984
5998
|
this.stopWatchdog();
|
|
5999
|
+
this.clearLoadNeverStartedWatchdog();
|
|
5985
6000
|
if (this.driver !== null) {
|
|
5986
6001
|
try {
|
|
5987
6002
|
this.driver.detachMedia();
|
|
@@ -6108,8 +6123,17 @@
|
|
|
6108
6123
|
delete hlsSafeSettings['extraParamsCallback'];
|
|
6109
6124
|
delete hlsSafeSettings['onCDNTokenError'];
|
|
6110
6125
|
delete hlsSafeSettings['signSegmentsWithCdnToken'];
|
|
6126
|
+
// Do NOT set an explicit auto-start disable here. hls.js starts loading
|
|
6127
|
+
// segments on its own by default, and the resume position is already
|
|
6128
|
+
// carried by startPosition below — hls.js honours it without any help.
|
|
6129
|
+
// Nothing on the VOD path would ever restart a stopped loader: the only
|
|
6130
|
+
// two startLoad() call sites in this file are recoverFromStall() (only
|
|
6131
|
+
// reachable after playback has started) and the video 'play' listener
|
|
6132
|
+
// (gated on state.isLive, so VOD never reaches it). Disabling auto-start
|
|
6133
|
+
// here parks the StreamController in STOPPED forever for any non-zero
|
|
6134
|
+
// resume position — no variant playlist, no segments, no error, no bus
|
|
6135
|
+
// event, spinner forever.
|
|
6111
6136
|
const driverConfig = {
|
|
6112
|
-
autoStartLoad: !config.startAt,
|
|
6113
6137
|
enableWorker: true,
|
|
6114
6138
|
backBufferLength: 30,
|
|
6115
6139
|
...hlsSafeSettings,
|
|
@@ -6191,6 +6215,11 @@
|
|
|
6191
6215
|
this.driver = driver;
|
|
6192
6216
|
// Pitfall 4: apply discontinuity workaround BEFORE attachMedia/loadSource
|
|
6193
6217
|
applyDiscontinuityWorkaround(driver, Hls.Events);
|
|
6218
|
+
// Hoisted once, used both for the retry wiring below and for gating the
|
|
6219
|
+
// "load never started" watchdog — the intro pass already has its own
|
|
6220
|
+
// bounds (INTRO_MAX_DURATION_MS, D-04 silent fall-through) and a second
|
|
6221
|
+
// overlapping bound would only race them.
|
|
6222
|
+
const isIntroPass = Boolean(config.preroll) && this.loadSourceUrl === config.preroll;
|
|
6194
6223
|
// Wire retry handler — pass engine context so unrecoverable DRM errors
|
|
6195
6224
|
// stop the stall watchdog (prevents useless reload loops) and surface to UI.
|
|
6196
6225
|
// For the intro pass (loadSourceUrl matches config.preroll), also wire
|
|
@@ -6199,7 +6228,6 @@
|
|
|
6199
6228
|
// This callback is intentionally NOT set for the main stream so transient
|
|
6200
6229
|
// network blips still trigger the normal startLoad() recovery.
|
|
6201
6230
|
if (config.retry) {
|
|
6202
|
-
const isIntroPass = Boolean(config.preroll) && this.loadSourceUrl === config.preroll;
|
|
6203
6231
|
handleHlsRetry(driver, {
|
|
6204
6232
|
get chromecast_casting() { return state.isCasting; },
|
|
6205
6233
|
onUnrecoverableError: (message) => {
|
|
@@ -6266,6 +6294,8 @@
|
|
|
6266
6294
|
this.resolveDriverReady();
|
|
6267
6295
|
// Register driver event handlers
|
|
6268
6296
|
this.registerDriverEvents(Hls, state);
|
|
6297
|
+
// Arm the "load never started" watchdog — see LOAD_NEVER_STARTED_TIMEOUT_MS.
|
|
6298
|
+
this.armLoadNeverStartedWatchdog(driver, Hls, src, isIntroPass);
|
|
6269
6299
|
// Pause/resume loading on video pause/play to stop manifest refreshes
|
|
6270
6300
|
// (and thus CDN token requests) while the player is paused.
|
|
6271
6301
|
// Only applies to live streams where hls.js continuously refreshes the manifest.
|
|
@@ -6334,6 +6364,43 @@
|
|
|
6334
6364
|
driver.on(Events.SUBTITLE_TRACKS_UPDATED, this._onSubtitleTracksUpdated.bind(this));
|
|
6335
6365
|
driver.on(Events.SUBTITLE_TRACK_SWITCH, this._onSubtitleTrackSwitch.bind(this));
|
|
6336
6366
|
}
|
|
6367
|
+
// -------------------------------------------------------------------------
|
|
6368
|
+
// "Load never started" watchdog
|
|
6369
|
+
// -------------------------------------------------------------------------
|
|
6370
|
+
/**
|
|
6371
|
+
* Arms a one-shot bound that turns an unobservable hang into `state.error`
|
|
6372
|
+
* + a typed bus event: hls.js emits neither when its StreamController
|
|
6373
|
+
* never leaves STOPPED. Disarmed by the first FRAG_LOADING (proof that a
|
|
6374
|
+
* fragment request was actually issued, whether or not playback was
|
|
6375
|
+
* allowed to start — so autoplay-blocked playback never false-positives).
|
|
6376
|
+
* Never armed for the intro pass — it already has its own bounds.
|
|
6377
|
+
*/
|
|
6378
|
+
armLoadNeverStartedWatchdog(driver, Hls, src, isIntroPass) {
|
|
6379
|
+
if (isIntroPass)
|
|
6380
|
+
return;
|
|
6381
|
+
driver.on(Hls.Events.FRAG_LOADING, this._onFragLoading.bind(this));
|
|
6382
|
+
this.loadNeverStartedTimer = setTimeout(this._onLoadNeverStartedTimeout.bind(this, src), LOAD_NEVER_STARTED_TIMEOUT_MS);
|
|
6383
|
+
}
|
|
6384
|
+
clearLoadNeverStartedWatchdog() {
|
|
6385
|
+
clearTimeout(this.loadNeverStartedTimer);
|
|
6386
|
+
this.loadNeverStartedTimer = 0;
|
|
6387
|
+
}
|
|
6388
|
+
_onFragLoading() {
|
|
6389
|
+
this.clearLoadNeverStartedWatchdog();
|
|
6390
|
+
}
|
|
6391
|
+
_onLoadNeverStartedTimeout(src) {
|
|
6392
|
+
if (this.detached)
|
|
6393
|
+
return;
|
|
6394
|
+
// Two-signal live gate (mirrors _onLevelLoaded): a stream that never
|
|
6395
|
+
// loaded a level detail never got its isLive set from the driver, so
|
|
6396
|
+
// the config-level signal must also be checked.
|
|
6397
|
+
if (this.state?.isLive === true || this.config?.isLive === true)
|
|
6398
|
+
return;
|
|
6399
|
+
if (this.state) {
|
|
6400
|
+
this.state.error = 'HlsEngine: load never started — no fragment request was issued within the bound';
|
|
6401
|
+
}
|
|
6402
|
+
this.bus?.emit('load-never-started', { src });
|
|
6403
|
+
}
|
|
6337
6404
|
_onManifestLoaded(_event, data) {
|
|
6338
6405
|
const state = this.eventState;
|
|
6339
6406
|
const driver = this.driver;
|
|
@@ -7438,6 +7505,7 @@
|
|
|
7438
7505
|
// skin-root.ts:141/318 and is a no-op for runtime mute.
|
|
7439
7506
|
const originalMuted = mergedConfig.muted ?? false;
|
|
7440
7507
|
const originalManager = mergedConfig.manager;
|
|
7508
|
+
const originalStartAt = mergedConfig.startAt;
|
|
7441
7509
|
const controller = new PlayerController(runtimeConfig);
|
|
7442
7510
|
controller.mount(container);
|
|
7443
7511
|
// Video element is available after mount() creates the skin DOM
|
|
@@ -7663,6 +7731,10 @@
|
|
|
7663
7731
|
// during the intro pass. Synchronize both objects on every swap.
|
|
7664
7732
|
mergedConfig.manager = originalManager;
|
|
7665
7733
|
controller.config.manager = originalManager;
|
|
7734
|
+
// Restore the viewer's resume position for the main asset — see the
|
|
7735
|
+
// rationale comment at the intro-side swap below (CR-05 sync applies here too).
|
|
7736
|
+
mergedConfig.startAt = originalStartAt;
|
|
7737
|
+
controller.config.startAt = originalStartAt;
|
|
7666
7738
|
// CR-03: clear any stale error that leaked from the intro/ad pass.
|
|
7667
7739
|
// IntroStreamManager's silent fall-through (D-04) treats error-fatal as a
|
|
7668
7740
|
// normal completion but leaves state.error populated with the intro
|
|
@@ -7811,6 +7883,13 @@
|
|
|
7811
7883
|
// CR-05: keep the dual-merged configs in sync (see openMainStream).
|
|
7812
7884
|
mergedConfig.manager = false;
|
|
7813
7885
|
controller.config.manager = false;
|
|
7886
|
+
// A viewer resume position belongs to the main asset only — applying it
|
|
7887
|
+
// to a short intro clip seeks past the whole clip. This defect survives
|
|
7888
|
+
// the startAt/autoStartLoad fix: after that fix, startPosition: 300 is
|
|
7889
|
+
// still applied to the intro, which is still wrong, just differently
|
|
7890
|
+
// wrong. Cleared here and restored in openMainStream() (CR-05 sync).
|
|
7891
|
+
mergedConfig.startAt = undefined;
|
|
7892
|
+
controller.config.startAt = undefined;
|
|
7814
7893
|
reference.open(mergedConfig.preroll);
|
|
7815
7894
|
}
|
|
7816
7895
|
// D-02/D-08-02 (Phase 8): ad-only configuration — no intro stream, so this
|