UNPKG

p2p-media-loader-core

Version:
106 lines 4.82 kB
import { sha1 } from "./hash.js"; const PEER_PROTOCOL_VERSION = "v2"; /** * Generates a stable, unique string ID for a stream based on its properties. * Uses a SHA-1 hash to avoid collisions and encodes the result to standard Base64. */ export function generateStreamShortId({ bitrate, codecs, width, height, language, channels, name, frameRate, videoRange, }) { const normalizedCodecs = codecs ? codecs .split(",") .map((c) => { c = c.trim().toLowerCase(); // Normalize decimal RFC 4281 avc1 codecs to hex (e.g., avc1.66.30 -> avc1.42001e) const parts = c.split("."); if (parts.length === 3 && (parts[0] === "avc1" || parts[0] === "avc")) { const profile = parseInt(parts[1], 10); const level = parseInt(parts[2], 10); if (!isNaN(profile) && !isNaN(level) && parts[1] === profile.toString() && parts[2] === level.toString()) { const profileHex = `00${profile.toString(16)}`.slice(-2); const levelHex = `00${level.toString(16)}`.slice(-2); c = `${parts[0]}.${profileHex}00${levelHex}`; } } return c; }) .sort() .join(",") : ""; const normalizedLanguage = language && language !== "und" ? language.slice(0, 2).toLowerCase() : ""; const normalizedChannels = channels ? channels.toString().split("/")[0] : ""; const normalizedName = name ? name.toLowerCase().trim() : ""; // Normalize frame rates to eliminate trailing zeros (e.g. "30.000" -> "30") const normalizedFrameRate = frameRate && !isNaN(Number(frameRate)) ? Number(frameRate).toString() : ""; const normalizedVideoRange = videoRange ? videoRange.toUpperCase().trim() : ""; const str = `${bitrate !== null && bitrate !== void 0 ? bitrate : 0}-${normalizedCodecs}-${width !== null && width !== void 0 ? width : ""}-${height !== null && height !== void 0 ? height : ""}-${normalizedLanguage}-${normalizedChannels}-${normalizedName}-${normalizedFrameRate}-${normalizedVideoRange}`; return btoa(sha1(str)); } export function getStreamSwarmId(swarmId, stream) { return `${PEER_PROTOCOL_VERSION}-${swarmId}-${getStreamId(stream)}`; } export function getSegmentFromStreamsMap(streams, segmentRuntimeId) { for (const stream of streams.values()) { const segment = stream.segments.get(segmentRuntimeId); if (segment) return segment; } } export function getSegmentFromStreamByExternalId(stream, segmentExternalId) { for (const segment of stream.segments.values()) { if (segment.externalId === segmentExternalId) return segment; } } export function getStreamId(stream) { return `${stream.type}-${stream.index}`; } export function getSegmentAvgDuration(stream) { const { segments } = stream; let sumDuration = 0; const { size } = segments; if (size === 0) return 0; for (const segment of segments.values()) { const duration = segment.endTime - segment.startTime; sumDuration += duration; } return sumDuration / size; } function calculateTimeWindows(timeWindowsConfig, availableMemoryInPercent) { const { highDemandTimeWindow, httpDownloadTimeWindow, p2pDownloadTimeWindow, } = timeWindowsConfig; const result = { highDemandTimeWindow, httpDownloadTimeWindow, p2pDownloadTimeWindow, }; if (availableMemoryInPercent <= 5) { result.httpDownloadTimeWindow = 0; result.p2pDownloadTimeWindow = 0; } else if (availableMemoryInPercent <= 10) { result.p2pDownloadTimeWindow = result.httpDownloadTimeWindow; } return result; } export function getSegmentPlaybackStatuses(segment, playback, timeWindowsConfig, currentP2PLoader, availableMemoryPercent) { const { highDemandTimeWindow, httpDownloadTimeWindow, p2pDownloadTimeWindow, } = calculateTimeWindows(timeWindowsConfig, availableMemoryPercent); return { isHighDemand: isSegmentInTimeWindow(segment, playback, highDemandTimeWindow), isHttpDownloadable: isSegmentInTimeWindow(segment, playback, httpDownloadTimeWindow), isP2PDownloadable: isSegmentInTimeWindow(segment, playback, p2pDownloadTimeWindow) && currentP2PLoader.isSegmentLoadingOrLoadedBySomeone(segment), }; } function isSegmentInTimeWindow(segment, playback, timeWindowLength) { const { startTime, endTime } = segment; const { position, rate } = playback; const rightMargin = position + timeWindowLength * rate; return !(rightMargin < startTime || position > endTime); } //# sourceMappingURL=stream.js.map