msc-node
Version:
mediasoup client side Node.js library
208 lines (207 loc) • 7.19 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyCodecParameters = exports.getCname = exports.extractDtlsParameters = exports.extractRtpCapabilities = void 0;
const sdpTransform = __importStar(require("sdp-transform"));
function extractRtpCapabilities({ sdpObject }) {
// Map of RtpCodecParameters indexed by payload type.
const codecsMap = new Map();
// Array of RtpHeaderExtensions.
const headerExtensions = [];
// Whether a m=audio/video section has been already found.
let gotAudio = false;
let gotVideo = false;
for (const m of sdpObject.media) {
const kind = m.type;
switch (kind) {
case 'audio':
{
if (gotAudio) {
continue;
}
gotAudio = true;
break;
}
case 'video':
{
if (gotVideo) {
continue;
}
gotVideo = true;
break;
}
default:
{
continue;
}
}
// Get codecs.
for (const rtp of m.rtp) {
const codec = {
kind: kind,
mimeType: `${kind}/${rtp.codec}`,
preferredPayloadType: rtp.payload,
clockRate: rtp.rate,
channels: rtp.encoding,
parameters: {},
rtcpFeedback: []
};
codecsMap.set(codec.preferredPayloadType, codec);
}
// Get codec parameters.
for (const fmtp of m.fmtp || []) {
const parameters = sdpTransform.parseParams(fmtp.config);
const codec = codecsMap.get(fmtp.payload);
if (!codec) {
continue;
}
// Specials case to convert parameter value to string.
if (parameters && parameters.hasOwnProperty('profile-level-id')) {
parameters['profile-level-id'] = String(parameters['profile-level-id']);
}
codec.parameters = parameters;
}
// Get RTCP feedback for each codec.
for (const fb of m.rtcpFb || []) {
const codec = codecsMap.get(fb.payload);
if (!codec) {
continue;
}
const feedback = {
type: fb.type,
parameter: fb.subtype
};
if (!feedback.parameter) {
delete feedback.parameter;
}
codec.rtcpFeedback.push(feedback);
}
// Get RTP header extensions.
for (const ext of m.ext || []) {
// Ignore encrypted extensions (not yet supported in mediasoup).
if (ext['encrypt-uri']) {
continue;
}
const headerExtension = {
kind: kind,
uri: ext.uri,
preferredId: ext.value
};
headerExtensions.push(headerExtension);
}
}
const rtpCapabilities = {
codecs: Array.from(codecsMap.values()),
headerExtensions: headerExtensions
};
return rtpCapabilities;
}
exports.extractRtpCapabilities = extractRtpCapabilities;
function extractDtlsParameters({ sdpObject }) {
const mediaObject = (sdpObject.media || [])
.find((m) => (m.iceUfrag && m.port !== 0));
if (!mediaObject) {
throw new Error('no active media section found');
}
const fingerprint = mediaObject.fingerprint || sdpObject.fingerprint;
let role;
switch (mediaObject.setup) {
case 'active':
role = 'client';
break;
case 'passive':
role = 'server';
break;
case 'actpass':
role = 'auto';
break;
}
const dtlsParameters = {
role,
fingerprints: [
{
algorithm: fingerprint.type,
value: fingerprint.hash
}
]
};
return dtlsParameters;
}
exports.extractDtlsParameters = extractDtlsParameters;
function getCname({ offerMediaObject }) {
const ssrcCnameLine = (offerMediaObject.ssrcs || [])
.find((line) => line.attribute === 'cname');
if (!ssrcCnameLine) {
return '';
}
return ssrcCnameLine.value;
}
exports.getCname = getCname;
/**
* Apply codec parameters in the given SDP m= section answer based on the
* given RTP parameters of an offer.
*/
function applyCodecParameters({ offerRtpParameters, answerMediaObject }) {
for (const codec of offerRtpParameters.codecs) {
const mimeType = codec.mimeType.toLowerCase();
// Avoid parsing codec parameters for unhandled codecs.
if (mimeType !== 'audio/opus') {
continue;
}
const rtp = (answerMediaObject.rtp || [])
.find((r) => r.payload === codec.payloadType);
if (!rtp) {
continue;
}
// Just in case.
answerMediaObject.fmtp = answerMediaObject.fmtp || [];
let fmtp = answerMediaObject.fmtp
.find((f) => f.payload === codec.payloadType);
if (!fmtp) {
fmtp = { payload: codec.payloadType, config: '' };
answerMediaObject.fmtp.push(fmtp);
}
const parameters = sdpTransform.parseParams(fmtp.config);
switch (mimeType) {
case 'audio/opus':
{
const spropStereo = codec.parameters['sprop-stereo'];
if (spropStereo !== undefined) {
parameters.stereo = spropStereo ? 1 : 0;
}
break;
}
}
// Write the codec fmtp.config back.
fmtp.config = '';
for (const key of Object.keys(parameters)) {
if (fmtp.config) {
fmtp.config += ';';
}
fmtp.config += `${key}=${parameters[key]}`;
}
}
}
exports.applyCodecParameters = applyCodecParameters;