UNPKG

msc-node

Version:

mediasoup client side Node.js library

156 lines (155 loc) 4.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addLegacySimulcast = exports.getRtpEncodings = void 0; function getRtpEncodings({ offerMediaObject, track }) { // First media SSRC (or the only one). let firstSsrc; const ssrcs = new Set(); for (const line of offerMediaObject.ssrcs || []) { if (line.attribute !== 'msid') { continue; } const trackId = line.value.split(' ')[1]; if (trackId === track.id) { const ssrc = line.id; ssrcs.add(ssrc); if (!firstSsrc) { firstSsrc = ssrc; } } } if (ssrcs.size === 0) { throw new Error(`a=ssrc line with msid information not found [track.id:${track.id}]`); } const ssrcToRtxSsrc = new Map(); // First assume RTX is used. for (const line of offerMediaObject.ssrcGroups || []) { if (line.semantics !== 'FID') { continue; } let [ssrc, rtxSsrc] = line.ssrcs.split(/\s+/); ssrc = Number(ssrc); rtxSsrc = Number(rtxSsrc); if (ssrcs.has(ssrc)) { // Remove both the SSRC and RTX SSRC from the set so later we know that they // are already handled. ssrcs.delete(ssrc); ssrcs.delete(rtxSsrc); // Add to the map. ssrcToRtxSsrc.set(ssrc, rtxSsrc); } } // If the set of SSRCs is not empty it means that RTX is not being used, so take // media SSRCs from there. for (const ssrc of ssrcs) { // Add to the map. ssrcToRtxSsrc.set(ssrc, null); } const encodings = []; for (const [ssrc, rtxSsrc] of ssrcToRtxSsrc) { const encoding = { ssrc }; if (rtxSsrc) { encoding.rtx = { ssrc: rtxSsrc }; } encodings.push(encoding); } return encodings; } exports.getRtpEncodings = getRtpEncodings; /** * Adds multi-ssrc based simulcast into the given SDP media section offer. */ function addLegacySimulcast({ offerMediaObject, track, numStreams }) { if (numStreams <= 1) { throw new TypeError('numStreams must be greater than 1'); } let firstSsrc; let firstRtxSsrc; let streamId; // Get the SSRC. const ssrcMsidLine = (offerMediaObject.ssrcs || []) .find((line) => { if (line.attribute !== 'msid') { return false; } const trackId = line.value.split(' ')[1]; if (trackId === track.id) { firstSsrc = line.id; streamId = line.value.split(' ')[0]; return true; } else { return false; } }); if (!ssrcMsidLine) { throw new Error(`a=ssrc line with msid information not found [track.id:${track.id}]`); } // Get the SSRC for RTX. (offerMediaObject.ssrcGroups || []) .some((line) => { if (line.semantics !== 'FID') { return false; } const ssrcs = line.ssrcs.split(/\s+/); if (Number(ssrcs[0]) === firstSsrc) { firstRtxSsrc = Number(ssrcs[1]); return true; } else { return false; } }); const ssrcCnameLine = offerMediaObject.ssrcs .find((line) => (line.attribute === 'cname' && line.id === firstSsrc)); if (!ssrcCnameLine) { throw new Error(`a=ssrc line with cname information not found [track.id:${track.id}]`); } const cname = ssrcCnameLine.value; const ssrcs = []; const rtxSsrcs = []; for (let i = 0; i < numStreams; ++i) { ssrcs.push(firstSsrc + i); if (firstRtxSsrc) { rtxSsrcs.push(firstRtxSsrc + i); } } offerMediaObject.ssrcGroups = offerMediaObject.ssrcGroups || []; offerMediaObject.ssrcs = offerMediaObject.ssrcs || []; offerMediaObject.ssrcGroups.push({ semantics: 'SIM', ssrcs: ssrcs.join(' ') }); for (let i = 0; i < ssrcs.length; ++i) { const ssrc = ssrcs[i]; offerMediaObject.ssrcs.push({ id: ssrc, attribute: 'cname', value: cname }); offerMediaObject.ssrcs.push({ id: ssrc, attribute: 'msid', value: `${streamId} ${track.id}` }); } for (let i = 0; i < rtxSsrcs.length; ++i) { const ssrc = ssrcs[i]; const rtxSsrc = rtxSsrcs[i]; offerMediaObject.ssrcs.push({ id: rtxSsrc, attribute: 'cname', value: cname }); offerMediaObject.ssrcs.push({ id: rtxSsrc, attribute: 'msid', value: `${streamId} ${track.id}` }); offerMediaObject.ssrcGroups.push({ semantics: 'FID', ssrcs: `${ssrc} ${rtxSsrc}` }); } } exports.addLegacySimulcast = addLegacySimulcast;