mediasoup
Version:
Cutting Edge WebRTC Video Conferencing
296 lines (295 loc) • 10.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PipeTransport = void 0;
exports.parsePipeTransportDumpResponse = parsePipeTransportDumpResponse;
const Logger_1 = require("./Logger");
const enhancedEvents_1 = require("./enhancedEvents");
const ortc = require("./ortc");
const Transport_1 = require("./Transport");
const Consumer_1 = require("./Consumer");
const RtpParameters_1 = require("./RtpParameters");
const SrtpParameters_1 = require("./SrtpParameters");
const utils_1 = require("./utils");
const media_kind_1 = require("./fbs/rtp-parameters/media-kind");
const FbsRtpParameters = require("./fbs/rtp-parameters");
const notification_1 = require("./fbs/notification");
const FbsRequest = require("./fbs/request");
const FbsTransport = require("./fbs/transport");
const FbsPipeTransport = require("./fbs/pipe-transport");
const logger = new Logger_1.Logger('PipeTransport');
class PipeTransport extends Transport_1.Transport {
// PipeTransport data.
#data;
/**
* @private
*/
constructor(options) {
const observer = new enhancedEvents_1.EnhancedEventEmitter();
super(options, observer);
logger.debug('constructor()');
const { data } = options;
this.#data = {
tuple: data.tuple,
sctpParameters: data.sctpParameters,
sctpState: data.sctpState,
rtx: data.rtx,
srtpParameters: data.srtpParameters,
};
this.handleWorkerNotifications();
}
/**
* Observer.
*
* @override
*/
get observer() {
return super.observer;
}
/**
* Transport tuple.
*/
get tuple() {
return this.#data.tuple;
}
/**
* SCTP parameters.
*/
get sctpParameters() {
return this.#data.sctpParameters;
}
/**
* SCTP state.
*/
get sctpState() {
return this.#data.sctpState;
}
/**
* SRTP parameters.
*/
get srtpParameters() {
return this.#data.srtpParameters;
}
/**
* Close the PipeTransport.
*
* @override
*/
close() {
if (this.closed) {
return;
}
if (this.#data.sctpState) {
this.#data.sctpState = 'closed';
}
super.close();
}
/**
* Router was closed.
*
* @private
* @override
*/
routerClosed() {
if (this.closed) {
return;
}
if (this.#data.sctpState) {
this.#data.sctpState = 'closed';
}
super.routerClosed();
}
/**
* Get PipeTransport stats.
*
* @override
*/
async getStats() {
logger.debug('getStats()');
const response = await this.channel.request(FbsRequest.Method.TRANSPORT_GET_STATS, undefined, undefined, this.internal.transportId);
/* Decode Response. */
const data = new FbsPipeTransport.GetStatsResponse();
response.body(data);
return [parseGetStatsResponse(data)];
}
/**
* Provide the PipeTransport remote parameters.
*
* @override
*/
async connect({ ip, port, srtpParameters, }) {
logger.debug('connect()');
const requestOffset = createConnectRequest({
builder: this.channel.bufferBuilder,
ip,
port,
srtpParameters,
});
// Wait for response.
const response = await this.channel.request(FbsRequest.Method.PIPETRANSPORT_CONNECT, FbsRequest.Body.PipeTransport_ConnectRequest, requestOffset, this.internal.transportId);
/* Decode Response. */
const data = new FbsPipeTransport.ConnectResponse();
response.body(data);
// Update data.
if (data.tuple()) {
this.#data.tuple = (0, Transport_1.parseTuple)(data.tuple());
}
}
/**
* Create a pipe Consumer.
*
* @override
*/
async consume({ producerId, appData, }) {
logger.debug('consume()');
if (!producerId || typeof producerId !== 'string') {
throw new TypeError('missing producerId');
}
else if (appData && typeof appData !== 'object') {
throw new TypeError('if given, appData must be an object');
}
const producer = this.getProducerById(producerId);
if (!producer) {
throw Error(`Producer with id "${producerId}" not found`);
}
// This may throw.
const rtpParameters = ortc.getPipeConsumerRtpParameters({
consumableRtpParameters: producer.consumableRtpParameters,
enableRtx: this.#data.rtx,
});
const consumerId = (0, utils_1.generateUUIDv4)();
const consumeRequestOffset = createConsumeRequest({
builder: this.channel.bufferBuilder,
consumerId,
producer,
rtpParameters,
});
const response = await this.channel.request(FbsRequest.Method.TRANSPORT_CONSUME, FbsRequest.Body.Transport_ConsumeRequest, consumeRequestOffset, this.internal.transportId);
/* Decode Response. */
const consumeResponse = new FbsTransport.ConsumeResponse();
response.body(consumeResponse);
const status = consumeResponse.unpack();
const data = {
producerId,
kind: producer.kind,
rtpParameters,
type: 'pipe',
};
const consumer = new Consumer_1.Consumer({
internal: {
...this.internal,
consumerId,
},
data,
channel: this.channel,
appData,
paused: status.paused,
producerPaused: status.producerPaused,
});
this.consumers.set(consumer.id, consumer);
consumer.on('@close', () => this.consumers.delete(consumer.id));
consumer.on('@producerclose', () => this.consumers.delete(consumer.id));
// Emit observer event.
this.observer.safeEmit('newconsumer', consumer);
return consumer;
}
handleWorkerNotifications() {
this.channel.on(this.internal.transportId, (event, data) => {
switch (event) {
case notification_1.Event.TRANSPORT_SCTP_STATE_CHANGE: {
const notification = new FbsTransport.SctpStateChangeNotification();
data.body(notification);
const sctpState = (0, Transport_1.parseSctpState)(notification.sctpState());
this.#data.sctpState = sctpState;
this.safeEmit('sctpstatechange', sctpState);
// Emit observer event.
this.observer.safeEmit('sctpstatechange', sctpState);
break;
}
case notification_1.Event.TRANSPORT_TRACE: {
const notification = new FbsTransport.TraceNotification();
data.body(notification);
const trace = (0, Transport_1.parseTransportTraceEventData)(notification);
this.safeEmit('trace', trace);
// Emit observer event.
this.observer.safeEmit('trace', trace);
break;
}
default: {
logger.error('ignoring unknown event "%s"', event);
}
}
});
}
}
exports.PipeTransport = PipeTransport;
/*
* flatbuffers helpers.
*/
function parsePipeTransportDumpResponse(binary) {
// Retrieve BaseTransportDump.
const baseTransportDump = (0, Transport_1.parseBaseTransportDump)(binary.base());
// Retrieve RTP Tuple.
const tuple = (0, Transport_1.parseTuple)(binary.tuple());
// Retrieve SRTP Parameters.
let srtpParameters;
if (binary.srtpParameters()) {
srtpParameters = (0, SrtpParameters_1.parseSrtpParameters)(binary.srtpParameters());
}
return {
...baseTransportDump,
tuple: tuple,
rtx: binary.rtx(),
srtpParameters: srtpParameters,
};
}
function parseGetStatsResponse(binary) {
const base = (0, Transport_1.parseBaseTransportStats)(binary.base());
return {
...base,
type: 'pipe-transport',
tuple: (0, Transport_1.parseTuple)(binary.tuple()),
};
}
function createConsumeRequest({ builder, consumerId, producer, rtpParameters, }) {
// Build the request.
const producerIdOffset = builder.createString(producer.id);
const consumerIdOffset = builder.createString(consumerId);
const rtpParametersOffset = (0, RtpParameters_1.serializeRtpParameters)(builder, rtpParameters);
let consumableRtpEncodingsOffset;
if (producer.consumableRtpParameters.encodings) {
consumableRtpEncodingsOffset = (0, RtpParameters_1.serializeRtpEncodingParameters)(builder, producer.consumableRtpParameters.encodings);
}
const ConsumeRequest = FbsTransport.ConsumeRequest;
// Create Consume Request.
ConsumeRequest.startConsumeRequest(builder);
ConsumeRequest.addConsumerId(builder, consumerIdOffset);
ConsumeRequest.addProducerId(builder, producerIdOffset);
ConsumeRequest.addKind(builder, producer.kind === 'audio' ? media_kind_1.MediaKind.AUDIO : media_kind_1.MediaKind.VIDEO);
ConsumeRequest.addRtpParameters(builder, rtpParametersOffset);
ConsumeRequest.addType(builder, FbsRtpParameters.Type.PIPE);
if (consumableRtpEncodingsOffset) {
ConsumeRequest.addConsumableRtpEncodings(builder, consumableRtpEncodingsOffset);
}
return ConsumeRequest.endConsumeRequest(builder);
}
function createConnectRequest({ builder, ip, port, srtpParameters, }) {
let ipOffset = 0;
let srtpParametersOffset = 0;
if (ip) {
ipOffset = builder.createString(ip);
}
// Serialize SrtpParameters.
if (srtpParameters) {
srtpParametersOffset = (0, SrtpParameters_1.serializeSrtpParameters)(builder, srtpParameters);
}
// Create PlainTransportConnectData.
FbsPipeTransport.ConnectRequest.startConnectRequest(builder);
FbsPipeTransport.ConnectRequest.addIp(builder, ipOffset);
if (typeof port === 'number') {
FbsPipeTransport.ConnectRequest.addPort(builder, port);
}
if (srtpParameters) {
FbsPipeTransport.ConnectRequest.addSrtpParameters(builder, srtpParametersOffset);
}
return FbsPipeTransport.ConnectRequest.endConnectRequest(builder);
}