msc-node
Version:
mediasoup client side Node.js library
298 lines (297 loc) • 12.2 kB
JavaScript
"use strict";
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;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FakeHandler = void 0;
const EnhancedEventEmitter_1 = require("../EnhancedEventEmitter");
const Logger_1 = require("../Logger");
const fake_mediastreamtrack_1 = require("fake-mediastreamtrack");
const utils = __importStar(require("../utils"));
const ortc = __importStar(require("../ortc"));
const HandlerInterface_1 = require("./HandlerInterface");
const logger = new Logger_1.Logger('FakeHandler');
class FakeDataChannel extends EnhancedEventEmitter_1.EnhancedEventEmitter {
constructor({ id, ordered, maxPacketLifeTime, maxRetransmits, priority, label, protocol }) {
super();
this.id = id;
this.ordered = ordered;
this.maxPacketLifeTime = maxPacketLifeTime;
this.maxRetransmits = maxRetransmits;
this.priority = priority;
this.label = label;
this.protocol = protocol;
}
close() {
this.safeEmit('close');
}
send(data) {
this.safeEmit('message', data);
}
addEventListener(event, fn) {
this.on(event, fn);
}
}
class FakeHandler extends HandlerInterface_1.HandlerInterface {
/**
* Creates a factory function.
*/
static createFactory(fakeParameters) {
return () => new FakeHandler(fakeParameters);
}
constructor(fakeParameters) {
super();
// Local RTCP CNAME.
this._cname = `CNAME-${utils.generateRandomNumber()}`;
// Got transport local and remote parameters.
this._transportReady = false;
// Next localId.
this._nextLocalId = 1;
// Sending and receiving tracks indexed by localId.
this._tracks = new Map();
// DataChannel id value counter. It must be incremented for each new DataChannel.
this._nextSctpStreamId = 0;
this.fakeParameters = fakeParameters;
}
get name() {
return 'FakeHandler';
}
close() {
logger.debug('close()');
}
// NOTE: Custom method for simulation purposes.
setConnectionState(connectionState) {
this.emit('@connectionstatechange', connectionState);
}
getNativeRtpCapabilities() {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('getNativeRtpCapabilities()');
return this.fakeParameters.generateNativeRtpCapabilities();
});
}
getNativeSctpCapabilities() {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('getNativeSctpCapabilities()');
return this.fakeParameters.generateNativeSctpCapabilities();
});
}
run({
/* eslint-disable @typescript-eslint/no-unused-vars */
direction, iceParameters, iceCandidates, dtlsParameters, sctpParameters, iceServers, iceTransportPolicy, proprietaryConstraints, extendedRtpCapabilities
/* eslint-enable @typescript-eslint/no-unused-vars */
}) {
logger.debug('run()');
// Generic sending RTP parameters for audio and video.
// @type {Object}
this._rtpParametersByKind =
{
audio: ortc.getSendingRtpParameters('audio', extendedRtpCapabilities),
video: ortc.getSendingRtpParameters('video', extendedRtpCapabilities)
};
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
updateIceServers(iceServers) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('updateIceServers()');
return;
});
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
restartIce(iceParameters) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('restartIce()');
return;
});
}
getTransportStats() {
return __awaiter(this, void 0, void 0, function* () {
return new Map(); // NOTE: Whatever.
});
}
send(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
{ track, encodings, codecOptions, codec }) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('send() [kind:%s, track.id:%s]', track.kind, track.id);
if (!this._transportReady) {
yield this._setupTransport({ localDtlsRole: 'server' });
}
const rtpParameters = utils.clone(this._rtpParametersByKind[track.kind], {});
const useRtx = rtpParameters.codecs
.some((_codec) => /.+\/rtx$/i.test(_codec.mimeType));
rtpParameters.mid = `mid-${utils.generateRandomNumber()}`;
if (!encodings) {
encodings = [{}];
}
for (const encoding of encodings) {
encoding.ssrc = utils.generateRandomNumber();
if (useRtx) {
encoding.rtx = { ssrc: utils.generateRandomNumber() };
}
}
rtpParameters.encodings = encodings;
// Fill RTCRtpParameters.rtcp.
rtpParameters.rtcp =
{
cname: this._cname,
reducedSize: true,
mux: true
};
const localId = this._nextLocalId++;
this._tracks.set(localId, track);
return { localId: String(localId), rtpParameters };
});
}
stopSending(localId) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('stopSending() [localId:%s]', localId);
if (!this._tracks.has(Number(localId))) {
throw new Error('local track not found');
}
this._tracks.delete(Number(localId));
});
}
replaceTrack(localId, track) {
return __awaiter(this, void 0, void 0, function* () {
if (track) {
logger.debug('replaceTrack() [localId:%s, track.id:%s]', localId, track.id);
}
else {
logger.debug('replaceTrack() [localId:%s, no track]', localId);
}
this._tracks.delete(Number(localId));
this._tracks.set(Number(localId), track);
});
}
setMaxSpatialLayer(localId, spatialLayer) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('setMaxSpatialLayer() [localId:%s, spatialLayer:%s]', localId, spatialLayer);
});
}
setRtpEncodingParameters(localId, params) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('setRtpEncodingParameters() [localId:%s, params:%o]', localId, params);
});
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getSenderStats(localId) {
return __awaiter(this, void 0, void 0, function* () {
return new Map(); // NOTE: Whatever.
});
}
sendDataChannel({ ordered, maxPacketLifeTime, maxRetransmits, label, protocol, priority }) {
return __awaiter(this, void 0, void 0, function* () {
if (!this._transportReady) {
yield this._setupTransport({ localDtlsRole: 'server' });
}
logger.debug('sendDataChannel()');
const dataChannel = new FakeDataChannel({
id: this._nextSctpStreamId++,
ordered,
maxPacketLifeTime,
maxRetransmits,
priority,
label,
protocol
});
const sctpStreamParameters = {
streamId: this._nextSctpStreamId,
ordered: ordered,
maxPacketLifeTime: maxPacketLifeTime,
maxRetransmits: maxRetransmits
};
// @ts-ignore.
return { dataChannel, sctpStreamParameters };
});
}
receive(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
{ trackId, kind, rtpParameters }) {
return __awaiter(this, void 0, void 0, function* () {
if (!this._transportReady) {
yield this._setupTransport({ localDtlsRole: 'client' });
}
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
const localId = this._nextLocalId++;
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind });
this._tracks.set(localId, track);
return { localId: String(localId), track };
});
}
stopReceiving(localId) {
return __awaiter(this, void 0, void 0, function* () {
logger.debug('stopReceiving() [localId:%s]', localId);
this._tracks.delete(Number(localId));
});
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getReceiverStats(localId) {
return __awaiter(this, void 0, void 0, function* () {
return new Map(); //
});
}
receiveDataChannel({ sctpStreamParameters, label, protocol }) {
return __awaiter(this, void 0, void 0, function* () {
if (!this._transportReady) {
yield this._setupTransport({ localDtlsRole: 'client' });
}
logger.debug('receiveDataChannel()');
const dataChannel = new FakeDataChannel({
id: sctpStreamParameters.streamId,
ordered: sctpStreamParameters.ordered,
maxPacketLifeTime: sctpStreamParameters.maxPacketLifeTime,
maxRetransmits: sctpStreamParameters.maxRetransmits,
label,
protocol
});
// @ts-ignore.
return { dataChannel };
});
}
_setupTransport({ localDtlsRole,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
localSdpObject }) {
return __awaiter(this, void 0, void 0, function* () {
const dtlsParameters = utils.clone(this.fakeParameters.generateLocalDtlsParameters(), {});
// Set our DTLS role.
if (localDtlsRole) {
dtlsParameters.role = localDtlsRole;
}
// Assume we are connecting now.
this.emit('@connectionstatechange', 'connecting');
// Need to tell the remote transport about our parameters.
yield new Promise((resolve, reject) => (this.emit('@connect', { dtlsParameters }, resolve, reject)));
this._transportReady = true;
});
}
}
exports.FakeHandler = FakeHandler;