mediasoup
Version:
Cutting Edge WebRTC Video Conferencing
235 lines (234 loc) • 8.52 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataProducerImpl = void 0;
exports.dataProducerTypeToFbs = dataProducerTypeToFbs;
exports.parseDataProducerDumpResponse = parseDataProducerDumpResponse;
const Logger_1 = require("./Logger");
const enhancedEvents_1 = require("./enhancedEvents");
const sctpParametersFbsUtils_1 = require("./sctpParametersFbsUtils");
const FbsTransport = require("./fbs/transport");
const FbsNotification = require("./fbs/notification");
const FbsRequest = require("./fbs/request");
const FbsDataProducer = require("./fbs/data-producer");
const logger = new Logger_1.Logger('DataProducer');
class DataProducerImpl extends enhancedEvents_1.EnhancedEventEmitter {
// Internal data.
#internal;
// DataProducer data.
#data;
// Channel instance.
#channel;
// Closed flag.
#closed = false;
// Paused flag.
#paused = false;
// Custom app data.
#appData;
// Observer instance.
#observer = new enhancedEvents_1.EnhancedEventEmitter();
constructor({ internal, data, channel, paused, appData, }) {
super();
logger.debug('constructor()');
this.#internal = internal;
this.#data = data;
this.#channel = channel;
this.#paused = paused;
this.#appData = appData ?? {};
this.handleWorkerNotifications();
this.handleListenerError();
}
get id() {
return this.#internal.dataProducerId;
}
get closed() {
return this.#closed;
}
get type() {
return this.#data.type;
}
get sctpStreamParameters() {
return this.#data.sctpStreamParameters;
}
get label() {
return this.#data.label;
}
get protocol() {
return this.#data.protocol;
}
get paused() {
return this.#paused;
}
get appData() {
return this.#appData;
}
set appData(appData) {
this.#appData = appData;
}
get observer() {
return this.#observer;
}
close() {
if (this.#closed) {
return;
}
logger.debug('close()');
this.#closed = true;
// Remove notification subscriptions.
this.#channel.removeAllListeners(this.#internal.dataProducerId);
/* Build Request. */
const requestOffset = new FbsTransport.CloseDataProducerRequestT(this.#internal.dataProducerId).pack(this.#channel.bufferBuilder);
this.#channel
.request(FbsRequest.Method.TRANSPORT_CLOSE_DATAPRODUCER, FbsRequest.Body.Transport_CloseDataProducerRequest, requestOffset, this.#internal.transportId)
.catch(() => { });
this.emit('@close');
// Emit observer event.
this.#observer.safeEmit('close');
}
transportClosed() {
if (this.#closed) {
return;
}
logger.debug('transportClosed()');
this.#closed = true;
// Remove notification subscriptions.
this.#channel.removeAllListeners(this.#internal.dataProducerId);
this.safeEmit('transportclose');
// Emit observer event.
this.#observer.safeEmit('close');
}
async dump() {
logger.debug('dump()');
const response = await this.#channel.request(FbsRequest.Method.DATAPRODUCER_DUMP, undefined, undefined, this.#internal.dataProducerId);
/* Decode Response. */
const produceResponse = new FbsDataProducer.DumpResponse();
response.body(produceResponse);
return parseDataProducerDumpResponse(produceResponse);
}
async getStats() {
logger.debug('getStats()');
const response = await this.#channel.request(FbsRequest.Method.DATAPRODUCER_GET_STATS, undefined, undefined, this.#internal.dataProducerId);
/* Decode Response. */
const data = new FbsDataProducer.GetStatsResponse();
response.body(data);
return [parseDataProducerStats(data)];
}
async pause() {
logger.debug('pause()');
await this.#channel.request(FbsRequest.Method.DATAPRODUCER_PAUSE, undefined, undefined, this.#internal.dataProducerId);
const wasPaused = this.#paused;
this.#paused = true;
// Emit observer event.
if (!wasPaused) {
this.#observer.safeEmit('pause');
}
}
async resume() {
logger.debug('resume()');
await this.#channel.request(FbsRequest.Method.DATAPRODUCER_RESUME, undefined, undefined, this.#internal.dataProducerId);
const wasPaused = this.#paused;
this.#paused = false;
// Emit observer event.
if (wasPaused) {
this.#observer.safeEmit('resume');
}
}
send(message, ppid, subchannels, requiredSubchannel) {
if (typeof message !== 'string' && !Buffer.isBuffer(message)) {
throw new TypeError('message must be a string or a Buffer');
}
/*
* +-------------------------------+----------+
* | Value | SCTP |
* | | PPID |
* +-------------------------------+----------+
* | WebRTC String | 51 |
* | WebRTC Binary Partial | 52 |
* | (Deprecated) | |
* | WebRTC Binary | 53 |
* | WebRTC String Partial | 54 |
* | (Deprecated) | |
* | WebRTC String Empty | 56 |
* | WebRTC Binary Empty | 57 |
* +-------------------------------+----------+
*/
if (typeof ppid !== 'number') {
ppid =
typeof message === 'string'
? message.length > 0
? 51
: 56
: message.length > 0
? 53
: 57;
}
// Ensure we honor PPIDs.
if (ppid === 56) {
message = ' ';
}
else if (ppid === 57) {
message = Buffer.alloc(1);
}
const builder = this.#channel.bufferBuilder;
const subchannelsOffset = FbsDataProducer.SendNotification.createSubchannelsVector(builder, subchannels ?? []);
if (typeof message === 'string') {
message = Buffer.from(message);
}
const dataOffset = FbsDataProducer.SendNotification.createDataVector(builder, message);
const notificationOffset = FbsDataProducer.SendNotification.createSendNotification(builder, ppid, dataOffset, subchannelsOffset, requiredSubchannel ?? null);
this.#channel.notify(FbsNotification.Event.DATAPRODUCER_SEND, FbsNotification.Body.DataProducer_SendNotification, notificationOffset, this.#internal.dataProducerId);
}
handleWorkerNotifications() {
// No need to subscribe to any event.
}
handleListenerError() {
this.on('listenererror', (eventName, error) => {
logger.error(`event listener threw an error [eventName:${eventName}]:`, error);
});
}
}
exports.DataProducerImpl = DataProducerImpl;
function dataProducerTypeToFbs(type) {
switch (type) {
case 'sctp': {
return FbsDataProducer.Type.SCTP;
}
case 'direct': {
return FbsDataProducer.Type.DIRECT;
}
default: {
throw new TypeError('invalid DataConsumerType: ${type}');
}
}
}
function dataProducerTypeFromFbs(type) {
switch (type) {
case FbsDataProducer.Type.SCTP: {
return 'sctp';
}
case FbsDataProducer.Type.DIRECT: {
return 'direct';
}
}
}
function parseDataProducerDumpResponse(data) {
return {
id: data.id(),
type: dataProducerTypeFromFbs(data.type()),
sctpStreamParameters: data.sctpStreamParameters() !== null
? (0, sctpParametersFbsUtils_1.parseSctpStreamParameters)(data.sctpStreamParameters())
: undefined,
label: data.label(),
protocol: data.protocol(),
paused: data.paused(),
};
}
function parseDataProducerStats(binary) {
return {
type: 'data-producer',
timestamp: Number(binary.timestamp()),
label: binary.label(),
protocol: binary.protocol(),
messagesReceived: Number(binary.messagesReceived()),
bytesReceived: Number(binary.bytesReceived()),
};
}