From 9a9409dda7fd6807d2dd7969a786e6d1dca81073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Thu, 2 May 2024 15:30:58 +0200 Subject: [PATCH 01/80] WIP: Node WorkerChannel native addon Substitute spawning a process with mediasoup for running mediasoup in a thread created by this addon. The communication is now done via message passing rather than using unixsocket, avoiding the kernel networking stack for each and every message passed from Node to C++ and viceversa. Performance gains are enhanced by approximately 8 times. Tested by sending a request from Node to C++ and waiting for the response N times in a loop. --- .gitignore | 6 + node/src/Channel.ts | 70 ++----- node/src/Worker.ts | 179 +++-------------- node/src/test/test-ActiveSpeakerObserver.ts | 4 - node/src/test/test-AudioLevelObserver.ts | 4 - node/src/test/test-Consumer.ts | 4 - node/src/test/test-DataConsumer.ts | 4 - node/src/test/test-DataProducer.ts | 4 - node/src/test/test-DirectTransport.ts | 4 - node/src/test/test-PipeTransport.ts | 8 - node/src/test/test-PlainTransport.ts | 4 - node/src/test/test-Producer.ts | 4 - node/src/test/test-Router.ts | 4 - node/src/test/test-WebRtcServer.ts | 4 - node/src/test/test-WebRtcTransport.ts | 4 - node/src/test/test-Worker.ts | 58 +----- node/src/test/test-multiopus.ts | 4 - node/src/test/test-node-sctp.ts | 4 - node/workerChannel/binding.gyp | 50 +++++ node/workerChannel/index.ts | 34 ++++ node/workerChannel/package-lock.json | 53 +++++ node/workerChannel/package.json | 20 ++ node/workerChannel/src/binding.cpp | 13 ++ node/workerChannel/src/workerChannel.cpp | 190 ++++++++++++++++++ node/workerChannel/src/workerChannel.hpp | 34 ++++ node/workerChannel/test.ts | 17 ++ node/workerChannel/tsconfig.json | 20 ++ npm-scripts.mjs | 21 ++ package-lock.json | 66 +++++- package.json | 4 +- worker/scripts/clang-format.mjs | 2 + .../src/RTC/RtpDictionaries/RtcpFeedback.cpp | 2 +- 32 files changed, 569 insertions(+), 330 deletions(-) create mode 100644 node/workerChannel/binding.gyp create mode 100644 node/workerChannel/index.ts create mode 100644 node/workerChannel/package-lock.json create mode 100644 node/workerChannel/package.json create mode 100644 node/workerChannel/src/binding.cpp create mode 100644 node/workerChannel/src/workerChannel.cpp create mode 100644 node/workerChannel/src/workerChannel.hpp create mode 100644 node/workerChannel/test.ts create mode 100644 node/workerChannel/tsconfig.json diff --git a/.gitignore b/.gitignore index e2f65fca29..22fabe4c16 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,12 @@ # flatc generated files. /node/src/fbs +## Node WorkerChannel addon. +/node/workerChannel/node_modules +/node/workerChannel/build +/node/workerChannel/lib +/node/workerChannel/.cache + ## Rust. /rust/examples-frontend/*/node_modules /rust/examples-frontend/*/package-lock.json diff --git a/node/src/Channel.ts b/node/src/Channel.ts index a2fa6b3a6c..b36eaf01c6 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -1,7 +1,7 @@ import * as os from 'node:os'; -import { Duplex } from 'node:stream'; import { info, warn } from 'node:console'; import * as flatbuffers from 'flatbuffers'; +import { WorkerChannel } from '../workerChannel'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; import { InvalidStateError } from './errors'; @@ -35,11 +35,8 @@ export class Channel extends EnhancedEventEmitter { // Closed flag. #closed = false; - // Unix Socket instance for sending messages to the worker process. - readonly #producerSocket: Duplex; - - // Unix Socket instance for receiving messages to the worker process. - readonly #consumerSocket: Duplex; + // WorkerChannel for sending and receiving messages to/from worker. + readonly #workerChannel: WorkerChannel; // Next id for messages sent to the worker process. #nextId = 0; @@ -57,23 +54,20 @@ export class Channel extends EnhancedEventEmitter { * @private */ constructor({ - producerSocket, - consumerSocket, + workerChannel, pid, }: { - producerSocket: any; - consumerSocket: any; + workerChannel: WorkerChannel; pid: number; }) { super(); logger.debug('constructor()'); - this.#producerSocket = producerSocket as Duplex; - this.#consumerSocket = consumerSocket as Duplex; + this.#workerChannel = workerChannel; // Read Channel responses/notifications from the worker. - this.#consumerSocket.on('data', (buffer: Buffer) => { + this.#workerChannel.on('data', (buffer: Buffer) => { if (!this.#recvBuffer.length) { this.#recvBuffer = buffer; } else { @@ -176,22 +170,6 @@ export class Channel extends EnhancedEventEmitter { this.#recvBuffer = this.#recvBuffer.slice(msgStart); } }); - - this.#consumerSocket.on('end', () => - logger.debug('Consumer Channel ended by the worker process') - ); - - this.#consumerSocket.on('error', error => - logger.error(`Consumer Channel error: ${error}`) - ); - - this.#producerSocket.on('end', () => - logger.debug('Producer Channel ended by the worker process') - ); - - this.#producerSocket.on('error', error => - logger.error(`Producer Channel error: ${error}`) - ); } /** @@ -217,24 +195,6 @@ export class Channel extends EnhancedEventEmitter { for (const sent of this.#sents.values()) { sent.close(); } - - // Remove event listeners but leave a fake 'error' hander to avoid - // propagation. - this.#consumerSocket.removeAllListeners('end'); - this.#consumerSocket.removeAllListeners('error'); - this.#consumerSocket.on('error', () => {}); - - this.#producerSocket.removeAllListeners('end'); - this.#producerSocket.removeAllListeners('error'); - this.#producerSocket.on('error', () => {}); - - // Destroy the sockets. - try { - this.#producerSocket.destroy(); - } catch (error) {} - try { - this.#consumerSocket.destroy(); - } catch (error) {} } /** @@ -282,12 +242,12 @@ export class Channel extends EnhancedEventEmitter { notificationOffset ); - // Finalizes the buffer and adds a 4 byte prefix with the size of the buffer. - this.#bufferBuilder.finishSizePrefixed(messageOffset); + // Finalizes the buffer. + this.#bufferBuilder.finish(messageOffset); // Create a new buffer with this data so multiple contiguous flatbuffers // do not point to the builder buffer overriding others info. - const buffer = new Uint8Array(this.#bufferBuilder.asUint8Array()); + const buffer = this.#bufferBuilder.asUint8Array(); // Clear the buffer builder so it's reused for the next request. this.#bufferBuilder.clear(); @@ -298,7 +258,7 @@ export class Channel extends EnhancedEventEmitter { try { // This may throw if closed or remote side ended. - this.#producerSocket.write(buffer, 'binary'); + this.#workerChannel.send(buffer); } catch (error) { logger.warn(`notify() | sending notification failed: ${error}`); @@ -354,12 +314,12 @@ export class Channel extends EnhancedEventEmitter { requestOffset ); - // Finalizes the buffer and adds a 4 byte prefix with the size of the buffer. - this.#bufferBuilder.finishSizePrefixed(messageOffset); + // Finalizes the buffer. + this.#bufferBuilder.finish(messageOffset); // Create a new buffer with this data so multiple contiguous flatbuffers // do not point to the builder buffer overriding others info. - const buffer = new Uint8Array(this.#bufferBuilder.asUint8Array()); + const buffer = this.#bufferBuilder.asUint8Array(); // Clear the buffer builder so it's reused for the next request. this.#bufferBuilder.clear(); @@ -369,7 +329,7 @@ export class Channel extends EnhancedEventEmitter { } // This may throw if closed or remote side ended. - this.#producerSocket.write(buffer, 'binary'); + this.#workerChannel.send(buffer); return new Promise((pResolve, pReject) => { const sent: Sent = { diff --git a/node/src/Worker.ts b/node/src/Worker.ts index b69d2c9c29..6344854c65 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -1,7 +1,6 @@ import * as process from 'node:process'; import * as path from 'node:path'; -import { spawn, ChildProcess } from 'node:child_process'; -import { version } from './'; +import { WorkerChannel } from '../workerChannel'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; import * as ortc from './ortc'; @@ -203,7 +202,6 @@ export type WorkerDump = { export type WorkerEvents = { died: [Error]; - subprocessclose: []; listenererror: [string, Error]; // Private events. '@success': []; @@ -247,11 +245,13 @@ const workerLogger = new Logger('Worker'); export class Worker< WorkerAppData extends AppData = AppData, > extends EnhancedEventEmitter { - // mediasoup-worker child process. - #child: ChildProcess; + /** + * WorkerChannel instance. + */ + #workerChannel: WorkerChannel; // Worker process PID. - readonly #pid: number; + readonly #pid: number = process.pid; // Channel instance. readonly #channel: Channel; @@ -262,9 +262,6 @@ export class Worker< // Died dlag. #died = false; - // Worker subprocess closed flag. - #subprocessClosed = false; - // Custom app data. #appData: WorkerAppData; @@ -345,157 +342,37 @@ export class Worker< spawnArgs.join(' ') ); - this.#child = spawn( - // command - spawnBin, - // args - spawnArgs, - // options - { - env: { - MEDIASOUP_VERSION: version, - // Let the worker process inherit all environment variables, useful - // if a custom and not in the path GCC is used so the user can set - // LD_LIBRARY_PATH environment variable for runtime. - ...process.env, - }, - - detached: false, - - // fd 0 (stdin) : Just ignore it. - // fd 1 (stdout) : Pipe it for 3rd libraries that log their own stuff. - // fd 2 (stderr) : Same as stdout. - // fd 3 (channel) : Producer Channel fd. - // fd 4 (channel) : Consumer Channel fd. - stdio: ['ignore', 'pipe', 'pipe', 'pipe', 'pipe'], - windowsHide: true, - } - ); - - this.#pid = this.#child.pid!; - - this.#channel = new Channel({ - producerSocket: this.#child.stdio[3], - consumerSocket: this.#child.stdio[4], - pid: this.#pid, - }); - - this.#appData = appData || ({} as WorkerAppData); - - let spawnDone = false; + this.#workerChannel = new WorkerChannel(spawnArgs); - // Listen for 'running' notification. - this.#channel.once(String(this.#pid), (event: Event) => { - if (!spawnDone && event === Event.WORKER_RUNNING) { - spawnDone = true; - - logger.debug('worker process running [pid:%s]', this.#pid); - - this.emit('@success'); - } - }); + this.#workerChannel.on('error', (code: number) => { + if (code === 42) { + logger.error('worker failed due to wrong settings [pid:%s]', this.#pid); - this.#child.on('exit', (code, signal) => { - // If killed by ourselves, do nothing. - if (this.#child.killed) { - return; - } - - if (!spawnDone) { - spawnDone = true; - - if (code === 42) { - logger.error( - 'worker process failed due to wrong settings [pid:%s]', - this.#pid - ); - - this.close(); - this.emit('@failure', new TypeError('wrong settings')); - } else { - logger.error( - 'worker process failed unexpectedly [pid:%s, code:%s, signal:%s]', - this.#pid, - code, - signal - ); - - this.close(); - this.emit( - '@failure', - new Error(`[pid:${this.#pid}, code:${code}, signal:${signal}]`) - ); - } + this.emit('@failure', new TypeError('wrong settings')); } else { logger.error( - 'worker process died unexpectedly [pid:%s, code:%s, signal:%s]', + 'worker failed unexpectedly [pid:%s, code:%s]', this.#pid, - code, - signal + code ); - this.workerDied( - new Error(`[pid:${this.#pid}, code:${code}, signal:${signal}]`) - ); + this.emit('@failure', new Error(`[pid:${this.#pid}, code:${code}]`)); } }); - this.#child.on('error', error => { - // If killed by ourselves, do nothing. - if (this.#child.killed) { - return; - } - - if (!spawnDone) { - spawnDone = true; - - logger.error( - 'worker process failed [pid:%s]: %s', - this.#pid, - error.message - ); - - this.close(); - this.emit('@failure', error); - } else { - logger.error( - 'worker process error [pid:%s]: %s', - this.#pid, - error.message - ); - - this.workerDied(error); - } + this.#channel = new Channel({ + workerChannel: this.#workerChannel, + pid: process.pid, }); - this.#child.on('close', (code, signal) => { - logger.debug( - 'worker subprocess closed [pid:%s, code:%s, signal:%s]', - this.#pid, - code, - signal - ); - - this.#subprocessClosed = true; - - this.safeEmit('subprocessclose'); - }); + this.#appData = appData || ({} as WorkerAppData); - // Be ready for 3rd party worker libraries logging to stdout. - this.#child.stdout!.on('data', buffer => { - for (const line of buffer.toString('utf8').split('\n')) { - if (line) { - workerLogger.debug(`(stdout) ${line}`); - } - } - }); + // Listen for 'running' notification. + this.#channel.once(String(process.pid), (event: Event) => { + if (event === Event.WORKER_RUNNING) { + logger.debug('worker process running [pid:%s]', this.#pid); - // In case of a worker bug, mediasoup will log to stderr. - this.#child.stderr!.on('data', buffer => { - for (const line of buffer.toString('utf8').split('\n')) { - if (line) { - workerLogger.error(`(stderr) ${line}`); - } + this.emit('@success'); } }); } @@ -521,13 +398,6 @@ export class Worker< return this.#died; } - /** - * Whether the Worker subprocess is closed. - */ - get subprocessClosed(): boolean { - return this.#subprocessClosed; - } - /** * App custom data. */ @@ -577,8 +447,7 @@ export class Worker< this.#closed = true; - // Kill the worker process. - this.#child.kill('SIGTERM'); + this.#channel.request(FbsRequest.Method.WORKER_CLOSE).catch(() => {}); // Close the Channel instance. this.#channel.close(); diff --git a/node/src/test/test-ActiveSpeakerObserver.ts b/node/src/test/test-ActiveSpeakerObserver.ts index f957a727c2..471e12f753 100644 --- a/node/src/test/test-ActiveSpeakerObserver.ts +++ b/node/src/test/test-ActiveSpeakerObserver.ts @@ -31,10 +31,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('router.createActiveSpeakerObserver() succeeds', async () => { diff --git a/node/src/test/test-AudioLevelObserver.ts b/node/src/test/test-AudioLevelObserver.ts index f6d6f61723..e319945ab6 100644 --- a/node/src/test/test-AudioLevelObserver.ts +++ b/node/src/test/test-AudioLevelObserver.ts @@ -31,10 +31,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('router.createAudioLevelObserver() succeeds', async () => { diff --git a/node/src/test/test-Consumer.ts b/node/src/test/test-Consumer.ts index 436145fbc2..4d4a20acc5 100644 --- a/node/src/test/test-Consumer.ts +++ b/node/src/test/test-Consumer.ts @@ -247,10 +247,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('transport.consume() succeeds', async () => { diff --git a/node/src/test/test-DataConsumer.ts b/node/src/test/test-DataConsumer.ts index e51a718095..748a707f0a 100644 --- a/node/src/test/test-DataConsumer.ts +++ b/node/src/test/test-DataConsumer.ts @@ -44,10 +44,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('transport.consumeData() succeeds', async () => { diff --git a/node/src/test/test-DataProducer.ts b/node/src/test/test-DataProducer.ts index ad1457caea..db60004d08 100644 --- a/node/src/test/test-DataProducer.ts +++ b/node/src/test/test-DataProducer.ts @@ -48,10 +48,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('webRtcTransport1.produceData() succeeds', async () => { diff --git a/node/src/test/test-DirectTransport.ts b/node/src/test/test-DirectTransport.ts index 3b7689acc1..4689f49761 100644 --- a/node/src/test/test-DirectTransport.ts +++ b/node/src/test/test-DirectTransport.ts @@ -16,10 +16,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('router.createDirectTransport() succeeds', async () => { diff --git a/node/src/test/test-PipeTransport.ts b/node/src/test/test-PipeTransport.ts index 0ded5cab8a..532ad46aa3 100644 --- a/node/src/test/test-PipeTransport.ts +++ b/node/src/test/test-PipeTransport.ts @@ -201,14 +201,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker1?.close(); ctx.worker2?.close(); - - if (ctx.worker1?.subprocessClosed === false) { - await enhancedOnce(ctx.worker1, 'subprocessclose'); - } - - if (ctx.worker2?.subprocessClosed === false) { - await enhancedOnce(ctx.worker2, 'subprocessclose'); - } }); test('router.pipeToRouter() succeeds with audio', async () => { diff --git a/node/src/test/test-PlainTransport.ts b/node/src/test/test-PlainTransport.ts index 31508bbddf..74187105b5 100644 --- a/node/src/test/test-PlainTransport.ts +++ b/node/src/test/test-PlainTransport.ts @@ -52,10 +52,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('router.createPlainTransport() succeeds', async () => { diff --git a/node/src/test/test-Producer.ts b/node/src/test/test-Producer.ts index fbf2cef5c1..ff85f7f7f7 100644 --- a/node/src/test/test-Producer.ts +++ b/node/src/test/test-Producer.ts @@ -148,10 +148,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('webRtcTransport1.produce() succeeds', async () => { diff --git a/node/src/test/test-Router.ts b/node/src/test/test-Router.ts index 50602aec32..fdf45e8dd4 100644 --- a/node/src/test/test-Router.ts +++ b/node/src/test/test-Router.ts @@ -46,10 +46,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('worker.createRouter() succeeds', async () => { diff --git a/node/src/test/test-WebRtcServer.ts b/node/src/test/test-WebRtcServer.ts index 8297941723..0a73097619 100644 --- a/node/src/test/test-WebRtcServer.ts +++ b/node/src/test/test-WebRtcServer.ts @@ -16,10 +16,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('worker.createWebRtcServer() succeeds', async () => { diff --git a/node/src/test/test-WebRtcTransport.ts b/node/src/test/test-WebRtcTransport.ts index 601073d209..f037942a5d 100644 --- a/node/src/test/test-WebRtcTransport.ts +++ b/node/src/test/test-WebRtcTransport.ts @@ -57,10 +57,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('router.createWebRtcTransport() succeeds', async () => { diff --git a/node/src/test/test-Worker.ts b/node/src/test/test-Worker.ts index 6f1b28dedc..208db014fb 100644 --- a/node/src/test/test-Worker.ts +++ b/node/src/test/test-Worker.ts @@ -50,10 +50,7 @@ test('createWorker() succeeds', async () => { worker1.close(); - await enhancedOnce(worker1, 'subprocessclose'); - expect(worker1.closed).toBe(true); - expect(worker1.died).toBe(false); const worker2 = await mediasoup.createWorker<{ foo: number; bar?: string }>({ logLevel: 'debug', @@ -74,10 +71,7 @@ test('createWorker() succeeds', async () => { worker2.close(); - await enhancedOnce(worker2, 'subprocessclose'); - expect(worker2.closed).toBe(true); - expect(worker2.died).toBe(false); }, 2000); test('createWorker() with wrong settings rejects with TypeError', async () => { @@ -117,8 +111,6 @@ test('worker.updateSettings() succeeds', async () => { ).resolves.toBeUndefined(); worker.close(); - - await enhancedOnce(worker, 'subprocessclose'); }, 2000); test('worker.updateSettings() with wrong settings rejects with TypeError', async () => { @@ -130,8 +122,6 @@ test('worker.updateSettings() with wrong settings rejects with TypeError', async ); worker.close(); - - await enhancedOnce(worker, 'subprocessclose'); }, 2000); test('worker.updateSettings() rejects with InvalidStateError if closed', async () => { @@ -139,8 +129,6 @@ test('worker.updateSettings() rejects with InvalidStateError if closed', async ( worker.close(); - await enhancedOnce(worker, 'subprocessclose'); - await expect(worker.updateSettings({ logLevel: 'error' })).rejects.toThrow( InvalidStateError ); @@ -167,8 +155,6 @@ test('worker.dump() rejects with InvalidStateError if closed', async () => { worker.close(); - await enhancedOnce(worker, 'subprocessclose'); - await expect(worker.dump()).rejects.toThrow(InvalidStateError); }, 2000); @@ -178,8 +164,6 @@ test('worker.getResourceUsage() succeeds', async () => { await expect(worker.getResourceUsage()).resolves.toMatchObject({}); worker.close(); - - await enhancedOnce(worker, 'subprocessclose'); }, 2000); test('worker.close() succeeds', async () => { @@ -189,14 +173,12 @@ test('worker.close() succeeds', async () => { worker.observer.once('close', onObserverClose); worker.close(); - await enhancedOnce(worker, 'subprocessclose'); - expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker.closed).toBe(true); expect(worker.died).toBe(false); }, 2000); -test('Worker emits "died" if worker process died unexpectedly', async () => { +test.skip('Worker emits "died" if worker process died unexpectedly', async () => { let onDied: ReturnType; let onObserverClose: ReturnType; @@ -225,11 +207,6 @@ test('Worker emits "died" if worker process died unexpectedly', async () => { process.kill(worker1.pid, 'SIGINT'); }); - if (!worker1.subprocessClosed) { - await enhancedOnce(worker1, 'subprocessclose'); - } - - expect(onDied).toHaveBeenCalledTimes(1); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker1.closed).toBe(true); expect(worker1.died).toBe(true); @@ -259,10 +236,6 @@ test('Worker emits "died" if worker process died unexpectedly', async () => { process.kill(worker2.pid, 'SIGTERM'); }); - if (!worker2.subprocessClosed) { - await enhancedOnce(worker2, 'subprocessclose'); - } - expect(onDied).toHaveBeenCalledTimes(1); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker2.closed).toBe(true); @@ -293,37 +266,8 @@ test('Worker emits "died" if worker process died unexpectedly', async () => { process.kill(worker3.pid, 'SIGKILL'); }); - if (!worker3.subprocessClosed) { - await enhancedOnce(worker3, 'subprocessclose'); - } - expect(onDied).toHaveBeenCalledTimes(1); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker3.closed).toBe(true); expect(worker3.died).toBe(true); }, 5000); - -// Windows doesn't have some signals such as SIGPIPE, SIGALRM, SIGUSR1, SIGUSR2 -// so we just skip this test in Windows. -if (os.platform() !== 'win32') { - test('worker process ignores PIPE, HUP, ALRM, USR1 and USR2 signals', async () => { - const worker = await mediasoup.createWorker({ logLevel: 'warn' }); - - await new Promise((resolve, reject) => { - worker.on('died', reject); - - process.kill(worker.pid, 'SIGPIPE'); - process.kill(worker.pid, 'SIGHUP'); - process.kill(worker.pid, 'SIGALRM'); - process.kill(worker.pid, 'SIGUSR1'); - process.kill(worker.pid, 'SIGUSR2'); - - setTimeout(() => { - expect(worker.closed).toBe(false); - - worker.close(); - worker.on('subprocessclose', resolve); - }, 2000); - }); - }, 3000); -} diff --git a/node/src/test/test-multiopus.ts b/node/src/test/test-multiopus.ts index d6542fb391..542ea79c1c 100644 --- a/node/src/test/test-multiopus.ts +++ b/node/src/test/test-multiopus.ts @@ -109,10 +109,6 @@ beforeEach(async () => { afterEach(async () => { ctx.worker?.close(); - - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } }); test('produce() and consume() succeed', async () => { diff --git a/node/src/test/test-node-sctp.ts b/node/src/test/test-node-sctp.ts index 46b2f93036..eb7117aa74 100644 --- a/node/src/test/test-node-sctp.ts +++ b/node/src/test/test-node-sctp.ts @@ -101,10 +101,6 @@ afterEach(async () => { ctx.sctpSocket?.end(); ctx.worker?.close(); - if (ctx.worker?.subprocessClosed === false) { - await enhancedOnce(ctx.worker, 'subprocessclose'); - } - // NOTE: For some reason we have to wait a bit for the SCTP stuff to release // internal things, otherwise Jest reports open handles. We don't care much // honestly. diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp new file mode 100644 index 0000000000..9447472ac2 --- /dev/null +++ b/node/workerChannel/binding.gyp @@ -0,0 +1,50 @@ +{ + "variables": { + "mediasoup_build_type%": "Release" + }, + "targets": [ + { + "target_name": "worker-channel", + "sources": [ + "src/binding.cpp", + "src/workerChannel.cpp" + ], + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'include_dirs': [ + " { + this.emit('data', data); + }); + + this.emitter.on('error', code => { + this.emit('error', code); + }); + } + + send(data: Uint8Array): void { + this.workerChannel.send(data); + } +} diff --git a/node/workerChannel/package-lock.json b/node/workerChannel/package-lock.json new file mode 100644 index 0000000000..166e3f14b8 --- /dev/null +++ b/node/workerChannel/package-lock.json @@ -0,0 +1,53 @@ +{ + "name": "mediasoup worker native module", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mediasoup worker native module", + "version": "0.0.0", + "dependencies": { + "bindings": "*", + "node-addon-api": "*" + }, + "devDependencies": { + "typescript": "^5.4.5" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/node-addon-api": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", + "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/node/workerChannel/package.json b/node/workerChannel/package.json new file mode 100644 index 0000000000..f9c1a03e6d --- /dev/null +++ b/node/workerChannel/package.json @@ -0,0 +1,20 @@ +{ + "name": "mediasoup worker native module", + "version": "0.0.0", + "description": "Node.js Addon do communicate with mediasoup worker", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "private": true, + "gypfile": true, + "scripts": { + "build": "rm -rf lib/ && tsc --project ./", + "test": "node lib/test.js" + }, + "dependencies": { + "bindings": "*", + "node-addon-api": "*" + }, + "devDependencies": { + "typescript": "^5.4.5" + } +} diff --git a/node/workerChannel/src/binding.cpp b/node/workerChannel/src/binding.cpp new file mode 100644 index 0000000000..4aaf1b9c30 --- /dev/null +++ b/node/workerChannel/src/binding.cpp @@ -0,0 +1,13 @@ +#include + +#include "./workerChannel.hpp" + +// Initialize native add-on. +Napi::Object Init(Napi::Env env, Napi::Object exports) +{ + WorkerChannel::Init(env, exports); + return exports; +} + +// Register and initialize native add-on. +NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init); diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp new file mode 100644 index 0000000000..20c6aee7f8 --- /dev/null +++ b/node/workerChannel/src/workerChannel.cpp @@ -0,0 +1,190 @@ +#include "./workerChannel.hpp" +#include "napi.h" + +#include +#include + +const char* version = "v3"; + +void deleteMessage(uint8_t* message, uint32_t messageLen, size_t ctx) +{ + delete[] message; +} + +ChannelReadFreeFn channelReadFn( + uint8_t** message, + uint32_t* messageLen, + size_t* messageCtx, + const void* handle, + ChannelReadCtx channelReadCtx) +{ + auto workerChannel = static_cast(channelReadCtx); + const uv_async_t* uvAsyncT = static_cast(handle); + + return workerChannel->OnChannelRead(message, messageLen, uvAsyncT); +} + +void channelWriteFn(const uint8_t* message, uint32_t messageLen, ChannelWriteCtx channelWriteCtx) +{ + auto workerChannel = static_cast(channelWriteCtx); + + return workerChannel->OnChannelWrite(message, messageLen); +} + +void libmediasoup(WorkerChannel* workerChannel, std::vector args) +{ + std::vector argv; + + for (auto& arg : args) + { + argv.push_back(arg.data()); + } + + auto result = mediasoup_worker_run( + argv.size(), argv.data(), version, 0, 0, channelReadFn, workerChannel, channelWriteFn, workerChannel); + + if (result != 0) + { + workerChannel->OnError(result); + } +} + +Napi::FunctionReference WorkerChannel::constructor; + +Napi::Object WorkerChannel::Init(Napi::Env env, Napi::Object exports) +{ + Napi::Function func = + DefineClass(env, "WorkerChannel", { InstanceMethod("send", &WorkerChannel::Send) }); + + Napi::FunctionReference* constructor = new Napi::FunctionReference(); + + // Create a persistent reference to the class constructor. This will allow + // a function called on a class prototype and a function + // called on instance of a class to be distinguished from each other. + *constructor = Napi::Persistent(func); + + exports.Set("WorkerChannel", func); + + // Store the constructor as the add-on instance data. This will allow this + // add-on to support multiple instances of itself running on multiple worker + // threads, as well as multiple instances of itself running in different + // contexts on the same thread. + // + // By default, the value set on the environment here will be destroyed when + // the add-on is unloaded using the `delete` operator, but it is also + // possible to supply a custom deleter. + env.SetInstanceData(constructor); + + return exports; +} + +WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) +{ + auto env = info.Env(); + auto cb = info[0].As(); + auto params = info[1].As(); + + this->emit = Napi::ThreadSafeFunction::New(env, cb, "WorkerChannel", 0, 1); + + std::vector args = { "" }; + + for (uint32_t i = 0; i < params.Length(); i++) + { + Napi::Value v = params[i]; + if (!v.IsString()) + { + continue; + } + + auto value = v.As(); + + args.push_back(value.Utf8Value()); + } + + this->thread = std::thread(libmediasoup, this, args); +} + +WorkerChannel::~WorkerChannel() +{ + std::cout << "~WorkerChannel()" << std::endl; +} + +void WorkerChannel::Finalize(Napi::Env env) +{ + std::cout << "Finalize()" << std::endl; + + this->emit.Release(); + // this->thread.join(); +} + +ChannelReadFreeFn WorkerChannel::OnChannelRead( + uint8_t** message, uint32_t* messageLen, const uv_async_t* handle) +{ + if (!this->handle) + { + this->handle = handle; + } + + if (this->messages.size() == 0) + { + return nullptr; + } + + this->mutex.lock(); + auto* msg = this->messages.front(); + this->messages.pop_front(); + this->mutex.unlock(); + + *message = msg; + + return deleteMessage; +} + +void WorkerChannel::OnChannelWrite(const uint8_t* message, uint32_t messageLen) +{ + auto copy = new uint8_t[messageLen]; + + std::memcpy(copy, message, messageLen); + + auto callback = [copy, messageLen](Napi::Env env, Napi::Function cb) + { + auto data = Napi::Buffer::New( + env, + const_cast(copy), + messageLen, + [](Napi::Env env, void* data) { delete[] (Napi::Buffer*)data; }); + + cb.Call({ Napi::String::New(env, "data"), data }); + }; + + this->emit.NonBlockingCall(callback); +} + +void WorkerChannel::OnError(const uint8_t code) +{ + auto callback = [code](Napi::Env env, Napi::Function cb) + { + auto value = Napi::Number::New(env, code); + + cb.Call({ Napi::String::New(env, "error"), value }); + }; + + this->emit.NonBlockingCall(callback); +} + +void WorkerChannel::Send(const Napi::CallbackInfo& info) +{ + // Copy the message into its own memory. + auto message = info[0].As(); + auto data = new uint8_t[message.ByteLength()]; + + std::memcpy(data, message.Data(), message.ByteLength()); + + // Store the message. + this->mutex.lock(); + this->messages.push_back(data); + this->mutex.unlock(); + + // Notify mediasoup about the new message. + uv_async_send(const_cast(this->handle)); +} diff --git a/node/workerChannel/src/workerChannel.hpp b/node/workerChannel/src/workerChannel.hpp new file mode 100644 index 0000000000..8d4c9f4523 --- /dev/null +++ b/node/workerChannel/src/workerChannel.hpp @@ -0,0 +1,34 @@ +#include "DepLibUV.hpp" +// mediasoup header files. +#include "common.hpp" +#include "lib.hpp" + +#include +#include +#include +#include + +class WorkerChannel : public Napi::ObjectWrap +{ +public: + static Napi::Object Init(Napi::Env env, Napi::Object exports); + WorkerChannel(const Napi::CallbackInfo& info); + ~WorkerChannel(); + + // Called when the wrapped native instance is freed. + void Finalize(Napi::Env env); + ChannelReadFreeFn OnChannelRead(uint8_t** message, uint32_t* messageLen, const uv_async_t* handle); + void OnChannelWrite(const uint8_t* message, uint32_t messageLen); + void OnError(const uint8_t code); + +private: + static Napi::FunctionReference constructor; + std::thread thread; + Napi::ThreadSafeFunction emit; + + const uv_async_t* handle; + std::mutex mutex; + std::deque messages; + + void Send(const Napi::CallbackInfo& info); +}; diff --git a/node/workerChannel/test.ts b/node/workerChannel/test.ts new file mode 100644 index 0000000000..ec410fe008 --- /dev/null +++ b/node/workerChannel/test.ts @@ -0,0 +1,17 @@ +import { WorkerChannel } from './'; + +const args = ['']; +const workerChannel = new WorkerChannel(args); + +workerChannel.on('data', value => { + console.log('### DATA event ... value: ', value); +}); + +// Wait for the thread to be created. +setTimeout(() => { + const uint8 = new Uint8Array(2); + + uint8[0] = 42; + + workerChannel.send(uint8); +}, 1000); diff --git a/node/workerChannel/tsconfig.json b/node/workerChannel/tsconfig.json new file mode 100644 index 0000000000..f347f69e60 --- /dev/null +++ b/node/workerChannel/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "lib": ["es2021"], + "target": "esnext", + "module": "commonjs", + "moduleResolution": "node", + "strict": true, + "outDir": "lib", + "declaration": true, + "declarationMap": true + }, + "include": ["./"], + "watchOptions": { + "watchFile": "useFsEvents", + "watchDirectory": "useFsEvents", + "fallbackPolling": "dynamicPriority", + "synchronousWatchDirectory": true + } +} diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 280f68c270..feb8cc0050 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -60,6 +60,7 @@ async function run() { case 'prepare': { flatcNode(); buildTypescript({ force: false }); + buildWorkerLib(); break; } @@ -128,6 +129,12 @@ async function run() { break; } + case 'worker:build-lib': { + buildWorkerLib(); + + break; + } + case 'worker:prebuild': { await prebuildWorker(); @@ -315,6 +322,20 @@ function buildWorker() { executeCmd(`"${PYTHON}" -m invoke -r worker mediasoup-worker`); } +function buildWorkerLib() { + logInfo('buildWorkerLib()'); + + installInvoke(); + + executeCmd(`"${PYTHON}" -m invoke -r worker libmediasoup-worker`); + + const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; + + executeCmd( + `cd node/workerChannel && GYP_DEFINES="mediasoup_build_type=${buildType}" npm i` + ); +} + function cleanWorkerArtifacts() { logInfo('cleanWorkerArtifacts()'); diff --git a/package-lock.json b/package-lock.json index fadd34ff9f..43a8124474 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "ini": "^4.1.2", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.0.1" + "tar": "^7.0.1", + "worker-channel": "file:./node/workerChannel" }, "devDependencies": { "@octokit/rest": "^20.1.0", @@ -2546,6 +2547,14 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3475,6 +3484,11 @@ "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5059,6 +5073,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-addon-api": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", + "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -6402,6 +6424,10 @@ "node": ">= 8" } }, + "node_modules/worker-channel": { + "resolved": "node/workerChannel", + "link": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6508,6 +6534,18 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node/workerChannel": { + "name": "mediasoup worker native module", + "version": "0.0.0", + "hasInstallScript": true, + "dependencies": { + "bindings": "*", + "node-addon-api": "*" + }, + "devDependencies": { + "typescript": "^5.4.5" + } } }, "dependencies": { @@ -8371,6 +8409,14 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -9009,6 +9055,11 @@ "token-types": "^5.0.1" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -10151,6 +10202,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node-addon-api": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", + "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==" + }, "node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -11042,6 +11098,14 @@ "isexe": "^2.0.0" } }, + "worker-channel": { + "version": "file:node/workerChannel", + "requires": { + "bindings": "*", + "node-addon-api": "*", + "typescript": "^5.4.5" + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 04ab196066..677686ec02 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "typescript:build": "node npm-scripts.mjs typescript:build", "typescript:watch": "node npm-scripts.mjs typescript:watch", "worker:build": "node npm-scripts.mjs worker:build", + "worker:build-lib": "node npm-scripts.mjs worker:build-lib", "worker:prebuild": "node npm-scripts.mjs worker:prebuild", "lint": "npm run lint:node && npm run lint:worker", "lint:node": "node npm-scripts.mjs lint:node", @@ -106,7 +107,8 @@ "ini": "^4.1.2", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.0.1" + "tar": "^7.0.1", + "worker-channel": "file:./node/workerChannel" }, "devDependencies": { "@octokit/rest": "^20.1.0", diff --git a/worker/scripts/clang-format.mjs b/worker/scripts/clang-format.mjs index c17152998a..a640b3a85c 100644 --- a/worker/scripts/clang-format.mjs +++ b/worker/scripts/clang-format.mjs @@ -15,6 +15,8 @@ async function run() { '../test/include/helpers.hpp', '../fuzzer/src/**/*.cpp', '../fuzzer/include/**/*.hpp', + '../../node/workerChannel/src/**/*.cpp', + '../../node/workerChannel/src/**/*.hpp', ]); switch (task) { diff --git a/worker/src/RTC/RtpDictionaries/RtcpFeedback.cpp b/worker/src/RTC/RtpDictionaries/RtcpFeedback.cpp index 0c9b367eb0..b95bb46e36 100644 --- a/worker/src/RTC/RtpDictionaries/RtcpFeedback.cpp +++ b/worker/src/RTC/RtpDictionaries/RtcpFeedback.cpp @@ -12,7 +12,7 @@ namespace RTC { MS_TRACE(); - this->type = data->type()->str(); + this->type = data->type()->str(); if (flatbuffers::IsFieldPresent(data, FBS::RtpParameters::RtcpFeedback::VT_PARAMETER)) { this->parameter = data->parameter()->str(); From 1e59102bc8e15c32c61132998d9c7f9aba518039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Thu, 9 May 2024 18:16:49 +0200 Subject: [PATCH 02/80] remove worker-channel from dependencies in package.json --- package-lock.json | 56 ++--------------------------------------------- package.json | 3 +-- 2 files changed, 3 insertions(+), 56 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43a8124474..f25ad9bb29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,7 @@ "ini": "^4.1.2", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.0.1", - "worker-channel": "file:./node/workerChannel" + "tar": "^7.0.1" }, "devDependencies": { "@octokit/rest": "^20.1.0", @@ -2547,14 +2546,6 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3484,11 +3475,6 @@ "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5073,14 +5059,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/node-addon-api": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", - "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==", - "engines": { - "node": "^18 || ^20 || >= 21" - } - }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -6424,10 +6402,6 @@ "node": ">= 8" } }, - "node_modules/worker-channel": { - "resolved": "node/workerChannel", - "link": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6538,7 +6512,7 @@ "node/workerChannel": { "name": "mediasoup worker native module", "version": "0.0.0", - "hasInstallScript": true, + "extraneous": true, "dependencies": { "bindings": "*", "node-addon-api": "*" @@ -8409,14 +8383,6 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -9055,11 +9021,6 @@ "token-types": "^5.0.1" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -10202,11 +10163,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node-addon-api": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", - "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==" - }, "node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -11098,14 +11054,6 @@ "isexe": "^2.0.0" } }, - "worker-channel": { - "version": "file:node/workerChannel", - "requires": { - "bindings": "*", - "node-addon-api": "*", - "typescript": "^5.4.5" - } - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 677686ec02..cb22668cb3 100644 --- a/package.json +++ b/package.json @@ -107,8 +107,7 @@ "ini": "^4.1.2", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.0.1", - "worker-channel": "file:./node/workerChannel" + "tar": "^7.0.1" }, "devDependencies": { "@octokit/rest": "^20.1.0", From ee186173f7a9b0eabf9b8d8d2283c94947282edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:09:23 +0200 Subject: [PATCH 03/80] provide version --- node/src/Worker.ts | 3 ++- node/workerChannel/index.ts | 3 ++- node/workerChannel/src/workerChannel.cpp | 23 +++++++++++++++-------- node/workerChannel/test.ts | 3 ++- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/node/src/Worker.ts b/node/src/Worker.ts index 6344854c65..e6e58ddd90 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -1,5 +1,6 @@ import * as process from 'node:process'; import * as path from 'node:path'; +import { version } from './'; import { WorkerChannel } from '../workerChannel'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; @@ -342,7 +343,7 @@ export class Worker< spawnArgs.join(' ') ); - this.#workerChannel = new WorkerChannel(spawnArgs); + this.#workerChannel = new WorkerChannel(version, spawnArgs); this.#workerChannel.on('error', (code: number) => { if (code === 42) { diff --git a/node/workerChannel/index.ts b/node/workerChannel/index.ts index ee64f7da75..c7b7ab243d 100644 --- a/node/workerChannel/index.ts +++ b/node/workerChannel/index.ts @@ -10,12 +10,13 @@ export class WorkerChannel extends EventEmitter { private emitter: EventEmitter; private workerChannel: typeof NativeWorkerChannel; - constructor(args: string[]) { + constructor(version: string, args: string[]) { super(); this.emitter = new EventEmitter(); this.workerChannel = new NativeWorkerChannel( this.emitter.emit.bind(this.emitter), + version, args ); diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index 20c6aee7f8..319a44d388 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -4,8 +4,6 @@ #include #include -const char* version = "v3"; - void deleteMessage(uint8_t* message, uint32_t messageLen, size_t ctx) { delete[] message; @@ -31,7 +29,7 @@ void channelWriteFn(const uint8_t* message, uint32_t messageLen, ChannelWriteCtx return workerChannel->OnChannelWrite(message, messageLen); } -void libmediasoup(WorkerChannel* workerChannel, std::vector args) +void libmediasoup(WorkerChannel* workerChannel, std::string version, std::vector args) { std::vector argv; @@ -41,7 +39,15 @@ void libmediasoup(WorkerChannel* workerChannel, std::vector args) } auto result = mediasoup_worker_run( - argv.size(), argv.data(), version, 0, 0, channelReadFn, workerChannel, channelWriteFn, workerChannel); + argv.size(), + argv.data(), + version.data(), + 0, + 0, + channelReadFn, + workerChannel, + channelWriteFn, + workerChannel); if (result != 0) { @@ -80,9 +86,10 @@ Napi::Object WorkerChannel::Init(Napi::Env env, Napi::Object exports) WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { - auto env = info.Env(); - auto cb = info[0].As(); - auto params = info[1].As(); + auto env = info.Env(); + auto cb = info[0].As(); + auto version = info[1].As(); + auto params = info[2].As(); this->emit = Napi::ThreadSafeFunction::New(env, cb, "WorkerChannel", 0, 1); @@ -101,7 +108,7 @@ WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap< args.push_back(value.Utf8Value()); } - this->thread = std::thread(libmediasoup, this, args); + this->thread = std::thread(libmediasoup, this, version.Utf8Value(), args); } WorkerChannel::~WorkerChannel() diff --git a/node/workerChannel/test.ts b/node/workerChannel/test.ts index ec410fe008..00d744ccd1 100644 --- a/node/workerChannel/test.ts +++ b/node/workerChannel/test.ts @@ -1,7 +1,8 @@ import { WorkerChannel } from './'; +const version = 'v3'; const args = ['']; -const workerChannel = new WorkerChannel(args); +const workerChannel = new WorkerChannel(version, args); workerChannel.on('data', value => { console.log('### DATA event ... value: ', value); From 2c804825c9c30c91f947cf74bf5c88d199f3dc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:14:41 +0200 Subject: [PATCH 04/80] add workerChannels to .eslintignore and .prettierignore --- .eslintignore | 1 + .prettierignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.eslintignore b/.eslintignore index cab871b0c9..4a2f2a413b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,6 +5,7 @@ /coverage /node/lib /node/src/fbs +/node/workerChannel/lib /rust /target /worker/deps diff --git a/.prettierignore b/.prettierignore index 1a5b7522c6..8e74a5fc1d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,6 +5,7 @@ /coverage /node/lib /node/src/fbs +/node/workerChannel/lib /rust /target /worker/deps From f925bfdbc4964810b05d859043ce37e0141ac317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:16:56 +0200 Subject: [PATCH 05/80] move header file to include folder --- node/workerChannel/{src => include}/workerChannel.hpp | 0 node/workerChannel/src/binding.cpp | 2 +- node/workerChannel/src/workerChannel.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename node/workerChannel/{src => include}/workerChannel.hpp (100%) diff --git a/node/workerChannel/src/workerChannel.hpp b/node/workerChannel/include/workerChannel.hpp similarity index 100% rename from node/workerChannel/src/workerChannel.hpp rename to node/workerChannel/include/workerChannel.hpp diff --git a/node/workerChannel/src/binding.cpp b/node/workerChannel/src/binding.cpp index 4aaf1b9c30..ea1f46724d 100644 --- a/node/workerChannel/src/binding.cpp +++ b/node/workerChannel/src/binding.cpp @@ -1,6 +1,6 @@ #include -#include "./workerChannel.hpp" +#include "../include/workerChannel.hpp" // Initialize native add-on. Napi::Object Init(Napi::Env env, Napi::Object exports) diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index 319a44d388..114c04a860 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -1,4 +1,4 @@ -#include "./workerChannel.hpp" +#include "../include/workerChannel.hpp" #include "napi.h" #include From 18971e0d60895271314b803d7aa878bd693233fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:18:05 +0200 Subject: [PATCH 06/80] remove blank line --- node/workerChannel/include/workerChannel.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/node/workerChannel/include/workerChannel.hpp b/node/workerChannel/include/workerChannel.hpp index 8d4c9f4523..8f42ccacff 100644 --- a/node/workerChannel/include/workerChannel.hpp +++ b/node/workerChannel/include/workerChannel.hpp @@ -1,8 +1,6 @@ #include "DepLibUV.hpp" -// mediasoup header files. -#include "common.hpp" -#include "lib.hpp" - +#include "common.hpp" // mediasoup header file. +#include "lib.hpp" // mediasoup header file. #include #include #include From 02d95d8d194752da14fa8021b98ab69089540d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:19:06 +0200 Subject: [PATCH 07/80] package.json: remove worker:build-lib script --- npm-scripts.mjs | 6 ------ package.json | 1 - 2 files changed, 7 deletions(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index feb8cc0050..8a8872da8a 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -129,12 +129,6 @@ async function run() { break; } - case 'worker:build-lib': { - buildWorkerLib(); - - break; - } - case 'worker:prebuild': { await prebuildWorker(); diff --git a/package.json b/package.json index cb22668cb3..04ab196066 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "typescript:build": "node npm-scripts.mjs typescript:build", "typescript:watch": "node npm-scripts.mjs typescript:watch", "worker:build": "node npm-scripts.mjs worker:build", - "worker:build-lib": "node npm-scripts.mjs worker:build-lib", "worker:prebuild": "node npm-scripts.mjs worker:prebuild", "lint": "npm run lint:node && npm run lint:worker", "lint:node": "node npm-scripts.mjs lint:node", From f6c222b03cc6499f3c6c6aedb7c56b76e53709b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:20:31 +0200 Subject: [PATCH 08/80] install workerChannel via 'npm ci' --- node/workerChannel/.npmrc | 4 ++++ npm-scripts.mjs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 node/workerChannel/.npmrc diff --git a/node/workerChannel/.npmrc b/node/workerChannel/.npmrc new file mode 100644 index 0000000000..05600b0d16 --- /dev/null +++ b/node/workerChannel/.npmrc @@ -0,0 +1,4 @@ +# Generate package-lock.json. +package-lock=true +# For bad node/npm version to throw actual error. +engine-strict=true diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 8a8872da8a..193cba7187 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -326,7 +326,7 @@ function buildWorkerLib() { const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; executeCmd( - `cd node/workerChannel && GYP_DEFINES="mediasoup_build_type=${buildType}" npm i` + `cd node/workerChannel && GYP_DEFINES="mediasoup_build_type=${buildType}" npm ci` ); } From 77a67b475b96cce8e361cc806aa1537c39ed889d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 10:51:14 +0200 Subject: [PATCH 09/80] properly build Debug/Release build types --- npm-scripts.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 193cba7187..f41f62ab2f 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -326,7 +326,7 @@ function buildWorkerLib() { const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; executeCmd( - `cd node/workerChannel && GYP_DEFINES="mediasoup_build_type=${buildType}" npm ci` + `cd node/workerChannel && npm ci --ignore-scripts && GYP_DEFINES="mediasoup_build_type=${buildType}" node-gyp rebuild --${buildType.toLowerCase()}` ); } From 23df1949803ce167600fab8b217706466df54c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 11:08:54 +0200 Subject: [PATCH 10/80] lint --- .eslintrc.js | 16 ++++++++++++++++ node/src/Worker.ts | 1 - node/src/test/test-ActiveSpeakerObserver.ts | 2 +- node/src/test/test-AudioLevelObserver.ts | 2 +- node/src/test/test-Consumer.ts | 2 +- node/src/test/test-DataConsumer.ts | 2 +- node/src/test/test-DataProducer.ts | 2 +- node/src/test/test-DirectTransport.ts | 2 +- node/src/test/test-PipeTransport.ts | 2 +- node/src/test/test-PlainTransport.ts | 2 +- node/src/test/test-Producer.ts | 2 +- node/src/test/test-Router.ts | 2 +- node/src/test/test-WebRtcServer.ts | 2 +- node/src/test/test-WebRtcTransport.ts | 2 +- node/src/test/test-Worker.ts | 5 ++--- node/src/test/test-multiopus.ts | 2 -- node/src/test/test-node-sctp.ts | 1 - node/workerChannel/index.ts | 3 ++- node/workerChannel/test.ts | 1 + 19 files changed, 33 insertions(+), 20 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index e69646071b..15c78fa350 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -175,4 +175,20 @@ eslintConfig.overrides.push({ }, }); +eslintConfig.overrides.push({ + files: ['node/workerChannel/*.ts'], + parser: '@typescript-eslint/parser', + parserOptions: { + ...eslintConfig.parserOptions, + project: 'node/workerChannel/tsconfig.json', + }, + plugins: [...eslintConfig.plugins, '@typescript-eslint'], + extends: [ + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + ...eslintConfig.extends, + ], + rules: { ...eslintConfig.rules, ...tsRules }, +}); + module.exports = eslintConfig; diff --git a/node/src/Worker.ts b/node/src/Worker.ts index e6e58ddd90..bd522f7c56 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -241,7 +241,6 @@ export const workerBin = process.env.MEDIASOUP_WORKER_BIN ); const logger = new Logger('Worker'); -const workerLogger = new Logger('Worker'); export class Worker< WorkerAppData extends AppData = AppData, diff --git a/node/src/test/test-ActiveSpeakerObserver.ts b/node/src/test/test-ActiveSpeakerObserver.ts index 471e12f753..973457f3cc 100644 --- a/node/src/test/test-ActiveSpeakerObserver.ts +++ b/node/src/test/test-ActiveSpeakerObserver.ts @@ -1,6 +1,6 @@ import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, ActiveSpeakerObserverEvents } from '../types'; +import { ActiveSpeakerObserverEvents } from '../types'; import * as utils from '../utils'; type TestContext = { diff --git a/node/src/test/test-AudioLevelObserver.ts b/node/src/test/test-AudioLevelObserver.ts index e319945ab6..7f9df88665 100644 --- a/node/src/test/test-AudioLevelObserver.ts +++ b/node/src/test/test-AudioLevelObserver.ts @@ -1,6 +1,6 @@ import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, AudioLevelObserverEvents } from '../types'; +import { AudioLevelObserverEvents } from '../types'; import * as utils from '../utils'; type TestContext = { diff --git a/node/src/test/test-Consumer.ts b/node/src/test/test-Consumer.ts index 4d4a20acc5..2c11710586 100644 --- a/node/src/test/test-Consumer.ts +++ b/node/src/test/test-Consumer.ts @@ -1,7 +1,7 @@ import * as flatbuffers from 'flatbuffers'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, ConsumerEvents } from '../types'; +import { ConsumerEvents } from '../types'; import { UnsupportedError } from '../errors'; import * as utils from '../utils'; import { diff --git a/node/src/test/test-DataConsumer.ts b/node/src/test/test-DataConsumer.ts index 748a707f0a..a85341ecf3 100644 --- a/node/src/test/test-DataConsumer.ts +++ b/node/src/test/test-DataConsumer.ts @@ -1,6 +1,6 @@ import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, DataConsumerEvents } from '../types'; +import { DataConsumerEvents } from '../types'; import * as utils from '../utils'; type TestContext = { diff --git a/node/src/test/test-DataProducer.ts b/node/src/test/test-DataProducer.ts index db60004d08..ae151e389c 100644 --- a/node/src/test/test-DataProducer.ts +++ b/node/src/test/test-DataProducer.ts @@ -1,6 +1,6 @@ import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, DataProducerEvents } from '../types'; +import { DataProducerEvents } from '../types'; import * as utils from '../utils'; type TestContext = { diff --git a/node/src/test/test-DirectTransport.ts b/node/src/test/test-DirectTransport.ts index 4689f49761..9e2a48fd7d 100644 --- a/node/src/test/test-DirectTransport.ts +++ b/node/src/test/test-DirectTransport.ts @@ -1,6 +1,6 @@ import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, DirectTransportEvents } from '../types'; +import { DirectTransportEvents } from '../types'; type TestContext = { worker?: mediasoup.types.Worker; diff --git a/node/src/test/test-PipeTransport.ts b/node/src/test/test-PipeTransport.ts index 532ad46aa3..8ccbd35e05 100644 --- a/node/src/test/test-PipeTransport.ts +++ b/node/src/test/test-PipeTransport.ts @@ -1,7 +1,7 @@ import { pickPort } from 'pick-port'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, ConsumerEvents, DataConsumerEvents } from '../types'; +import { ConsumerEvents, DataConsumerEvents } from '../types'; import * as utils from '../utils'; type TestContext = { diff --git a/node/src/test/test-PlainTransport.ts b/node/src/test/test-PlainTransport.ts index 74187105b5..4f82af85d2 100644 --- a/node/src/test/test-PlainTransport.ts +++ b/node/src/test/test-PlainTransport.ts @@ -2,7 +2,7 @@ import * as os from 'node:os'; import { pickPort } from 'pick-port'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, PlainTransportEvents } from '../types'; +import { PlainTransportEvents } from '../types'; import * as utils from '../utils'; const IS_WINDOWS = os.platform() === 'win32'; diff --git a/node/src/test/test-Producer.ts b/node/src/test/test-Producer.ts index ff85f7f7f7..dde7d1730d 100644 --- a/node/src/test/test-Producer.ts +++ b/node/src/test/test-Producer.ts @@ -1,7 +1,7 @@ import * as flatbuffers from 'flatbuffers'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, ProducerEvents } from '../types'; +import { ProducerEvents } from '../types'; import { UnsupportedError } from '../errors'; import * as utils from '../utils'; import { diff --git a/node/src/test/test-Router.ts b/node/src/test/test-Router.ts index fdf45e8dd4..701cd3b6c3 100644 --- a/node/src/test/test-Router.ts +++ b/node/src/test/test-Router.ts @@ -1,6 +1,6 @@ import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, RouterEvents } from '../types'; +import { RouterEvents } from '../types'; import { InvalidStateError } from '../errors'; import * as utils from '../utils'; diff --git a/node/src/test/test-WebRtcServer.ts b/node/src/test/test-WebRtcServer.ts index 0a73097619..76563d5905 100644 --- a/node/src/test/test-WebRtcServer.ts +++ b/node/src/test/test-WebRtcServer.ts @@ -1,7 +1,7 @@ import { pickPort } from 'pick-port'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, WebRtcServerEvents } from '../types'; +import { WebRtcServerEvents } from '../types'; import { InvalidStateError } from '../errors'; type TestContext = { diff --git a/node/src/test/test-WebRtcTransport.ts b/node/src/test/test-WebRtcTransport.ts index f037942a5d..13ba4a68d5 100644 --- a/node/src/test/test-WebRtcTransport.ts +++ b/node/src/test/test-WebRtcTransport.ts @@ -2,7 +2,7 @@ import { pickPort } from 'pick-port'; import * as flatbuffers from 'flatbuffers'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents, WebRtcTransportEvents } from '../types'; +import { WebRtcTransportEvents } from '../types'; import * as utils from '../utils'; import { serializeProtocol, TransportTuple } from '../Transport'; import { diff --git a/node/src/test/test-Worker.ts b/node/src/test/test-Worker.ts index 208db014fb..1e92d89f8f 100644 --- a/node/src/test/test-Worker.ts +++ b/node/src/test/test-Worker.ts @@ -1,9 +1,6 @@ -import * as os from 'node:os'; import * as process from 'node:process'; import * as path from 'node:path'; import * as mediasoup from '../'; -import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents } from '../types'; import { InvalidStateError } from '../errors'; test('Worker.workerBin matches mediasoup-worker absolute path', () => { @@ -178,6 +175,7 @@ test('worker.close() succeeds', async () => { expect(worker.died).toBe(false); }, 2000); +/* test.skip('Worker emits "died" if worker process died unexpectedly', async () => { let onDied: ReturnType; let onObserverClose: ReturnType; @@ -271,3 +269,4 @@ test.skip('Worker emits "died" if worker process died unexpectedly', async () => expect(worker3.closed).toBe(true); expect(worker3.died).toBe(true); }, 5000); +*/ diff --git a/node/src/test/test-multiopus.ts b/node/src/test/test-multiopus.ts index 542ea79c1c..ecade44bc6 100644 --- a/node/src/test/test-multiopus.ts +++ b/node/src/test/test-multiopus.ts @@ -1,6 +1,4 @@ import * as mediasoup from '../'; -import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents } from '../types'; import { UnsupportedError } from '../errors'; import * as utils from '../utils'; diff --git a/node/src/test/test-node-sctp.ts b/node/src/test/test-node-sctp.ts index eb7117aa74..94be5732e5 100644 --- a/node/src/test/test-node-sctp.ts +++ b/node/src/test/test-node-sctp.ts @@ -3,7 +3,6 @@ import * as dgram from 'node:dgram'; import * as sctp from 'sctp'; import * as mediasoup from '../'; import { enhancedOnce } from '../enhancedEvents'; -import { WorkerEvents } from '../types'; type TestContext = { worker?: mediasoup.types.Worker; diff --git a/node/workerChannel/index.ts b/node/workerChannel/index.ts index c7b7ab243d..73a6b3f97d 100644 --- a/node/workerChannel/index.ts +++ b/node/workerChannel/index.ts @@ -1,7 +1,8 @@ -import { createRequire } from 'node:module'; import { EventEmitter } from 'events'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires const { WorkerChannel: NativeWorkerChannel } = require( `../build/${buildType}/worker-channel.node` ); diff --git a/node/workerChannel/test.ts b/node/workerChannel/test.ts index 00d744ccd1..9b8324bc77 100644 --- a/node/workerChannel/test.ts +++ b/node/workerChannel/test.ts @@ -5,6 +5,7 @@ const args = ['']; const workerChannel = new WorkerChannel(version, args); workerChannel.on('data', value => { + // eslint-disable-next-line no-console console.log('### DATA event ... value: ', value); }); From 65ae95e186f44a972be778d42c1c0b857f6006f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 15:19:08 +0200 Subject: [PATCH 11/80] remove .eslintignore and .prettierignore --- .eslintignore | 22 ---------------------- .prettierignore | 21 --------------------- 2 files changed, 43 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .prettierignore diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 4a2f2a413b..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,22 +0,0 @@ -# NOTE: This file and .prettierignore must contain same paths. - -/.cache -/art -/coverage -/node/lib -/node/src/fbs -/node/workerChannel/lib -/rust -/target -/worker/deps -/worker/fbs -/worker/fuzzer -/worker/include -/worker/prebuild -/worker/pip_invoke -/worker/src -/worker/subprojects -/worker/test -/worker/out -/NO_GIT - diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 8e74a5fc1d..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,21 +0,0 @@ -# NOTE: This file and .eslintignore must contain same paths. - -/.cache -/art -/coverage -/node/lib -/node/src/fbs -/node/workerChannel/lib -/rust -/target -/worker/deps -/worker/fbs -/worker/fuzzer -/worker/include -/worker/prebuild -/worker/pip_invoke -/worker/src -/worker/subprojects -/worker/test -/worker/out -/NO_GIT From 6ed5f889b65b05bffe72025cbc82d59e0ea8c25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 15:23:42 +0200 Subject: [PATCH 12/80] add workerChannel to eslint and prettier --- npm-scripts.mjs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 63e95f83d8..ffe5eb655b 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -26,11 +26,14 @@ const GH_OWNER = 'versatica'; const GH_REPO = 'mediasoup'; // Paths for ESLint to check. Converted to string for convenience. -const ESLINT_PATHS = ['node/src', 'npm-scripts.mjs', 'worker/scripts'].join( - ' ' -); +const ESLINT_PATHS = [ + 'node/src', + 'node/workerChannel', + 'npm-scripts.mjs', + 'worker/scripts', +].join(' '); // Paths for ESLint to ignore. Converted to string argument for convenience. -const ESLINT_IGNORE_PATTERN_ARGS = ['node/src/fbs'] +const ESLINT_IGNORE_PATTERN_ARGS = ['node/src/fbs', '/node/workerChannel/lib'] .map(entry => `--ignore-pattern ${entry}`) .join(' '); // Paths for Prettier to check/write. Converted to string for convenience. @@ -42,6 +45,7 @@ const PRETTIER_PATHS = [ 'README.md', 'doc', 'node/src', + 'node/workerChannel', 'npm-scripts.mjs', 'package.json', 'worker/scripts', From fbe21202993f38a0c59eabcea2b4638153c985fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 10 May 2024 15:28:38 +0200 Subject: [PATCH 13/80] fix name for libmediasoup-worker library in linux --- node/workerChannel/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 9447472ac2..771ea6cdd3 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -19,7 +19,7 @@ 'conditions': [ ['OS=="linux"', { "libraries": [ - " Date: Fri, 10 May 2024 17:11:17 +0200 Subject: [PATCH 14/80] add *.ts files inside src/ folder --- node/workerChannel/{ => src}/index.ts | 0 node/workerChannel/{ => src}/test.ts | 0 node/workerChannel/tsconfig.json | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename node/workerChannel/{ => src}/index.ts (100%) rename node/workerChannel/{ => src}/test.ts (100%) diff --git a/node/workerChannel/index.ts b/node/workerChannel/src/index.ts similarity index 100% rename from node/workerChannel/index.ts rename to node/workerChannel/src/index.ts diff --git a/node/workerChannel/test.ts b/node/workerChannel/src/test.ts similarity index 100% rename from node/workerChannel/test.ts rename to node/workerChannel/src/test.ts diff --git a/node/workerChannel/tsconfig.json b/node/workerChannel/tsconfig.json index f347f69e60..87394576c7 100644 --- a/node/workerChannel/tsconfig.json +++ b/node/workerChannel/tsconfig.json @@ -10,7 +10,7 @@ "declaration": true, "declarationMap": true }, - "include": ["./"], + "include": ["src"], "watchOptions": { "watchFile": "useFsEvents", "watchDirectory": "useFsEvents", From 69bc91f5f81be5fe57e5ce39c7b976f5f521a0d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 13 May 2024 15:29:26 +0200 Subject: [PATCH 15/80] workerChannel: npm-scripts.ts --- node/workerChannel/npm-scripts.mjs | 119 +++++++++++++++++++++++++++++ node/workerChannel/package.json | 6 +- npm-scripts.mjs | 7 +- 3 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 node/workerChannel/npm-scripts.mjs diff --git a/node/workerChannel/npm-scripts.mjs b/node/workerChannel/npm-scripts.mjs new file mode 100644 index 0000000000..b15e25422c --- /dev/null +++ b/node/workerChannel/npm-scripts.mjs @@ -0,0 +1,119 @@ +import * as process from 'node:process'; +import * as fs from 'node:fs'; +import { execSync } from 'node:child_process'; + +const task = process.argv[2]; +const args = process.argv.slice(3).join(' '); + +run(); + +async function run() { + logInfo(args ? `[args:"${args}"]` : ''); + + switch (task) { + case 'binding:build': { + logInfo(`binding:build: [args:"${args}"]`); + buildBinding(); + + break; + } + + case 'typescript:build': { + buildTypescript(); + + break; + } + + case 'typescript:watch': { + deleteNodeLib(); + executeCmd(`tsc --project ./ --watch ${args}`); + + break; + } + + case 'test': { + buildTypescript(); + testNode(); + + break; + } + + default: { + logError('unknown task'); + + exitWithError(); + } + } +} + +function deleteNodeLib() { + if (!fs.existsSync('node/lib')) { + return; + } + + logInfo('deleteNodeLib()'); + + fs.rmSync('node/lib', { recursive: true, force: true }); +} + +function buildTypescript() { + logInfo('buildTypescript()'); + + deleteNodeLib(); + executeCmd('tsc --project ./'); +} + +function buildBinding() { + logInfo('buildBinding()'); + + executeCmd('npm ci --ignore-scripts}'); + + const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; + + process.env.GYP_DEFINES = `mediasoup_build_type=${buildType}`; + + executeCmd(`node-gyp rebuild --${buildType.toLowerCase()}`); +} + +function testNode() { + logInfo('testNode()'); + + executeCmd('node lib/test.js'); +} + +function executeCmd(command, exitOnError = true) { + logInfo(`executeCmd(): ${command}`); + + try { + execSync(command, { + stdio: ['ignore', process.stdout, process.stderr], + }); + } catch (error) { + if (exitOnError) { + logError(`executeCmd() failed, exiting: ${error}`); + + exitWithError(); + } else { + logInfo(`executeCmd() failed, ignoring: ${error}`); + } + } +} + +function logInfo(message) { + // eslint-disable-next-line no-console + console.log(`npm-scripts.mjs \x1b[36m[INFO] [${task}]\x1b[0m`, message); +} + +function logWarn(message) { + // eslint-disable-next-line no-console + console.warn(`npm-scripts.mjs \x1b[33m[WARN] [${task}]\x1b\0m`, message); +} + +function logError(message) { + // eslint-disable-next-line no-console + console.error(`npm-scripts.mjs \x1b[31m[ERROR] [${task}]\x1b[0m`, message); +} + +function exitWithError() { + process.exit(1); +} diff --git a/node/workerChannel/package.json b/node/workerChannel/package.json index f9c1a03e6d..15ecabf2cb 100644 --- a/node/workerChannel/package.json +++ b/node/workerChannel/package.json @@ -7,8 +7,10 @@ "private": true, "gypfile": true, "scripts": { - "build": "rm -rf lib/ && tsc --project ./", - "test": "node lib/test.js" + "binding:build": "node npm-scripts.mjs binding:build", + "typescript:build": "node npm-scripts.mjs typescript:build", + "typescript:watch": "node npm-scripts.mjs typescript:watch", + "test": "node npm-scripts.mjs test" }, "dependencies": { "bindings": "*", diff --git a/npm-scripts.mjs b/npm-scripts.mjs index ffe5eb655b..a8e649f88b 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -349,11 +349,8 @@ function buildWorkerLib() { executeCmd(`"${PYTHON}" -m invoke -r worker libmediasoup-worker`); - const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; - - executeCmd( - `cd node/workerChannel && npm ci --ignore-scripts && GYP_DEFINES="mediasoup_build_type=${buildType}" node-gyp rebuild --${buildType.toLowerCase()}` - ); + executeCmd('cd node/workerChannel && npm run binding:build'); + executeCmd('cd node/workerChannel && npm run typescript:build'); } function cleanWorkerArtifacts() { From 10076801d1bac57d571508eced466c694e4cbda3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 13 May 2024 15:48:39 +0200 Subject: [PATCH 16/80] npm-scripts: build worker lib before typescript --- npm-scripts.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 20db0ec9de..58e3fa73ef 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -87,8 +87,8 @@ async function run() { // TypeScript to JavaScript. case 'prepare': { flatcNode(); - buildTypescript({ force: false }); buildWorkerLib(); + buildTypescript({ force: false }); break; } @@ -115,7 +115,9 @@ async function run() { 'skipping mediasoup-worker prebuilt download, building it locally' ); + // TODO: remove buildWorker. buildWorker(); + buildWorkerLib(); if (!process.env.MEDIASOUP_LOCAL_DEV) { cleanWorkerArtifacts(); @@ -127,7 +129,9 @@ async function run() { `couldn't fetch any mediasoup-worker prebuilt binary, building it locally` ); + // TODO: remove buildWorker. buildWorker(); + buildWorkerLib(); if (!process.env.MEDIASOUP_LOCAL_DEV) { cleanWorkerArtifacts(); From 906d3ba6b043583fd074c5842e099776e97b7446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 13 May 2024 15:57:08 +0200 Subject: [PATCH 17/80] npm-scripts: remove typo --- node/workerChannel/npm-scripts.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/npm-scripts.mjs b/node/workerChannel/npm-scripts.mjs index d2458e3463..794d4d1913 100644 --- a/node/workerChannel/npm-scripts.mjs +++ b/node/workerChannel/npm-scripts.mjs @@ -66,7 +66,7 @@ function buildTypescript() { function buildBinding() { logInfo('buildBinding()'); - executeCmd('npm ci --ignore-scripts}'); + executeCmd('npm ci --ignore-scripts'); const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; From 71d7a75d06616f7faec79140e7a7eb078704ad1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 14 May 2024 10:03:38 +0200 Subject: [PATCH 18/80] workerChannel: initialize pointer And use std::lock_guard for better RAII --- node/workerChannel/include/workerChannel.hpp | 2 +- node/workerChannel/src/workerChannel.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/node/workerChannel/include/workerChannel.hpp b/node/workerChannel/include/workerChannel.hpp index 8f42ccacff..16668017e0 100644 --- a/node/workerChannel/include/workerChannel.hpp +++ b/node/workerChannel/include/workerChannel.hpp @@ -24,7 +24,7 @@ class WorkerChannel : public Napi::ObjectWrap std::thread thread; Napi::ThreadSafeFunction emit; - const uv_async_t* handle; + const uv_async_t* handle{ nullptr }; std::mutex mutex; std::deque messages; diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index 114c04a860..25afbce3b2 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -132,15 +132,15 @@ ChannelReadFreeFn WorkerChannel::OnChannelRead( this->handle = handle; } + std::lock_guard guard(this->mutex); + if (this->messages.size() == 0) { return nullptr; } - this->mutex.lock(); auto* msg = this->messages.front(); this->messages.pop_front(); - this->mutex.unlock(); *message = msg; @@ -187,10 +187,10 @@ void WorkerChannel::Send(const Napi::CallbackInfo& info) std::memcpy(data, message.Data(), message.ByteLength()); - // Store the message. - this->mutex.lock(); - this->messages.push_back(data); - this->mutex.unlock(); + { + std::lock_guard guard(this->mutex); + this->messages.push_back(data); + } // Notify mediasoup about the new message. uv_async_send(const_cast(this->handle)); From 20334b758a08e754213a9efd62d2a1ddc65e0435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 14 May 2024 10:42:23 +0200 Subject: [PATCH 19/80] binding.gyp: use a common path for libmediasoup-worker library --- node/workerChannel/binding.gyp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 771ea6cdd3..ca0a8715c4 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -15,17 +15,12 @@ " Date: Tue, 14 May 2024 11:23:07 +0200 Subject: [PATCH 20/80] binding.gyp: use module_root_dir rather than pwd Which should work in windows too. --- node/workerChannel/binding.gyp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index ca0a8715c4..e0c0530a7b 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -13,10 +13,10 @@ 'cflags_cc!': [ '-fno-exceptions' ], 'include_dirs': [ " Date: Wed, 15 May 2024 10:10:25 +0200 Subject: [PATCH 21/80] Windows: test --- node/workerChannel/binding.gyp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index e0c0530a7b..8698eb125e 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -23,7 +23,13 @@ ['OS=="win"', { "msvs_settings": { "VCCLCompilerTool": { - "ExceptionHandling": 1 + "ExceptionHandling": 1, + # RuntimeLibrary: + # 0 - MultiThreaded (/MT) + # 1 - MultiThreadedDebug (/MTd) + # 2 - MultiThreadedDLL (/MD) + # 3 - MultiThreadedDebugDLL (/MDd) + 'RuntimeLibrary': 1, } } }], From 8362703a918f846e8083983305731d4d37ca0d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 10:26:54 +0200 Subject: [PATCH 22/80] npm-scripts: do not build mediasoup-worker but libmediasoup-worker --- npm-scripts.mjs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 58e3fa73ef..c4f7d162bd 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -115,8 +115,6 @@ async function run() { 'skipping mediasoup-worker prebuilt download, building it locally' ); - // TODO: remove buildWorker. - buildWorker(); buildWorkerLib(); if (!process.env.MEDIASOUP_LOCAL_DEV) { @@ -129,8 +127,6 @@ async function run() { `couldn't fetch any mediasoup-worker prebuilt binary, building it locally` ); - // TODO: remove buildWorker. - buildWorker(); buildWorkerLib(); if (!process.env.MEDIASOUP_LOCAL_DEV) { From e1df7017977ac54a171e1a9d792835a6123c7273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 10:32:04 +0200 Subject: [PATCH 23/80] remove worker died event --- node/src/Worker.ts | 42 --------------- node/src/test/test-Worker.ts | 99 ------------------------------------ 2 files changed, 141 deletions(-) diff --git a/node/src/Worker.ts b/node/src/Worker.ts index bd522f7c56..27e15bdf66 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -202,7 +202,6 @@ export type WorkerDump = { }; export type WorkerEvents = { - died: [Error]; listenererror: [string, Error]; // Private events. '@success': []; @@ -259,9 +258,6 @@ export class Worker< // Closed flag. #closed = false; - // Died dlag. - #died = false; - // Custom app data. #appData: WorkerAppData; @@ -391,13 +387,6 @@ export class Worker< return this.#closed; } - /** - * Whether the Worker died. - */ - get died(): boolean { - return this.#died; - } - /** * App custom data. */ @@ -663,37 +652,6 @@ export class Worker< return router; } - - private workerDied(error: Error): void { - if (this.#closed) { - return; - } - - logger.debug(`died() [error:${error}]`); - - this.#closed = true; - this.#died = true; - - // Close the Channel instance. - this.#channel.close(); - - // Close every Router. - for (const router of this.#routers) { - router.workerClosed(); - } - this.#routers.clear(); - - // Close every WebRtcServer. - for (const webRtcServer of this.#webRtcServers) { - webRtcServer.workerClosed(); - } - this.#webRtcServers.clear(); - - this.safeEmit('died', error); - - // Emit observer event. - this.#observer.safeEmit('close'); - } } export function parseWorkerDumpResponse( diff --git a/node/src/test/test-Worker.ts b/node/src/test/test-Worker.ts index 1e92d89f8f..04d3cded48 100644 --- a/node/src/test/test-Worker.ts +++ b/node/src/test/test-Worker.ts @@ -43,7 +43,6 @@ test('createWorker() succeeds', async () => { expect(worker1.constructor.name).toBe('Worker'); expect(typeof worker1.pid).toBe('number'); expect(worker1.closed).toBe(false); - expect(worker1.died).toBe(false); worker1.close(); @@ -63,7 +62,6 @@ test('createWorker() succeeds', async () => { expect(worker2.constructor.name).toBe('Worker'); expect(typeof worker2.pid).toBe('number'); expect(worker2.closed).toBe(false); - expect(worker2.died).toBe(false); expect(worker2.appData).toEqual({ foo: 456 }); worker2.close(); @@ -172,101 +170,4 @@ test('worker.close() succeeds', async () => { expect(onObserverClose).toHaveBeenCalledTimes(1); expect(worker.closed).toBe(true); - expect(worker.died).toBe(false); }, 2000); - -/* -test.skip('Worker emits "died" if worker process died unexpectedly', async () => { - let onDied: ReturnType; - let onObserverClose: ReturnType; - - const worker1 = await mediasoup.createWorker({ logLevel: 'warn' }); - - onDied = jest.fn(); - onObserverClose = jest.fn(); - - worker1.observer.once('close', onObserverClose); - - await new Promise((resolve, reject) => { - worker1.on('died', () => { - onDied(); - - if (onObserverClose.mock.calls.length > 0) { - reject( - new Error('observer "close" event emitted before worker "died" event') - ); - } else if (worker1.closed) { - resolve(); - } else { - reject(new Error('worker.closed is false')); - } - }); - - process.kill(worker1.pid, 'SIGINT'); - }); - - expect(onObserverClose).toHaveBeenCalledTimes(1); - expect(worker1.closed).toBe(true); - expect(worker1.died).toBe(true); - - const worker2 = await mediasoup.createWorker({ logLevel: 'warn' }); - - onDied = jest.fn(); - onObserverClose = jest.fn(); - - worker2.observer.once('close', onObserverClose); - - await new Promise((resolve, reject) => { - worker2.on('died', () => { - onDied(); - - if (onObserverClose.mock.calls.length > 0) { - reject( - new Error('observer "close" event emitted before worker "died" event') - ); - } else if (worker2.closed) { - resolve(); - } else { - reject(new Error('worker.closed is false')); - } - }); - - process.kill(worker2.pid, 'SIGTERM'); - }); - - expect(onDied).toHaveBeenCalledTimes(1); - expect(onObserverClose).toHaveBeenCalledTimes(1); - expect(worker2.closed).toBe(true); - expect(worker2.died).toBe(true); - - const worker3 = await mediasoup.createWorker({ logLevel: 'warn' }); - - onDied = jest.fn(); - onObserverClose = jest.fn(); - - worker3.observer.once('close', onObserverClose); - - await new Promise((resolve, reject) => { - worker3.on('died', () => { - onDied(); - - if (onObserverClose.mock.calls.length > 0) { - reject( - new Error('observer "close" event emitted before worker "died" event') - ); - } else if (worker3.closed) { - resolve(); - } else { - reject(new Error('worker.closed is false')); - } - }); - - process.kill(worker3.pid, 'SIGKILL'); - }); - - expect(onDied).toHaveBeenCalledTimes(1); - expect(onObserverClose).toHaveBeenCalledTimes(1); - expect(worker3.closed).toBe(true); - expect(worker3.died).toBe(true); -}, 5000); -*/ From 82361c07910105b1c3d90c197ecd4cbf3f538b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 10:41:28 +0200 Subject: [PATCH 24/80] windows test --- node/workerChannel/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 8698eb125e..0712427ae3 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -29,7 +29,7 @@ # 1 - MultiThreadedDebug (/MTd) # 2 - MultiThreadedDLL (/MD) # 3 - MultiThreadedDebugDLL (/MDd) - 'RuntimeLibrary': 1, + 'RuntimeLibrary': 2, } } }], From c933523cc82167beb7f5c12b5d9bddc966a34aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 11:00:44 +0200 Subject: [PATCH 25/80] windows test cont. --- node/workerChannel/binding.gyp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 0712427ae3..135decde7f 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -29,8 +29,11 @@ # 1 - MultiThreadedDebug (/MTd) # 2 - MultiThreadedDLL (/MD) # 3 - MultiThreadedDebugDLL (/MDd) - 'RuntimeLibrary': 2, - } + 'RuntimeLibrary': 1, + }, + 'VCLinkerTool': { + 'AdditionalOptions': [ '/NODEFAULTLIB:library' ], + }, } }], ['OS=="mac"', { From 33a736059f86c4a9935b3c013e3a96fa11798a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 11:20:16 +0200 Subject: [PATCH 26/80] windows test --- node/workerChannel/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 135decde7f..661d3f8c13 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -29,7 +29,7 @@ # 1 - MultiThreadedDebug (/MTd) # 2 - MultiThreadedDLL (/MD) # 3 - MultiThreadedDebugDLL (/MDd) - 'RuntimeLibrary': 1, + 'RuntimeLibrary': 0, }, 'VCLinkerTool': { 'AdditionalOptions': [ '/NODEFAULTLIB:library' ], From 439874f5cad8f1505cd21f64f6125cfc1c75a05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 11:21:46 +0200 Subject: [PATCH 27/80] workflow remove every OS but windows --- .github/workflows/mediasoup-node.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/mediasoup-node.yaml b/.github/workflows/mediasoup-node.yaml index b035e0c56f..75b330636a 100644 --- a/.github/workflows/mediasoup-node.yaml +++ b/.github/workflows/mediasoup-node.yaml @@ -13,19 +13,19 @@ jobs: strategy: matrix: ci: - - os: ubuntu-20.04 - node: 18 - - os: ubuntu-22.04 - node: 20 - - os: macos-12 - node: 18 - - os: macos-14 - node: 20 + # - os: ubuntu-20.04 + # node: 18 + # - os: ubuntu-22.04 + # node: 20 + # - os: macos-12 + # node: 18 + # - os: macos-14 + # node: 20 - os: windows-2022 node: 20 build-type: - Release - - Debug + # - Debug runs-on: ${{ matrix.ci.os }} From d9f6bf7281c8af3782ca301ca7117572e7d0daeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 12:07:28 +0200 Subject: [PATCH 28/80] Windows: test --- node/workerChannel/binding.gyp | 1 + 1 file changed, 1 insertion(+) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 661d3f8c13..95b21c93ab 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -30,6 +30,7 @@ # 2 - MultiThreadedDLL (/MD) # 3 - MultiThreadedDebugDLL (/MDd) 'RuntimeLibrary': 0, + 'AdditionalOptions': [ '/MT' ], }, 'VCLinkerTool': { 'AdditionalOptions': [ '/NODEFAULTLIB:library' ], From e331bd43693c564f38ceec0d40ee3e22b67cd2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 12:31:28 +0200 Subject: [PATCH 29/80] binding.gyp: remove unneeded dependency --- node/workerChannel/binding.gyp | 1 - 1 file changed, 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 95b21c93ab..f2d3fb961f 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -18,7 +18,6 @@ "libraries": [ "<(module_root_dir)/../../worker/out/<(mediasoup_build_type)/build/libmediasoup-worker.a" ], - 'dependencies': [" Date: Wed, 15 May 2024 12:33:57 +0200 Subject: [PATCH 30/80] worker-channel: remove unused dependency --- node/workerChannel/package-lock.json | 14 -------------- node/workerChannel/package.json | 1 - 2 files changed, 15 deletions(-) diff --git a/node/workerChannel/package-lock.json b/node/workerChannel/package-lock.json index 166e3f14b8..e4c39de2b8 100644 --- a/node/workerChannel/package-lock.json +++ b/node/workerChannel/package-lock.json @@ -8,26 +8,12 @@ "name": "mediasoup worker native module", "version": "0.0.0", "dependencies": { - "bindings": "*", "node-addon-api": "*" }, "devDependencies": { "typescript": "^5.4.5" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "node_modules/node-addon-api": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", diff --git a/node/workerChannel/package.json b/node/workerChannel/package.json index 15ecabf2cb..d0918bb444 100644 --- a/node/workerChannel/package.json +++ b/node/workerChannel/package.json @@ -13,7 +13,6 @@ "test": "node npm-scripts.mjs test" }, "dependencies": { - "bindings": "*", "node-addon-api": "*" }, "devDependencies": { From 7329f63a2ad7998c11155546649ecaf40a4b8a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 13:00:40 +0200 Subject: [PATCH 31/80] npm-scripts: build addon with --verbose option --- node/workerChannel/npm-scripts.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/npm-scripts.mjs b/node/workerChannel/npm-scripts.mjs index 794d4d1913..a0bb5968f4 100644 --- a/node/workerChannel/npm-scripts.mjs +++ b/node/workerChannel/npm-scripts.mjs @@ -72,7 +72,7 @@ function buildBinding() { process.env.GYP_DEFINES = `mediasoup_build_type=${buildType}`; - executeCmd(`node-gyp rebuild --${buildType.toLowerCase()}`); + executeCmd(`node-gyp rebuild --${buildType.toLowerCase()} --verbose`); } function testNode() { From fc527eb41ff83c2f8d0dbeaee602316df25b457d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 13:21:23 +0200 Subject: [PATCH 32/80] meson.build: set b_vscrt option to use /MT runtime library for windows --- worker/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/worker/meson.build b/worker/meson.build index 1be338815b..de985a0351 100644 --- a/worker/meson.build +++ b/worker/meson.build @@ -5,6 +5,7 @@ project( 'warning_level=1', 'cpp_std=c++17', 'default_library=static', + 'b_vscrt=static_from_buildtype', ], meson_version: '>= 1.1.0', ) From 93fe29590cd4c480e510db3c6ce22d8073fa4c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 14:01:25 +0200 Subject: [PATCH 33/80] windows: test --- node/workerChannel/binding.gyp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index f2d3fb961f..cbb1c168c8 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -20,6 +20,9 @@ ], 'conditions': [ ['OS=="win"', { + "libraries": [ + "Ws2_32.lib", + ], "msvs_settings": { "VCCLCompilerTool": { "ExceptionHandling": 1, From d1897f5b9273d147d862625cec1c999d9d09271d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 14:14:38 +0200 Subject: [PATCH 34/80] windows: test, add more needed libraries for windows --- node/workerChannel/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index cbb1c168c8..b016b7e846 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -21,7 +21,7 @@ 'conditions': [ ['OS=="win"', { "libraries": [ - "Ws2_32.lib", + "Ws2_32.lib", "Dbghelp.lib", "Crypt32.lib", "Userenv.lib", ], "msvs_settings": { "VCCLCompilerTool": { From 3246f845e8e8800109f56519b8d610cb4dde60d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 15:20:19 +0200 Subject: [PATCH 35/80] workerChannel: include uv.h rather than DepLibUV.hpp In order to avoid the error: error LNK2005: uv_async_send already defined in node.lib(node.exe) --- node/workerChannel/include/workerChannel.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/workerChannel/include/workerChannel.hpp b/node/workerChannel/include/workerChannel.hpp index 16668017e0..10e0ebb600 100644 --- a/node/workerChannel/include/workerChannel.hpp +++ b/node/workerChannel/include/workerChannel.hpp @@ -1,9 +1,9 @@ -#include "DepLibUV.hpp" #include "common.hpp" // mediasoup header file. #include "lib.hpp" // mediasoup header file. +#include +#include #include #include -#include #include class WorkerChannel : public Napi::ObjectWrap From 99542b8f8a2e021efb47537800936b55434e41cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 15 May 2024 15:51:40 +0200 Subject: [PATCH 36/80] windows: WIP, do not import libuv --- node/workerChannel/include/workerChannel.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node/workerChannel/include/workerChannel.hpp b/node/workerChannel/include/workerChannel.hpp index 10e0ebb600..7df2b88e59 100644 --- a/node/workerChannel/include/workerChannel.hpp +++ b/node/workerChannel/include/workerChannel.hpp @@ -1,7 +1,9 @@ #include "common.hpp" // mediasoup header file. #include "lib.hpp" // mediasoup header file. #include +#ifndef _WIN32 #include +#endif #include #include #include From 6e2909db0fbfc972ffc81a7a880bae9bba014d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 10:01:23 +0200 Subject: [PATCH 37/80] handle feedback --- node/workerChannel/include/workerChannel.hpp | 4 +--- node/workerChannel/src/workerChannel.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/node/workerChannel/include/workerChannel.hpp b/node/workerChannel/include/workerChannel.hpp index 7df2b88e59..851c0f130f 100644 --- a/node/workerChannel/include/workerChannel.hpp +++ b/node/workerChannel/include/workerChannel.hpp @@ -1,9 +1,7 @@ +#include "DepLibUV.hpp" // mediasoup header file. #include "common.hpp" // mediasoup header file. #include "lib.hpp" // mediasoup header file. #include -#ifndef _WIN32 -#include -#endif #include #include #include diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index 25afbce3b2..f2e0c5ef67 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -98,6 +98,7 @@ WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap< for (uint32_t i = 0; i < params.Length(); i++) { Napi::Value v = params[i]; + if (!v.IsString()) { continue; @@ -113,15 +114,18 @@ WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap< WorkerChannel::~WorkerChannel() { - std::cout << "~WorkerChannel()" << std::endl; + std::lock_guard guard(this->mutex); + + for (const auto* message: this->messages) + { + delete[] message; + } } void WorkerChannel::Finalize(Napi::Env env) { - std::cout << "Finalize()" << std::endl; - this->emit.Release(); - // this->thread.join(); + this->thread.join(); } ChannelReadFreeFn WorkerChannel::OnChannelRead( From 2062749f852fd4e434668da72d9990dd696a4c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 11:03:24 +0200 Subject: [PATCH 38/80] tests --- node/workerChannel/src/test.ts | 110 ++++++++++++++++++++--- node/workerChannel/src/workerChannel.cpp | 48 ++++++++-- 2 files changed, 136 insertions(+), 22 deletions(-) diff --git a/node/workerChannel/src/test.ts b/node/workerChannel/src/test.ts index 9b8324bc77..e780597995 100644 --- a/node/workerChannel/src/test.ts +++ b/node/workerChannel/src/test.ts @@ -1,19 +1,103 @@ -import { WorkerChannel } from './'; +import assert = require('node:assert'); +import { beforeEach, describe, it } from 'node:test'; -const version = 'v3'; -const args = ['']; -const workerChannel = new WorkerChannel(version, args); +const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; -workerChannel.on('data', value => { - // eslint-disable-next-line no-console - console.log('### DATA event ... value: ', value); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { WorkerChannel: NativeWorkerChannel } = require( + `../build/${buildType}/worker-channel.node` +); + +describe('NativeWorkerChannel constructor', () => { + it('fails if no argument is passed', () => { + assert.throws(() => new NativeWorkerChannel(), TypeError); + }); + + it('fails if a single argument is passed', () => { + const func = () => {}; + + assert.throws(() => new NativeWorkerChannel(func), TypeError); + }); + + [true, 1, 'one'].forEach(func => { + it(`fails if the first argument ("${func}") is not a Function`, () => { + const version = 'X'; + + assert.throws(() => new NativeWorkerChannel(func, version), TypeError); + }); + }); + + [true, 1, () => {}].forEach(version => { + it(`fails if the second argument ("${version}") is not a String`, () => { + const func = () => {}; + + assert.throws(() => new NativeWorkerChannel(func, version), TypeError); + }); + }); + + [true, 1, 'one', () => {}].forEach(args => { + it(`fails if the third argument is present ("${args}") and is not an Array`, () => { + const func = () => {}; + const version = 'X'; + + assert.throws( + () => new NativeWorkerChannel(func, version, args), + TypeError + ); + }); + }); + + [true, 1, () => {}].forEach(item => { + it(`fails if the third argument is present and contains a non String item (${item})`, () => { + const func = () => {}; + const version = 'X'; + const args = ['one', 'two', 'three']; + + // @ts-ignore. + args.push(item); + + assert.throws( + () => new NativeWorkerChannel(func, version, args), + TypeError + ); + }); + }); + + it('succeeds if the given arguments are a Function and a String respectively', () => { + const func = () => {}; + const version = 'X'; + + assert.doesNotThrow(() => new NativeWorkerChannel(func, version)); + }); + + it('succeeds if the third argument is an Array of Strings', () => { + const func = () => {}; + const version = 'X'; + const args = ['one', 'two', 'three']; + + assert.doesNotThrow(() => new NativeWorkerChannel(func, version, args)); + }); }); -// Wait for the thread to be created. -setTimeout(() => { - const uint8 = new Uint8Array(2); +describe('NativeWorkerChannel send', () => { + const version = 'X'; + const func = () => {}; + + let workerChannel: any; + + beforeEach(() => { + workerChannel = new NativeWorkerChannel(func, version); + }); - uint8[0] = 42; + [true, 1, 'one', () => {}].forEach(data => { + it(`fails if send() is called with a value (${data}) different than an Uint8Array`, () => { + assert.throws(() => workerChannel.send(data), TypeError); + }); + }); - workerChannel.send(uint8); -}, 1000); + it(`succeeds if send() is called with a Uint8Array`, () => { + const data = new Uint8Array(2); + + workerChannel.send(data); + }); +}); diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index f2e0c5ef67..787a6db7ae 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -87,28 +87,45 @@ Napi::Object WorkerChannel::Init(Napi::Env env, Napi::Object exports) WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { auto env = info.Env(); + + if (info.Length() < 2) { + throw Napi::TypeError::New(env, "Expected at least two arguments"); + } else if (!info[0].IsFunction()) { + throw Napi::TypeError::New(env, "Expected first arg to be function"); + } else if (!info[1].IsString()) { + throw Napi::TypeError::New(env, "Expected second arg to be string"); + } + auto cb = info[0].As(); auto version = info[1].As(); - auto params = info[2].As(); this->emit = Napi::ThreadSafeFunction::New(env, cb, "WorkerChannel", 0, 1); std::vector args = { "" }; - for (uint32_t i = 0; i < params.Length(); i++) - { - Napi::Value v = params[i]; + if (info.Length() == 3) { + if (!info[2].IsArray()) { + throw Napi::TypeError::New(env, "Expected third arg to be array"); + } - if (!v.IsString()) + auto params = info[2].As(); + + for (uint32_t i = 0; i < params.Length(); i++) { - continue; - } + Napi::Value v = params[i]; - auto value = v.As(); + if (!v.IsString()) + { + throw Napi::TypeError::New(env, "Expected array item to be string"); + } - args.push_back(value.Utf8Value()); + auto value = v.As(); + + args.push_back(value.Utf8Value()); + } } + this->thread = std::thread(libmediasoup, this, version.Utf8Value(), args); } @@ -185,6 +202,15 @@ void WorkerChannel::OnError(const uint8_t code) void WorkerChannel::Send(const Napi::CallbackInfo& info) { + + if (info.Length() != 1) { + throw Napi::TypeError::New(info.Env(), "Expected one argument"); + } + + if (!info[0].IsTypedArray()) { + throw Napi::TypeError::New(info.Env(), "Expected arg to be a Uint8Array"); + } + // Copy the message into its own memory. auto message = info[0].As(); auto data = new uint8_t[message.ByteLength()]; @@ -196,6 +222,10 @@ void WorkerChannel::Send(const Napi::CallbackInfo& info) this->messages.push_back(data); } + if (!this->handle) { + return; + } + // Notify mediasoup about the new message. uv_async_send(const_cast(this->handle)); } From 5f64e7d1009818e4cab566ceadb0d5aa21a77e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 11:05:48 +0200 Subject: [PATCH 39/80] add missing include --- node/workerChannel/src/workerChannel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index 787a6db7ae..f81c408d1c 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -1,8 +1,7 @@ #include "../include/workerChannel.hpp" #include "napi.h" - #include -#include +#include void deleteMessage(uint8_t* message, uint32_t messageLen, size_t ctx) { From bc98653226b6c6e8cdee754649e97bee334b4d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 11:08:06 +0200 Subject: [PATCH 40/80] windows: linker option to allow multiple symbols Temporal work around until libmediasoup-worker does not expose libuv symbols --- node/workerChannel/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index b016b7e846..2b8c0518e2 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -35,7 +35,7 @@ 'AdditionalOptions': [ '/MT' ], }, 'VCLinkerTool': { - 'AdditionalOptions': [ '/NODEFAULTLIB:library' ], + 'AdditionalOptions': ['/FORCE:MULTIPLE'], }, } }], From 8c4bc936320a5b647d92bddebc65964e5b2452e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 11:11:30 +0200 Subject: [PATCH 41/80] format --- node/workerChannel/src/workerChannel.cpp | 34 +++++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/node/workerChannel/src/workerChannel.cpp b/node/workerChannel/src/workerChannel.cpp index f81c408d1c..bb04b947dd 100644 --- a/node/workerChannel/src/workerChannel.cpp +++ b/node/workerChannel/src/workerChannel.cpp @@ -85,13 +85,18 @@ Napi::Object WorkerChannel::Init(Napi::Env env, Napi::Object exports) WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { - auto env = info.Env(); + auto env = info.Env(); - if (info.Length() < 2) { + if (info.Length() < 2) + { throw Napi::TypeError::New(env, "Expected at least two arguments"); - } else if (!info[0].IsFunction()) { + } + else if (!info[0].IsFunction()) + { throw Napi::TypeError::New(env, "Expected first arg to be function"); - } else if (!info[1].IsString()) { + } + else if (!info[1].IsString()) + { throw Napi::TypeError::New(env, "Expected second arg to be string"); } @@ -102,12 +107,14 @@ WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap< std::vector args = { "" }; - if (info.Length() == 3) { - if (!info[2].IsArray()) { + if (info.Length() == 3) + { + if (!info[2].IsArray()) + { throw Napi::TypeError::New(env, "Expected third arg to be array"); } - auto params = info[2].As(); + auto params = info[2].As(); for (uint32_t i = 0; i < params.Length(); i++) { @@ -124,7 +131,6 @@ WorkerChannel::WorkerChannel(const Napi::CallbackInfo& info) : Napi::ObjectWrap< } } - this->thread = std::thread(libmediasoup, this, version.Utf8Value(), args); } @@ -132,7 +138,7 @@ WorkerChannel::~WorkerChannel() { std::lock_guard guard(this->mutex); - for (const auto* message: this->messages) + for (const auto* message : this->messages) { delete[] message; } @@ -201,12 +207,13 @@ void WorkerChannel::OnError(const uint8_t code) void WorkerChannel::Send(const Napi::CallbackInfo& info) { - - if (info.Length() != 1) { + if (info.Length() != 1) + { throw Napi::TypeError::New(info.Env(), "Expected one argument"); } - if (!info[0].IsTypedArray()) { + if (!info[0].IsTypedArray()) + { throw Napi::TypeError::New(info.Env(), "Expected arg to be a Uint8Array"); } @@ -221,7 +228,8 @@ void WorkerChannel::Send(const Napi::CallbackInfo& info) this->messages.push_back(data); } - if (!this->handle) { + if (!this->handle) + { return; } From 95b822590f2adffd2b23dafbe17c776c54581733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 11:18:37 +0200 Subject: [PATCH 42/80] use EnhancedEventEmitter rather than EventEmitter --- node/workerChannel/src/index.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/node/workerChannel/src/index.ts b/node/workerChannel/src/index.ts index 73a6b3f97d..e6e49c18ce 100644 --- a/node/workerChannel/src/index.ts +++ b/node/workerChannel/src/index.ts @@ -1,4 +1,5 @@ import { EventEmitter } from 'events'; +import { EnhancedEventEmitter } from '../../src/enhancedEvents'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; @@ -7,7 +8,12 @@ const { WorkerChannel: NativeWorkerChannel } = require( `../build/${buildType}/worker-channel.node` ); -export class WorkerChannel extends EventEmitter { +export type WorkerChannelEvents = { + data: [Uint8Array]; + error: [number]; +}; + +export class WorkerChannel extends EnhancedEventEmitter { private emitter: EventEmitter; private workerChannel: typeof NativeWorkerChannel; @@ -22,11 +28,11 @@ export class WorkerChannel extends EventEmitter { ); this.emitter.on('data', data => { - this.emit('data', data); + this.safeEmit('data', data); }); this.emitter.on('error', code => { - this.emit('error', code); + this.safeEmit('error', code); }); } From 1fec8b90bfe2215170e609af1a2e47c1a6b1f108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 12:30:56 +0200 Subject: [PATCH 43/80] be able to provide a specific libmediasoup_worker.a library --- node/workerChannel/binding.gyp | 16 ++++++++++++---- node/workerChannel/npm-scripts.mjs | 4 ++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 2b8c0518e2..696de29f79 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -1,6 +1,7 @@ { "variables": { - "mediasoup_build_type%": "Release" + "mediasoup_build_type%": "Release", + "mediasoup_worker_lib%": "" }, "targets": [ { @@ -15,10 +16,17 @@ " Date: Fri, 17 May 2024 12:38:31 +0200 Subject: [PATCH 44/80] binding.gyp: use single quotes --- node/workerChannel/binding.gyp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 696de29f79..a2f0d36a52 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -1,14 +1,14 @@ { - "variables": { - "mediasoup_build_type%": "Release", - "mediasoup_worker_lib%": "" + 'variables': { + 'mediasoup_build_type%': 'Release', + 'mediasoup_worker_lib%': '' }, "targets": [ { - "target_name": "worker-channel", - "sources": [ - "src/binding.cpp", - "src/workerChannel.cpp" + 'target_name': 'worker-channel', + 'sources': [ + 'src/binding.cpp', + 'src/workerChannel.cpp' ], 'cflags!': [ '-fno-exceptions' ], 'cflags_cc!': [ '-fno-exceptions' ], @@ -18,22 +18,22 @@ ], 'conditions': [ ['mediasoup_worker_lib==""', { - "libraries": [ - "<(module_root_dir)/../../worker/out/<(mediasoup_build_type)/build/libmediasoup-worker.a" + 'libraries': [ + '<(module_root_dir)/../../worker/out/<(mediasoup_build_type)/build/libmediasoup-worker.a' ], }, { "libraries": [ - "<(mediasoup_worker_lib)" + '<(mediasoup_worker_lib)' ], } ], ['OS=="win"', { - "libraries": [ - "Ws2_32.lib", "Dbghelp.lib", "Crypt32.lib", "Userenv.lib", + 'libraries': [ + 'Ws2_32.lib', 'Dbghelp.lib', 'Crypt32.lib', 'Userenv.lib', ], - "msvs_settings": { - "VCCLCompilerTool": { - "ExceptionHandling": 1, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'ExceptionHandling': 1, # RuntimeLibrary: # 0 - MultiThreaded (/MT) # 1 - MultiThreadedDebug (/MTd) @@ -48,8 +48,8 @@ } }], ['OS=="mac"', { - "xcode_settings": { - "CLANG_CXX_LIBRARY": "libc++", + 'xcode_settings': { + "CLANG_CXX_LIBRARY": 'libc++', 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', # TODO: This should be the same as the one used for libmediasoup # Is it really needed? From 76426445b08526a8188f02501290f3625cfaa316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 12:48:14 +0200 Subject: [PATCH 45/80] Windows: only add debug symbols on Debug build type --- node/workerChannel/binding.gyp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index a2f0d36a52..218092d8f3 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -28,8 +28,13 @@ } ], ['OS=="win"', { + 'conditions': [ + ['mediasoup_build_type=="Debug"', { + 'libraries': ['Dbghelp.lib'], + }], + ], 'libraries': [ - 'Ws2_32.lib', 'Dbghelp.lib', 'Crypt32.lib', 'Userenv.lib', + 'Ws2_32.lib', 'Crypt32.lib', 'Userenv.lib', ], 'msvs_settings': { 'VCCLCompilerTool': { From 00a2b1ae2dbcfd284721b9194cb642a41c81dacf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 13:00:23 +0200 Subject: [PATCH 46/80] npm-scripts: use a cons for addon path --- npm-scripts.mjs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index c4f7d162bd..b3951699db 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -22,18 +22,22 @@ const WORKER_RELEASE_BIN_PATH = `${WORKER_RELEASE_DIR}/${WORKER_RELEASE_BIN}`; const WORKER_PREBUILD_DIR = 'worker/prebuild'; const WORKER_PREBUILD_TAR = getWorkerPrebuildTarName(); const WORKER_PREBUILD_TAR_PATH = `${WORKER_PREBUILD_DIR}/${WORKER_PREBUILD_TAR}`; +const WORKER_CHANNEL_ADDON_PATH = 'node/workerChannel'; const GH_OWNER = 'versatica'; const GH_REPO = 'mediasoup'; // Paths for ESLint to check. Converted to string for convenience. const ESLINT_PATHS = [ 'node/src', - 'node/workerChannel', + WORKER_CHANNEL_ADDON_PATH, 'npm-scripts.mjs', 'worker/scripts', ].join(' '); // Paths for ESLint to ignore. Converted to string argument for convenience. -const ESLINT_IGNORE_PATTERN_ARGS = ['node/src/fbs', '/node/workerChannel/lib'] +const ESLINT_IGNORE_PATTERN_ARGS = [ + 'node/src/fbs', + `${WORKER_CHANNEL_ADDON_PATH}/lib`, +] .map(entry => `--ignore-pattern ${entry}`) .join(' '); // Paths for Prettier to check/write. Converted to string for convenience. @@ -46,8 +50,8 @@ const PRETTIER_PATHS = [ 'doc', 'node/src', 'node/tsconfig.json', - 'node/workerChannel/src', - 'node/workerChannel/tsconfig.json', + `${WORKER_CHANNEL_ADDON_PATH}/src`, + `${WORKER_CHANNEL_ADDON_PATH}/tsconfig.json`, 'npm-scripts.mjs', 'package.json', 'worker/scripts', @@ -351,8 +355,8 @@ function buildWorkerLib() { executeCmd(`"${PYTHON}" -m invoke -r worker libmediasoup-worker`); - executeCmd('cd node/workerChannel && npm run binding:build'); - executeCmd('cd node/workerChannel && npm run typescript:build'); + executeCmd(`cd ${WORKER_CHANNEL_ADDON_PATH} && npm run binding:build`); + executeCmd(`cd ${WORKER_CHANNEL_ADDON_PATH} && npm run typescript:build`); } function cleanWorkerArtifacts() { From 5e3b4ad937805acab4389e698179f0093a9f3036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 13:28:34 +0200 Subject: [PATCH 47/80] package.json: fix name and description --- node/workerChannel/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/workerChannel/package.json b/node/workerChannel/package.json index d0918bb444..4dd765c046 100644 --- a/node/workerChannel/package.json +++ b/node/workerChannel/package.json @@ -1,7 +1,7 @@ { - "name": "mediasoup worker native module", + "name": "mediasoup worker channel", "version": "0.0.0", - "description": "Node.js Addon do communicate with mediasoup worker", + "description": "Node.js Addon to communicate with mediasoup worker", "main": "lib/index.js", "types": "lib/index.d.ts", "private": true, From 8f46779c189f9f5dd8dc9a3e744183e34ecc9fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Fri, 17 May 2024 13:28:48 +0200 Subject: [PATCH 48/80] Revert "Windows: only add debug symbols on Debug build type" This reverts commit 76426445b08526a8188f02501290f3625cfaa316. debug library is needed to create minidump files when the process crashes. --- node/workerChannel/binding.gyp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/node/workerChannel/binding.gyp b/node/workerChannel/binding.gyp index 218092d8f3..a2f0d36a52 100644 --- a/node/workerChannel/binding.gyp +++ b/node/workerChannel/binding.gyp @@ -28,13 +28,8 @@ } ], ['OS=="win"', { - 'conditions': [ - ['mediasoup_build_type=="Debug"', { - 'libraries': ['Dbghelp.lib'], - }], - ], 'libraries': [ - 'Ws2_32.lib', 'Crypt32.lib', 'Userenv.lib', + 'Ws2_32.lib', 'Dbghelp.lib', 'Crypt32.lib', 'Userenv.lib', ], 'msvs_settings': { 'VCCLCompilerTool': { From 53025e73137ad649c529f3a52e2438416d58dec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 11:09:24 +0200 Subject: [PATCH 49/80] make workerChannel a completely separate npm module --- node/src/Channel.ts | 2 +- node/src/Worker.ts | 2 +- node/workerChannel/package-lock.json | 30 +++++++++++++++++++++++---- node/workerChannel/package.json | 5 +++-- node/workerChannel/src/index.ts | 4 ++-- package-lock.json | 31 ++++++++++++++++++++++++---- package.json | 3 ++- 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/node/src/Channel.ts b/node/src/Channel.ts index b36eaf01c6..abab10c2eb 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -1,7 +1,7 @@ import * as os from 'node:os'; import { info, warn } from 'node:console'; import * as flatbuffers from 'flatbuffers'; -import { WorkerChannel } from '../workerChannel'; +import { WorkerChannel } from 'worker-channel'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; import { InvalidStateError } from './errors'; diff --git a/node/src/Worker.ts b/node/src/Worker.ts index 27e15bdf66..d7c9bee5ef 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -1,7 +1,7 @@ import * as process from 'node:process'; import * as path from 'node:path'; +import { WorkerChannel } from 'worker-channel'; import { version } from './'; -import { WorkerChannel } from '../workerChannel'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; import * as ortc from './ortc'; diff --git a/node/workerChannel/package-lock.json b/node/workerChannel/package-lock.json index e4c39de2b8..8ea0568616 100644 --- a/node/workerChannel/package-lock.json +++ b/node/workerChannel/package-lock.json @@ -1,19 +1,41 @@ { - "name": "mediasoup worker native module", - "version": "0.0.0", + "name": "worker-channel", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "mediasoup worker native module", - "version": "0.0.0", + "name": "worker-channel", + "version": "1.0.0", "dependencies": { + "debug": "^4.3.4", "node-addon-api": "*" }, "devDependencies": { "typescript": "^5.4.5" } }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/node-addon-api": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", diff --git a/node/workerChannel/package.json b/node/workerChannel/package.json index 4dd765c046..bd96eb166a 100644 --- a/node/workerChannel/package.json +++ b/node/workerChannel/package.json @@ -1,6 +1,6 @@ { - "name": "mediasoup worker channel", - "version": "0.0.0", + "name": "worker-channel", + "version": "1.0.0", "description": "Node.js Addon to communicate with mediasoup worker", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -13,6 +13,7 @@ "test": "node npm-scripts.mjs test" }, "dependencies": { + "debug": "^4.3.4", "node-addon-api": "*" }, "devDependencies": { diff --git a/node/workerChannel/src/index.ts b/node/workerChannel/src/index.ts index e6e49c18ce..de44b5bced 100644 --- a/node/workerChannel/src/index.ts +++ b/node/workerChannel/src/index.ts @@ -1,5 +1,5 @@ import { EventEmitter } from 'events'; -import { EnhancedEventEmitter } from '../../src/enhancedEvents'; +import { EnhancedEventEmitter } from './enhancedEvents'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; @@ -9,7 +9,7 @@ const { WorkerChannel: NativeWorkerChannel } = require( ); export type WorkerChannelEvents = { - data: [Uint8Array]; + data: [Buffer]; error: [number]; }; diff --git a/package-lock.json b/package-lock.json index 8caf01a522..1f8f8b2da0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "ini": "^4.1.2", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.1.0" + "tar": "^7.1.0", + "worker-channel": "file:node/workerChannel" }, "devDependencies": { "@octokit/rest": "^20.1.1", @@ -4889,6 +4890,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-addon-api": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", + "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -6232,6 +6241,10 @@ "node": ">= 8" } }, + "node_modules/worker-channel": { + "resolved": "node/workerChannel", + "link": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6340,11 +6353,9 @@ } }, "node/workerChannel": { - "name": "mediasoup worker native module", + "name": "worker-channel", "version": "0.0.0", - "extraneous": true, "dependencies": { - "bindings": "*", "node-addon-api": "*" }, "devDependencies": { @@ -9868,6 +9879,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node-addon-api": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", + "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==" + }, "node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -10759,6 +10775,13 @@ "isexe": "^2.0.0" } }, + "worker-channel": { + "version": "file:node/workerChannel", + "requires": { + "node-addon-api": "*", + "typescript": "^5.4.5" + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 0eb048158f..fd6bbf523a 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,8 @@ "ini": "^4.1.2", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.1.0" + "tar": "^7.1.0", + "worker-channel": "file:node/workerChannel" }, "devDependencies": { "@octokit/rest": "^20.1.1", From 4237fc26fd1a899fb750120e521ffea375d80406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 11:24:37 +0200 Subject: [PATCH 50/80] make workerChannel a completely separate npm module --- node/src/Channel.ts | 2 ++ node/workerChannel/npm-scripts.mjs | 2 +- node/workerChannel/src/test.ts | 16 ++++++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/node/src/Channel.ts b/node/src/Channel.ts index abab10c2eb..ed55f8b166 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -321,6 +321,8 @@ export class Channel extends EnhancedEventEmitter { // do not point to the builder buffer overriding others info. const buffer = this.#bufferBuilder.asUint8Array(); + console.warn('buffer: ', buffer); + // Clear the buffer builder so it's reused for the next request. this.#bufferBuilder.clear(); diff --git a/node/workerChannel/npm-scripts.mjs b/node/workerChannel/npm-scripts.mjs index 5a8c99cc11..9691cd2770 100644 --- a/node/workerChannel/npm-scripts.mjs +++ b/node/workerChannel/npm-scripts.mjs @@ -82,7 +82,7 @@ function buildBinding() { function testNode() { logInfo('testNode()'); - executeCmd('node lib/test.js'); + executeCmd('node --test-only lib/test.js'); } function executeCmd(command, exitOnError = true) { diff --git a/node/workerChannel/src/test.ts b/node/workerChannel/src/test.ts index e780597995..5184028902 100644 --- a/node/workerChannel/src/test.ts +++ b/node/workerChannel/src/test.ts @@ -1,5 +1,5 @@ import assert = require('node:assert'); -import { beforeEach, describe, it } from 'node:test'; +import { afterEach, beforeEach, describe, it } from 'node:test'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; @@ -8,6 +8,14 @@ const { WorkerChannel: NativeWorkerChannel } = require( `../build/${buildType}/worker-channel.node` ); +const closeRequest = new Uint8Array([ + 12, 0, 0, 0, 8, 0, 10, 0, 9, 0, 4, + 0, 8, 0, 0, 0, 16, 0, 0, 0, 0, 1, + 10, 0, 12, 0, 8, 0, 0, 0, 4, 0, 10, + 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +]); + describe('NativeWorkerChannel constructor', () => { it('fails if no argument is passed', () => { assert.throws(() => new NativeWorkerChannel(), TypeError); @@ -79,7 +87,7 @@ describe('NativeWorkerChannel constructor', () => { }); }); -describe('NativeWorkerChannel send', () => { +describe.only('NativeWorkerChannel send', () => { const version = 'X'; const func = () => {}; @@ -89,6 +97,10 @@ describe('NativeWorkerChannel send', () => { workerChannel = new NativeWorkerChannel(func, version); }); + afterEach(() => { + workerChannel.send(closeRequest); + }); + [true, 1, 'one', () => {}].forEach(data => { it(`fails if send() is called with a value (${data}) different than an Uint8Array`, () => { assert.throws(() => workerChannel.send(data), TypeError); From 54cc2a2f8bdfa5d16570ed62d767ba05476769eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 11:26:17 +0200 Subject: [PATCH 51/80] add missing Logger and enhancedEvents files --- node/workerChannel/src/Logger.ts | 39 +++++++ node/workerChannel/src/enhancedEvents.ts | 140 +++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 node/workerChannel/src/Logger.ts create mode 100644 node/workerChannel/src/enhancedEvents.ts diff --git a/node/workerChannel/src/Logger.ts b/node/workerChannel/src/Logger.ts new file mode 100644 index 0000000000..c753b1c9f1 --- /dev/null +++ b/node/workerChannel/src/Logger.ts @@ -0,0 +1,39 @@ +import debug from 'debug'; + +const APP_NAME = 'worker-channel'; + +export class Logger { + readonly #debug: debug.Debugger; + readonly #warn: debug.Debugger; + readonly #error: debug.Debugger; + + constructor(prefix?: string) { + if (prefix) { + this.#debug = debug(`${APP_NAME}:${prefix}`); + this.#warn = debug(`${APP_NAME}:WARN:${prefix}`); + this.#error = debug(`${APP_NAME}:ERROR:${prefix}`); + } else { + this.#debug = debug(APP_NAME); + this.#warn = debug(`${APP_NAME}:WARN`); + this.#error = debug(`${APP_NAME}:ERROR`); + } + + /* eslint-disable no-console */ + this.#debug.log = console.info.bind(console); + this.#warn.log = console.warn.bind(console); + this.#error.log = console.error.bind(console); + /* eslint-enable no-console */ + } + + get debug(): debug.Debugger { + return this.#debug; + } + + get warn(): debug.Debugger { + return this.#warn; + } + + get error(): debug.Debugger { + return this.#error; + } +} diff --git a/node/workerChannel/src/enhancedEvents.ts b/node/workerChannel/src/enhancedEvents.ts new file mode 100644 index 0000000000..a5458d3a08 --- /dev/null +++ b/node/workerChannel/src/enhancedEvents.ts @@ -0,0 +1,140 @@ +import { EventEmitter, once } from 'node:events'; +import { Logger } from './Logger'; + +const enhancedEventEmitterLogger = new Logger('EnhancedEventEmitter'); + +type Events = Record; + +export class EnhancedEventEmitter< + E extends Events = Events, +> extends EventEmitter { + constructor() { + super(); + this.setMaxListeners(Infinity); + } + + emit(eventName: K, ...args: E[K]): boolean { + return super.emit(eventName, ...args); + } + + /** + * Special addition to the EventEmitter API. + */ + safeEmit(eventName: K, ...args: E[K]): boolean { + try { + return super.emit(eventName, ...args); + } catch (error) { + enhancedEventEmitterLogger.error( + 'safeEmit() | event listener threw an error [eventName:%s]:%o', + eventName, + error + ); + + try { + super.emit('listenererror', eventName, error); + } catch (error2) { + // Ignore it. + } + + return Boolean(super.listenerCount(eventName)); + } + } + + on( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.on(eventName, listener as (...args: any[]) => void); + + return this; + } + + off( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.off(eventName, listener as (...args: any[]) => void); + + return this; + } + + addListener( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.on(eventName, listener as (...args: any[]) => void); + + return this; + } + + prependListener( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.prependListener(eventName, listener as (...args: any[]) => void); + + return this; + } + + once( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.once(eventName, listener as (...args: any[]) => void); + + return this; + } + + prependOnceListener( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.prependOnceListener(eventName, listener as (...args: any[]) => void); + + return this; + } + + removeListener( + eventName: K, + listener: (...args: E[K]) => void + ): this { + super.off(eventName, listener as (...args: any[]) => void); + + return this; + } + + removeAllListeners(eventName?: K): this { + super.removeAllListeners(eventName); + + return this; + } + + listenerCount(eventName: K): number { + return super.listenerCount(eventName); + } + + listeners(eventName: K): Function[] { + return super.listeners(eventName); + } + + rawListeners(eventName: K): Function[] { + return super.rawListeners(eventName); + } +} + +/** + * TypeScript version of events.once(): + * https://nodejs.org/api/events.html#eventsonceemitter-name-options + * + * Usage example: + * ```ts + * await enhancedOnce(videoConsumer, 'producerpause'); + * ```` + */ +export async function enhancedOnce( + emmiter: EnhancedEventEmitter, + eventName: keyof E & string, + options?: any +): Promise { + return once(emmiter, eventName, options); +} From 17bbc6c319220a7dbbfcde659e96f7e2ee313b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 11:27:23 +0200 Subject: [PATCH 52/80] Revert "make workerChannel a completely separate npm module" This reverts commit 4237fc26fd1a899fb750120e521ffea375d80406. --- node/src/Channel.ts | 2 -- node/workerChannel/npm-scripts.mjs | 2 +- node/workerChannel/src/test.ts | 16 ++-------------- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/node/src/Channel.ts b/node/src/Channel.ts index ed55f8b166..abab10c2eb 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -321,8 +321,6 @@ export class Channel extends EnhancedEventEmitter { // do not point to the builder buffer overriding others info. const buffer = this.#bufferBuilder.asUint8Array(); - console.warn('buffer: ', buffer); - // Clear the buffer builder so it's reused for the next request. this.#bufferBuilder.clear(); diff --git a/node/workerChannel/npm-scripts.mjs b/node/workerChannel/npm-scripts.mjs index 9691cd2770..5a8c99cc11 100644 --- a/node/workerChannel/npm-scripts.mjs +++ b/node/workerChannel/npm-scripts.mjs @@ -82,7 +82,7 @@ function buildBinding() { function testNode() { logInfo('testNode()'); - executeCmd('node --test-only lib/test.js'); + executeCmd('node lib/test.js'); } function executeCmd(command, exitOnError = true) { diff --git a/node/workerChannel/src/test.ts b/node/workerChannel/src/test.ts index 5184028902..e780597995 100644 --- a/node/workerChannel/src/test.ts +++ b/node/workerChannel/src/test.ts @@ -1,5 +1,5 @@ import assert = require('node:assert'); -import { afterEach, beforeEach, describe, it } from 'node:test'; +import { beforeEach, describe, it } from 'node:test'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; @@ -8,14 +8,6 @@ const { WorkerChannel: NativeWorkerChannel } = require( `../build/${buildType}/worker-channel.node` ); -const closeRequest = new Uint8Array([ - 12, 0, 0, 0, 8, 0, 10, 0, 9, 0, 4, - 0, 8, 0, 0, 0, 16, 0, 0, 0, 0, 1, - 10, 0, 12, 0, 8, 0, 0, 0, 4, 0, 10, - 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -]); - describe('NativeWorkerChannel constructor', () => { it('fails if no argument is passed', () => { assert.throws(() => new NativeWorkerChannel(), TypeError); @@ -87,7 +79,7 @@ describe('NativeWorkerChannel constructor', () => { }); }); -describe.only('NativeWorkerChannel send', () => { +describe('NativeWorkerChannel send', () => { const version = 'X'; const func = () => {}; @@ -97,10 +89,6 @@ describe.only('NativeWorkerChannel send', () => { workerChannel = new NativeWorkerChannel(func, version); }); - afterEach(() => { - workerChannel.send(closeRequest); - }); - [true, 1, 'one', () => {}].forEach(data => { it(`fails if send() is called with a value (${data}) different than an Uint8Array`, () => { assert.throws(() => workerChannel.send(data), TypeError); From 9c170dab137cddfbf563fa04f468e671f8bb1918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 12:40:16 +0200 Subject: [PATCH 53/80] do not use a separate TS or npm project for WorkerChannel --- node/src/Channel.ts | 2 +- node/src/Worker.ts | 2 +- node/tsconfig.json | 2 +- node/workerChannel/.npmrc | 4 - node/workerChannel/package-lock.json | 61 -------- node/workerChannel/package.json | 22 --- .../{npm-scripts.mjs => scripts.mjs} | 33 ----- node/workerChannel/src/Logger.ts | 39 ----- node/workerChannel/src/enhancedEvents.ts | 140 ------------------ node/workerChannel/src/index.ts | 2 +- node/workerChannel/tsconfig.json | 20 --- npm-scripts.mjs | 5 +- package-lock.json | 19 +-- package.json | 4 +- 14 files changed, 14 insertions(+), 341 deletions(-) delete mode 100644 node/workerChannel/.npmrc delete mode 100644 node/workerChannel/package-lock.json delete mode 100644 node/workerChannel/package.json rename node/workerChannel/{npm-scripts.mjs => scripts.mjs} (78%) delete mode 100644 node/workerChannel/src/Logger.ts delete mode 100644 node/workerChannel/src/enhancedEvents.ts delete mode 100644 node/workerChannel/tsconfig.json diff --git a/node/src/Channel.ts b/node/src/Channel.ts index abab10c2eb..a969f5983d 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -1,7 +1,7 @@ import * as os from 'node:os'; import { info, warn } from 'node:console'; import * as flatbuffers from 'flatbuffers'; -import { WorkerChannel } from 'worker-channel'; +import { WorkerChannel } from '../workerChannel/src'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; import { InvalidStateError } from './errors'; diff --git a/node/src/Worker.ts b/node/src/Worker.ts index d7c9bee5ef..62afaa164e 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -1,6 +1,6 @@ import * as process from 'node:process'; import * as path from 'node:path'; -import { WorkerChannel } from 'worker-channel'; +import { WorkerChannel } from '../workerChannel/src'; import { version } from './'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; diff --git a/node/tsconfig.json b/node/tsconfig.json index 87394576c7..3271cdb50c 100644 --- a/node/tsconfig.json +++ b/node/tsconfig.json @@ -10,7 +10,7 @@ "declaration": true, "declarationMap": true }, - "include": ["src"], + "include": ["src", "workerChannel/src"], "watchOptions": { "watchFile": "useFsEvents", "watchDirectory": "useFsEvents", diff --git a/node/workerChannel/.npmrc b/node/workerChannel/.npmrc deleted file mode 100644 index 05600b0d16..0000000000 --- a/node/workerChannel/.npmrc +++ /dev/null @@ -1,4 +0,0 @@ -# Generate package-lock.json. -package-lock=true -# For bad node/npm version to throw actual error. -engine-strict=true diff --git a/node/workerChannel/package-lock.json b/node/workerChannel/package-lock.json deleted file mode 100644 index 8ea0568616..0000000000 --- a/node/workerChannel/package-lock.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "worker-channel", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "worker-channel", - "version": "1.0.0", - "dependencies": { - "debug": "^4.3.4", - "node-addon-api": "*" - }, - "devDependencies": { - "typescript": "^5.4.5" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/node-addon-api": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", - "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==", - "engines": { - "node": "^18 || ^20 || >= 21" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - } - } -} diff --git a/node/workerChannel/package.json b/node/workerChannel/package.json deleted file mode 100644 index bd96eb166a..0000000000 --- a/node/workerChannel/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "worker-channel", - "version": "1.0.0", - "description": "Node.js Addon to communicate with mediasoup worker", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "private": true, - "gypfile": true, - "scripts": { - "binding:build": "node npm-scripts.mjs binding:build", - "typescript:build": "node npm-scripts.mjs typescript:build", - "typescript:watch": "node npm-scripts.mjs typescript:watch", - "test": "node npm-scripts.mjs test" - }, - "dependencies": { - "debug": "^4.3.4", - "node-addon-api": "*" - }, - "devDependencies": { - "typescript": "^5.4.5" - } -} diff --git a/node/workerChannel/npm-scripts.mjs b/node/workerChannel/scripts.mjs similarity index 78% rename from node/workerChannel/npm-scripts.mjs rename to node/workerChannel/scripts.mjs index 5a8c99cc11..430510acc6 100644 --- a/node/workerChannel/npm-scripts.mjs +++ b/node/workerChannel/scripts.mjs @@ -18,21 +18,7 @@ async function run() { break; } - case 'typescript:build': { - buildTypescript(); - - break; - } - - case 'typescript:watch': { - deleteNodeLib(); - executeCmd(`tsc --project ./ --watch ${args}`); - - break; - } - case 'test': { - buildTypescript(); testNode(); break; @@ -46,28 +32,9 @@ async function run() { } } -function deleteNodeLib() { - if (!fs.existsSync('node/lib')) { - return; - } - - logInfo('deleteNodeLib()'); - - fs.rmSync('node/lib', { recursive: true, force: true }); -} - -function buildTypescript() { - logInfo('buildTypescript()'); - - deleteNodeLib(); - executeCmd('tsc --project ./'); -} - function buildBinding() { logInfo('buildBinding()'); - executeCmd('npm ci --ignore-scripts'); - const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; process.env.GYP_DEFINES = `mediasoup_build_type=${buildType}`; diff --git a/node/workerChannel/src/Logger.ts b/node/workerChannel/src/Logger.ts deleted file mode 100644 index c753b1c9f1..0000000000 --- a/node/workerChannel/src/Logger.ts +++ /dev/null @@ -1,39 +0,0 @@ -import debug from 'debug'; - -const APP_NAME = 'worker-channel'; - -export class Logger { - readonly #debug: debug.Debugger; - readonly #warn: debug.Debugger; - readonly #error: debug.Debugger; - - constructor(prefix?: string) { - if (prefix) { - this.#debug = debug(`${APP_NAME}:${prefix}`); - this.#warn = debug(`${APP_NAME}:WARN:${prefix}`); - this.#error = debug(`${APP_NAME}:ERROR:${prefix}`); - } else { - this.#debug = debug(APP_NAME); - this.#warn = debug(`${APP_NAME}:WARN`); - this.#error = debug(`${APP_NAME}:ERROR`); - } - - /* eslint-disable no-console */ - this.#debug.log = console.info.bind(console); - this.#warn.log = console.warn.bind(console); - this.#error.log = console.error.bind(console); - /* eslint-enable no-console */ - } - - get debug(): debug.Debugger { - return this.#debug; - } - - get warn(): debug.Debugger { - return this.#warn; - } - - get error(): debug.Debugger { - return this.#error; - } -} diff --git a/node/workerChannel/src/enhancedEvents.ts b/node/workerChannel/src/enhancedEvents.ts deleted file mode 100644 index a5458d3a08..0000000000 --- a/node/workerChannel/src/enhancedEvents.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { EventEmitter, once } from 'node:events'; -import { Logger } from './Logger'; - -const enhancedEventEmitterLogger = new Logger('EnhancedEventEmitter'); - -type Events = Record; - -export class EnhancedEventEmitter< - E extends Events = Events, -> extends EventEmitter { - constructor() { - super(); - this.setMaxListeners(Infinity); - } - - emit(eventName: K, ...args: E[K]): boolean { - return super.emit(eventName, ...args); - } - - /** - * Special addition to the EventEmitter API. - */ - safeEmit(eventName: K, ...args: E[K]): boolean { - try { - return super.emit(eventName, ...args); - } catch (error) { - enhancedEventEmitterLogger.error( - 'safeEmit() | event listener threw an error [eventName:%s]:%o', - eventName, - error - ); - - try { - super.emit('listenererror', eventName, error); - } catch (error2) { - // Ignore it. - } - - return Boolean(super.listenerCount(eventName)); - } - } - - on( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.on(eventName, listener as (...args: any[]) => void); - - return this; - } - - off( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.off(eventName, listener as (...args: any[]) => void); - - return this; - } - - addListener( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.on(eventName, listener as (...args: any[]) => void); - - return this; - } - - prependListener( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.prependListener(eventName, listener as (...args: any[]) => void); - - return this; - } - - once( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.once(eventName, listener as (...args: any[]) => void); - - return this; - } - - prependOnceListener( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.prependOnceListener(eventName, listener as (...args: any[]) => void); - - return this; - } - - removeListener( - eventName: K, - listener: (...args: E[K]) => void - ): this { - super.off(eventName, listener as (...args: any[]) => void); - - return this; - } - - removeAllListeners(eventName?: K): this { - super.removeAllListeners(eventName); - - return this; - } - - listenerCount(eventName: K): number { - return super.listenerCount(eventName); - } - - listeners(eventName: K): Function[] { - return super.listeners(eventName); - } - - rawListeners(eventName: K): Function[] { - return super.rawListeners(eventName); - } -} - -/** - * TypeScript version of events.once(): - * https://nodejs.org/api/events.html#eventsonceemitter-name-options - * - * Usage example: - * ```ts - * await enhancedOnce(videoConsumer, 'producerpause'); - * ```` - */ -export async function enhancedOnce( - emmiter: EnhancedEventEmitter, - eventName: keyof E & string, - options?: any -): Promise { - return once(emmiter, eventName, options); -} diff --git a/node/workerChannel/src/index.ts b/node/workerChannel/src/index.ts index de44b5bced..bcad469c31 100644 --- a/node/workerChannel/src/index.ts +++ b/node/workerChannel/src/index.ts @@ -1,5 +1,5 @@ import { EventEmitter } from 'events'; -import { EnhancedEventEmitter } from './enhancedEvents'; +import { EnhancedEventEmitter } from '../../src/enhancedEvents'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; diff --git a/node/workerChannel/tsconfig.json b/node/workerChannel/tsconfig.json deleted file mode 100644 index 87394576c7..0000000000 --- a/node/workerChannel/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compileOnSave": true, - "compilerOptions": { - "lib": ["es2021"], - "target": "esnext", - "module": "commonjs", - "moduleResolution": "node", - "strict": true, - "outDir": "lib", - "declaration": true, - "declarationMap": true - }, - "include": ["src"], - "watchOptions": { - "watchFile": "useFsEvents", - "watchDirectory": "useFsEvents", - "fallbackPolling": "dynamicPriority", - "synchronousWatchDirectory": true - } -} diff --git a/npm-scripts.mjs b/npm-scripts.mjs index b3951699db..025f3828d6 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -355,8 +355,9 @@ function buildWorkerLib() { executeCmd(`"${PYTHON}" -m invoke -r worker libmediasoup-worker`); - executeCmd(`cd ${WORKER_CHANNEL_ADDON_PATH} && npm run binding:build`); - executeCmd(`cd ${WORKER_CHANNEL_ADDON_PATH} && npm run typescript:build`); + executeCmd( + `cd ${WORKER_CHANNEL_ADDON_PATH} && node scripts.mjs binding:build` + ); } function cleanWorkerArtifacts() { diff --git a/package-lock.json b/package-lock.json index 1f8f8b2da0..87757ab3cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,10 +15,10 @@ "flatbuffers": "^24.3.25", "h264-profile-level-id": "^2.0.0", "ini": "^4.1.2", + "node-addon-api": "^8.0.0", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.1.0", - "worker-channel": "file:node/workerChannel" + "tar": "^7.1.0" }, "devDependencies": { "@octokit/rest": "^20.1.1", @@ -6241,10 +6241,6 @@ "node": ">= 8" } }, - "node_modules/worker-channel": { - "resolved": "node/workerChannel", - "link": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6354,8 +6350,10 @@ }, "node/workerChannel": { "name": "worker-channel", - "version": "0.0.0", + "version": "1.0.0", + "extraneous": true, "dependencies": { + "debug": "^4.3.4", "node-addon-api": "*" }, "devDependencies": { @@ -10775,13 +10773,6 @@ "isexe": "^2.0.0" } }, - "worker-channel": { - "version": "file:node/workerChannel", - "requires": { - "node-addon-api": "*", - "typescript": "^5.4.5" - } - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index fd6bbf523a..7fe61314b3 100644 --- a/package.json +++ b/package.json @@ -104,10 +104,10 @@ "flatbuffers": "^24.3.25", "h264-profile-level-id": "^2.0.0", "ini": "^4.1.2", + "node-addon-api": "^8.0.0", "node-fetch": "^3.3.2", "supports-color": "^9.4.0", - "tar": "^7.1.0", - "worker-channel": "file:node/workerChannel" + "tar": "^7.1.0" }, "devDependencies": { "@octokit/rest": "^20.1.1", From 4037cab7da741c1a5417ca8aa38ba404edae340d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 13:08:58 +0200 Subject: [PATCH 54/80] lint --- .eslintrc.js | 16 ---------------- node/workerChannel/scripts.mjs | 1 - npm-scripts.mjs | 6 +----- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d7bf3d6a6e..e69646071b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -175,20 +175,4 @@ eslintConfig.overrides.push({ }, }); -eslintConfig.overrides.push({ - files: ['node/workerChannel/src/*.ts'], - parser: '@typescript-eslint/parser', - parserOptions: { - ...eslintConfig.parserOptions, - project: 'node/workerChannel/tsconfig.json', - }, - plugins: [...eslintConfig.plugins, '@typescript-eslint'], - extends: [ - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - ...eslintConfig.extends, - ], - rules: { ...eslintConfig.rules, ...tsRules }, -}); - module.exports = eslintConfig; diff --git a/node/workerChannel/scripts.mjs b/node/workerChannel/scripts.mjs index 430510acc6..c46dbfe434 100644 --- a/node/workerChannel/scripts.mjs +++ b/node/workerChannel/scripts.mjs @@ -1,5 +1,4 @@ import * as process from 'node:process'; -import * as fs from 'node:fs'; import { execSync } from 'node:child_process'; const task = process.argv[2]; diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 025f3828d6..8407d8d7ae 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -34,10 +34,7 @@ const ESLINT_PATHS = [ 'worker/scripts', ].join(' '); // Paths for ESLint to ignore. Converted to string argument for convenience. -const ESLINT_IGNORE_PATTERN_ARGS = [ - 'node/src/fbs', - `${WORKER_CHANNEL_ADDON_PATH}/lib`, -] +const ESLINT_IGNORE_PATTERN_ARGS = ['node/src/fbs'] .map(entry => `--ignore-pattern ${entry}`) .join(' '); // Paths for Prettier to check/write. Converted to string for convenience. @@ -51,7 +48,6 @@ const PRETTIER_PATHS = [ 'node/src', 'node/tsconfig.json', `${WORKER_CHANNEL_ADDON_PATH}/src`, - `${WORKER_CHANNEL_ADDON_PATH}/tsconfig.json`, 'npm-scripts.mjs', 'package.json', 'worker/scripts', From 1b248e882e768ec2f3e06ec3c99215ec13d1303c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Mon, 20 May 2024 13:46:25 +0200 Subject: [PATCH 55/80] npm-scripts: test, --forceExit Node will clean the native addon once it garbage collects the corresponding JS instance. --- npm-scripts.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 8407d8d7ae..c4a169eff2 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -459,7 +459,7 @@ function flatcWorker() { function testNode() { logInfo('testNode()'); - executeCmd(`jest --silent false --detectOpenHandles ${args}`); + executeCmd(`jest --silent false --detectOpenHandles --forceExit ${args}`); } function testWorker() { From f437881f02221c4acbc2a481b4973b3a5b79e176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 10:17:56 +0200 Subject: [PATCH 56/80] workerChannel: add into node/src --- node/src/Channel.ts | 2 +- node/src/Worker.ts | 2 +- node/{ => src}/workerChannel/binding.gyp | 4 ++-- .../workerChannel/include/workerChannel.hpp | 0 node/{ => src}/workerChannel/scripts.mjs | 0 node/{ => src}/workerChannel/src/binding.cpp | 0 node/{ => src}/workerChannel/src/index.ts | 2 +- node/{ => src}/workerChannel/src/test.ts | 0 .../workerChannel/src/workerChannel.cpp | 0 npm-scripts.mjs | 17 ++++++++++++++++- 10 files changed, 21 insertions(+), 6 deletions(-) rename node/{ => src}/workerChannel/binding.gyp (91%) rename node/{ => src}/workerChannel/include/workerChannel.hpp (100%) rename node/{ => src}/workerChannel/scripts.mjs (100%) rename node/{ => src}/workerChannel/src/binding.cpp (100%) rename node/{ => src}/workerChannel/src/index.ts (93%) rename node/{ => src}/workerChannel/src/test.ts (100%) rename node/{ => src}/workerChannel/src/workerChannel.cpp (100%) diff --git a/node/src/Channel.ts b/node/src/Channel.ts index a969f5983d..5a462b8e64 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -1,7 +1,7 @@ import * as os from 'node:os'; import { info, warn } from 'node:console'; import * as flatbuffers from 'flatbuffers'; -import { WorkerChannel } from '../workerChannel/src'; +import { WorkerChannel } from './workerChannel/src'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; import { InvalidStateError } from './errors'; diff --git a/node/src/Worker.ts b/node/src/Worker.ts index 62afaa164e..a34bf60773 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -1,6 +1,6 @@ import * as process from 'node:process'; import * as path from 'node:path'; -import { WorkerChannel } from '../workerChannel/src'; +import { WorkerChannel } from './workerChannel/src'; import { version } from './'; import { Logger } from './Logger'; import { EnhancedEventEmitter } from './enhancedEvents'; diff --git a/node/workerChannel/binding.gyp b/node/src/workerChannel/binding.gyp similarity index 91% rename from node/workerChannel/binding.gyp rename to node/src/workerChannel/binding.gyp index a2f0d36a52..22474dec8f 100644 --- a/node/workerChannel/binding.gyp +++ b/node/src/workerChannel/binding.gyp @@ -14,12 +14,12 @@ 'cflags_cc!': [ '-fno-exceptions' ], 'include_dirs': [ " Date: Tue, 21 May 2024 10:57:29 +0200 Subject: [PATCH 57/80] WorkerChannel: .gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 22fabe4c16..983e03df11 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,7 @@ /node/src/fbs ## Node WorkerChannel addon. -/node/workerChannel/node_modules /node/workerChannel/build -/node/workerChannel/lib /node/workerChannel/.cache ## Rust. From e22cace1657588109dbe72091353789fb9caa013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 11:13:07 +0200 Subject: [PATCH 58/80] workflow: enable all SO --- .github/workflows/mediasoup-node.yaml | 16 ++++++++-------- npm-scripts.mjs | 1 - package.json | 1 + 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/mediasoup-node.yaml b/.github/workflows/mediasoup-node.yaml index 75b330636a..28ada0f0e7 100644 --- a/.github/workflows/mediasoup-node.yaml +++ b/.github/workflows/mediasoup-node.yaml @@ -13,14 +13,14 @@ jobs: strategy: matrix: ci: - # - os: ubuntu-20.04 - # node: 18 - # - os: ubuntu-22.04 - # node: 20 - # - os: macos-12 - # node: 18 - # - os: macos-14 - # node: 20 + - os: ubuntu-20.04 + node: 18 + - os: ubuntu-22.04 + node: 20 + - os: macos-12 + node: 18 + - os: macos-14 + node: 20 - os: windows-2022 node: 20 build-type: diff --git a/npm-scripts.mjs b/npm-scripts.mjs index b9ad8c02de..145b5a89ae 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -87,7 +87,6 @@ async function run() { // TypeScript to JavaScript. case 'prepare': { flatcNode(); - buildWorkerLib(); buildTypescript({ force: false }); break; diff --git a/package.json b/package.json index 7fe61314b3..ed6b3e6d42 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "types": "node/lib/index.d.ts", "files": [ "node/lib", + "node/src/workerChannel", "worker/deps/libwebrtc", "worker/fbs", "worker/fuzzer/include", From 147b08d2927bbd82c7618442650079ec40bf8ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 11:23:31 +0200 Subject: [PATCH 59/80] lint --- npm-scripts.mjs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 145b5a89ae..479d65d09b 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -15,9 +15,7 @@ const MAYOR_VERSION = PKG.version.split('.')[0]; const PYTHON = getPython(); const PIP_INVOKE_DIR = path.resolve('worker/pip_invoke'); const WORKER_RELEASE_DIR = 'worker/out/Release'; -const WORKER_RELEASE_BIN = IS_WINDOWS - ? 'mediasoup-worker.exe' - : 'mediasoup-worker'; +const WORKER_RELEASE_BIN = 'libmediasoup-worker.a'; const WORKER_RELEASE_BIN_PATH = `${WORKER_RELEASE_DIR}/${WORKER_RELEASE_BIN}`; const WORKER_PREBUILD_DIR = 'worker/prebuild'; const WORKER_PREBUILD_TAR = getWorkerPrebuildTarName(); @@ -27,12 +25,9 @@ const GH_OWNER = 'versatica'; const GH_REPO = 'mediasoup'; // Paths for ESLint to check. Converted to string for convenience. -const ESLINT_PATHS = [ - 'node/src', - WORKER_CHANNEL_ADDON_PATH, - 'npm-scripts.mjs', - 'worker/scripts', -].join(' '); +const ESLINT_PATHS = ['node/src', 'npm-scripts.mjs', 'worker/scripts'].join( + ' ' +); // Paths for ESLint to ignore. Converted to string argument for convenience. const ESLINT_IGNORE_PATTERN_ARGS = ['node/src/fbs'] .map(entry => `--ignore-pattern ${entry}`) @@ -47,7 +42,6 @@ const PRETTIER_PATHS = [ 'doc', 'node/src', 'node/tsconfig.json', - `${WORKER_CHANNEL_ADDON_PATH}/src`, 'npm-scripts.mjs', 'package.json', 'worker/scripts', @@ -499,7 +493,7 @@ function checkRelease() { installNodeDeps(); flatcNode(); buildTypescript({ force: true }); - buildWorker(); + buildWorkerLib(); lintNode(); lintWorker(); testNode(); From a258ea65f4ffff8efc1add69cf85863635f58997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 11:30:38 +0200 Subject: [PATCH 60/80] workflow: fix tabs --- .github/workflows/mediasoup-node.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mediasoup-node.yaml b/.github/workflows/mediasoup-node.yaml index 28ada0f0e7..b035e0c56f 100644 --- a/.github/workflows/mediasoup-node.yaml +++ b/.github/workflows/mediasoup-node.yaml @@ -14,18 +14,18 @@ jobs: matrix: ci: - os: ubuntu-20.04 - node: 18 + node: 18 - os: ubuntu-22.04 - node: 20 + node: 20 - os: macos-12 - node: 18 + node: 18 - os: macos-14 - node: 20 + node: 20 - os: windows-2022 node: 20 build-type: - Release - # - Debug + - Debug runs-on: ${{ matrix.ci.os }} From b8927417b643f507b787492d859cb4a5a60933b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 11:37:32 +0200 Subject: [PATCH 61/80] clang-format --- worker/scripts/clang-format.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worker/scripts/clang-format.mjs b/worker/scripts/clang-format.mjs index a640b3a85c..95612d1466 100644 --- a/worker/scripts/clang-format.mjs +++ b/worker/scripts/clang-format.mjs @@ -15,8 +15,8 @@ async function run() { '../test/include/helpers.hpp', '../fuzzer/src/**/*.cpp', '../fuzzer/include/**/*.hpp', - '../../node/workerChannel/src/**/*.cpp', - '../../node/workerChannel/src/**/*.hpp', + '../../node/src/workerChannel/include/**/*.cpp', + '../../node/src/workerChannel/src/**/*.hpp', ]); switch (task) { From 19d5242eb6e7f7efcbd3a305819412ce31121086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 11:40:52 +0200 Subject: [PATCH 62/80] clang-format: typo --- worker/scripts/clang-format.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worker/scripts/clang-format.mjs b/worker/scripts/clang-format.mjs index 95612d1466..4cbd6907aa 100644 --- a/worker/scripts/clang-format.mjs +++ b/worker/scripts/clang-format.mjs @@ -15,8 +15,8 @@ async function run() { '../test/include/helpers.hpp', '../fuzzer/src/**/*.cpp', '../fuzzer/include/**/*.hpp', - '../../node/src/workerChannel/include/**/*.cpp', - '../../node/src/workerChannel/src/**/*.hpp', + '../../node/src/workerChannel/include/**/*.hpp', + '../../node/src/workerChannel/src/**/*.cpp', ]); switch (task) { From 738acea9f7e3dd9980c5a17e8a749ee8c6a56074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 16:47:59 +0200 Subject: [PATCH 63/80] test: remove --forceExit assign JS instance of the addon to 'undefined' when closed, to indicate the Node GC that it can be freed. Otherwise the tests won't finish due to the correponsing handles being opened. --- node/src/Worker.ts | 5 +++++ node/src/workerChannel/src/index.ts | 7 +++++++ npm-scripts.mjs | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/node/src/Worker.ts b/node/src/Worker.ts index a34bf60773..4a42323532 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -354,6 +354,8 @@ export class Worker< this.emit('@failure', new Error(`[pid:${this.#pid}, code:${code}]`)); } + + this.close(); }); this.#channel = new Channel({ @@ -441,6 +443,9 @@ export class Worker< // Close the Channel instance. this.#channel.close(); + // Close the WorkerChannel instance. + this.#workerChannel.close(); + // Close every Router. for (const router of this.#routers) { router.workerClosed(); diff --git a/node/src/workerChannel/src/index.ts b/node/src/workerChannel/src/index.ts index 30b9ac2e1c..3edbc178f5 100644 --- a/node/src/workerChannel/src/index.ts +++ b/node/src/workerChannel/src/index.ts @@ -36,6 +36,13 @@ export class WorkerChannel extends EnhancedEventEmitter { }); } + close() { + // By setting the instance to `undefined`, the garbage collector will clean up + // the native instance, calling its `Finalize()` method accordingly. + // Without it, the tests will never finish due to remaining open handles. + this.workerChannel = undefined; + } + send(data: Uint8Array): void { this.workerChannel.send(data); } diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 479d65d09b..a154fdf0e5 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -467,7 +467,7 @@ function flatcWorker() { function testNode() { logInfo('testNode()'); - executeCmd(`jest --silent false --detectOpenHandles --forceExit ${args}`); + executeCmd(`jest --silent false --detectOpenHandles ${args}`); } function testWorker() { From 0c15f42ef2851328c833d7ff279f8a8449446c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 16:50:12 +0200 Subject: [PATCH 64/80] .gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 983e03df11..93bff8b7a2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,8 @@ /node/src/fbs ## Node WorkerChannel addon. -/node/workerChannel/build -/node/workerChannel/.cache +/node/src/workerChannel/build +/node/src/workerChannel/.cache ## Rust. /rust/examples-frontend/*/node_modules From 89022397c330f416529a6dbaca216b7088cd98d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 16:50:41 +0200 Subject: [PATCH 65/80] worker: format --- node/src/workerChannel/include/workerChannel.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/src/workerChannel/include/workerChannel.hpp b/node/src/workerChannel/include/workerChannel.hpp index 851c0f130f..583fd3cf70 100644 --- a/node/src/workerChannel/include/workerChannel.hpp +++ b/node/src/workerChannel/include/workerChannel.hpp @@ -1,9 +1,9 @@ -#include "DepLibUV.hpp" // mediasoup header file. #include "common.hpp" // mediasoup header file. +#include "DepLibUV.hpp" // mediasoup header file. #include "lib.hpp" // mediasoup header file. -#include #include #include +#include #include class WorkerChannel : public Napi::ObjectWrap From 85784adada6fb95efff36c092c32f7747d3a90ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 18:11:49 +0200 Subject: [PATCH 66/80] windows: set RuntimeLibrary for Debug and Release --- .github/workflows/mediasoup-node.yaml | 16 ++++++++-------- node/src/workerChannel/binding.gyp | 17 ++++++++++++++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/.github/workflows/mediasoup-node.yaml b/.github/workflows/mediasoup-node.yaml index b035e0c56f..4e6cdf8ab5 100644 --- a/.github/workflows/mediasoup-node.yaml +++ b/.github/workflows/mediasoup-node.yaml @@ -13,14 +13,14 @@ jobs: strategy: matrix: ci: - - os: ubuntu-20.04 - node: 18 - - os: ubuntu-22.04 - node: 20 - - os: macos-12 - node: 18 - - os: macos-14 - node: 20 + # - os: ubuntu-20.04 + # node: 18 + # - os: ubuntu-22.04 + # node: 20 + # - os: macos-12 + # node: 18 + # - os: macos-14 + # node: 20 - os: windows-2022 node: 20 build-type: diff --git a/node/src/workerChannel/binding.gyp b/node/src/workerChannel/binding.gyp index 22474dec8f..aa1cd60596 100644 --- a/node/src/workerChannel/binding.gyp +++ b/node/src/workerChannel/binding.gyp @@ -22,7 +22,7 @@ '<(module_root_dir)/../../../worker/out/<(mediasoup_build_type)/build/libmediasoup-worker.a' ], }, { - "libraries": [ + 'libraries': [ '<(mediasoup_worker_lib)' ], } @@ -31,6 +31,17 @@ 'libraries': [ 'Ws2_32.lib', 'Dbghelp.lib', 'Crypt32.lib', 'Userenv.lib', ], + 'conditions': [ + ['mediasoup_build_type=="Release"', { + 'variables': { + 'runtime_library': '0', + }, + }, { + 'variables': { + 'runtime_library': '1', + }, + }], + ], 'msvs_settings': { 'VCCLCompilerTool': { 'ExceptionHandling': 1, @@ -39,8 +50,8 @@ # 1 - MultiThreadedDebug (/MTd) # 2 - MultiThreadedDLL (/MD) # 3 - MultiThreadedDebugDLL (/MDd) - 'RuntimeLibrary': 0, - 'AdditionalOptions': [ '/MT' ], + 'RuntimeLibrary': '<(runtime_library)', + # 'AdditionalOptions': [ '/MT' ], }, 'VCLinkerTool': { 'AdditionalOptions': ['/FORCE:MULTIPLE'], From b3044ad8386ce54e68bdac4008715e929846022a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 21 May 2024 18:35:04 +0200 Subject: [PATCH 67/80] workflow: enable all OS in mediasoup-node --- .github/workflows/mediasoup-node.yaml | 16 ++++++++-------- node/src/workerChannel/binding.gyp | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/mediasoup-node.yaml b/.github/workflows/mediasoup-node.yaml index 4e6cdf8ab5..b035e0c56f 100644 --- a/.github/workflows/mediasoup-node.yaml +++ b/.github/workflows/mediasoup-node.yaml @@ -13,14 +13,14 @@ jobs: strategy: matrix: ci: - # - os: ubuntu-20.04 - # node: 18 - # - os: ubuntu-22.04 - # node: 20 - # - os: macos-12 - # node: 18 - # - os: macos-14 - # node: 20 + - os: ubuntu-20.04 + node: 18 + - os: ubuntu-22.04 + node: 20 + - os: macos-12 + node: 18 + - os: macos-14 + node: 20 - os: windows-2022 node: 20 build-type: diff --git a/node/src/workerChannel/binding.gyp b/node/src/workerChannel/binding.gyp index aa1cd60596..39af52f9e3 100644 --- a/node/src/workerChannel/binding.gyp +++ b/node/src/workerChannel/binding.gyp @@ -51,7 +51,6 @@ # 2 - MultiThreadedDLL (/MD) # 3 - MultiThreadedDebugDLL (/MDd) 'RuntimeLibrary': '<(runtime_library)', - # 'AdditionalOptions': [ '/MT' ], }, 'VCLinkerTool': { 'AdditionalOptions': ['/FORCE:MULTIPLE'], From e80a59e5cda9ed3f4eebb2587b889388fbfd54a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 10:59:30 +0200 Subject: [PATCH 68/80] tests: add comment of addon tests --- node/src/workerChannel/src/test.ts | 7 +++++++ node/tsconfig.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/node/src/workerChannel/src/test.ts b/node/src/workerChannel/src/test.ts index e780597995..ee0bbbd70c 100644 --- a/node/src/workerChannel/src/test.ts +++ b/node/src/workerChannel/src/test.ts @@ -1,3 +1,10 @@ +/** + * NOTE: These tests are to be run locally only, if needed. + * When running them within a testing environment (jest|node) the native addon + * handle will remain open and the test process won't terminate, making any + * CI process fail. + */ + import assert = require('node:assert'); import { beforeEach, describe, it } from 'node:test'; diff --git a/node/tsconfig.json b/node/tsconfig.json index 3271cdb50c..87394576c7 100644 --- a/node/tsconfig.json +++ b/node/tsconfig.json @@ -10,7 +10,7 @@ "declaration": true, "declarationMap": true }, - "include": ["src", "workerChannel/src"], + "include": ["src"], "watchOptions": { "watchFile": "useFsEvents", "watchDirectory": "useFsEvents", From c3e5d678781777e4ab33b7523482c7ef7968332d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 11:13:35 +0200 Subject: [PATCH 69/80] WIP: prebuild --- .github/workflows/mediasoup-worker-prebuild.yaml | 10 ++++++---- node/src/workerChannel/scripts.mjs | 2 +- npm-scripts.mjs | 13 ++++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/mediasoup-worker-prebuild.yaml b/.github/workflows/mediasoup-worker-prebuild.yaml index 762361367b..9910db4146 100644 --- a/.github/workflows/mediasoup-worker-prebuild.yaml +++ b/.github/workflows/mediasoup-worker-prebuild.yaml @@ -1,9 +1,11 @@ name: mediasoup-worker-prebuild # Only trigger on GitHub releases. -on: - release: - types: [published] +# on: + # release: + # types: [published] + +on: [pull_request, workflow_dispatch] jobs: ci: @@ -67,4 +69,4 @@ jobs: - name: Upload mediasoup-worker prebuilt binary uses: softprops/action-gh-release@v1 with: - files: worker/prebuild/mediasoup-worker-*.tgz + files: worker/prebuild/libmediasoup-worker-*.tgz diff --git a/node/src/workerChannel/scripts.mjs b/node/src/workerChannel/scripts.mjs index c46dbfe434..a0e0ae7435 100644 --- a/node/src/workerChannel/scripts.mjs +++ b/node/src/workerChannel/scripts.mjs @@ -38,7 +38,7 @@ function buildBinding() { process.env.GYP_DEFINES = `mediasoup_build_type=${buildType}`; - if (process.env.MEDIASOUP_WORKER_LIB) { + if (process.env.MEDIASOUP_WORKER_BIN) { process.env.GYP_DEFINES += ` mediasoup_worker_lib=${process.env.MEDIASOUP_WORKER_LIB}`; } diff --git a/npm-scripts.mjs b/npm-scripts.mjs index a154fdf0e5..373da77f68 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -109,6 +109,7 @@ async function run() { ); buildWorkerLib(); + buildAddon(); if (!process.env.MEDIASOUP_LOCAL_DEV) { cleanWorkerArtifacts(); @@ -121,6 +122,7 @@ async function run() { ); buildWorkerLib(); + buildAddon(); if (!process.env.MEDIASOUP_LOCAL_DEV) { cleanWorkerArtifacts(); @@ -145,7 +147,7 @@ async function run() { } case 'worker:build': { - buildWorker(); + buildWorkerLib(); break; } @@ -345,6 +347,12 @@ function buildWorkerLib() { installInvoke(); executeCmd(`"${PYTHON}" -m invoke -r worker libmediasoup-worker`); +} + +function buildAddon() { + logInfo('buildAddon()'); + + installInvoke(); executeCmd( `cd ${WORKER_CHANNEL_ADDON_PATH} && node scripts.mjs binding:build` @@ -354,6 +362,8 @@ function buildWorkerLib() { } function copyAddon() { + logInfo('copyAddon()'); + const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; const outDir = `node/lib/workerChannel/build/${buildType}`; @@ -494,6 +504,7 @@ function checkRelease() { flatcNode(); buildTypescript({ force: true }); buildWorkerLib(); + buildAddon(); lintNode(); lintWorker(); testNode(); From 95d9cd0a71d746492b7805486f21cef98ec07601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 11:23:35 +0200 Subject: [PATCH 70/80] lint --- npm-scripts.mjs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 373da77f68..84dffe608e 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -333,14 +333,6 @@ function buildTypescript({ force = false } = { force: false }) { copyAddon(); } -function buildWorker() { - logInfo('buildWorker()'); - - installInvoke(); - - executeCmd(`"${PYTHON}" -m invoke -r worker mediasoup-worker`); -} - function buildWorkerLib() { logInfo('buildWorkerLib()'); From cbf9b30f3958976c6985634108170f6ab053e431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 11:40:40 +0200 Subject: [PATCH 71/80] WIP: prebuilt --- .github/workflows/mediasoup-worker-prebuild.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mediasoup-worker-prebuild.yaml b/.github/workflows/mediasoup-worker-prebuild.yaml index 9910db4146..d44b097c52 100644 --- a/.github/workflows/mediasoup-worker-prebuild.yaml +++ b/.github/workflows/mediasoup-worker-prebuild.yaml @@ -69,4 +69,5 @@ jobs: - name: Upload mediasoup-worker prebuilt binary uses: softprops/action-gh-release@v1 with: + tag: addon-test-3 files: worker/prebuild/libmediasoup-worker-*.tgz From f83ca80a3a2fab14b31b69b30ce438c992ab400f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 11:47:06 +0200 Subject: [PATCH 72/80] WIP: prebuilt --- .github/workflows/mediasoup-worker-prebuild.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mediasoup-worker-prebuild.yaml b/.github/workflows/mediasoup-worker-prebuild.yaml index d44b097c52..a8f10cc8b8 100644 --- a/.github/workflows/mediasoup-worker-prebuild.yaml +++ b/.github/workflows/mediasoup-worker-prebuild.yaml @@ -69,5 +69,5 @@ jobs: - name: Upload mediasoup-worker prebuilt binary uses: softprops/action-gh-release@v1 with: - tag: addon-test-3 + tag_name: addon-test-4 files: worker/prebuild/libmediasoup-worker-*.tgz From 376bdcfb8f70fc6bea2b58e2a34e4d730615fedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 11:58:37 +0200 Subject: [PATCH 73/80] WIP: prebuilt --- .github/workflows/mediasoup-worker-prebuild.yaml | 2 +- npm-scripts.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mediasoup-worker-prebuild.yaml b/.github/workflows/mediasoup-worker-prebuild.yaml index a8f10cc8b8..0f7d9b1128 100644 --- a/.github/workflows/mediasoup-worker-prebuild.yaml +++ b/.github/workflows/mediasoup-worker-prebuild.yaml @@ -69,5 +69,5 @@ jobs: - name: Upload mediasoup-worker prebuilt binary uses: softprops/action-gh-release@v1 with: - tag_name: addon-test-4 + tag_name: addon-test-5 files: worker/prebuild/libmediasoup-worker-*.tgz diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 84dffe608e..bdd7427d08 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -282,7 +282,7 @@ function getPython() { } function getWorkerPrebuildTarName() { - let name = `mediasoup-worker-${PKG.version}-${os.platform()}-${os.arch()}`; + let name = `libmediasoup-worker-${PKG.version}-${os.platform()}-${os.arch()}`; // In Linux we want to know about kernel version since kernel >= 6 supports // io-uring. From b559e4d968fab9fdc35beb6abbd75d2bf59366de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 15:27:37 +0200 Subject: [PATCH 74/80] prebuilt working --- .../workflows/mediasoup-worker-prebuild.yaml | 9 ++--- npm-scripts.mjs | 40 ------------------- 2 files changed, 3 insertions(+), 46 deletions(-) diff --git a/.github/workflows/mediasoup-worker-prebuild.yaml b/.github/workflows/mediasoup-worker-prebuild.yaml index 0f7d9b1128..203810a3d6 100644 --- a/.github/workflows/mediasoup-worker-prebuild.yaml +++ b/.github/workflows/mediasoup-worker-prebuild.yaml @@ -1,11 +1,9 @@ name: mediasoup-worker-prebuild # Only trigger on GitHub releases. -# on: - # release: - # types: [published] - -on: [pull_request, workflow_dispatch] +on: + release: + types: [published] jobs: ci: @@ -69,5 +67,4 @@ jobs: - name: Upload mediasoup-worker prebuilt binary uses: softprops/action-gh-release@v1 with: - tag_name: addon-test-5 files: worker/prebuild/libmediasoup-worker-*.tgz diff --git a/npm-scripts.mjs b/npm-scripts.mjs index bdd7427d08..1c1fd22f44 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -598,46 +598,6 @@ async function downloadPrebuiltWorker() { `downloadPrebuiltWorker() | failed to give execution permissions to the mediasoup-worker prebuilt binary: ${error}` ); } - - // Let's confirm that the fetched mediasoup-worker prebuit binary does - // run in current host. This is to prevent weird issues related to - // different versions of libc in the system and so on. - // So run mediasoup-worker without the required MEDIASOUP_VERSION env and - // expect exit code 41 (see main.cpp). - - logInfo( - 'downloadPrebuiltWorker() | checking fetched mediasoup-worker prebuilt binary in current host' - ); - - try { - const resolvedBinPath = path.resolve(WORKER_RELEASE_BIN_PATH); - - // This will always fail on purpose, but if status code is 41 then - // it's good. - execSync(`"${resolvedBinPath}"`, { - stdio: ['ignore', 'ignore', 'ignore'], - // Ensure no env is passed to avoid accidents. - env: {}, - }); - } catch (error) { - if (error.status === 41) { - logInfo( - 'downloadPrebuiltWorker() | fetched mediasoup-worker prebuilt binary is valid for current host' - ); - - resolve(true); - } else { - logError( - `downloadPrebuiltWorker() | fetched mediasoup-worker prebuilt binary fails to run in this host [status:${error.status}]` - ); - - try { - fs.unlinkSync(WORKER_RELEASE_BIN_PATH); - } catch (error2) {} - - resolve(false); - } - } }) .on('error', error => { logError( From 9f24c508d976284d3d22605472831eae8fb92b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 15:38:32 +0200 Subject: [PATCH 75/80] comment --- node/src/Channel.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node/src/Channel.ts b/node/src/Channel.ts index 5a462b8e64..9eee23b0fe 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -245,11 +245,11 @@ export class Channel extends EnhancedEventEmitter { // Finalizes the buffer. this.#bufferBuilder.finish(messageOffset); - // Create a new buffer with this data so multiple contiguous flatbuffers - // do not point to the builder buffer overriding others info. + // Take a reference of the inner buffer. const buffer = this.#bufferBuilder.asUint8Array(); // Clear the buffer builder so it's reused for the next request. + // NOTE: This merely resets the buffer offset, it does not clear the content. this.#bufferBuilder.clear(); if (buffer.byteLength > MESSAGE_MAX_LEN) { @@ -317,11 +317,11 @@ export class Channel extends EnhancedEventEmitter { // Finalizes the buffer. this.#bufferBuilder.finish(messageOffset); - // Create a new buffer with this data so multiple contiguous flatbuffers - // do not point to the builder buffer overriding others info. + // Take a reference of the inner buffer. const buffer = this.#bufferBuilder.asUint8Array(); // Clear the buffer builder so it's reused for the next request. + // NOTE: This merely resets the buffer offset, it does not clear the content. this.#bufferBuilder.clear(); if (buffer.byteLength > MESSAGE_MAX_LEN) { From a003c63fe80f67056d308adb138fe7119ba55e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 15:59:35 +0200 Subject: [PATCH 76/80] workerChannel: Do not copy the addon binary into node/lib --- node/src/workerChannel/src/index.ts | 7 ++++++- npm-scripts.mjs | 17 ----------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/node/src/workerChannel/src/index.ts b/node/src/workerChannel/src/index.ts index 3edbc178f5..f894f8992a 100644 --- a/node/src/workerChannel/src/index.ts +++ b/node/src/workerChannel/src/index.ts @@ -3,9 +3,14 @@ import { EnhancedEventEmitter } from '../../enhancedEvents'; const buildType = process.env.MEDIASOUP_BUILDTYPE ?? 'Release'; +/** + * NOTE: The following path is reachable from: + * - current file: node/src/workerChannel/src/index.ts + * - transpiled JS file: node/lib/workerChannel/src/index.js + */ // eslint-disable-next-line @typescript-eslint/no-var-requires const { WorkerChannel: NativeWorkerChannel } = require( - `../build/${buildType}/worker-channel.node` + `../../../src/workerChannel/build/${buildType}/worker-channel.node` ); export type WorkerChannelEvents = { diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 1c1fd22f44..9daac3348c 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -329,8 +329,6 @@ function buildTypescript({ force = false } = { force: false }) { deleteNodeLib(); executeCmd('tsc --project node'); - - copyAddon(); } function buildWorkerLib() { @@ -349,21 +347,6 @@ function buildAddon() { executeCmd( `cd ${WORKER_CHANNEL_ADDON_PATH} && node scripts.mjs binding:build` ); - - copyAddon(); -} - -function copyAddon() { - logInfo('copyAddon()'); - - const buildType = process.env.MEDIASOUP_BUILDTYPE || 'Release'; - const outDir = `node/lib/workerChannel/build/${buildType}`; - - ensureDir(outDir); - - fs.cpSync(`${WORKER_CHANNEL_ADDON_PATH}/build/${buildType}`, outDir, { - recursive: true, - }); } function cleanWorkerArtifacts() { From 9fd5dfbf663f5733a85b096f951f801e020d8563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 16:51:19 +0200 Subject: [PATCH 77/80] package.json: files, add workerChannel files --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ed6b3e6d42..308ce5dde6 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,10 @@ "types": "node/lib/index.d.ts", "files": [ "node/lib", - "node/src/workerChannel", + "node/src/workerChannel/binding.gyp", + "node/src/workerChannel/include", + "node/src/workerChannel/scripts.mjs", + "node/src/workerChannel/src", "worker/deps/libwebrtc", "worker/fbs", "worker/fuzzer/include", From c82c605309f0007771048100f87e629fe7a32934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 16:59:59 +0200 Subject: [PATCH 78/80] .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 93bff8b7a2..3ff697e6e7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ ## Node WorkerChannel addon. /node/src/workerChannel/build -/node/src/workerChannel/.cache ## Rust. /rust/examples-frontend/*/node_modules From e469bf2715cf7d74d7eb374f79e1327983284bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 17:53:33 +0200 Subject: [PATCH 79/80] cleanup --- node/src/workerChannel/binding.gyp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/node/src/workerChannel/binding.gyp b/node/src/workerChannel/binding.gyp index 39af52f9e3..3f7b7ab452 100644 --- a/node/src/workerChannel/binding.gyp +++ b/node/src/workerChannel/binding.gyp @@ -19,7 +19,7 @@ 'conditions': [ ['mediasoup_worker_lib==""', { 'libraries': [ - '<(module_root_dir)/../../../worker/out/<(mediasoup_build_type)/build/libmediasoup-worker.a' + '<(module_root_dir)/../../../worker/out/<(mediasoup_build_type)/libmediasoup-worker.a' ], }, { 'libraries': [ @@ -61,8 +61,7 @@ 'xcode_settings': { "CLANG_CXX_LIBRARY": 'libc++', 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', - # TODO: This should be the same as the one used for libmediasoup - # Is it really needed? + # TODO: This should be the same as the one used for libmediasoup? 'MACOSX_DEPLOYMENT_TARGET': '14' } }] From d95db9d9c5e93adc3c4149486571067b42349f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 22 May 2024 18:26:48 +0200 Subject: [PATCH 80/80] package.json: engines, set a minimum npm version Lower npm versions than 10.3.0 fail building the addon. Error: No module named 'distutils' --- package-lock.json | 3 ++- package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87757ab3cf..37c633feb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,8 @@ "typescript": "^5.4.5" }, "engines": { - "node": ">=18" + "node": ">=18", + "npm": ">=10.3.0" }, "funding": { "type": "opencollective", diff --git a/package.json b/package.json index 308ce5dde6..f96b9a7572 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,8 @@ "npm-scripts.mjs" ], "engines": { - "node": ">=18" + "node": ">=18", + "npm": ">=10.3.0" }, "keywords": [ "webrtc",