UNPKG

p2p-media-loader-hlsjs

Version:
295 lines (294 loc) 9.2 kB
import { Core as e, Core as t, CoreRequestError as n, debug as r, generateStreamShortId as i } from "p2p-media-loader-core"; //#region src/utils.ts function a(e, t) { return t ? `${e}|${t.start}-${t.end}` : e; } function o(e, t) { if (e !== void 0 && t !== void 0 && e <= t) return { start: e, end: t }; } //#endregion //#region src/fragment-loader.ts var s = 10, c = class { context; config; stats; #e; #t; #n; #r; #i; #a; constructor(e, t) { this.#r = t, this.#t = () => new e.loader(e), this.stats = { aborted: !1, chunkCount: 0, loading: { start: 0, first: 0, end: 0 }, buffering: { start: 0, first: 0, end: 0 }, parsing: { start: 0, end: 0 }, total: 1, loaded: 1, bwEstimate: 0, retry: 0 }; } load(e, t, r) { this.context = e, this.config = t, this.#e = r; let { stats: i } = this, { rangeStart: s, rangeEnd: c } = e, u = o(s, c === void 0 ? void 0 : c - 1); this.#a = a(e.url, u); let d = this.#r.isSegmentLoadable(this.#a); if (!this.#r.hasSegment(this.#a) || !d) { this.#n = this.#t(), this.#n.stats = this.stats, this.#n.load(e, t, r); return; } this.#r.loadSegment(this.#a, { onSuccess: (t) => { if (!this.#e) return; this.#i = t; let n = this.#i.data.byteLength; i.loading = l(this.#i.bandwidth, n, performance.now()), i.total = n, i.loaded = n; let r = this.#i.data.slice(0); this.#e.onProgress && this.#e.onProgress(this.stats, e, r, void 0), this.#e.onSuccess({ data: r, url: e.url }, this.stats, e, void 0); }, onError: (e) => { e instanceof n && e.type === "aborted" && this.stats.aborted || this.#o(e); } }); } #o(e) { let t = { code: 0, text: "" }; (e instanceof n && e.type === "failed" || e instanceof Error) && (t.text = e.message), this.#e?.onError(t, this.context, null, this.stats); } #s() { !this.#i && this.#a && (this.stats.aborted = !0, this.#r.abortSegmentLoading(this.#a)); } abort() { this.#n ? this.#n.abort() : (this.#s(), this.#e?.onAbort?.(this.stats, this.context, {})); } destroy() { this.#n ? this.#n.destroy() : (this.stats.aborted || this.#s(), this.#e = null, this.config = null); } }; function l(e, t, n) { let r = e > 0 ? t * 8e3 / e : 0, i = Math.max(0, n - r); return { start: Math.max(0, i - s), first: i, end: n }; } //#endregion //#region src/playlist-loader.ts var u = class { #e; context; stats; constructor(e) { this.#e = new e.loader(e), this.stats = this.#e.stats, this.context = this.#e.context; } load(e, t, n) { this.#e.load(e, t, n); } abort() { this.#e.abort(); } destroy() { this.#e.destroy(); } }, d = class { core; constructor(e) { this.core = e; } processMainManifest(e) { let { levels: t, audioTracks: n } = e; for (let e of t) { let { url: t, bitrate: n, maxBitrate: r, videoCodec: a, width: o, height: s } = e, c = r ?? n, l = c === 0, u = e.attrs["FRAME-RATE"], d = e.attrs["VIDEO-RANGE"], f = i({ bitrate: c, codecs: l ? void 0 : a, width: l ? void 0 : o, height: l ? void 0 : s, frameRate: l ? void 0 : u, videoRange: l ? void 0 : d }); this.core.addStreamIfNoneExists({ runtimeId: Array.isArray(t) ? t[0] : t, type: "main", index: f }); } for (let e of n) { let { url: t, audioCodec: n, lang: r, channels: a, name: o } = e, s = i({ bitrate: 0, codecs: n, language: r, channels: a, name: o }); this.core.addStreamIfNoneExists({ runtimeId: Array.isArray(t) ? t[0] : t, type: "secondary", index: s }); } } updatePlaylist(e) { let { details: { url: t, fragments: n, live: r } } = e, i = this.core.getStream(t); if (!i) return; let s = new Set(i.segments.keys()), c = []; n.forEach((e, t) => { let { url: n, byteRange: l, sn: u, start: d, end: f } = e, [p, m] = l, h = o(p, m === void 0 ? void 0 : m - 1), g = a(n, h); s.delete(g), !i.segments.has(g) && c.push({ runtimeId: g, url: n, externalId: r ? u : t, byteRange: h, startTime: d, endTime: f }); }), !(!c.length && !s.size) && this.core.updateStream(t, c, s.values()); } }; //#endregion //#region src/engine-static.ts function f(e) { return class extends e { #e; get p2pEngine() { return this.#e; } constructor(...e) { let { p2p: t, ...n } = e[0] ?? {}, r = new m(t); super({ ...n, ...r.getConfigForHlsJs() }), r.bindHls(this), this.#e = r, t?.onHlsJsCreated?.(this); } }; } //#endregion //#region src/engine.ts var p = 120, m = class { core; segmentManager; hlsInstanceGetter; currentHlsInstance; debug = r("p2pml-hlsjs:engine"); static injectMixin(e) { return f(e); } constructor(e) { this.core = new t(e?.core), this.segmentManager = new d(this.core); } addEventListener(e, t) { this.core.addEventListener(e, t); } removeEventListener(e, t) { this.core.removeEventListener(e, t); } getConfigForHlsJs() { return { fLoader: this.createFragmentLoaderClass(), pLoader: this.createPlaylistLoaderClass() }; } getConfig() { return { core: this.core.getConfig() }; } applyDynamicConfig(e) { e.core && this.core.applyDynamicConfig(e.core); } bindHls(e) { this.hlsInstanceGetter = typeof e == "function" ? e : () => e; } initHlsEvents() { let e = this.hlsInstanceGetter?.(); this.currentHlsInstance !== e && (this.currentHlsInstance && this.destroy(), this.currentHlsInstance = e, this.updateHlsEventsHandlers("register"), this.updateMediaElementEventHandlers("register")); } updateHlsEventsHandlers(e) { let t = this.currentHlsInstance; if (!t) return; let n = e === "register" ? "on" : "off"; t[n]("hlsManifestLoaded", this.handleManifestLoaded), t[n]("hlsLevelSwitching", this.handleLevelSwitching), t[n]("hlsLevelUpdated", this.handleLevelUpdated), t[n]("hlsAudioTrackLoaded", this.handleLevelUpdated), t[n]("hlsDestroying", this.destroy), t[n]("hlsMediaAttaching", this.destroyCore), t[n]("hlsManifestLoading", this.destroyCore), t[n]("hlsMediaDetached", this.handleMediaDetached), t[n]("hlsMediaAttached", this.handleMediaAttached); } updateMediaElementEventHandlers = (e) => { let t = this.currentHlsInstance?.media; if (!t) return; let n = e === "register" ? "addEventListener" : "removeEventListener"; t[n]("timeupdate", this.handlePlaybackUpdate), t[n]("seeking", this.handlePlaybackUpdate), t[n]("ratechange", this.handlePlaybackUpdate); }; handleManifestLoaded = (e, t) => { let n = t.networkDetails; n instanceof XMLHttpRequest ? this.core.setManifestResponseUrl(n.responseURL) : n instanceof Response && this.core.setManifestResponseUrl(n.url), this.segmentManager.processMainManifest(t); }; handleLevelSwitching = (e, t) => { t.bitrate && this.core.setActiveLevelBitrate(t.bitrate); }; handleLevelUpdated = (e, t) => { this.currentHlsInstance && t.details.fragments[0].type === "main" && t.details.fragments.length > 4 && (t.details.live && !this.currentHlsInstance.userConfig.liveSyncDuration && !this.currentHlsInstance.userConfig.liveSyncDurationCount && this.updateLiveSyncDurationCount(t), !this.currentHlsInstance.userConfig.maxBufferLength && !this.currentHlsInstance.userConfig.maxMaxBufferLength && this.updateMaxBufferLength(t.details.targetduration)), this.core.setIsLive(t.details.live), this.segmentManager.updatePlaylist(t); }; updateLiveSyncDurationCount(e) { let t = e.details.targetduration, n = Math.floor(p / t), r = Math.min(e.details.fragments.length - 1, n); this.currentHlsInstance && this.currentHlsInstance.config.liveSyncDurationCount !== r && (this.debug(`Setting liveSyncDurationCount to ${r}`), this.currentHlsInstance.config.liveSyncDurationCount = r); } updateMaxBufferLength(e) { if (!this.currentHlsInstance) return; let t = this.core.getConfig(), n = Math.max(t.mainStream.highDemandTimeWindow, t.secondaryStream.highDemandTimeWindow), r = Math.max(e * 2, n); this.currentHlsInstance.config.maxBufferLength > r && (this.debug(`Setting maxBufferLength to ${r}`), this.currentHlsInstance.config.maxBufferLength = r), this.currentHlsInstance.config.maxMaxBufferLength > r && (this.debug(`Setting maxMaxBufferLength to ${r}`), this.currentHlsInstance.config.maxMaxBufferLength = r); } handleMediaAttached = () => { this.updateMediaElementEventHandlers("register"); }; handleMediaDetached = () => { this.updateMediaElementEventHandlers("unregister"); }; handlePlaybackUpdate = (e) => { let t = e.target; this.core.updatePlayback(t.currentTime, t.playbackRate); }; destroyCore = () => this.core.destroy(); destroy = () => { this.destroyCore(), this.updateHlsEventsHandlers("unregister"), this.updateMediaElementEventHandlers("unregister"), this.currentHlsInstance = void 0; }; createFragmentLoaderClass() { let { core: e } = this, t = this; return class extends c { constructor(t) { super(t, e); } static getEngine() { return t; } }; } createPlaylistLoaderClass() { let e = this; return class extends u { constructor(t) { super(t), e.initHlsEvents(); } }; } }; //#endregion export { e as Core, m as HlsJsP2PEngine }; //# sourceMappingURL=p2p-media-loader-hlsjs.es.min.js.map