msc-node
Version:
mediasoup client side Node.js library
156 lines (155 loc) • 4.91 kB
JavaScript
;
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;