@cdn365/p2p-media-loader-hlsjs 1.0.0
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/LICENSE +202 -0
- package/README.md +104 -0
- package/dist/p2p-media-loader-hlsjs.es.js +480 -0
- package/dist/p2p-media-loader-hlsjs.es.js.map +1 -0
- package/dist/p2p-media-loader-hlsjs.es.min.js +202 -0
- package/dist/p2p-media-loader-hlsjs.es.min.js.map +1 -0
- package/lib/engine-static.d.ts +2 -0
- package/lib/engine-static.js +34 -0
- package/lib/engine-static.js.map +1 -0
- package/lib/engine.d.ts +189 -0
- package/lib/engine.js +342 -0
- package/lib/engine.js.map +1 -0
- package/lib/fragment-loader.d.ts +12 -0
- package/lib/fragment-loader.js +140 -0
- package/lib/fragment-loader.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/playlist-loader.d.ts +10 -0
- package/lib/playlist-loader.js +43 -0
- package/lib/playlist-loader.js.map +1 -0
- package/lib/segment-mananger.d.ts +8 -0
- package/lib/segment-mananger.js +61 -0
- package/lib/segment-mananger.js.map +1 -0
- package/lib/utils.d.ts +3 -0
- package/lib/utils.js +13 -0
- package/lib/utils.js.map +1 -0
- package/package.json +55 -0
- package/src/engine-static.ts +43 -0
- package/src/engine.ts +400 -0
- package/src/fragment-loader.ts +167 -0
- package/src/index.ts +9 -0
- package/src/playlist-loader.ts +37 -0
- package/src/segment-mananger.ts +80 -0
- package/src/utils.ts +22 -0
package/lib/engine.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { FragmentLoaderBase } from "./fragment-loader.js";
|
|
2
|
+
import { PlaylistLoaderBase } from "./playlist-loader.js";
|
|
3
|
+
import { SegmentManager } from "./segment-mananger.js";
|
|
4
|
+
import { Core, debug, } from "p2p-media-loader-core";
|
|
5
|
+
import { injectMixin } from "./engine-static.js";
|
|
6
|
+
const MAX_LIVE_SYNC_DURATION = 120;
|
|
7
|
+
/**
|
|
8
|
+
* Represents a P2P (peer-to-peer) engine for HLS (HTTP Live Streaming) to enhance media streaming efficiency.
|
|
9
|
+
* This class integrates P2P technologies into HLS.js, enabling the distribution of media segments via a peer network
|
|
10
|
+
* alongside traditional HTTP fetching. It reduces server bandwidth costs and improves scalability by sharing the load
|
|
11
|
+
* across multiple clients.
|
|
12
|
+
*
|
|
13
|
+
* The engine manages core functionalities such as segment fetching, segment management, peer connection management,
|
|
14
|
+
* and event handling related to the P2P and HLS processes.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Creating an instance of HlsJsP2PEngine with custom configuration
|
|
18
|
+
* const hlsP2PEngine = new HlsJsP2PEngine({
|
|
19
|
+
* core: {
|
|
20
|
+
* highDemandTimeWindow: 30, // 30 seconds
|
|
21
|
+
* simultaneousHttpDownloads: 3,
|
|
22
|
+
* webRtcMaxMessageSize: 64 * 1024, // 64 KB
|
|
23
|
+
* p2pNotReceivingBytesTimeoutMs: 10000, // 10 seconds
|
|
24
|
+
* p2pInactiveLoaderDestroyTimeoutMs: 15000, // 15 seconds
|
|
25
|
+
* httpNotReceivingBytesTimeoutMs: 8000, // 8 seconds
|
|
26
|
+
* httpErrorRetries: 2,
|
|
27
|
+
* p2pErrorRetries: 2,
|
|
28
|
+
* announceTrackers: ["wss://personal.tracker.com"],
|
|
29
|
+
* rtcConfig: {
|
|
30
|
+
* iceServers: [{ urls: "stun:personal.stun.com" }]
|
|
31
|
+
* },
|
|
32
|
+
* swarmId: "example-swarm-id"
|
|
33
|
+
* }
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
export class HlsJsP2PEngine {
|
|
38
|
+
/**
|
|
39
|
+
* Enhances a given Hls.js class by injecting additional P2P (peer-to-peer) functionalities.
|
|
40
|
+
*
|
|
41
|
+
* @returns {HlsWithP2PInstance} - The enhanced Hls.js class with P2P functionalities.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const HlsWithP2P = HlsJsP2PEngine.injectMixin(Hls);
|
|
45
|
+
*
|
|
46
|
+
* const hls = new HlsWithP2P({
|
|
47
|
+
* // Hls.js configuration
|
|
48
|
+
* startLevel: 0, // Example of Hls.js config parameter
|
|
49
|
+
* p2p: {
|
|
50
|
+
* core: {
|
|
51
|
+
* // P2P core configuration
|
|
52
|
+
* },
|
|
53
|
+
* onHlsJsCreated(hls) {
|
|
54
|
+
* // Do something with the Hls.js instance
|
|
55
|
+
* },
|
|
56
|
+
* },
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
static injectMixin(hls) {
|
|
60
|
+
return injectMixin(hls);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Constructs an instance of HlsJsP2PEngine.
|
|
64
|
+
* @param config Optional configuration for P2P engine setup.
|
|
65
|
+
*/
|
|
66
|
+
constructor(config) {
|
|
67
|
+
Object.defineProperty(this, "core", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: void 0
|
|
72
|
+
});
|
|
73
|
+
Object.defineProperty(this, "segmentManager", {
|
|
74
|
+
enumerable: true,
|
|
75
|
+
configurable: true,
|
|
76
|
+
writable: true,
|
|
77
|
+
value: void 0
|
|
78
|
+
});
|
|
79
|
+
Object.defineProperty(this, "hlsInstanceGetter", {
|
|
80
|
+
enumerable: true,
|
|
81
|
+
configurable: true,
|
|
82
|
+
writable: true,
|
|
83
|
+
value: void 0
|
|
84
|
+
});
|
|
85
|
+
Object.defineProperty(this, "currentHlsInstance", {
|
|
86
|
+
enumerable: true,
|
|
87
|
+
configurable: true,
|
|
88
|
+
writable: true,
|
|
89
|
+
value: void 0
|
|
90
|
+
});
|
|
91
|
+
Object.defineProperty(this, "debug", {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
configurable: true,
|
|
94
|
+
writable: true,
|
|
95
|
+
value: debug("p2pml-hlsjs:engine")
|
|
96
|
+
});
|
|
97
|
+
Object.defineProperty(this, "updateMediaElementEventHandlers", {
|
|
98
|
+
enumerable: true,
|
|
99
|
+
configurable: true,
|
|
100
|
+
writable: true,
|
|
101
|
+
value: (type) => {
|
|
102
|
+
const media = this.currentHlsInstance?.media;
|
|
103
|
+
if (!media)
|
|
104
|
+
return;
|
|
105
|
+
const method = type === "register" ? "addEventListener" : "removeEventListener";
|
|
106
|
+
media[method]("timeupdate", this.handlePlaybackUpdate);
|
|
107
|
+
media[method]("seeking", this.handlePlaybackUpdate);
|
|
108
|
+
media[method]("ratechange", this.handlePlaybackUpdate);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
Object.defineProperty(this, "handleManifestLoaded", {
|
|
112
|
+
enumerable: true,
|
|
113
|
+
configurable: true,
|
|
114
|
+
writable: true,
|
|
115
|
+
value: (event, data) => {
|
|
116
|
+
// eslint-disable-next-line prefer-destructuring
|
|
117
|
+
const networkDetails = data.networkDetails;
|
|
118
|
+
if (networkDetails instanceof XMLHttpRequest) {
|
|
119
|
+
this.core.setManifestResponseUrl(networkDetails.responseURL);
|
|
120
|
+
}
|
|
121
|
+
else if (networkDetails instanceof Response) {
|
|
122
|
+
this.core.setManifestResponseUrl(networkDetails.url);
|
|
123
|
+
}
|
|
124
|
+
this.segmentManager.processMainManifest(data);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
Object.defineProperty(this, "handleLevelSwitching", {
|
|
128
|
+
enumerable: true,
|
|
129
|
+
configurable: true,
|
|
130
|
+
writable: true,
|
|
131
|
+
value: (event, data) => {
|
|
132
|
+
if (data.bitrate)
|
|
133
|
+
this.core.setActiveLevelBitrate(data.bitrate);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
Object.defineProperty(this, "handleLevelUpdated", {
|
|
137
|
+
enumerable: true,
|
|
138
|
+
configurable: true,
|
|
139
|
+
writable: true,
|
|
140
|
+
value: (event, data) => {
|
|
141
|
+
if (this.currentHlsInstance &&
|
|
142
|
+
data.details.live &&
|
|
143
|
+
data.details.fragments[0].type === "main" &&
|
|
144
|
+
!this.currentHlsInstance.userConfig.liveSyncDuration &&
|
|
145
|
+
!this.currentHlsInstance.userConfig.liveSyncDurationCount &&
|
|
146
|
+
data.details.fragments.length > 4) {
|
|
147
|
+
this.updateLiveSyncDurationCount(data);
|
|
148
|
+
}
|
|
149
|
+
this.core.setIsLive(data.details.live);
|
|
150
|
+
this.segmentManager.updatePlaylist(data);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
Object.defineProperty(this, "handleMediaAttached", {
|
|
154
|
+
enumerable: true,
|
|
155
|
+
configurable: true,
|
|
156
|
+
writable: true,
|
|
157
|
+
value: () => {
|
|
158
|
+
this.updateMediaElementEventHandlers("register");
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
Object.defineProperty(this, "handleMediaDetached", {
|
|
162
|
+
enumerable: true,
|
|
163
|
+
configurable: true,
|
|
164
|
+
writable: true,
|
|
165
|
+
value: () => {
|
|
166
|
+
this.updateMediaElementEventHandlers("unregister");
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
Object.defineProperty(this, "handlePlaybackUpdate", {
|
|
170
|
+
enumerable: true,
|
|
171
|
+
configurable: true,
|
|
172
|
+
writable: true,
|
|
173
|
+
value: (event) => {
|
|
174
|
+
const media = event.target;
|
|
175
|
+
this.core.updatePlayback(media.currentTime, media.playbackRate);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
Object.defineProperty(this, "destroyCore", {
|
|
179
|
+
enumerable: true,
|
|
180
|
+
configurable: true,
|
|
181
|
+
writable: true,
|
|
182
|
+
value: () => this.core.destroy()
|
|
183
|
+
});
|
|
184
|
+
/** Clean up and release all resources. Unregister all event handlers. */
|
|
185
|
+
Object.defineProperty(this, "destroy", {
|
|
186
|
+
enumerable: true,
|
|
187
|
+
configurable: true,
|
|
188
|
+
writable: true,
|
|
189
|
+
value: () => {
|
|
190
|
+
this.destroyCore();
|
|
191
|
+
this.updateHlsEventsHandlers("unregister");
|
|
192
|
+
this.updateMediaElementEventHandlers("unregister");
|
|
193
|
+
this.currentHlsInstance = undefined;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
this.core = new Core(config?.core);
|
|
197
|
+
this.segmentManager = new SegmentManager(this.core);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Adds an event listener for the specified event.
|
|
201
|
+
* @param eventName The name of the event to listen for.
|
|
202
|
+
* @param listener The callback function to be invoked when the event is triggered.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* // Listening for a segment being successfully loaded
|
|
206
|
+
* p2pEngine.addEventListener('onSegmentLoaded', (details) => {
|
|
207
|
+
* console.log('Segment Loaded:', details);
|
|
208
|
+
* });
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* // Handling segment load errors
|
|
212
|
+
* p2pEngine.addEventListener('onSegmentError', (errorDetails) => {
|
|
213
|
+
* console.error('Error loading segment:', errorDetails);
|
|
214
|
+
* });
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* // Tracking data downloaded from peers
|
|
218
|
+
* p2pEngine.addEventListener('onChunkDownloaded', (bytesLength, downloadSource, peerId) => {
|
|
219
|
+
* console.log(`Downloaded ${bytesLength} bytes from ${downloadSource} ${peerId ? 'from peer ' + peerId : 'from server'}`);
|
|
220
|
+
* });
|
|
221
|
+
*/
|
|
222
|
+
addEventListener(eventName, listener) {
|
|
223
|
+
this.core.addEventListener(eventName, listener);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Removes an event listener for the specified event.
|
|
227
|
+
* @param eventName The name of the event.
|
|
228
|
+
* @param listener The callback function that was previously added.
|
|
229
|
+
*/
|
|
230
|
+
removeEventListener(eventName, listener) {
|
|
231
|
+
this.core.removeEventListener(eventName, listener);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* provides the Hls.js P2P specific configuration for Hls.js loaders.
|
|
235
|
+
* @returns An object with fragment loader (fLoader) and playlist loader (pLoader).
|
|
236
|
+
*/
|
|
237
|
+
getConfigForHlsJs() {
|
|
238
|
+
return {
|
|
239
|
+
fLoader: this.createFragmentLoaderClass(),
|
|
240
|
+
pLoader: this.createPlaylistLoaderClass(),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Returns the configuration of the HLS.js P2P engine.
|
|
245
|
+
* @returns A readonly version of the HlsJsP2PEngineConfig.
|
|
246
|
+
*/
|
|
247
|
+
getConfig() {
|
|
248
|
+
return { core: this.core.getConfig() };
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Applies dynamic configuration updates to the P2P engine.
|
|
252
|
+
* @param dynamicConfig Configuration changes to apply.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* // Assuming `hlsP2PEngine` is an instance of HlsJsP2PEngine
|
|
256
|
+
*
|
|
257
|
+
* const newDynamicConfig = {
|
|
258
|
+
* core: {
|
|
259
|
+
* // Increase the number of cached segments to 1000
|
|
260
|
+
* cachedSegmentsCount: 1000,
|
|
261
|
+
* // 50 minutes of segments will be downloaded further through HTTP connections if P2P fails
|
|
262
|
+
* httpDownloadTimeWindow: 3000,
|
|
263
|
+
* // 100 minutes of segments will be downloaded further through P2P connections
|
|
264
|
+
* p2pDownloadTimeWindow: 6000,
|
|
265
|
+
* };
|
|
266
|
+
*
|
|
267
|
+
* hlsP2PEngine.applyDynamicConfig(newDynamicConfig);
|
|
268
|
+
*/
|
|
269
|
+
applyDynamicConfig(dynamicConfig) {
|
|
270
|
+
if (dynamicConfig.core)
|
|
271
|
+
this.core.applyDynamicConfig(dynamicConfig.core);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Sets the HLS instance for handling media.
|
|
275
|
+
* @param hls The HLS instance or a function that returns an HLS instance.
|
|
276
|
+
*/
|
|
277
|
+
bindHls(hls) {
|
|
278
|
+
this.hlsInstanceGetter =
|
|
279
|
+
typeof hls === "function" ? hls : () => hls;
|
|
280
|
+
}
|
|
281
|
+
initHlsEvents() {
|
|
282
|
+
const hlsInstance = this.hlsInstanceGetter?.();
|
|
283
|
+
if (this.currentHlsInstance === hlsInstance)
|
|
284
|
+
return;
|
|
285
|
+
if (this.currentHlsInstance)
|
|
286
|
+
this.destroy();
|
|
287
|
+
this.currentHlsInstance = hlsInstance;
|
|
288
|
+
this.updateHlsEventsHandlers("register");
|
|
289
|
+
this.updateMediaElementEventHandlers("register");
|
|
290
|
+
}
|
|
291
|
+
updateHlsEventsHandlers(type) {
|
|
292
|
+
const hls = this.currentHlsInstance;
|
|
293
|
+
if (!hls)
|
|
294
|
+
return;
|
|
295
|
+
const method = type === "register" ? "on" : "off";
|
|
296
|
+
hls[method]("hlsManifestLoaded", this.handleManifestLoaded);
|
|
297
|
+
hls[method]("hlsLevelSwitching", this.handleLevelSwitching);
|
|
298
|
+
hls[method]("hlsLevelUpdated", this.handleLevelUpdated);
|
|
299
|
+
hls[method]("hlsAudioTrackLoaded", this.handleLevelUpdated);
|
|
300
|
+
hls[method]("hlsDestroying", this.destroy);
|
|
301
|
+
hls[method]("hlsMediaAttaching", this.destroyCore);
|
|
302
|
+
hls[method]("hlsManifestLoading", this.destroyCore);
|
|
303
|
+
hls[method]("hlsMediaDetached", this.handleMediaDetached);
|
|
304
|
+
hls[method]("hlsMediaAttached", this.handleMediaAttached);
|
|
305
|
+
}
|
|
306
|
+
updateLiveSyncDurationCount(data) {
|
|
307
|
+
const fragmentDuration = data.details.targetduration;
|
|
308
|
+
const maxLiveSyncCount = Math.floor(MAX_LIVE_SYNC_DURATION / fragmentDuration);
|
|
309
|
+
const newLiveSyncDurationCount = Math.min(data.details.fragments.length - 1, maxLiveSyncCount);
|
|
310
|
+
if (this.currentHlsInstance &&
|
|
311
|
+
this.currentHlsInstance.config.liveSyncDurationCount !==
|
|
312
|
+
newLiveSyncDurationCount) {
|
|
313
|
+
this.debug(`Setting liveSyncDurationCount to ${newLiveSyncDurationCount}`);
|
|
314
|
+
this.currentHlsInstance.config.liveSyncDurationCount =
|
|
315
|
+
newLiveSyncDurationCount;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
createFragmentLoaderClass() {
|
|
319
|
+
const { core } = this;
|
|
320
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
321
|
+
const engine = this;
|
|
322
|
+
return class FragmentLoader extends FragmentLoaderBase {
|
|
323
|
+
constructor(config) {
|
|
324
|
+
super(config, core);
|
|
325
|
+
}
|
|
326
|
+
static getEngine() {
|
|
327
|
+
return engine;
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
createPlaylistLoaderClass() {
|
|
332
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
333
|
+
const engine = this;
|
|
334
|
+
return class PlaylistLoader extends PlaylistLoaderBase {
|
|
335
|
+
constructor(config) {
|
|
336
|
+
super(config);
|
|
337
|
+
engine.initHlsEvents();
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FragmentLoaderContext, HlsConfig, Loader, LoaderCallbacks, LoaderConfiguration, LoaderContext, LoaderStats } from "hls.js";
|
|
2
|
+
import { Core } from "p2p-media-loader-core";
|
|
3
|
+
export declare class FragmentLoaderBase implements Loader<FragmentLoaderContext> {
|
|
4
|
+
#private;
|
|
5
|
+
context: FragmentLoaderContext;
|
|
6
|
+
config: LoaderConfiguration | null;
|
|
7
|
+
stats: LoaderStats;
|
|
8
|
+
constructor(config: HlsConfig, core: Core);
|
|
9
|
+
load(context: FragmentLoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks<LoaderContext>): void;
|
|
10
|
+
abort(): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _FragmentLoaderBase_instances, _FragmentLoaderBase_callbacks, _FragmentLoaderBase_createDefaultLoader, _FragmentLoaderBase_defaultLoader, _FragmentLoaderBase_core, _FragmentLoaderBase_response, _FragmentLoaderBase_segmentId, _FragmentLoaderBase_handleError, _FragmentLoaderBase_abortInternal;
|
|
13
|
+
import * as Utils from "./utils.js";
|
|
14
|
+
import { CoreRequestError } from "p2p-media-loader-core";
|
|
15
|
+
const DEFAULT_DOWNLOAD_LATENCY = 10;
|
|
16
|
+
export class FragmentLoaderBase {
|
|
17
|
+
constructor(config, core) {
|
|
18
|
+
_FragmentLoaderBase_instances.add(this);
|
|
19
|
+
Object.defineProperty(this, "context", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: void 0
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(this, "config", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: void 0
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(this, "stats", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: void 0
|
|
36
|
+
});
|
|
37
|
+
_FragmentLoaderBase_callbacks.set(this, void 0);
|
|
38
|
+
_FragmentLoaderBase_createDefaultLoader.set(this, void 0);
|
|
39
|
+
_FragmentLoaderBase_defaultLoader.set(this, void 0);
|
|
40
|
+
_FragmentLoaderBase_core.set(this, void 0);
|
|
41
|
+
_FragmentLoaderBase_response.set(this, void 0);
|
|
42
|
+
_FragmentLoaderBase_segmentId.set(this, void 0);
|
|
43
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_core, core, "f");
|
|
44
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_createDefaultLoader, () => new config.loader(config), "f");
|
|
45
|
+
this.stats = {
|
|
46
|
+
aborted: false,
|
|
47
|
+
chunkCount: 0,
|
|
48
|
+
loading: { start: 0, first: 0, end: 0 },
|
|
49
|
+
buffering: { start: 0, first: 0, end: 0 },
|
|
50
|
+
parsing: { start: 0, end: 0 },
|
|
51
|
+
// set total and loaded to 1 to prevent hls.js
|
|
52
|
+
// on progress loading monitoring in AbrController
|
|
53
|
+
total: 1,
|
|
54
|
+
loaded: 1,
|
|
55
|
+
bwEstimate: 0,
|
|
56
|
+
retry: 0,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
load(context, config, callbacks) {
|
|
60
|
+
this.context = context;
|
|
61
|
+
this.config = config;
|
|
62
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_callbacks, callbacks, "f");
|
|
63
|
+
const { stats } = this;
|
|
64
|
+
const { rangeStart: start, rangeEnd: end } = context;
|
|
65
|
+
const byteRange = Utils.getByteRange(start, end !== undefined ? end - 1 : undefined);
|
|
66
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_segmentId, Utils.getSegmentRuntimeId(context.url, byteRange), "f");
|
|
67
|
+
const isSegmentDownloadableByP2PCore = __classPrivateFieldGet(this, _FragmentLoaderBase_core, "f").isSegmentLoadable(__classPrivateFieldGet(this, _FragmentLoaderBase_segmentId, "f"));
|
|
68
|
+
if (!__classPrivateFieldGet(this, _FragmentLoaderBase_core, "f").hasSegment(__classPrivateFieldGet(this, _FragmentLoaderBase_segmentId, "f")) ||
|
|
69
|
+
!isSegmentDownloadableByP2PCore) {
|
|
70
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_defaultLoader, __classPrivateFieldGet(this, _FragmentLoaderBase_createDefaultLoader, "f").call(this), "f");
|
|
71
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_defaultLoader, "f").stats = this.stats;
|
|
72
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_defaultLoader, "f").load(context, config, callbacks);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const onSuccess = (response) => {
|
|
76
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_response, response, "f");
|
|
77
|
+
const loadedBytes = __classPrivateFieldGet(this, _FragmentLoaderBase_response, "f").data.byteLength;
|
|
78
|
+
stats.loading = getLoadingStat(__classPrivateFieldGet(this, _FragmentLoaderBase_response, "f").bandwidth, loadedBytes, performance.now());
|
|
79
|
+
stats.total = loadedBytes;
|
|
80
|
+
stats.loaded = loadedBytes;
|
|
81
|
+
if (callbacks.onProgress) {
|
|
82
|
+
callbacks.onProgress(this.stats, context, __classPrivateFieldGet(this, _FragmentLoaderBase_response, "f").data, undefined);
|
|
83
|
+
}
|
|
84
|
+
callbacks.onSuccess({ data: __classPrivateFieldGet(this, _FragmentLoaderBase_response, "f").data, url: context.url }, this.stats, context, undefined);
|
|
85
|
+
};
|
|
86
|
+
const onError = (error) => {
|
|
87
|
+
if (error instanceof CoreRequestError &&
|
|
88
|
+
error.type === "aborted" &&
|
|
89
|
+
this.stats.aborted) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_instances, "m", _FragmentLoaderBase_handleError).call(this, error);
|
|
93
|
+
};
|
|
94
|
+
void __classPrivateFieldGet(this, _FragmentLoaderBase_core, "f").loadSegment(__classPrivateFieldGet(this, _FragmentLoaderBase_segmentId, "f"), { onSuccess, onError });
|
|
95
|
+
}
|
|
96
|
+
abort() {
|
|
97
|
+
if (__classPrivateFieldGet(this, _FragmentLoaderBase_defaultLoader, "f")) {
|
|
98
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_defaultLoader, "f").abort();
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_instances, "m", _FragmentLoaderBase_abortInternal).call(this);
|
|
102
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_callbacks, "f")?.onAbort?.(this.stats, this.context, {});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
destroy() {
|
|
106
|
+
if (__classPrivateFieldGet(this, _FragmentLoaderBase_defaultLoader, "f")) {
|
|
107
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_defaultLoader, "f").destroy();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if (!this.stats.aborted)
|
|
111
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_instances, "m", _FragmentLoaderBase_abortInternal).call(this);
|
|
112
|
+
__classPrivateFieldSet(this, _FragmentLoaderBase_callbacks, null, "f");
|
|
113
|
+
this.config = null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
_FragmentLoaderBase_callbacks = new WeakMap(), _FragmentLoaderBase_createDefaultLoader = new WeakMap(), _FragmentLoaderBase_defaultLoader = new WeakMap(), _FragmentLoaderBase_core = new WeakMap(), _FragmentLoaderBase_response = new WeakMap(), _FragmentLoaderBase_segmentId = new WeakMap(), _FragmentLoaderBase_instances = new WeakSet(), _FragmentLoaderBase_handleError = function _FragmentLoaderBase_handleError(thrownError) {
|
|
118
|
+
const error = { code: 0, text: "" };
|
|
119
|
+
if (thrownError instanceof CoreRequestError &&
|
|
120
|
+
thrownError.type === "failed") {
|
|
121
|
+
// error.code = thrownError.code;
|
|
122
|
+
error.text = thrownError.message;
|
|
123
|
+
}
|
|
124
|
+
else if (thrownError instanceof Error) {
|
|
125
|
+
error.text = thrownError.message;
|
|
126
|
+
}
|
|
127
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_callbacks, "f")?.onError(error, this.context, null, this.stats);
|
|
128
|
+
}, _FragmentLoaderBase_abortInternal = function _FragmentLoaderBase_abortInternal() {
|
|
129
|
+
if (!__classPrivateFieldGet(this, _FragmentLoaderBase_response, "f") && __classPrivateFieldGet(this, _FragmentLoaderBase_segmentId, "f")) {
|
|
130
|
+
this.stats.aborted = true;
|
|
131
|
+
__classPrivateFieldGet(this, _FragmentLoaderBase_core, "f").abortSegmentLoading(__classPrivateFieldGet(this, _FragmentLoaderBase_segmentId, "f"));
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
function getLoadingStat(targetBitrate, loadedBytes, loadingEndTime) {
|
|
135
|
+
const timeForLoading = (loadedBytes * 8000) / targetBitrate;
|
|
136
|
+
const first = loadingEndTime - timeForLoading;
|
|
137
|
+
const start = first - DEFAULT_DOWNLOAD_LATENCY;
|
|
138
|
+
return { start, first, end: loadingEndTime };
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=fragment-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragment-loader.js","sourceRoot":"","sources":["../src/fragment-loader.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HlsConfig, Loader, LoaderCallbacks, LoaderConfiguration, LoaderContext, LoaderStats, PlaylistLoaderContext } from "hls.js";
|
|
2
|
+
export declare class PlaylistLoaderBase implements Loader<PlaylistLoaderContext> {
|
|
3
|
+
#private;
|
|
4
|
+
context: PlaylistLoaderContext;
|
|
5
|
+
stats: LoaderStats;
|
|
6
|
+
constructor(config: HlsConfig);
|
|
7
|
+
load(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks<LoaderContext>): void;
|
|
8
|
+
abort(): void;
|
|
9
|
+
destroy(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _PlaylistLoaderBase_defaultLoader;
|
|
13
|
+
export class PlaylistLoaderBase {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
_PlaylistLoaderBase_defaultLoader.set(this, void 0);
|
|
16
|
+
Object.defineProperty(this, "context", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: void 0
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "stats", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: void 0
|
|
27
|
+
});
|
|
28
|
+
__classPrivateFieldSet(this, _PlaylistLoaderBase_defaultLoader, new config.loader(config), "f");
|
|
29
|
+
this.stats = __classPrivateFieldGet(this, _PlaylistLoaderBase_defaultLoader, "f").stats;
|
|
30
|
+
this.context = __classPrivateFieldGet(this, _PlaylistLoaderBase_defaultLoader, "f").context;
|
|
31
|
+
}
|
|
32
|
+
load(context, config, callbacks) {
|
|
33
|
+
__classPrivateFieldGet(this, _PlaylistLoaderBase_defaultLoader, "f").load(context, config, callbacks);
|
|
34
|
+
}
|
|
35
|
+
abort() {
|
|
36
|
+
__classPrivateFieldGet(this, _PlaylistLoaderBase_defaultLoader, "f").abort();
|
|
37
|
+
}
|
|
38
|
+
destroy() {
|
|
39
|
+
__classPrivateFieldGet(this, _PlaylistLoaderBase_defaultLoader, "f").destroy();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
_PlaylistLoaderBase_defaultLoader = new WeakMap();
|
|
43
|
+
//# sourceMappingURL=playlist-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playlist-loader.js","sourceRoot":"","sources":["../src/playlist-loader.ts"],"names":[],"mappings":";;;;;;;;;;;;AAUA,MAAM,OAAO,kBAAkB;IAK7B,YAAY,MAAiB;QAJ7B,oDAAsC;QACtC;;;;;WAA+B;QAC/B;;;;;WAAmB;QAGjB,uBAAA,IAAI,qCAAkB,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAA,CAAC;QAChD,IAAI,CAAC,KAAK,GAAG,uBAAA,IAAI,yCAAe,CAAC,KAAK,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,uBAAA,IAAI,yCAAe,CAAC,OAAgC,CAAC;IACtE,CAAC;IAED,IAAI,CACF,OAAsB,EACtB,MAA2B,EAC3B,SAAyC;QAEzC,uBAAA,IAAI,yCAAe,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,KAAK;QACH,uBAAA,IAAI,yCAAe,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO;QACL,uBAAA,IAAI,yCAAe,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ManifestLoadedData, LevelUpdatedData, AudioTrackLoadedData } from "hls.js";
|
|
2
|
+
import { Core } from "p2p-media-loader-core";
|
|
3
|
+
export declare class SegmentManager {
|
|
4
|
+
core: Core;
|
|
5
|
+
constructor(core: Core);
|
|
6
|
+
processMainManifest(data: ManifestLoadedData): void;
|
|
7
|
+
updatePlaylist(data: LevelUpdatedData | AudioTrackLoadedData): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as Utils from "./utils.js";
|
|
2
|
+
export class SegmentManager {
|
|
3
|
+
constructor(core) {
|
|
4
|
+
Object.defineProperty(this, "core", {
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true,
|
|
8
|
+
value: void 0
|
|
9
|
+
});
|
|
10
|
+
this.core = core;
|
|
11
|
+
}
|
|
12
|
+
processMainManifest(data) {
|
|
13
|
+
const { levels, audioTracks } = data;
|
|
14
|
+
// in the case of audio only stream it is stored in levels
|
|
15
|
+
for (const [index, level] of levels.entries()) {
|
|
16
|
+
const { url } = level;
|
|
17
|
+
this.core.addStreamIfNoneExists({
|
|
18
|
+
runtimeId: Array.isArray(url) ? url[0] : url,
|
|
19
|
+
type: "main",
|
|
20
|
+
index,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
for (const [index, track] of audioTracks.entries()) {
|
|
24
|
+
const { url } = track;
|
|
25
|
+
this.core.addStreamIfNoneExists({
|
|
26
|
+
runtimeId: Array.isArray(url) ? url[0] : url,
|
|
27
|
+
type: "secondary",
|
|
28
|
+
index,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
updatePlaylist(data) {
|
|
33
|
+
const { details: { url, fragments, live }, } = data;
|
|
34
|
+
const playlist = this.core.getStream(url);
|
|
35
|
+
if (!playlist)
|
|
36
|
+
return;
|
|
37
|
+
const segmentToRemoveIds = new Set(playlist.segments.keys());
|
|
38
|
+
const newSegments = [];
|
|
39
|
+
fragments.forEach((fragment, index) => {
|
|
40
|
+
const { url: responseUrl, byteRange: fragByteRange, sn, start: startTime, end: endTime, } = fragment;
|
|
41
|
+
const [start, end] = fragByteRange;
|
|
42
|
+
const byteRange = Utils.getByteRange(start, end !== undefined ? end - 1 : undefined);
|
|
43
|
+
const runtimeId = Utils.getSegmentRuntimeId(responseUrl, byteRange);
|
|
44
|
+
segmentToRemoveIds.delete(runtimeId);
|
|
45
|
+
if (playlist.segments.has(runtimeId))
|
|
46
|
+
return;
|
|
47
|
+
newSegments.push({
|
|
48
|
+
runtimeId,
|
|
49
|
+
url: responseUrl,
|
|
50
|
+
externalId: live ? sn : index,
|
|
51
|
+
byteRange,
|
|
52
|
+
startTime,
|
|
53
|
+
endTime,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
if (!newSegments.length && !segmentToRemoveIds.size)
|
|
57
|
+
return;
|
|
58
|
+
this.core.updateStream(url, newSegments, segmentToRemoveIds.values());
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=segment-mananger.js.map
|