UNPKG

mediasoup

Version:

Cutting Edge WebRTC Video Conferencing

235 lines (234 loc) 8.52 kB
"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()), }; }