p2p-media-loader-hlsjs
Version:
P2P Media Loader hls.js integration
203 lines (202 loc) • 7.84 kB
JavaScript
import { CoreRequestError as E, debug as M, Core as C } from "p2p-media-loader-core";
function H(r, t) {
return t ? `${r}|${t.start}-${t.end}` : r;
}
function L(r, t) {
if (r !== void 0 && t !== void 0 && r <= t) return { start: r, end: t };
}
class I {
context;
config;
stats;
#t;
#a;
#e;
#i;
#s;
#n;
constructor(t, e) {
this.#i = e, this.#a = () => new t.loader(t), 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(t, e, s) {
this.context = t, this.config = e, this.#t = s;
const { stats: i } = this, { rangeStart: a, rangeEnd: n } = t, o = L(a, n !== void 0 ? n - 1 : void 0);
this.#n = H(t.url, o);
const u = this.#i.isSegmentLoadable(this.#n);
if (!this.#i.hasSegment(this.#n) || !u) return this.#e = this.#a(), this.#e.stats = this.stats, void this.#e.load(t, e, s);
this.#i.loadSegment(this.#n, { onSuccess: (d) => {
this.#s = d;
const h = this.#s.data.byteLength;
i.loading = (function(g, f, c) {
const p = 8e3 * f / g, l = c - p;
return { start: l - 10, first: l, end: c };
})(this.#s.bandwidth, h, performance.now()), i.total = h, i.loaded = h, s.onProgress && s.onProgress(this.stats, t, this.#s.data, void 0), s.onSuccess({ data: this.#s.data, url: t.url }, this.stats, t, void 0);
}, onError: (d) => {
d instanceof E && d.type === "aborted" && this.stats.aborted || this.#o(d);
} });
}
#o(t) {
const e = { code: 0, text: "" };
(t instanceof E && t.type === "failed" || t instanceof Error) && (e.text = t.message), this.#t?.onError(e, this.context, null, this.stats);
}
#r() {
!this.#s && this.#n && (this.stats.aborted = !0, this.#i.abortSegmentLoading(this.#n));
}
abort() {
this.#e ? this.#e.abort() : (this.#r(), this.#t?.onAbort?.(this.stats, this.context, {}));
}
destroy() {
this.#e ? this.#e.destroy() : (this.stats.aborted || this.#r(), this.#t = null, this.config = null);
}
}
class S {
#t;
context;
stats;
constructor(t) {
this.#t = new t.loader(t), this.stats = this.#t.stats, this.context = this.#t.context;
}
load(t, e, s) {
this.#t.load(t, e, s);
}
abort() {
this.#t.abort();
}
destroy() {
this.#t.destroy();
}
}
class x {
core;
constructor(t) {
this.core = t;
}
processMainManifest(t) {
const { levels: e, audioTracks: s } = t;
for (const [i, a] of e.entries()) {
const { url: n } = a;
this.core.addStreamIfNoneExists({ runtimeId: Array.isArray(n) ? n[0] : n, type: "main", index: i });
}
for (const [i, a] of s.entries()) {
const { url: n } = a;
this.core.addStreamIfNoneExists({ runtimeId: Array.isArray(n) ? n[0] : n, type: "secondary", index: i });
}
}
updatePlaylist(t) {
const { details: { url: e, fragments: s, live: i } } = t, a = this.core.getStream(e);
if (!a) return;
const n = new Set(a.segments.keys()), o = [];
s.forEach((u, d) => {
const { url: h, byteRange: g, sn: f, start: c, end: p } = u, [l, v] = g, m = L(l, v !== void 0 ? v - 1 : void 0), y = H(h, m);
n.delete(y), a.segments.has(y) || o.push({ runtimeId: y, url: h, externalId: i ? f : d, byteRange: m, startTime: c, endTime: p });
}), (o.length || n.size) && this.core.updateStream(e, o, n.values());
}
}
class b {
core;
segmentManager;
hlsInstanceGetter;
currentHlsInstance;
debug = M("p2pml-hlsjs:engine");
static injectMixin(t) {
return e = t, class extends e {
#t;
get p2pEngine() {
return this.#t;
}
constructor(...s) {
const i = s[0], { p2p: a, ...n } = i ?? {}, o = new b(a);
super({ ...n, ...o.getConfigForHlsJs() }), o.bindHls(this), this.#t = o, a?.onHlsJsCreated?.(this);
}
};
var e;
}
constructor(t) {
this.core = new C(t?.core), this.segmentManager = new x(this.core);
}
addEventListener(t, e) {
this.core.addEventListener(t, e);
}
removeEventListener(t, e) {
this.core.removeEventListener(t, e);
}
getConfigForHlsJs() {
return { fLoader: this.createFragmentLoaderClass(), pLoader: this.createPlaylistLoaderClass() };
}
getConfig() {
return { core: this.core.getConfig() };
}
applyDynamicConfig(t) {
t.core && this.core.applyDynamicConfig(t.core);
}
bindHls(t) {
this.hlsInstanceGetter = typeof t == "function" ? t : () => t;
}
initHlsEvents() {
const t = this.hlsInstanceGetter?.();
this.currentHlsInstance !== t && (this.currentHlsInstance && this.destroy(), this.currentHlsInstance = t, this.updateHlsEventsHandlers("register"), this.updateMediaElementEventHandlers("register"));
}
updateHlsEventsHandlers(t) {
const e = this.currentHlsInstance;
if (!e) return;
const s = t === "register" ? "on" : "off";
e[s]("hlsManifestLoaded", this.handleManifestLoaded), e[s]("hlsLevelSwitching", this.handleLevelSwitching), e[s]("hlsLevelUpdated", this.handleLevelUpdated), e[s]("hlsAudioTrackLoaded", this.handleLevelUpdated), e[s]("hlsDestroying", this.destroy), e[s]("hlsMediaAttaching", this.destroyCore), e[s]("hlsManifestLoading", this.destroyCore), e[s]("hlsMediaDetached", this.handleMediaDetached), e[s]("hlsMediaAttached", this.handleMediaAttached);
}
updateMediaElementEventHandlers = (t) => {
const e = this.currentHlsInstance?.media;
if (!e) return;
const s = t === "register" ? "addEventListener" : "removeEventListener";
e[s]("timeupdate", this.handlePlaybackUpdate), e[s]("seeking", this.handlePlaybackUpdate), e[s]("ratechange", this.handlePlaybackUpdate);
};
handleManifestLoaded = (t, e) => {
const s = e.networkDetails;
s instanceof XMLHttpRequest ? this.core.setManifestResponseUrl(s.responseURL) : s instanceof Response && this.core.setManifestResponseUrl(s.url), this.segmentManager.processMainManifest(e);
};
handleLevelSwitching = (t, e) => {
e.bitrate && this.core.setActiveLevelBitrate(e.bitrate);
};
handleLevelUpdated = (t, e) => {
this.currentHlsInstance && e.details.live && e.details.fragments[0].type === "main" && !this.currentHlsInstance.userConfig.liveSyncDuration && !this.currentHlsInstance.userConfig.liveSyncDurationCount && e.details.fragments.length > 4 && this.updateLiveSyncDurationCount(e), this.core.setIsLive(e.details.live), this.segmentManager.updatePlaylist(e);
};
updateLiveSyncDurationCount(t) {
const e = t.details.targetduration, s = Math.floor(120 / e), i = Math.min(t.details.fragments.length - 1, s);
this.currentHlsInstance && this.currentHlsInstance.config.liveSyncDurationCount !== i && (this.debug(`Setting liveSyncDurationCount to ${i}`), this.currentHlsInstance.config.liveSyncDurationCount = i);
}
handleMediaAttached = () => {
this.updateMediaElementEventHandlers("register");
};
handleMediaDetached = () => {
this.updateMediaElementEventHandlers("unregister");
};
handlePlaybackUpdate = (t) => {
const e = t.target;
this.core.updatePlayback(e.currentTime, e.playbackRate);
};
destroyCore = () => this.core.destroy();
destroy = () => {
this.destroyCore(), this.updateHlsEventsHandlers("unregister"), this.updateMediaElementEventHandlers("unregister"), this.currentHlsInstance = void 0;
};
createFragmentLoaderClass() {
const { core: t } = this, e = this;
return class extends I {
constructor(s) {
super(s, t);
}
static getEngine() {
return e;
}
};
}
createPlaylistLoaderClass() {
const t = this;
return class extends S {
constructor(e) {
super(e), t.initHlsEvents();
}
};
}
}
export {
b as HlsJsP2PEngine
};
//# sourceMappingURL=p2p-media-loader-hlsjs.es.min.js.map