p2p-media-loader-shaka
Version:
P2P Media Loader Shaka Player integration
89 lines (75 loc) • 2.42 kB
text/typescript
import type shaka from "shaka-player/dist/shaka-player.compiled.d.ts";
import { StreamWithReadonlySegments } from "./types.js";
import { Segment, ByteRange } from "p2p-media-loader-core";
export function createSegment({
segmentReference,
externalId,
runtimeId,
}: {
segmentReference: shaka.media.SegmentReference;
externalId: number;
runtimeId?: string;
}): Segment {
const { byteRange, url, startTime, endTime } =
getSegmentInfoFromReference(segmentReference);
return {
runtimeId: runtimeId ?? getSegmentRuntimeId(url, byteRange),
externalId,
byteRange,
url,
startTime,
endTime,
};
}
export function getSegmentRuntimeIdFromReference(
segmentReference: shaka.media.SegmentReference,
) {
const { url, byteRange } = getSegmentInfoFromReference(segmentReference);
return getSegmentRuntimeId(url, byteRange);
}
export function getSegmentRuntimeId(
url: string,
byteRange?: ByteRange | string,
) {
if (!byteRange) return url;
const range: ByteRange | undefined =
typeof byteRange === "string"
? getByteRangeFromHeaderString(byteRange)
: byteRange;
if (!range) return url;
return `${url}|${range.start}-${range.end}`;
}
export function getByteRangeFromHeaderString(
rangeStr: string | undefined,
): ByteRange | undefined {
if (!rangeStr?.includes("bytes=")) return undefined;
const parts = rangeStr.split("=")[1].split("-");
const start = parseInt(parts[0]);
const end = parseInt(parts[1]);
if (isNaN(start) || isNaN(end)) return undefined;
return { start, end };
}
export function getSegmentInfoFromReference(
segmentReference: shaka.media.SegmentReference,
) {
const uris = segmentReference.getUris();
const responseUrl = uris[1] ?? uris[0];
const start = segmentReference.getStartByte();
const end = segmentReference.getEndByte() ?? undefined;
const startTime = segmentReference.getStartTime();
const endTime = segmentReference.getEndTime();
return {
byteRange: end !== undefined ? { start, end } : undefined,
url: responseUrl,
startTime,
endTime,
};
}
export function getStreamLastMediaSequence(stream: StreamWithReadonlySegments) {
const { shakaStream } = stream;
const map = shakaStream.mediaSequenceTimeMap;
if (!map) return;
const firstMediaSequence = map.keys().next().value;
if (firstMediaSequence === undefined) return;
return firstMediaSequence + map.size - 1;
}