[mirotalksfu] - update mediasoup

main
Miroslav Pejic 4 years ago
parent de339133ba
commit 67a8f715d9

@ -20,8 +20,8 @@
"cors": "2.8.5", "cors": "2.8.5",
"express": "4.17.2", "express": "4.17.2",
"httpolyglot": "0.1.2", "httpolyglot": "0.1.2",
"mediasoup": "3.9.4", "mediasoup": "3.9.5",
"mediasoup-client": "3.6.47", "mediasoup-client": "3.6.48",
"ngrok": "4.2.2", "ngrok": "4.2.2",
"socket.io": "4.4.1", "socket.io": "4.4.1",
"swagger-ui-express": "4.3.0", "swagger-ui-express": "4.3.0",

@ -2409,7 +2409,7 @@
/** /**
* Selects a color for a debug namespace * Selects a color for a debug namespace
* @param {String} namespace The namespace string for the for the debug instance to be colored * @param {String} namespace The namespace string for the debug instance to be colored
* @return {Number|String} An ANSI color code for the given namespace * @return {Number|String} An ANSI color code for the given namespace
* @api private * @api private
*/ */
@ -4254,6 +4254,15 @@
const Consumer_1 = require('./Consumer'); const Consumer_1 = require('./Consumer');
const DataProducer_1 = require('./DataProducer'); const DataProducer_1 = require('./DataProducer');
const DataConsumer_1 = require('./DataConsumer'); const DataConsumer_1 = require('./DataConsumer');
class ConsumerCreationTask {
constructor(consumerOptions) {
this.consumerOptions = consumerOptions;
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
}
const logger = new Logger_1.Logger('Transport'); const logger = new Logger_1.Logger('Transport');
class Transport extends EnhancedEventEmitter_1.EnhancedEventEmitter { class Transport extends EnhancedEventEmitter_1.EnhancedEventEmitter {
/** /**
@ -4297,6 +4306,10 @@
this._awaitQueue = new awaitqueue_1.AwaitQueue({ this._awaitQueue = new awaitqueue_1.AwaitQueue({
ClosedErrorClass: errors_1.InvalidStateError, ClosedErrorClass: errors_1.InvalidStateError,
}); });
// Consumer creation tasks awaiting to be processed.
this._pendingConsumerTasks = [];
// Consumer creation in progress flag.
this._consumerCreationInProgress = false;
// Observer instance. // Observer instance.
this._observer = new EnhancedEventEmitter_1.EnhancedEventEmitter(); this._observer = new EnhancedEventEmitter_1.EnhancedEventEmitter();
logger.debug('constructor() [id:%s, direction:%s]', id, direction); logger.debug('constructor() [id:%s, direction:%s]', id, direction);
@ -4573,49 +4586,23 @@
throw new TypeError('no "connect" listener set into this transport'); throw new TypeError('no "connect" listener set into this transport');
else if (appData && typeof appData !== 'object') else if (appData && typeof appData !== 'object')
throw new TypeError('if given, appData must be an object'); throw new TypeError('if given, appData must be an object');
// Enqueue command. // Ensure the device can consume it.
return this._awaitQueue.push(async () => { const canConsume = ortc.canReceive(rtpParameters, this._extendedRtpCapabilities);
// Ensure the device can consume it. if (!canConsume) throw new errors_1.UnsupportedError('cannot consume this Producer');
const canConsume = ortc.canReceive(rtpParameters, this._extendedRtpCapabilities); const consumerCreationTask = new ConsumerCreationTask({
if (!canConsume) throw new errors_1.UnsupportedError('cannot consume this Producer'); id,
const { localId, rtpReceiver, track } = await this._handler.receive({ producerId,
trackId: id, kind,
kind, rtpParameters,
rtpParameters, appData,
}); });
const consumer = new Consumer_1.Consumer({ // Store the Consumer creation task.
id, this._pendingConsumerTasks.push(consumerCreationTask);
localId, // There is no Consumer creation in progress, create it now.
producerId, if (this._consumerCreationInProgress === false) {
rtpReceiver, this._createPendingConsumers();
track, }
rtpParameters, return consumerCreationTask.promise;
appData,
});
this._consumers.set(consumer.id, consumer);
this._handleConsumer(consumer);
// If this is the first video Consumer and the Consumer for RTP probation
// has not yet been created, create it now.
if (!this._probatorConsumerCreated && kind === 'video') {
try {
const probatorRtpParameters = ortc.generateProbatorRtpParameters(
consumer.rtpParameters,
);
await this._handler.receive({
trackId: 'probator',
kind: 'video',
rtpParameters: probatorRtpParameters,
});
logger.debug('consume() | Consumer for RTP probation created');
this._probatorConsumerCreated = true;
} catch (error) {
logger.error('consume() | failed to create Consumer for RTP probation:%o', error);
}
}
// Emit observer event.
this._observer.safeEmit('newconsumer', consumer);
return consumer;
}, 'transport.consume()');
} }
/** /**
* Create a DataProducer * Create a DataProducer
@ -4716,6 +4703,95 @@
return dataConsumer; return dataConsumer;
}, 'transport.consumeData()'); }, 'transport.consumeData()');
} }
// This method is guaranteed to never throw.
async _createPendingConsumers() {
this._awaitQueue
.push(async () => {
this._consumerCreationInProgress = true;
const pendingConsumerTasks = [...this._pendingConsumerTasks];
// Clear pending Consumer tasks.
this._pendingConsumerTasks = [];
// Video Consumer in order to create the probator.
let videoConsumerForProbator = undefined;
// Fill options list.
const optionsList = [];
for (const task of pendingConsumerTasks) {
const { id, kind, rtpParameters } = task.consumerOptions;
optionsList.push({
trackId: id,
kind: kind,
rtpParameters,
});
}
try {
const results = await this._handler.receive(optionsList);
for (let idx = 0; idx < results.length; idx++) {
const task = pendingConsumerTasks[idx];
const result = results[idx];
const { id, producerId, kind, rtpParameters, appData } = task.consumerOptions;
const { localId, rtpReceiver, track } = result;
const consumer = new Consumer_1.Consumer({
id: id,
localId,
producerId: producerId,
rtpReceiver,
track,
rtpParameters,
appData,
});
this._consumers.set(consumer.id, consumer);
this._handleConsumer(consumer);
// If this is the first video Consumer and the Consumer for RTP probation
// has not yet been created, it's time to create it.
if (
!this._probatorConsumerCreated &&
!videoConsumerForProbator &&
kind === 'video'
) {
videoConsumerForProbator = consumer;
}
// Emit observer event.
this._observer.safeEmit('newconsumer', consumer);
task.resolve(consumer);
}
} catch (error) {
for (const task of pendingConsumerTasks) {
task.reject(error);
}
}
// If RTP probation must be handled, do it now.
if (videoConsumerForProbator) {
try {
const probatorRtpParameters = ortc.generateProbatorRtpParameters(
videoConsumerForProbator.rtpParameters,
);
await this._handler.receive([
{
trackId: 'probator',
kind: 'video',
rtpParameters: probatorRtpParameters,
},
]);
logger.debug('_createPendingConsumers() | Consumer for RTP probation created');
this._probatorConsumerCreated = true;
} catch (error) {
logger.error(
'_createPendingConsumers() | failed to create Consumer for RTP probation:%o',
error,
);
}
}
this._consumerCreationInProgress = false;
}, 'transport._createPendingConsumers()')
.then(() => {
// There are pending Consumer tasks, enqueue their creation.
if (this._pendingConsumerTasks.length > 0) {
this._createPendingConsumers();
}
})
// NOTE: We only get here when the await queue is closed.
.catch(() => {});
}
_handleHandler() { _handleHandler() {
const handler = this._handler; const handler = this._handler;
handler.on('@connect', ({ dtlsParameters }, callback, errback) => { handler.on('@connect', ({ dtlsParameters }, callback, errback) => {
@ -5262,32 +5338,39 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = trackId; for (const options of optionsList) {
const mid = kind; const { trackId, kind, rtpParameters } = options;
const streamId = rtpParameters.rtcp.cname; logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
this._remoteSdp.receive({ const mid = kind;
mid, const streamId = rtpParameters.rtcp.cname;
kind, this._remoteSdp.receive({
offerRtpParameters: rtpParameters, mid,
streamId, kind,
trackId, offerRtpParameters: rtpParameters,
}); streamId,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { kind, rtpParameters } = options;
// parameters in the offer. const mid = kind;
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -5298,12 +5381,19 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const stream = this._pc.getRemoteStreams().find((s) => s.id === streamId); for (const options of optionsList) {
const track = stream.getTrackById(localId); const { kind, trackId, rtpParameters } = options;
if (!track) throw new Error('remote track not found'); const mid = kind;
// Insert into the map. const localId = trackId;
this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters }); const streamId = rtpParameters.rtcp.cname;
return { localId, track }; const stream = this._pc.getRemoteStreams().find((s) => s.id === streamId);
const track = stream.getTrackById(localId);
if (!track) throw new Error('remote track not found');
// Insert into the map.
this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters });
results.push({ localId, track });
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -5829,31 +5919,41 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
optionsList,
) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = trackId; for (const options of optionsList) {
const mid = kind; const { trackId, kind, rtpParameters } = options;
this._remoteSdp.receive({ logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
mid, const mid = kind;
kind, this._remoteSdp.receive({
offerRtpParameters: rtpParameters, mid,
streamId: rtpParameters.rtcp.cname, kind,
trackId, offerRtpParameters: rtpParameters,
}); streamId: rtpParameters.rtcp.cname,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { kind, rtpParameters } = options;
// parameters in the offer. const mid = kind;
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -5864,15 +5964,21 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const rtpReceiver = this._pc.getReceivers().find((r) => r.track && r.track.id === localId); for (const options of optionsList) {
if (!rtpReceiver) throw new Error('new RTCRtpReceiver not'); const { kind, trackId, rtpParameters } = options;
// Insert into the map. const localId = trackId;
this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters, rtpReceiver }); const mid = kind;
return { const rtpReceiver = this._pc.getReceivers().find((r) => r.track && r.track.id === localId);
localId, if (!rtpReceiver) throw new Error('new RTCRtpReceiver not');
track: rtpReceiver.track, // Insert into the map.
rtpReceiver, this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters, rtpReceiver });
}; results.push({
localId,
track: rtpReceiver.track,
rtpReceiver,
});
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -6415,30 +6521,38 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = rtpParameters.mid || String(this._mapMidTransceiver.size); for (const options of optionsList) {
this._remoteSdp.receive({ const { trackId, kind, rtpParameters } = options;
mid: localId, logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
kind, const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
offerRtpParameters: rtpParameters, this._remoteSdp.receive({
streamId: rtpParameters.rtcp.cname, mid: localId,
trackId, kind,
}); offerRtpParameters: rtpParameters,
streamId: rtpParameters.rtcp.cname,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { rtpParameters } = options;
// parameters in the offer. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -6449,15 +6563,20 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId); for (const options of optionsList) {
if (!transceiver) throw new Error('new RTCRtpTransceiver not found'); const { rtpParameters } = options;
// Store in the map. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
this._mapMidTransceiver.set(localId, transceiver); const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId);
return { if (!transceiver) throw new Error('new RTCRtpTransceiver not found');
localId, // Store in the map.
track: transceiver.receiver.track, this._mapMidTransceiver.set(localId, transceiver);
rtpReceiver: transceiver.receiver, results.push({
}; localId,
track: transceiver.receiver.track,
rtpReceiver: transceiver.receiver,
});
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -6989,30 +7108,38 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = rtpParameters.mid || String(this._mapMidTransceiver.size); for (const options of optionsList) {
this._remoteSdp.receive({ const { trackId, kind, rtpParameters } = options;
mid: localId, logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
kind, const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
offerRtpParameters: rtpParameters, this._remoteSdp.receive({
streamId: rtpParameters.rtcp.cname, mid: localId,
trackId, kind,
}); offerRtpParameters: rtpParameters,
streamId: rtpParameters.rtcp.cname,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { rtpParameters } = options;
// parameters in the offer. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -7023,15 +7150,23 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId); for (const options of optionsList) {
if (!transceiver) throw new Error('new RTCRtpTransceiver not found'); const { rtpParameters } = options;
// Store in the map. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
this._mapMidTransceiver.set(localId, transceiver); const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId);
return { if (!transceiver) {
localId, throw new Error('new RTCRtpTransceiver not found');
track: transceiver.receiver.track, } else {
rtpReceiver: transceiver.receiver, // Store in the map.
}; this._mapMidTransceiver.set(localId, transceiver);
results.push({
localId,
track: transceiver.receiver.track,
rtpReceiver: transceiver.receiver,
});
}
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -7396,27 +7531,35 @@
) { ) {
throw new errors_1.UnsupportedError('not implemented'); throw new errors_1.UnsupportedError('not implemented');
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
for (const options of optionsList) {
const { trackId, kind } = options;
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
}
if (!this._transportReady) await this._setupTransport({ localDtlsRole: 'server' }); if (!this._transportReady) await this._setupTransport({ localDtlsRole: 'server' });
logger.debug('receive() | calling new RTCRtpReceiver()'); for (const options of optionsList) {
const rtpReceiver = new RTCRtpReceiver(this._dtlsTransport, kind); const { trackId, kind, rtpParameters } = options;
rtpReceiver.addEventListener('error', (event) => { logger.debug('receive() | calling new RTCRtpReceiver()');
logger.error('rtpReceiver "error" event [event:%o]', event); const rtpReceiver = new RTCRtpReceiver(this._dtlsTransport, kind);
}); rtpReceiver.addEventListener('error', (event) => {
// NOTE: Convert our standard RTCRtpParameters into those that Edge logger.error('rtpReceiver "error" event [event:%o]', event);
// expects. });
const edgeRtpParameters = edgeUtils.mangleRtpParameters(rtpParameters); // NOTE: Convert our standard RTCRtpParameters into those that Edge
logger.debug('receive() | calling rtpReceiver.receive() [params:%o]', edgeRtpParameters); // expects.
await rtpReceiver.receive(edgeRtpParameters); const edgeRtpParameters = edgeUtils.mangleRtpParameters(rtpParameters);
const localId = trackId; logger.debug('receive() | calling rtpReceiver.receive() [params:%o]', edgeRtpParameters);
// Store it. await rtpReceiver.receive(edgeRtpParameters);
this._rtpReceivers.set(localId, rtpReceiver); const localId = trackId;
return { // Store it.
localId, this._rtpReceivers.set(localId, rtpReceiver);
track: rtpReceiver.track, results.push({
rtpReceiver, localId,
}; track: rtpReceiver.track,
rtpReceiver,
});
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
logger.debug('stopReceiving() [localId:%s]', localId); logger.debug('stopReceiving() [localId:%s]', localId);
@ -8008,43 +8151,59 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
optionsList,
) {
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = rtpParameters.mid || String(this._mapMidTransceiver.size); for (const options of optionsList) {
this._remoteSdp.receive({ const { trackId, kind, rtpParameters } = options;
mid: localId, logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
kind, const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
offerRtpParameters: rtpParameters, this._remoteSdp.receive({
streamId: rtpParameters.rtcp.cname, mid: localId,
trackId, kind,
}); offerRtpParameters: rtpParameters,
streamId: rtpParameters.rtcp.cname,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { rtpParameters } = options;
// parameters in the offer. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; offerRtpParameters: rtpParameters,
answerMediaObject,
});
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
}
if (!this._transportReady) if (!this._transportReady)
await this._setupTransport({ localDtlsRole: 'client', localSdpObject }); await this._setupTransport({ localDtlsRole: 'client', localSdpObject });
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId); for (const options of optionsList) {
if (!transceiver) throw new Error('new RTCRtpTransceiver not found'); const { rtpParameters } = options;
// Store in the map. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
this._mapMidTransceiver.set(localId, transceiver); const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId);
return { if (!transceiver) throw new Error('new RTCRtpTransceiver not found');
localId, // Store in the map.
track: transceiver.receiver.track, this._mapMidTransceiver.set(localId, transceiver);
rtpReceiver: transceiver.receiver, results.push({
}; localId,
track: transceiver.receiver.track,
rtpReceiver: transceiver.receiver,
});
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -8581,40 +8740,47 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = trackId; for (const options of optionsList) {
const mid = kind; const { trackId, kind, rtpParameters } = options;
let streamId = rtpParameters.rtcp.cname; logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
// NOTE: In React-Native we cannot reuse the same remote MediaStream for new const mid = kind;
// remote tracks. This is because react-native-webrtc does not react on new let streamId = rtpParameters.rtcp.cname;
// tracks generated within already existing streams, so force the streamId // NOTE: In React-Native we cannot reuse the same remote MediaStream for new
// to be different. // remote tracks. This is because react-native-webrtc does not react on new
logger.debug( // tracks generated within already existing streams, so force the streamId
'receive() | forcing a random remote streamId to avoid well known bug in react-native-webrtc', // to be different.
); logger.debug(
streamId += `-hack-${utils.generateRandomNumber()}`; 'receive() | forcing a random remote streamId to avoid well known bug in react-native-webrtc',
this._remoteSdp.receive({ );
mid, streamId += `-hack-${utils.generateRandomNumber()}`;
kind, this._remoteSdp.receive({
offerRtpParameters: rtpParameters, mid,
streamId, kind,
trackId, offerRtpParameters: rtpParameters,
}); streamId,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { kind, rtpParameters } = options;
// parameters in the offer. const mid = kind;
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -8625,12 +8791,19 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const stream = this._pc.getRemoteStreams().find((s) => s.id === streamId); for (const options of optionsList) {
const track = stream.getTrackById(localId); const { kind, trackId, rtpParameters } = options;
if (!track) throw new Error('remote track not found'); const localId = trackId;
// Insert into the map. const mid = kind;
this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters }); const streamId = rtpParameters.rtcp.cname;
return { localId, track }; const stream = this._pc.getRemoteStreams().find((s) => s.id === streamId);
const track = stream.getTrackById(localId);
if (!track) throw new Error('remote track not found');
// Insert into the map.
this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters });
results.push({ localId, track });
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -9152,31 +9325,38 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = trackId; for (const options of optionsList) {
const mid = kind; const { trackId, kind, rtpParameters } = options;
this._remoteSdp.receive({ logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
mid, const mid = kind;
kind, this._remoteSdp.receive({
offerRtpParameters: rtpParameters, mid,
streamId: rtpParameters.rtcp.cname, kind,
trackId, offerRtpParameters: rtpParameters,
}); streamId: rtpParameters.rtcp.cname,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { kind, rtpParameters } = options;
// parameters in the offer. const mid = kind;
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === mid);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -9187,15 +9367,21 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const rtpReceiver = this._pc.getReceivers().find((r) => r.track && r.track.id === localId); for (const options of optionsList) {
if (!rtpReceiver) throw new Error('new RTCRtpReceiver not'); const { kind, trackId, rtpParameters } = options;
// Insert into the map. const mid = kind;
this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters, rtpReceiver }); const localId = trackId;
return { const rtpReceiver = this._pc.getReceivers().find((r) => r.track && r.track.id === localId);
localId, if (!rtpReceiver) throw new Error('new RTCRtpReceiver not');
track: rtpReceiver.track, // Insert into the map.
rtpReceiver, this._mapRecvLocalIdInfo.set(localId, { mid, rtpParameters, rtpReceiver });
}; results.push({
localId,
track: rtpReceiver.track,
rtpReceiver,
});
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -9697,30 +9883,38 @@
}; };
return { dataChannel, sctpStreamParameters }; return { dataChannel, sctpStreamParameters };
} }
async receive({ trackId, kind, rtpParameters }) { async receive(optionsList) {
var _a; var _a;
this._assertRecvDirection(); this._assertRecvDirection();
logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind); const results = [];
const localId = rtpParameters.mid || String(this._mapMidTransceiver.size); for (const options of optionsList) {
this._remoteSdp.receive({ const { trackId, kind, rtpParameters } = options;
mid: localId, logger.debug('receive() [trackId:%s, kind:%s]', trackId, kind);
kind, const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
offerRtpParameters: rtpParameters, this._remoteSdp.receive({
streamId: rtpParameters.rtcp.cname, mid: localId,
trackId, kind,
}); offerRtpParameters: rtpParameters,
streamId: rtpParameters.rtcp.cname,
trackId,
});
}
const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() }; const offer = { type: 'offer', sdp: this._remoteSdp.getSdp() };
logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer); logger.debug('receive() | calling pc.setRemoteDescription() [offer:%o]', offer);
await this._pc.setRemoteDescription(offer); await this._pc.setRemoteDescription(offer);
let answer = await this._pc.createAnswer(); let answer = await this._pc.createAnswer();
const localSdpObject = sdpTransform.parse(answer.sdp); const localSdpObject = sdpTransform.parse(answer.sdp);
const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId); for (const options of optionsList) {
// May need to modify codec parameters in the answer based on codec const { rtpParameters } = options;
// parameters in the offer. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
sdpCommonUtils.applyCodecParameters({ const answerMediaObject = localSdpObject.media.find((m) => String(m.mid) === localId);
offerRtpParameters: rtpParameters, // May need to modify codec parameters in the answer based on codec
answerMediaObject, // parameters in the offer.
}); sdpCommonUtils.applyCodecParameters({
offerRtpParameters: rtpParameters,
answerMediaObject,
});
}
answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) }; answer = { type: 'answer', sdp: sdpTransform.write(localSdpObject) };
if (!this._transportReady) { if (!this._transportReady) {
await this._setupTransport({ await this._setupTransport({
@ -9731,15 +9925,20 @@
} }
logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer); logger.debug('receive() | calling pc.setLocalDescription() [answer:%o]', answer);
await this._pc.setLocalDescription(answer); await this._pc.setLocalDescription(answer);
const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId); for (const options of optionsList) {
if (!transceiver) throw new Error('new RTCRtpTransceiver not found'); const { rtpParameters } = options;
// Store in the map. const localId = rtpParameters.mid || String(this._mapMidTransceiver.size);
this._mapMidTransceiver.set(localId, transceiver); const transceiver = this._pc.getTransceivers().find((t) => t.mid === localId);
return { if (!transceiver) throw new Error('new RTCRtpTransceiver not found');
localId, // Store in the map.
track: transceiver.receiver.track, this._mapMidTransceiver.set(localId, transceiver);
rtpReceiver: transceiver.receiver, results.push({
}; localId,
track: transceiver.receiver.track,
rtpReceiver: transceiver.receiver,
});
}
return results;
} }
async stopReceiving(localId) { async stopReceiving(localId) {
this._assertRecvDirection(); this._assertRecvDirection();
@ -11342,7 +11541,7 @@
/** /**
* Expose mediasoup-client version. * Expose mediasoup-client version.
*/ */
exports.version = '3.6.47'; exports.version = '3.6.48';
/** /**
* Expose parseScalabilityMode() function. * Expose parseScalabilityMode() function.
*/ */
@ -12108,7 +12307,6 @@
// Per codec special checks. // Per codec special checks.
switch (aMimeType) { switch (aMimeType) {
case 'video/h264': { case 'video/h264': {
// If strict matching check profile-level-id.
if (strict) { if (strict) {
const aPacketizationMode = aCodec.parameters['packetization-mode'] || 0; const aPacketizationMode = aCodec.parameters['packetization-mode'] || 0;
const bPacketizationMode = bCodec.parameters['packetization-mode'] || 0; const bPacketizationMode = bCodec.parameters['packetization-mode'] || 0;
@ -12136,7 +12334,6 @@
break; break;
} }
case 'video/vp9': { case 'video/vp9': {
// If strict matching check profile-id.
if (strict) { if (strict) {
const aProfileId = aCodec.parameters['profile-id'] || 0; const aProfileId = aCodec.parameters['profile-id'] || 0;
const bProfileId = bCodec.parameters['profile-id'] || 0; const bProfileId = bCodec.parameters['profile-id'] || 0;

Loading…
Cancel
Save