eb-player 2.0.9 → 2.0.11
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 +132 -20
- package/dist/build/ebplayer.bundle.js.map +1 -1
- package/dist/build/types/eb-player.d.ts.map +1 -1
- package/dist/build/types/engines/base-engine.d.ts.map +1 -1
- package/dist/build/types/engines/cdn-token-manager.d.ts +1 -0
- package/dist/build/types/engines/cdn-token-manager.d.ts.map +1 -1
- package/dist/build/types/engines/dash.d.ts.map +1 -1
- package/dist/build/types/engines/hls.d.ts.map +1 -1
- package/dist/build/types/engines/snapshot/hls.d.ts +10 -0
- package/dist/build/types/engines/snapshot/hls.d.ts.map +1 -1
- package/dist/dev/easybroadcast.js +64 -15
- package/dist/dev/easybroadcast.js.map +1 -1
- package/dist/dev/index.html +1 -1
- package/dist/players/equipe/EB_lequipe-preprod.js +6 -6
- package/package.json +19 -19
|
@@ -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.0.
|
|
7
|
+
var __EB_PLAYER_VERSION__ = "2.0.11";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Finite State Machine for player playback state transitions.
|
|
@@ -4284,12 +4284,20 @@
|
|
|
4284
4284
|
video.addEventListener('ended', () => {
|
|
4285
4285
|
state.playbackState = 'ended';
|
|
4286
4286
|
}, { signal });
|
|
4287
|
-
// Safety net:
|
|
4288
|
-
//
|
|
4289
|
-
//
|
|
4290
|
-
//
|
|
4287
|
+
// Safety net: reconcile stale FSM state when playback is clearly advancing.
|
|
4288
|
+
// Covers two scenarios:
|
|
4289
|
+
// 1. Live stream segment boundaries where browser fires 'waiting' but never
|
|
4290
|
+
// fires 'playing' even though video resumes from buffer.
|
|
4291
|
+
// 2. Safari autoplay: when the browser starts playback via the autoplay attribute,
|
|
4292
|
+
// the 'playing' event can be missed or arrive out of order, leaving the FSM
|
|
4293
|
+
// stuck in 'loading' or 'buffering' while the video is actually playing.
|
|
4294
|
+
// The timeupdate event fires reliably while time advances, so we use it to recover.
|
|
4295
|
+
// Note: Safari with MSE/hls.js may report readyState=2 (HAVE_CURRENT_DATA) even
|
|
4296
|
+
// while actively playing and advancing currentTime. We don't gate on readyState
|
|
4297
|
+
// here — the fact that timeupdate fires with !paused is sufficient proof of playback.
|
|
4291
4298
|
video.addEventListener('timeupdate', () => {
|
|
4292
|
-
|
|
4299
|
+
const stuck = state.playbackState === 'buffering' || state.playbackState === 'loading';
|
|
4300
|
+
if (stuck && !video.paused) {
|
|
4293
4301
|
state.playbackState = 'playing';
|
|
4294
4302
|
}
|
|
4295
4303
|
}, { signal });
|
|
@@ -4487,6 +4495,7 @@
|
|
|
4487
4495
|
this.expirationMarginInSeconds = expirationMarginInSeconds;
|
|
4488
4496
|
this.lastTokenResponse = null;
|
|
4489
4497
|
this.resetAttemptCounterTimeout = null;
|
|
4498
|
+
this.inFlightFetch = null;
|
|
4490
4499
|
}
|
|
4491
4500
|
resetAttemptCounter() {
|
|
4492
4501
|
if (this.resetAttemptCounterTimeout) {
|
|
@@ -4730,21 +4739,35 @@
|
|
|
4730
4739
|
console.warn('CDNToken: Missing src to tokenize');
|
|
4731
4740
|
return null;
|
|
4732
4741
|
}
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
break;
|
|
4740
|
-
case TOKEN_TYPES.VENOM:
|
|
4741
|
-
case TOKEN_TYPES.EASY_B:
|
|
4742
|
-
this.lastTokenResponse = await this._fetchEasyBToken(src);
|
|
4743
|
-
break;
|
|
4744
|
-
default:
|
|
4745
|
-
this.lastTokenResponse = await this._fetchDefaultToken(src);
|
|
4742
|
+
// Deduplicate concurrent fetches: if a fetch is already in flight,
|
|
4743
|
+
// return the same promise instead of firing a second network request.
|
|
4744
|
+
// This prevents the main player and snapshot handler from both triggering
|
|
4745
|
+
// separate generate calls when their manifest refreshes overlap.
|
|
4746
|
+
if (this.inFlightFetch) {
|
|
4747
|
+
return this.inFlightFetch;
|
|
4746
4748
|
}
|
|
4747
|
-
|
|
4749
|
+
const doFetch = async () => {
|
|
4750
|
+
switch (this.tokenType) {
|
|
4751
|
+
case TOKEN_TYPES.BUNNY:
|
|
4752
|
+
return this._fetchBunnyToken(src);
|
|
4753
|
+
case TOKEN_TYPES.AKAMAI:
|
|
4754
|
+
return this._fetchAkamaiToken(src);
|
|
4755
|
+
case TOKEN_TYPES.VENOM:
|
|
4756
|
+
case TOKEN_TYPES.EASY_B:
|
|
4757
|
+
return this._fetchEasyBToken(src);
|
|
4758
|
+
default:
|
|
4759
|
+
return this._fetchDefaultToken(src);
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4762
|
+
this.inFlightFetch = doFetch().then((response) => {
|
|
4763
|
+
this.lastTokenResponse = response;
|
|
4764
|
+
this.inFlightFetch = null;
|
|
4765
|
+
return response;
|
|
4766
|
+
}).catch((error) => {
|
|
4767
|
+
this.inFlightFetch = null;
|
|
4768
|
+
throw error;
|
|
4769
|
+
});
|
|
4770
|
+
return this.inFlightFetch;
|
|
4748
4771
|
}
|
|
4749
4772
|
// -------------------------------------------------------------------------
|
|
4750
4773
|
// Public: updateUrlWithTokenParams
|
|
@@ -4847,6 +4870,7 @@
|
|
|
4847
4870
|
}
|
|
4848
4871
|
this.attempt = 0;
|
|
4849
4872
|
this.lastTokenResponse = null;
|
|
4873
|
+
this.inFlightFetch = null;
|
|
4850
4874
|
console.log('CDNTokenManager: destroyed');
|
|
4851
4875
|
}
|
|
4852
4876
|
// -------------------------------------------------------------------------
|
|
@@ -5382,6 +5406,39 @@
|
|
|
5382
5406
|
}, { signal });
|
|
5383
5407
|
// Start stall watchdog
|
|
5384
5408
|
this.startWatchdog();
|
|
5409
|
+
// Post-init state reconciliation: during the async init() above, the browser
|
|
5410
|
+
// may have started or blocked playback in ways that leave the FSM out of sync.
|
|
5411
|
+
// Two cases:
|
|
5412
|
+
// A) Video is playing but FSM missed the 'playing' event (Safari event ordering)
|
|
5413
|
+
// B) Autoplay was blocked — Safari fires 'waiting' (→ buffering) but may not
|
|
5414
|
+
// fire 'pause', leaving the spinner visible over a paused video
|
|
5415
|
+
// A short periodic check covers both cases and self-cleans after convergence.
|
|
5416
|
+
const reconcileVideo = video;
|
|
5417
|
+
const reconcileState = state;
|
|
5418
|
+
let reconcileCount = 0;
|
|
5419
|
+
const reconcileTimer = setInterval(() => {
|
|
5420
|
+
reconcileCount++;
|
|
5421
|
+
if (reconcileCount >= 10) {
|
|
5422
|
+
clearInterval(reconcileTimer);
|
|
5423
|
+
return;
|
|
5424
|
+
}
|
|
5425
|
+
const fsm = reconcileState.playbackState;
|
|
5426
|
+
// Case A: video is playing but FSM disagrees
|
|
5427
|
+
// Note: Safari/MSE may report readyState=2 while actively playing, so we
|
|
5428
|
+
// check currentTime advancement instead of readyState >= 3.
|
|
5429
|
+
if (fsm !== 'playing' && !reconcileVideo.paused && reconcileVideo.currentTime > 0) {
|
|
5430
|
+
reconcileState.playbackState = 'playing';
|
|
5431
|
+
clearInterval(reconcileTimer);
|
|
5432
|
+
return;
|
|
5433
|
+
}
|
|
5434
|
+
// Case B: autoplay blocked — video is paused but FSM stuck in buffering/loading
|
|
5435
|
+
if ((fsm === 'buffering' || fsm === 'loading') && reconcileVideo.paused) {
|
|
5436
|
+
reconcileState.playbackState = 'paused';
|
|
5437
|
+
clearInterval(reconcileTimer);
|
|
5438
|
+
}
|
|
5439
|
+
}, 200);
|
|
5440
|
+
// Clean up on engine detach
|
|
5441
|
+
signal.addEventListener('abort', () => clearInterval(reconcileTimer), { once: true });
|
|
5385
5442
|
}
|
|
5386
5443
|
// -------------------------------------------------------------------------
|
|
5387
5444
|
// Driver event mapping
|
|
@@ -5857,6 +5914,28 @@
|
|
|
5857
5914
|
};
|
|
5858
5915
|
player.on(dashjs.MediaPlayer.events['STREAM_INITIALIZED'], onInit);
|
|
5859
5916
|
});
|
|
5917
|
+
// Post-init state reconciliation (same as HLS engine — see comment there)
|
|
5918
|
+
const reconcileVideo = video;
|
|
5919
|
+
const reconcileState = state;
|
|
5920
|
+
let reconcileCount = 0;
|
|
5921
|
+
const reconcileTimer = setInterval(() => {
|
|
5922
|
+
reconcileCount++;
|
|
5923
|
+
if (reconcileCount >= 10) {
|
|
5924
|
+
clearInterval(reconcileTimer);
|
|
5925
|
+
return;
|
|
5926
|
+
}
|
|
5927
|
+
const fsm = reconcileState.playbackState;
|
|
5928
|
+
if (fsm !== 'playing' && !reconcileVideo.paused && reconcileVideo.currentTime > 0) {
|
|
5929
|
+
reconcileState.playbackState = 'playing';
|
|
5930
|
+
clearInterval(reconcileTimer);
|
|
5931
|
+
return;
|
|
5932
|
+
}
|
|
5933
|
+
if ((fsm === 'buffering' || fsm === 'loading') && reconcileVideo.paused) {
|
|
5934
|
+
reconcileState.playbackState = 'paused';
|
|
5935
|
+
clearInterval(reconcileTimer);
|
|
5936
|
+
}
|
|
5937
|
+
}, 200);
|
|
5938
|
+
signal.addEventListener('abort', () => clearInterval(reconcileTimer), { once: true });
|
|
5860
5939
|
}
|
|
5861
5940
|
// -------------------------------------------------------------------------
|
|
5862
5941
|
// Event mapping
|
|
@@ -6113,6 +6192,24 @@
|
|
|
6113
6192
|
getVideo() {
|
|
6114
6193
|
return this.offscreenVideo;
|
|
6115
6194
|
}
|
|
6195
|
+
/**
|
|
6196
|
+
* Stop manifest refreshes (and thus CDN token requests) while the main player is paused.
|
|
6197
|
+
* For live streams, the snapshot hls.js instance continuously refreshes the manifest
|
|
6198
|
+
* on the playlist interval — this prevents unnecessary generate calls during pause.
|
|
6199
|
+
*/
|
|
6200
|
+
stopLoad() {
|
|
6201
|
+
if (this.driver && typeof this.driver['stopLoad'] === 'function') {
|
|
6202
|
+
this.driver['stopLoad']();
|
|
6203
|
+
}
|
|
6204
|
+
}
|
|
6205
|
+
/**
|
|
6206
|
+
* Resume manifest refreshes when the main player resumes playback.
|
|
6207
|
+
*/
|
|
6208
|
+
startLoad() {
|
|
6209
|
+
if (this.driver && typeof this.driver['startLoad'] === 'function') {
|
|
6210
|
+
this.driver['startLoad'](-1);
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6116
6213
|
/**
|
|
6117
6214
|
* Destroy the snapshot Hls instance and clean up resources.
|
|
6118
6215
|
*/
|
|
@@ -6410,6 +6507,21 @@
|
|
|
6410
6507
|
if (snapshotVideo !== null) {
|
|
6411
6508
|
controller.bus.emit('snapshot-handler-ready', { take: (time) => handler.take(time), video: snapshotVideo });
|
|
6412
6509
|
}
|
|
6510
|
+
// Stop/start snapshot manifest refreshes on pause/play to prevent
|
|
6511
|
+
// CDN token generate calls while the player is paused (live streams only).
|
|
6512
|
+
// Mirrors the same logic in hls.ts for the main engine.
|
|
6513
|
+
if (video) {
|
|
6514
|
+
video.addEventListener('pause', () => {
|
|
6515
|
+
if (controller.state?.isLive) {
|
|
6516
|
+
handler.stopLoad();
|
|
6517
|
+
}
|
|
6518
|
+
}, { signal: controller.signal });
|
|
6519
|
+
video.addEventListener('play', () => {
|
|
6520
|
+
if (controller.state?.isLive) {
|
|
6521
|
+
setTimeout(() => handler.startLoad(), 0);
|
|
6522
|
+
}
|
|
6523
|
+
}, { signal: controller.signal });
|
|
6524
|
+
}
|
|
6413
6525
|
})
|
|
6414
6526
|
.catch((error) => {
|
|
6415
6527
|
console.warn('EBPlayer: HlsSnapshotHandler init failed:', error);
|