From d1516cc95dc054185149578f74cf8e18123b329f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Baz=20Castillo?= Date: Mon, 24 Mar 2025 02:19:59 +0100 Subject: [PATCH 1/3] Modernize --- CHANGELOG.md | 1 + eslint.config.mjs | 17 ++-- jest.config.mjs | 18 ++++ node/src/ActiveSpeakerObserver.ts | 2 +- node/src/AudioLevelObserver.ts | 2 +- node/src/Channel.ts | 2 +- node/src/DirectTransport.ts | 12 +-- node/src/PipeTransport.ts | 8 +- node/src/PlainTransport.ts | 6 +- node/src/Router.ts | 6 +- node/src/WebRtcTransport.ts | 8 +- node/src/Worker.ts | 14 +-- node/src/enhancedEvents.ts | 29 +++--- node/src/ortc.ts | 18 ++-- node/src/test/test-Consumer.ts | 44 ++++---- node/src/test/test-DirectTransport.ts | 34 +++---- node/src/test/test-PipeTransport.ts | 6 +- node/src/test/test-PlainTransport.ts | 46 ++++----- node/src/test/test-Producer.ts | 36 +++---- node/src/test/test-WebRtcServer.ts | 30 +++--- node/src/test/test-WebRtcTransport.ts | 140 ++++++++++++++------------ node/src/test/test-Worker.ts | 6 +- node/src/test/test-ortc.ts | 78 +++++++------- npm-scripts.mjs | 42 ++++---- package.json | 43 +++----- tsconfig.json | 46 ++++++--- 26 files changed, 374 insertions(+), 320 deletions(-) create mode 100644 jest.config.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 66a26ed9df..94e983b19f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### NEXT - CI: Remove redundant hosts `macos-14` and `windows-2022` from `mediasoup-worker-prebuild` job ([PR #1506](https://github.com/versatica/mediasoup/pull/1506)). +- Node: Modernize code ([PR #XXXX](https://github.com/versatica/mediasoup/pull/XXXX)). ### 3.15.6 diff --git a/eslint.config.mjs b/eslint.config.mjs index 4794a8551f..1187e845fc 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,7 +8,7 @@ const config = tsEslint.config( { languageOptions: { sourceType: 'module', - globals: { ...globals.nodeBuiltin }, + globals: { ...globals.node }, }, linterOptions: { noInlineConfig: false, @@ -108,18 +108,20 @@ const config = tsEslint.config( yoda: 2, }, }, - // NOTE: We need to apply this only to .ts files (and not to .mjs files). + // NOTE: We need to apply this only to .ts source files (and not to .mjs + // files). ...tsEslint.configs.recommendedTypeChecked.map(item => ({ ...item, files: ['node/src/**/*.ts'], })), - // NOTE: We need to apply this only to .ts files (and not to .mjs files). + // NOTE: We need to apply this only to .ts source files (and not to .mjs + // files). ...tsEslint.configs.stylisticTypeChecked.map(item => ({ ...item, files: ['node/src/**/*.ts'], })), { - name: 'mediasoup .ts files', + name: '.ts source files', files: ['node/src/**/*.ts'], languageOptions: { parserOptions: { @@ -153,7 +155,10 @@ const config = tsEslint.config( ], // Sorry, we need many `any` usage. '@typescript-eslint/no-explicit-any': 0, - '@typescript-eslint/explicit-function-return-type': 2, + '@typescript-eslint/explicit-function-return-type': [ + 2, + { allowExpressions: true }, + ], '@typescript-eslint/no-unsafe-member-access': 0, '@typescript-eslint/no-unsafe-assignment': 0, '@typescript-eslint/no-unsafe-call': 0, @@ -169,7 +174,7 @@ const config = tsEslint.config( }, }, { - name: 'mediasoup .ts test files', + name: '.ts test files', ...jestEslint.configs['flat/recommended'], files: ['node/src/test/**/*.ts'], rules: { diff --git a/jest.config.mjs b/jest.config.mjs new file mode 100644 index 0000000000..cbe0b43e42 --- /dev/null +++ b/jest.config.mjs @@ -0,0 +1,18 @@ +const config = { + verbose: true, + testEnvironment: 'node', + testRegex: 'node/src/test/test-.*\\.ts', + transform: { + '^.+\\.ts?$': ['ts-jest'], + }, + coveragePathIgnorePatterns: [ + 'node/src/Logger.ts', + 'node/src/enhancedEvents.ts', + 'node/src/fbs', + 'node/src/test', + ], + modulePathIgnorePatterns: ['worker', 'rust', 'target'], + cacheDirectory: '.cache/jest', +}; + +export default config; diff --git a/node/src/ActiveSpeakerObserver.ts b/node/src/ActiveSpeakerObserver.ts index a46ac16ab4..e87acbd845 100644 --- a/node/src/ActiveSpeakerObserver.ts +++ b/node/src/ActiveSpeakerObserver.ts @@ -44,7 +44,7 @@ export class ActiveSpeakerObserverImpl< return 'activespeaker'; } - get observer(): ActiveSpeakerObserverObserver { + override get observer(): ActiveSpeakerObserverObserver { return super.observer; } diff --git a/node/src/AudioLevelObserver.ts b/node/src/AudioLevelObserver.ts index 5890956fdb..e9934d0403 100644 --- a/node/src/AudioLevelObserver.ts +++ b/node/src/AudioLevelObserver.ts @@ -46,7 +46,7 @@ export class AudioLevelObserverImpl< return 'audiolevel'; } - get observer(): AudioLevelObserverObserver { + override get observer(): AudioLevelObserverObserver { return super.observer; } diff --git a/node/src/Channel.ts b/node/src/Channel.ts index 6621d1e188..0fed06282b 100644 --- a/node/src/Channel.ts +++ b/node/src/Channel.ts @@ -48,7 +48,7 @@ export class Channel extends EnhancedEventEmitter { readonly #sents: Map = new Map(); // Buffer for reading messages from the worker. - #recvBuffer = Buffer.alloc(0); + #recvBuffer: Buffer = Buffer.alloc(0); // flatbuffers builder. #bufferBuilder: flatbuffers.Builder = new flatbuffers.Builder(1024); diff --git a/node/src/DirectTransport.ts b/node/src/DirectTransport.ts index a75d4b18bb..7d0b84aedc 100644 --- a/node/src/DirectTransport.ts +++ b/node/src/DirectTransport.ts @@ -72,11 +72,11 @@ export class DirectTransportImpl< return 'direct'; } - get observer(): DirectTransportObserver { + override get observer(): DirectTransportObserver { return super.observer; } - close(): void { + override close(): void { if (this.closed) { return; } @@ -84,7 +84,7 @@ export class DirectTransportImpl< super.close(); } - routerClosed(): void { + override routerClosed(): void { if (this.closed) { return; } @@ -134,21 +134,21 @@ export class DirectTransportImpl< } // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/require-await - async setMaxIncomingBitrate(bitrate: number): Promise { + override async setMaxIncomingBitrate(bitrate: number): Promise { throw new UnsupportedError( 'setMaxIncomingBitrate() not implemented in DirectTransport' ); } // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/require-await - async setMaxOutgoingBitrate(bitrate: number): Promise { + override async setMaxOutgoingBitrate(bitrate: number): Promise { throw new UnsupportedError( 'setMaxOutgoingBitrate() not implemented in DirectTransport' ); } // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/require-await - async setMinOutgoingBitrate(bitrate: number): Promise { + override async setMinOutgoingBitrate(bitrate: number): Promise { throw new UnsupportedError( 'setMinOutgoingBitrate() not implemented in DirectTransport' ); diff --git a/node/src/PipeTransport.ts b/node/src/PipeTransport.ts index 266c0d50d4..239bda9f63 100644 --- a/node/src/PipeTransport.ts +++ b/node/src/PipeTransport.ts @@ -96,7 +96,7 @@ export class PipeTransportImpl return 'pipe'; } - get observer(): PipeTransportObserver { + override get observer(): PipeTransportObserver { return super.observer; } @@ -116,7 +116,7 @@ export class PipeTransportImpl return this.#data.srtpParameters; } - close(): void { + override close(): void { if (this.closed) { return; } @@ -128,7 +128,7 @@ export class PipeTransportImpl super.close(); } - routerClosed(): void { + override routerClosed(): void { if (this.closed) { return; } @@ -213,7 +213,7 @@ export class PipeTransportImpl } } - async consume({ + override async consume({ producerId, appData, }: PipeConsumerOptions): Promise> { diff --git a/node/src/PlainTransport.ts b/node/src/PlainTransport.ts index 5e595152c1..f9646a5a90 100644 --- a/node/src/PlainTransport.ts +++ b/node/src/PlainTransport.ts @@ -89,7 +89,7 @@ export class PlainTransportImpl return 'plain'; } - get observer(): PlainTransportObserver { + override get observer(): PlainTransportObserver { return super.observer; } @@ -113,7 +113,7 @@ export class PlainTransportImpl return this.#data.srtpParameters; } - close(): void { + override close(): void { if (this.closed) { return; } @@ -125,7 +125,7 @@ export class PlainTransportImpl super.close(); } - routerClosed(): void { + override routerClosed(): void { if (this.closed) { return; } diff --git a/node/src/Router.ts b/node/src/Router.ts index ebe6a3f1a7..39c0821cb1 100644 --- a/node/src/Router.ts +++ b/node/src/Router.ts @@ -985,8 +985,8 @@ export class RouterImpl if (pipeTransportPairPromise) { pipeTransportPair = await pipeTransportPairPromise; - localPipeTransport = pipeTransportPair[this.id]; - remotePipeTransport = pipeTransportPair[router.id]; + localPipeTransport = pipeTransportPair[this.id]!; + remotePipeTransport = pipeTransportPair[router.id]!; } else { pipeTransportPairPromise = new Promise((resolve, reject) => { Promise.all([ @@ -1190,7 +1190,7 @@ export class RouterImpl pipeTransportPairPromise .then(pipeTransportPair => { - const localPipeTransport = pipeTransportPair[this.id]; + const localPipeTransport = pipeTransportPair[this.id]!; // NOTE: No need to do any other cleanup here since that is done by the // Router calling this method on us. diff --git a/node/src/WebRtcTransport.ts b/node/src/WebRtcTransport.ts index 522882cd65..3aa6e0c207 100644 --- a/node/src/WebRtcTransport.ts +++ b/node/src/WebRtcTransport.ts @@ -112,7 +112,7 @@ export class WebRtcTransportImpl< return 'webrtc'; } - get observer(): WebRtcTransportObserver { + override get observer(): WebRtcTransportObserver { return super.observer; } @@ -156,7 +156,7 @@ export class WebRtcTransportImpl< return this.#data.sctpState; } - close(): void { + override close(): void { if (this.closed) { return; } @@ -172,7 +172,7 @@ export class WebRtcTransportImpl< super.close(); } - routerClosed(): void { + override routerClosed(): void { if (this.closed) { return; } @@ -188,7 +188,7 @@ export class WebRtcTransportImpl< super.routerClosed(); } - listenServerClosed(): void { + override listenServerClosed(): void { if (this.closed) { return; } diff --git a/node/src/Worker.ts b/node/src/Worker.ts index b30c5d70ba..53e68dfe2d 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -34,9 +34,9 @@ import { Protocol as FbsTransportProtocol } from './fbs/transport/protocol'; // If env MEDIASOUP_WORKER_BIN is given, use it as worker binary. // Otherwise if env MEDIASOUP_BUILDTYPE is 'Debug' use the Debug binary. // Otherwise use the Release binary. -export const workerBin = process.env.MEDIASOUP_WORKER_BIN - ? process.env.MEDIASOUP_WORKER_BIN - : process.env.MEDIASOUP_BUILDTYPE === 'Debug' +export const workerBin = process.env['MEDIASOUP_WORKER_BIN'] + ? process.env['MEDIASOUP_WORKER_BIN'] + : process.env['MEDIASOUP_BUILDTYPE'] === 'Debug' ? path.join( __dirname, '..', @@ -112,12 +112,12 @@ export class WorkerImpl let spawnBin = workerBin; let spawnArgs: string[] = []; - if (process.env.MEDIASOUP_USE_VALGRIND === 'true') { - spawnBin = process.env.MEDIASOUP_VALGRIND_BIN ?? 'valgrind'; + if (process.env['MEDIASOUP_USE_VALGRIND'] === 'true') { + spawnBin = process.env['MEDIASOUP_VALGRIND_BIN'] ?? 'valgrind'; - if (process.env.MEDIASOUP_VALGRIND_OPTIONS) { + if (process.env['MEDIASOUP_VALGRIND_OPTIONS']) { spawnArgs = spawnArgs.concat( - process.env.MEDIASOUP_VALGRIND_OPTIONS.split(/\s+/) + process.env['MEDIASOUP_VALGRIND_OPTIONS'].split(/\s+/) ); } diff --git a/node/src/enhancedEvents.ts b/node/src/enhancedEvents.ts index 8c030df65e..751e3e35da 100644 --- a/node/src/enhancedEvents.ts +++ b/node/src/enhancedEvents.ts @@ -15,7 +15,10 @@ export class EnhancedEventEmitter< this.setMaxListeners(Infinity); } - emit(eventName: K, ...args: E2[K]): boolean { + override emit( + eventName: K, + ...args: E2[K] + ): boolean { return super.emit(eventName, ...args); } @@ -36,7 +39,7 @@ export class EnhancedEventEmitter< } } - on( + override on( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -45,7 +48,7 @@ export class EnhancedEventEmitter< return this; } - off( + override off( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -54,7 +57,7 @@ export class EnhancedEventEmitter< return this; } - addListener( + override addListener( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -63,7 +66,7 @@ export class EnhancedEventEmitter< return this; } - prependListener( + override prependListener( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -72,7 +75,7 @@ export class EnhancedEventEmitter< return this; } - once( + override once( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -81,7 +84,7 @@ export class EnhancedEventEmitter< return this; } - prependOnceListener( + override prependOnceListener( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -90,7 +93,7 @@ export class EnhancedEventEmitter< return this; } - removeListener( + override removeListener( eventName: K, listener: (...args: E2[K]) => void ): this { @@ -99,23 +102,25 @@ export class EnhancedEventEmitter< return this; } - removeAllListeners(eventName?: K): this { + override removeAllListeners( + eventName?: K + ): this { super.removeAllListeners(eventName); return this; } - listenerCount(eventName: K): number { + override listenerCount(eventName: K): number { return super.listenerCount(eventName); } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - listeners(eventName: K): Function[] { + override listeners(eventName: K): Function[] { return super.listeners(eventName); } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type - rawListeners(eventName: K): Function[] { + override rawListeners(eventName: K): Function[] { return super.rawListeners(eventName); } } diff --git a/node/src/ortc.ts b/node/src/ortc.ts index be79bab7c2..dbb15635d9 100644 --- a/node/src/ortc.ts +++ b/node/src/ortc.ts @@ -490,8 +490,8 @@ export function getConsumableRtpParameters( utils.clone(params.encodings) ?? []; for (let i = 0; i < consumableEncodings.length; ++i) { - const consumableEncoding = consumableEncodings[i]; - const { mappedSsrc } = rtpMapping.encodings[i]; + const consumableEncoding = consumableEncodings[i]!; + const { mappedSsrc } = rtpMapping.encodings[i]!; // Remove useless fields. delete consumableEncoding.rid; @@ -537,7 +537,7 @@ export function canConsume( } // Ensure there is at least one media codec. - if (matchingCodecs.length === 0 || isRtxCodec(matchingCodecs[0])) { + if (matchingCodecs.length === 0 || isRtxCodec(matchingCodecs[0]!)) { return false; } @@ -602,7 +602,7 @@ export function getConsumerRtpParameters({ // Must sanitize the list of matched codecs by removing useless RTX codecs. for (let idx = consumerParams.codecs.length - 1; idx >= 0; --idx) { - const codec = consumerParams.codecs[idx]; + const codec = consumerParams.codecs[idx]!; if (isRtxCodec(codec)) { // Search for the associated media codec. @@ -621,7 +621,7 @@ export function getConsumerRtpParameters({ // Ensure there is at least one media codec. if ( consumerParams.codecs.length === 0 || - isRtxCodec(consumerParams.codecs[0]) + isRtxCodec(consumerParams.codecs[0]!) ) { throw new UnsupportedError('no compatible media codecs'); } @@ -722,7 +722,7 @@ export function getConsumerRtpParameters({ const baseRtxSsrc = utils.generateRandomNumber(); for (let i = 0; i < consumableEncodings.length; ++i) { - const encoding = consumableEncodings[i]; + const encoding = consumableEncodings[i]!; encoding.ssrc = baseSsrc + i; @@ -798,7 +798,7 @@ export function getPipeConsumerRtpParameters({ const baseRtxSsrc = utils.generateRandomNumber(); for (let i = 0; i < consumableEncodings.length; ++i) { - const encoding = consumableEncodings[i]; + const encoding = consumableEncodings[i]!; encoding.ssrc = baseSsrc + i; @@ -982,7 +982,7 @@ function validateRtpCodecCapability(codec: RtpCodecCapability): void { } // Just override kind with media component of mimeType. - codec.kind = mimeTypeMatch[1].toLowerCase() as MediaKind; + codec.kind = mimeTypeMatch[1]!.toLowerCase() as MediaKind; // preferredPayloadType is optional. if ( @@ -1136,7 +1136,7 @@ function validateRtpCodecParameters(codec: RtpCodecParameters): void { throw new TypeError('missing codec.clockRate'); } - const kind = mimeTypeMatch[1].toLowerCase() as MediaKind; + const kind = mimeTypeMatch[1]!.toLowerCase() as MediaKind; // channels is optional. If unset, set it to 1 (just if audio). if (kind === 'audio') { diff --git a/node/src/test/test-Consumer.ts b/node/src/test/test-Consumer.ts index 286076c27a..47dc911f0c 100644 --- a/node/src/test/test-Consumer.ts +++ b/node/src/test/test-Consumer.ts @@ -613,17 +613,17 @@ test('consumer.dump() succeeds', async () => { expect(typeof dump1.rtpParameters).toBe('object'); expect(Array.isArray(dump1.rtpParameters.codecs)).toBe(true); expect(dump1.rtpParameters.codecs.length).toBe(1); - expect(dump1.rtpParameters.codecs[0].mimeType).toBe('audio/opus'); - expect(dump1.rtpParameters.codecs[0].payloadType).toBe(100); - expect(dump1.rtpParameters.codecs[0].clockRate).toBe(48000); - expect(dump1.rtpParameters.codecs[0].channels).toBe(2); - expect(dump1.rtpParameters.codecs[0].parameters).toEqual({ + expect(dump1.rtpParameters.codecs[0]!.mimeType).toBe('audio/opus'); + expect(dump1.rtpParameters.codecs[0]!.payloadType).toBe(100); + expect(dump1.rtpParameters.codecs[0]!.clockRate).toBe(48000); + expect(dump1.rtpParameters.codecs[0]!.channels).toBe(2); + expect(dump1.rtpParameters.codecs[0]!.parameters).toEqual({ useinbandfec: 1, usedtx: 1, foo: 222.222, bar: '333', }); - expect(dump1.rtpParameters.codecs[0].rtcpFeedback).toEqual([]); + expect(dump1.rtpParameters.codecs[0]!.rtcpFeedback).toEqual([]); expect(Array.isArray(dump1.rtpParameters.headerExtensions)).toBe(true); expect(dump1.rtpParameters.headerExtensions!.length).toBe(3); expect(dump1.rtpParameters.headerExtensions).toEqual([ @@ -651,7 +651,7 @@ test('consumer.dump() succeeds', async () => { expect(dump1.rtpParameters.encodings).toEqual([ expect.objectContaining({ codecPayloadType: 100, - ssrc: audioConsumer.rtpParameters.encodings?.[0].ssrc, + ssrc: audioConsumer.rtpParameters.encodings![0]!.ssrc, }), ]); expect(dump1.type).toBe('simple'); @@ -659,7 +659,7 @@ test('consumer.dump() succeeds', async () => { expect(dump1.consumableRtpEncodings!.length).toBe(1); expect(dump1.consumableRtpEncodings).toEqual([ expect.objectContaining({ - ssrc: ctx.audioProducer!.consumableRtpParameters.encodings?.[0].ssrc, + ssrc: ctx.audioProducer!.consumableRtpParameters.encodings![0]!.ssrc, }), ]); expect(dump1.supportedCodecPayloadTypes).toEqual([100]); @@ -680,15 +680,15 @@ test('consumer.dump() succeeds', async () => { expect(typeof dump2.rtpParameters).toBe('object'); expect(Array.isArray(dump2.rtpParameters.codecs)).toBe(true); expect(dump2.rtpParameters.codecs.length).toBe(2); - expect(dump2.rtpParameters.codecs[0].mimeType).toBe('video/H264'); - expect(dump2.rtpParameters.codecs[0].payloadType).toBe(103); - expect(dump2.rtpParameters.codecs[0].clockRate).toBe(90000); - expect(dump2.rtpParameters.codecs[0].channels).toBeUndefined(); - expect(dump2.rtpParameters.codecs[0].parameters).toEqual({ + expect(dump2.rtpParameters.codecs[0]!.mimeType).toBe('video/H264'); + expect(dump2.rtpParameters.codecs[0]!.payloadType).toBe(103); + expect(dump2.rtpParameters.codecs[0]!.clockRate).toBe(90000); + expect(dump2.rtpParameters.codecs[0]!.channels).toBeUndefined(); + expect(dump2.rtpParameters.codecs[0]!.parameters).toEqual({ 'packetization-mode': 1, 'profile-level-id': '4d0032', }); - expect(dump2.rtpParameters.codecs[0].rtcpFeedback).toEqual([ + expect(dump2.rtpParameters.codecs[0]!.rtcpFeedback).toEqual([ { type: 'nack' }, { type: 'nack', parameter: 'pli' }, { type: 'ccm', parameter: 'fir' }, @@ -727,9 +727,9 @@ test('consumer.dump() succeeds', async () => { expect(dump2.rtpParameters.encodings).toMatchObject([ { codecPayloadType: 103, - ssrc: videoConsumer.rtpParameters.encodings?.[0].ssrc, + ssrc: videoConsumer.rtpParameters.encodings![0]!.ssrc, rtx: { - ssrc: videoConsumer.rtpParameters.encodings?.[0].rtx?.ssrc, + ssrc: videoConsumer.rtpParameters.encodings![0]!.rtx?.ssrc, }, scalabilityMode: 'L4T5', }, @@ -738,25 +738,25 @@ test('consumer.dump() succeeds', async () => { expect(dump2.consumableRtpEncodings!.length).toBe(4); expect(dump2.consumableRtpEncodings![0]).toEqual( expect.objectContaining({ - ssrc: ctx.videoProducer!.consumableRtpParameters.encodings?.[0].ssrc, + ssrc: ctx.videoProducer!.consumableRtpParameters.encodings![0]!.ssrc, scalabilityMode: 'L1T5', }) ); expect(dump2.consumableRtpEncodings![1]).toEqual( expect.objectContaining({ - ssrc: ctx.videoProducer!.consumableRtpParameters.encodings?.[1].ssrc, + ssrc: ctx.videoProducer!.consumableRtpParameters.encodings![1]!.ssrc, scalabilityMode: 'L1T5', }) ); expect(dump2.consumableRtpEncodings![2]).toEqual( expect.objectContaining({ - ssrc: ctx.videoProducer!.consumableRtpParameters.encodings?.[2].ssrc, + ssrc: ctx.videoProducer!.consumableRtpParameters.encodings![2]!.ssrc, scalabilityMode: 'L1T5', }) ); expect(dump2.consumableRtpEncodings![3]).toEqual( expect.objectContaining({ - ssrc: ctx.videoProducer!.consumableRtpParameters.encodings?.[3].ssrc, + ssrc: ctx.videoProducer!.consumableRtpParameters.encodings![3]!.ssrc, scalabilityMode: 'L1T5', }) ); @@ -777,7 +777,7 @@ test('consumer.getStats() succeeds', async () => { type: 'outbound-rtp', kind: 'audio', mimeType: 'audio/opus', - ssrc: audioConsumer.rtpParameters.encodings?.[0].ssrc, + ssrc: audioConsumer.rtpParameters.encodings![0]!.ssrc, }), ]); @@ -791,7 +791,7 @@ test('consumer.getStats() succeeds', async () => { type: 'outbound-rtp', kind: 'video', mimeType: 'video/H264', - ssrc: videoConsumer.rtpParameters.encodings?.[0].ssrc, + ssrc: videoConsumer.rtpParameters.encodings![0]!.ssrc, }), ]); }, 2000); diff --git a/node/src/test/test-DirectTransport.ts b/node/src/test/test-DirectTransport.ts index 217a28fd51..18decccadd 100644 --- a/node/src/test/test-DirectTransport.ts +++ b/node/src/test/test-DirectTransport.ts @@ -76,23 +76,23 @@ test('directTransport.getStats() succeeds', async () => { expect(Array.isArray(stats)).toBe(true); expect(stats.length).toBe(1); - expect(stats[0].type).toBe('direct-transport'); - expect(stats[0].transportId).toBe(directTransport.id); - expect(typeof stats[0].timestamp).toBe('number'); - expect(stats[0].bytesReceived).toBe(0); - expect(stats[0].recvBitrate).toBe(0); - expect(stats[0].bytesSent).toBe(0); - expect(stats[0].sendBitrate).toBe(0); - expect(stats[0].rtpBytesReceived).toBe(0); - expect(stats[0].rtpRecvBitrate).toBe(0); - expect(stats[0].rtpBytesSent).toBe(0); - expect(stats[0].rtpSendBitrate).toBe(0); - expect(stats[0].rtxBytesReceived).toBe(0); - expect(stats[0].rtxRecvBitrate).toBe(0); - expect(stats[0].rtxBytesSent).toBe(0); - expect(stats[0].rtxSendBitrate).toBe(0); - expect(stats[0].probationBytesSent).toBe(0); - expect(stats[0].probationSendBitrate).toBe(0); + expect(stats[0]!.type).toBe('direct-transport'); + expect(stats[0]!.transportId).toBe(directTransport.id); + expect(typeof stats[0]!.timestamp).toBe('number'); + expect(stats[0]!.bytesReceived).toBe(0); + expect(stats[0]!.recvBitrate).toBe(0); + expect(stats[0]!.bytesSent).toBe(0); + expect(stats[0]!.sendBitrate).toBe(0); + expect(stats[0]!.rtpBytesReceived).toBe(0); + expect(stats[0]!.rtpRecvBitrate).toBe(0); + expect(stats[0]!.rtpBytesSent).toBe(0); + expect(stats[0]!.rtpSendBitrate).toBe(0); + expect(stats[0]!.rtxBytesReceived).toBe(0); + expect(stats[0]!.rtxRecvBitrate).toBe(0); + expect(stats[0]!.rtxBytesSent).toBe(0); + expect(stats[0]!.rtxSendBitrate).toBe(0); + expect(stats[0]!.probationBytesSent).toBe(0); + expect(stats[0]!.probationSendBitrate).toBe(0); }, 2000); test('directTransport.connect() succeeds', async () => { diff --git a/node/src/test/test-PipeTransport.ts b/node/src/test/test-PipeTransport.ts index 2bffccc5a8..ede8791841 100644 --- a/node/src/test/test-PipeTransport.ts +++ b/node/src/test/test-PipeTransport.ts @@ -828,9 +828,9 @@ test('transport.consume() for a pipe Producer succeeds', async () => { }, ]); expect(videoConsumer.rtpParameters.encodings?.length).toBe(1); - expect(typeof videoConsumer.rtpParameters.encodings?.[0].ssrc).toBe('number'); - expect(typeof videoConsumer.rtpParameters.encodings?.[0].rtx).toBe('object'); - expect(typeof videoConsumer.rtpParameters.encodings?.[0].rtx?.ssrc).toBe( + expect(typeof videoConsumer.rtpParameters.encodings![0]!.ssrc).toBe('number'); + expect(typeof videoConsumer.rtpParameters.encodings![0]!.rtx).toBe('object'); + expect(typeof videoConsumer.rtpParameters.encodings![0]!.rtx?.ssrc).toBe( 'number' ); expect(videoConsumer.type).toBe('simulcast'); diff --git a/node/src/test/test-PlainTransport.ts b/node/src/test/test-PlainTransport.ts index 9fd58564a6..ff332f183d 100644 --- a/node/src/test/test-PlainTransport.ts +++ b/node/src/test/test-PlainTransport.ts @@ -401,30 +401,30 @@ test('plainTransport.getStats() succeeds', async () => { expect(Array.isArray(stats)).toBe(true); expect(stats.length).toBe(1); - expect(stats[0].type).toBe('plain-rtp-transport'); - expect(stats[0].transportId).toBe(plainTransport.id); - expect(typeof stats[0].timestamp).toBe('number'); - expect(stats[0].bytesReceived).toBe(0); - expect(stats[0].recvBitrate).toBe(0); - expect(stats[0].bytesSent).toBe(0); - expect(stats[0].sendBitrate).toBe(0); - expect(stats[0].rtpBytesReceived).toBe(0); - expect(stats[0].rtpRecvBitrate).toBe(0); - expect(stats[0].rtpBytesSent).toBe(0); - expect(stats[0].rtpSendBitrate).toBe(0); - expect(stats[0].rtxBytesReceived).toBe(0); - expect(stats[0].rtxRecvBitrate).toBe(0); - expect(stats[0].rtxBytesSent).toBe(0); - expect(stats[0].rtxSendBitrate).toBe(0); - expect(stats[0].probationBytesSent).toBe(0); - expect(stats[0].probationSendBitrate).toBe(0); - expect(typeof stats[0].tuple).toBe('object'); + expect(stats[0]!.type).toBe('plain-rtp-transport'); + expect(stats[0]!.transportId).toBe(plainTransport.id); + expect(typeof stats[0]!.timestamp).toBe('number'); + expect(stats[0]!.bytesReceived).toBe(0); + expect(stats[0]!.recvBitrate).toBe(0); + expect(stats[0]!.bytesSent).toBe(0); + expect(stats[0]!.sendBitrate).toBe(0); + expect(stats[0]!.rtpBytesReceived).toBe(0); + expect(stats[0]!.rtpRecvBitrate).toBe(0); + expect(stats[0]!.rtpBytesSent).toBe(0); + expect(stats[0]!.rtpSendBitrate).toBe(0); + expect(stats[0]!.rtxBytesReceived).toBe(0); + expect(stats[0]!.rtxRecvBitrate).toBe(0); + expect(stats[0]!.rtxBytesSent).toBe(0); + expect(stats[0]!.rtxSendBitrate).toBe(0); + expect(stats[0]!.probationBytesSent).toBe(0); + expect(stats[0]!.probationSendBitrate).toBe(0); + expect(typeof stats[0]!.tuple).toBe('object'); // @deprecated Use tuple.localAddress instead. - expect(stats[0].tuple.localIp).toBe('127.0.0.1'); - expect(stats[0].tuple.localAddress).toBe('127.0.0.1'); - expect(typeof stats[0].tuple.localPort).toBe('number'); - expect(stats[0].tuple.protocol).toBe('udp'); - expect(stats[0].rtcpTuple).toBeUndefined(); + expect(stats[0]!.tuple.localIp).toBe('127.0.0.1'); + expect(stats[0]!.tuple.localAddress).toBe('127.0.0.1'); + expect(typeof stats[0]!.tuple.localPort).toBe('number'); + expect(stats[0]!.tuple.protocol).toBe('udp'); + expect(stats[0]!.rtcpTuple).toBeUndefined(); }, 2000); test('plainTransport.connect() succeeds', async () => { diff --git a/node/src/test/test-Producer.ts b/node/src/test/test-Producer.ts index 38ad33607f..c16b633955 100644 --- a/node/src/test/test-Producer.ts +++ b/node/src/test/test-Producer.ts @@ -499,17 +499,17 @@ test('producer.dump() succeeds', async () => { expect(typeof dump1.rtpParameters).toBe('object'); expect(Array.isArray(dump1.rtpParameters.codecs)).toBe(true); expect(dump1.rtpParameters.codecs.length).toBe(1); - expect(dump1.rtpParameters.codecs[0].mimeType).toBe('audio/opus'); - expect(dump1.rtpParameters.codecs[0].payloadType).toBe(0); - expect(dump1.rtpParameters.codecs[0].clockRate).toBe(48000); - expect(dump1.rtpParameters.codecs[0].channels).toBe(2); - expect(dump1.rtpParameters.codecs[0].parameters).toEqual({ + expect(dump1.rtpParameters.codecs[0]!.mimeType).toBe('audio/opus'); + expect(dump1.rtpParameters.codecs[0]!.payloadType).toBe(0); + expect(dump1.rtpParameters.codecs[0]!.clockRate).toBe(48000); + expect(dump1.rtpParameters.codecs[0]!.channels).toBe(2); + expect(dump1.rtpParameters.codecs[0]!.parameters).toEqual({ useinbandfec: 1, usedtx: 1, foo: 222.222, bar: '333', }); - expect(dump1.rtpParameters.codecs[0].rtcpFeedback).toEqual([]); + expect(dump1.rtpParameters.codecs[0]!.rtcpFeedback).toEqual([]); expect(Array.isArray(dump1.rtpParameters.headerExtensions)).toBe(true); expect(dump1.rtpParameters.headerExtensions!.length).toBe(2); expect(dump1.rtpParameters.headerExtensions).toEqual([ @@ -546,25 +546,25 @@ test('producer.dump() succeeds', async () => { expect(typeof dump2.rtpParameters).toBe('object'); expect(Array.isArray(dump2.rtpParameters.codecs)).toBe(true); expect(dump2.rtpParameters.codecs.length).toBe(2); - expect(dump2.rtpParameters.codecs[0].mimeType).toBe('video/H264'); - expect(dump2.rtpParameters.codecs[0].payloadType).toBe(112); - expect(dump2.rtpParameters.codecs[0].clockRate).toBe(90000); - expect(dump2.rtpParameters.codecs[0].channels).toBeUndefined(); - expect(dump2.rtpParameters.codecs[0].parameters).toEqual({ + expect(dump2.rtpParameters.codecs[0]!.mimeType).toBe('video/H264'); + expect(dump2.rtpParameters.codecs[0]!.payloadType).toBe(112); + expect(dump2.rtpParameters.codecs[0]!.clockRate).toBe(90000); + expect(dump2.rtpParameters.codecs[0]!.channels).toBeUndefined(); + expect(dump2.rtpParameters.codecs[0]!.parameters).toEqual({ 'packetization-mode': 1, 'profile-level-id': '4d0032', }); - expect(dump2.rtpParameters.codecs[0].rtcpFeedback).toEqual([ + expect(dump2.rtpParameters.codecs[0]!.rtcpFeedback).toEqual([ { type: 'nack' }, { type: 'nack', parameter: 'pli' }, { type: 'goog-remb' }, ]); - expect(dump2.rtpParameters.codecs[1].mimeType).toBe('video/rtx'); - expect(dump2.rtpParameters.codecs[1].payloadType).toBe(113); - expect(dump2.rtpParameters.codecs[1].clockRate).toBe(90000); - expect(dump2.rtpParameters.codecs[1].channels).toBeUndefined(); - expect(dump2.rtpParameters.codecs[1].parameters).toEqual({ apt: 112 }); - expect(dump2.rtpParameters.codecs[1].rtcpFeedback).toEqual([]); + expect(dump2.rtpParameters.codecs[1]!.mimeType).toBe('video/rtx'); + expect(dump2.rtpParameters.codecs[1]!.payloadType).toBe(113); + expect(dump2.rtpParameters.codecs[1]!.clockRate).toBe(90000); + expect(dump2.rtpParameters.codecs[1]!.channels).toBeUndefined(); + expect(dump2.rtpParameters.codecs[1]!.parameters).toEqual({ apt: 112 }); + expect(dump2.rtpParameters.codecs[1]!.rtcpFeedback).toEqual([]); expect(Array.isArray(dump2.rtpParameters.headerExtensions)).toBe(true); expect(dump2.rtpParameters.headerExtensions!.length).toBe(2); expect(dump2.rtpParameters.headerExtensions).toEqual([ diff --git a/node/src/test/test-WebRtcServer.ts b/node/src/test/test-WebRtcServer.ts index 669e8ab8ef..1aa1904dd5 100644 --- a/node/src/test/test-WebRtcServer.ts +++ b/node/src/test/test-WebRtcServer.ts @@ -429,11 +429,11 @@ test('router.createWebRtcTransport() with webRtcServer succeeds and transport is const iceCandidates = transport.iceCandidates; expect(iceCandidates.length).toBe(1); - expect(iceCandidates[0].ip).toBe('127.0.0.1'); - expect(iceCandidates[0].port).toBe(port2); - expect(iceCandidates[0].protocol).toBe('tcp'); - expect(iceCandidates[0].type).toBe('host'); - expect(iceCandidates[0].tcpType).toBe('passive'); + expect(iceCandidates[0]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[0]!.port).toBe(port2); + expect(iceCandidates[0]!.protocol).toBe('tcp'); + expect(iceCandidates[0]!.type).toBe('host'); + expect(iceCandidates[0]!.tcpType).toBe('passive'); expect(transport.iceState).toBe('new'); expect(transport.iceSelectedTuple).toBeUndefined(); @@ -528,16 +528,16 @@ test('router.createWebRtcTransport() with webRtcServer succeeds and webRtcServer const iceCandidates = transport.iceCandidates; expect(iceCandidates.length).toBe(2); - expect(iceCandidates[0].ip).toBe('127.0.0.1'); - expect(iceCandidates[0].port).toBe(port1); - expect(iceCandidates[0].protocol).toBe('udp'); - expect(iceCandidates[0].type).toBe('host'); - expect(iceCandidates[0].tcpType).toBeUndefined(); - expect(iceCandidates[1].ip).toBe('127.0.0.1'); - expect(iceCandidates[1].port).toBe(port2); - expect(iceCandidates[1].protocol).toBe('tcp'); - expect(iceCandidates[1].type).toBe('host'); - expect(iceCandidates[1].tcpType).toBe('passive'); + expect(iceCandidates[0]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[0]!.port).toBe(port1); + expect(iceCandidates[0]!.protocol).toBe('udp'); + expect(iceCandidates[0]!.type).toBe('host'); + expect(iceCandidates[0]!.tcpType).toBeUndefined(); + expect(iceCandidates[1]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[1]!.port).toBe(port2); + expect(iceCandidates[1]!.protocol).toBe('tcp'); + expect(iceCandidates[1]!.type).toBe('host'); + expect(iceCandidates[1]!.tcpType).toBe('passive'); expect(transport.iceState).toBe('new'); expect(transport.iceSelectedTuple).toBeUndefined(); diff --git a/node/src/test/test-WebRtcTransport.ts b/node/src/test/test-WebRtcTransport.ts index a241bcf2f7..6391c99f3a 100644 --- a/node/src/test/test-WebRtcTransport.ts +++ b/node/src/test/test-WebRtcTransport.ts @@ -143,35 +143,45 @@ test('router.createWebRtcTransport() succeeds', async () => { const iceCandidates = webRtcTransport.iceCandidates; - expect(iceCandidates[0].ip).toBe('9.9.9.1'); - expect(iceCandidates[0].protocol).toBe('udp'); - expect(iceCandidates[0].type).toBe('host'); - expect(iceCandidates[0].tcpType).toBeUndefined(); - expect(iceCandidates[1].ip).toBe('9.9.9.1'); - expect(iceCandidates[1].protocol).toBe('tcp'); - expect(iceCandidates[1].type).toBe('host'); - expect(iceCandidates[1].tcpType).toBe('passive'); - expect(iceCandidates[2].ip).toBe('foo1.bar.org'); - expect(iceCandidates[2].protocol).toBe('udp'); - expect(iceCandidates[2].type).toBe('host'); - expect(iceCandidates[2].tcpType).toBeUndefined(); - expect(iceCandidates[3].ip).toBe('foo2.bar.org'); - expect(iceCandidates[3].protocol).toBe('tcp'); - expect(iceCandidates[3].type).toBe('host'); - expect(iceCandidates[3].tcpType).toBe('passive'); - expect(iceCandidates[4].ip).toBe('127.0.0.1'); - expect(iceCandidates[4].protocol).toBe('udp'); - expect(iceCandidates[4].type).toBe('host'); - expect(iceCandidates[4].tcpType).toBeUndefined(); - expect(iceCandidates[5].ip).toBe('127.0.0.1'); - expect(iceCandidates[5].protocol).toBe('tcp'); - expect(iceCandidates[5].type).toBe('host'); - expect(iceCandidates[5].tcpType).toBe('passive'); - expect(iceCandidates[0].priority).toBeGreaterThan(iceCandidates[1].priority); - expect(iceCandidates[1].priority).toBeGreaterThan(iceCandidates[2].priority); - expect(iceCandidates[2].priority).toBeGreaterThan(iceCandidates[3].priority); - expect(iceCandidates[3].priority).toBeGreaterThan(iceCandidates[4].priority); - expect(iceCandidates[4].priority).toBeGreaterThan(iceCandidates[5].priority); + expect(iceCandidates[0]!.ip).toBe('9.9.9.1'); + expect(iceCandidates[0]!.protocol).toBe('udp'); + expect(iceCandidates[0]!.type).toBe('host'); + expect(iceCandidates[0]!.tcpType).toBeUndefined(); + expect(iceCandidates[1]!.ip).toBe('9.9.9.1'); + expect(iceCandidates[1]!.protocol).toBe('tcp'); + expect(iceCandidates[1]!.type).toBe('host'); + expect(iceCandidates[1]!.tcpType).toBe('passive'); + expect(iceCandidates[2]!.ip).toBe('foo1.bar.org'); + expect(iceCandidates[2]!.protocol).toBe('udp'); + expect(iceCandidates[2]!.type).toBe('host'); + expect(iceCandidates[2]!.tcpType).toBeUndefined(); + expect(iceCandidates[3]!.ip).toBe('foo2.bar.org'); + expect(iceCandidates[3]!.protocol).toBe('tcp'); + expect(iceCandidates[3]!.type).toBe('host'); + expect(iceCandidates[3]!.tcpType).toBe('passive'); + expect(iceCandidates[4]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[4]!.protocol).toBe('udp'); + expect(iceCandidates[4]!.type).toBe('host'); + expect(iceCandidates[4]!.tcpType).toBeUndefined(); + expect(iceCandidates[5]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[5]!.protocol).toBe('tcp'); + expect(iceCandidates[5]!.type).toBe('host'); + expect(iceCandidates[5]!.tcpType).toBe('passive'); + expect(iceCandidates[0]!.priority).toBeGreaterThan( + iceCandidates[1]!.priority + ); + expect(iceCandidates[1]!.priority).toBeGreaterThan( + iceCandidates[2]!.priority + ); + expect(iceCandidates[2]!.priority).toBeGreaterThan( + iceCandidates[3]!.priority + ); + expect(iceCandidates[3]!.priority).toBeGreaterThan( + iceCandidates[4]!.priority + ); + expect(iceCandidates[4]!.priority).toBeGreaterThan( + iceCandidates[5]!.priority + ); expect(webRtcTransport.iceState).toBe('new'); expect(webRtcTransport.iceSelectedTuple).toBeUndefined(); @@ -218,15 +228,17 @@ test('router.createWebRtcTransport() with deprecated listenIps succeeds', async const iceCandidates = webRtcTransport.iceCandidates; - expect(iceCandidates[0].ip).toBe('127.0.0.1'); - expect(iceCandidates[0].protocol).toBe('udp'); - expect(iceCandidates[0].type).toBe('host'); - expect(iceCandidates[0].tcpType).toBeUndefined(); - expect(iceCandidates[1].ip).toBe('127.0.0.1'); - expect(iceCandidates[1].protocol).toBe('tcp'); - expect(iceCandidates[1].type).toBe('host'); - expect(iceCandidates[1].tcpType).toBe('passive'); - expect(iceCandidates[0].priority).toBeGreaterThan(iceCandidates[1].priority); + expect(iceCandidates[0]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[0]!.protocol).toBe('udp'); + expect(iceCandidates[0]!.type).toBe('host'); + expect(iceCandidates[0]!.tcpType).toBeUndefined(); + expect(iceCandidates[1]!.ip).toBe('127.0.0.1'); + expect(iceCandidates[1]!.protocol).toBe('tcp'); + expect(iceCandidates[1]!.type).toBe('host'); + expect(iceCandidates[1]!.tcpType).toBe('passive'); + expect(iceCandidates[0]!.priority).toBeGreaterThan( + iceCandidates[1]!.priority + ); }, 2000); test('router.createWebRtcTransport() with fixed port succeeds', async () => { @@ -242,7 +254,7 @@ test('router.createWebRtcTransport() with fixed port succeeds', async () => { ], }); - expect(webRtcTransport.iceCandidates[0].port).toEqual(port); + expect(webRtcTransport.iceCandidates[0]!.port).toEqual(port); }, 2000); test('router.createWebRtcTransport() with portRange succeeds', async () => { @@ -252,7 +264,7 @@ test('router.createWebRtcTransport() with portRange succeeds', async () => { listenInfos: [{ protocol: 'udp', ip: '127.0.0.1', portRange }], }); - const iceCandidate1 = webRtcTransport1.iceCandidates[0]; + const iceCandidate1 = webRtcTransport1.iceCandidates[0]!; expect(iceCandidate1.ip).toBe('127.0.0.1'); expect( @@ -264,7 +276,7 @@ test('router.createWebRtcTransport() with portRange succeeds', async () => { listenInfos: [{ protocol: 'udp', ip: '127.0.0.1', portRange }], }); - const iceCandidate2 = webRtcTransport2.iceCandidates[0]; + const iceCandidate2 = webRtcTransport2.iceCandidates[0]!; expect(iceCandidate2.ip).toBe('127.0.0.1'); expect( @@ -357,29 +369,29 @@ test('webRtcTransport.getStats() succeeds', async () => { expect(Array.isArray(stats)).toBe(true); expect(stats.length).toBe(1); - expect(stats[0].type).toBe('webrtc-transport'); - expect(stats[0].transportId).toBe(webRtcTransport.id); - expect(typeof stats[0].timestamp).toBe('number'); - expect(stats[0].iceRole).toBe('controlled'); - expect(stats[0].iceState).toBe('new'); - expect(stats[0].dtlsState).toBe('new'); - expect(stats[0].sctpState).toBeUndefined(); - expect(stats[0].bytesReceived).toBe(0); - expect(stats[0].recvBitrate).toBe(0); - expect(stats[0].bytesSent).toBe(0); - expect(stats[0].sendBitrate).toBe(0); - expect(stats[0].rtpBytesReceived).toBe(0); - expect(stats[0].rtpRecvBitrate).toBe(0); - expect(stats[0].rtpBytesSent).toBe(0); - expect(stats[0].rtpSendBitrate).toBe(0); - expect(stats[0].rtxBytesReceived).toBe(0); - expect(stats[0].rtxRecvBitrate).toBe(0); - expect(stats[0].rtxBytesSent).toBe(0); - expect(stats[0].rtxSendBitrate).toBe(0); - expect(stats[0].probationBytesSent).toBe(0); - expect(stats[0].probationSendBitrate).toBe(0); - expect(stats[0].iceSelectedTuple).toBeUndefined(); - expect(stats[0].maxIncomingBitrate).toBeUndefined(); + expect(stats[0]!.type).toBe('webrtc-transport'); + expect(stats[0]!.transportId).toBe(webRtcTransport.id); + expect(typeof stats[0]!.timestamp).toBe('number'); + expect(stats[0]!.iceRole).toBe('controlled'); + expect(stats[0]!.iceState).toBe('new'); + expect(stats[0]!.dtlsState).toBe('new'); + expect(stats[0]!.sctpState).toBeUndefined(); + expect(stats[0]!.bytesReceived).toBe(0); + expect(stats[0]!.recvBitrate).toBe(0); + expect(stats[0]!.bytesSent).toBe(0); + expect(stats[0]!.sendBitrate).toBe(0); + expect(stats[0]!.rtpBytesReceived).toBe(0); + expect(stats[0]!.rtpRecvBitrate).toBe(0); + expect(stats[0]!.rtpBytesSent).toBe(0); + expect(stats[0]!.rtpSendBitrate).toBe(0); + expect(stats[0]!.rtxBytesReceived).toBe(0); + expect(stats[0]!.rtxRecvBitrate).toBe(0); + expect(stats[0]!.rtxBytesSent).toBe(0); + expect(stats[0]!.rtxSendBitrate).toBe(0); + expect(stats[0]!.probationBytesSent).toBe(0); + expect(stats[0]!.probationSendBitrate).toBe(0); + expect(stats[0]!.iceSelectedTuple).toBeUndefined(); + expect(stats[0]!.maxIncomingBitrate).toBeUndefined(); }, 2000); test('webRtcTransport.connect() succeeds', async () => { diff --git a/node/src/test/test-Worker.ts b/node/src/test/test-Worker.ts index 06e4fb767b..7782ffe0a7 100644 --- a/node/src/test/test-Worker.ts +++ b/node/src/test/test-Worker.ts @@ -7,9 +7,9 @@ import type { WorkerEvents } from '../types'; import { InvalidStateError } from '../errors'; test('mediasoup.workerBin matches mediasoup-worker absolute path', () => { - const workerBin = process.env.MEDIASOUP_WORKER_BIN - ? process.env.MEDIASOUP_WORKER_BIN - : process.env.MEDIASOUP_BUILDTYPE === 'Debug' + const workerBin = process.env['MEDIASOUP_WORKER_BIN'] + ? process.env['MEDIASOUP_WORKER_BIN'] + : process.env['MEDIASOUP_BUILDTYPE'] === 'Debug' ? path.join( __dirname, '..', diff --git a/node/src/test/test-ortc.ts b/node/src/test/test-ortc.ts index e07ad9d091..9ac227fc5f 100644 --- a/node/src/test/test-ortc.ts +++ b/node/src/test/test-ortc.ts @@ -259,15 +259,15 @@ test('getProducerRtpParametersMapping(), getConsumableRtpParameters(), getConsum { payloadType: 112, mappedPayloadType: 102 }, ]); - expect(rtpMapping.encodings[0].ssrc).toBe(11111111); - expect(rtpMapping.encodings[0].rid).toBeUndefined(); - expect(typeof rtpMapping.encodings[0].mappedSsrc).toBe('number'); - expect(rtpMapping.encodings[1].ssrc).toBe(21111111); - expect(rtpMapping.encodings[1].rid).toBeUndefined(); - expect(typeof rtpMapping.encodings[1].mappedSsrc).toBe('number'); - expect(rtpMapping.encodings[2].ssrc).toBeUndefined(); - expect(rtpMapping.encodings[2].rid).toBe('high'); - expect(typeof rtpMapping.encodings[2].mappedSsrc).toBe('number'); + expect(rtpMapping.encodings[0]!.ssrc).toBe(11111111); + expect(rtpMapping.encodings[0]!.rid).toBeUndefined(); + expect(typeof rtpMapping.encodings[0]!.mappedSsrc).toBe('number'); + expect(rtpMapping.encodings[1]!.ssrc).toBe(21111111); + expect(rtpMapping.encodings[1]!.rid).toBeUndefined(); + expect(typeof rtpMapping.encodings[1]!.mappedSsrc).toBe('number'); + expect(rtpMapping.encodings[2]!.ssrc).toBeUndefined(); + expect(rtpMapping.encodings[2]!.rid).toBe('high'); + expect(typeof rtpMapping.encodings[2]!.mappedSsrc).toBe('number'); const consumableRtpParameters = ortc.getConsumableRtpParameters( 'video', @@ -276,32 +276,32 @@ test('getProducerRtpParametersMapping(), getConsumableRtpParameters(), getConsum rtpMapping ); - expect(consumableRtpParameters.codecs[0].mimeType).toBe('video/H264'); - expect(consumableRtpParameters.codecs[0].payloadType).toBe(101); - expect(consumableRtpParameters.codecs[0].clockRate).toBe(90000); - expect(consumableRtpParameters.codecs[0].parameters).toEqual({ + expect(consumableRtpParameters.codecs[0]!.mimeType).toBe('video/H264'); + expect(consumableRtpParameters.codecs[0]!.payloadType).toBe(101); + expect(consumableRtpParameters.codecs[0]!.clockRate).toBe(90000); + expect(consumableRtpParameters.codecs[0]!.parameters).toEqual({ foo: 1234, 'packetization-mode': 1, 'profile-level-id': '4d0032', }); - expect(consumableRtpParameters.codecs[1].mimeType).toBe('video/rtx'); - expect(consumableRtpParameters.codecs[1].payloadType).toBe(102); - expect(consumableRtpParameters.codecs[1].clockRate).toBe(90000); - expect(consumableRtpParameters.codecs[1].parameters).toEqual({ apt: 101 }); + expect(consumableRtpParameters.codecs[1]!.mimeType).toBe('video/rtx'); + expect(consumableRtpParameters.codecs[1]!.payloadType).toBe(102); + expect(consumableRtpParameters.codecs[1]!.clockRate).toBe(90000); + expect(consumableRtpParameters.codecs[1]!.parameters).toEqual({ apt: 101 }); expect(consumableRtpParameters.encodings?.[0]).toEqual({ - ssrc: rtpMapping.encodings[0].mappedSsrc, + ssrc: rtpMapping.encodings[0]!.mappedSsrc, maxBitrate: 111111, scalabilityMode: 'L1T3', }); expect(consumableRtpParameters.encodings?.[1]).toEqual({ - ssrc: rtpMapping.encodings[1].mappedSsrc, + ssrc: rtpMapping.encodings[1]!.mappedSsrc, maxBitrate: 222222, scalabilityMode: 'L1T3', }); expect(consumableRtpParameters.encodings?.[2]).toEqual({ - ssrc: rtpMapping.encodings[2].mappedSsrc, + ssrc: rtpMapping.encodings[2]!.mappedSsrc, maxBitrate: 333333, scalabilityMode: 'L1T3', }); @@ -428,12 +428,12 @@ test('getProducerRtpParametersMapping(), getConsumableRtpParameters(), getConsum rtcpFeedback: [], }); - expect(consumerRtpParameters.encodings?.length).toBe(1); - expect(typeof consumerRtpParameters.encodings?.[0].ssrc).toBe('number'); - expect(typeof consumerRtpParameters.encodings?.[0].rtx).toBe('object'); - expect(typeof consumerRtpParameters.encodings?.[0].rtx?.ssrc).toBe('number'); - expect(consumerRtpParameters.encodings?.[0].scalabilityMode).toBe('L3T3'); - expect(consumerRtpParameters.encodings?.[0].maxBitrate).toBe(333333); + expect(consumerRtpParameters.encodings!.length).toBe(1); + expect(typeof consumerRtpParameters.encodings![0]!.ssrc).toBe('number'); + expect(typeof consumerRtpParameters.encodings![0]!.rtx).toBe('object'); + expect(typeof consumerRtpParameters.encodings![0]!.rtx?.ssrc).toBe('number'); + expect(consumerRtpParameters.encodings![0]!.scalabilityMode).toBe('L3T3'); + expect(consumerRtpParameters.encodings![0]!.maxBitrate).toBe(333333); expect(consumerRtpParameters.headerExtensions).toEqual([ { @@ -482,25 +482,25 @@ test('getProducerRtpParametersMapping(), getConsumableRtpParameters(), getConsum ], }); - expect(pipeConsumerRtpParameters.encodings?.length).toBe(3); - expect(typeof pipeConsumerRtpParameters.encodings?.[0].ssrc).toBe('number'); - expect(pipeConsumerRtpParameters.encodings?.[0].rtx).toBeUndefined(); - expect(typeof pipeConsumerRtpParameters.encodings?.[0].maxBitrate).toBe( + expect(pipeConsumerRtpParameters.encodings!.length).toBe(3); + expect(typeof pipeConsumerRtpParameters.encodings![0]!.ssrc).toBe('number'); + expect(pipeConsumerRtpParameters.encodings![0]!.rtx).toBeUndefined(); + expect(typeof pipeConsumerRtpParameters.encodings![0]!.maxBitrate).toBe( 'number' ); - expect(pipeConsumerRtpParameters.encodings?.[0].scalabilityMode).toBe('L1T3'); - expect(typeof pipeConsumerRtpParameters.encodings?.[1].ssrc).toBe('number'); - expect(pipeConsumerRtpParameters.encodings?.[1].rtx).toBeUndefined(); - expect(typeof pipeConsumerRtpParameters.encodings?.[1].maxBitrate).toBe( + expect(pipeConsumerRtpParameters.encodings![0]!.scalabilityMode).toBe('L1T3'); + expect(typeof pipeConsumerRtpParameters.encodings![1]!.ssrc).toBe('number'); + expect(pipeConsumerRtpParameters.encodings![1]!.rtx).toBeUndefined(); + expect(typeof pipeConsumerRtpParameters.encodings![1]!.maxBitrate).toBe( 'number' ); - expect(pipeConsumerRtpParameters.encodings?.[1].scalabilityMode).toBe('L1T3'); - expect(typeof pipeConsumerRtpParameters.encodings?.[2].ssrc).toBe('number'); - expect(pipeConsumerRtpParameters.encodings?.[2].rtx).toBeUndefined(); - expect(typeof pipeConsumerRtpParameters.encodings?.[2].maxBitrate).toBe( + expect(pipeConsumerRtpParameters.encodings![1]!.scalabilityMode).toBe('L1T3'); + expect(typeof pipeConsumerRtpParameters.encodings![2]!.ssrc).toBe('number'); + expect(pipeConsumerRtpParameters.encodings![2]!.rtx).toBeUndefined(); + expect(typeof pipeConsumerRtpParameters.encodings![2]!.maxBitrate).toBe( 'number' ); - expect(pipeConsumerRtpParameters.encodings?.[2].scalabilityMode).toBe('L1T3'); + expect(pipeConsumerRtpParameters.encodings![2]!.scalabilityMode).toBe('L1T3'); expect(pipeConsumerRtpParameters.rtcp).toEqual({ cname: rtpParameters.rtcp?.cname, diff --git a/npm-scripts.mjs b/npm-scripts.mjs index 559ec7d044..9cbaa890e4 100644 --- a/npm-scripts.mjs +++ b/npm-scripts.mjs @@ -26,14 +26,17 @@ const GH_REPO = 'mediasoup'; // Paths for ESLint to check. Converted to string for convenience. const ESLINT_PATHS = [ 'eslint.config.mjs', + 'jest.config.mjs', '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}`) .join(' '); + // Paths for Prettier to check/write. Converted to string for convenience. // NOTE: Prettier ignores paths in .gitignore so we don't need to care about // node/src/fbs. @@ -42,6 +45,8 @@ const PRETTIER_PATHS = [ 'CONTRIBUTING.md', 'README.md', 'doc', + 'eslint.config.mjs', + 'jest.config.mjs', 'node/src', 'npm-scripts.mjs', 'package.json', @@ -64,7 +69,7 @@ if (process.env.PYTHONPATH) { process.env.PYTHONPATH = PIP_INVOKE_DIR; } -run(); +void run(); async function run() { logInfo(args ? `[args:"${args}"]` : ''); @@ -133,15 +138,13 @@ async function run() { } case 'typescript:build': { - installNodeDeps(); buildTypescript({ force: true }); break; } case 'typescript:watch': { - deleteNodeLib(); - executeCmd(`tsc --watch ${args}`); + watchTypescript(); break; } @@ -203,7 +206,6 @@ async function run() { } case 'test:node': { - buildTypescript({ force: false }); testNode(); break; @@ -216,7 +218,6 @@ async function run() { } case 'coverage:node': { - buildTypescript({ force: false }); executeCmd(`jest --coverage ${args}`); executeCmd('open-cli coverage/lcov-report/index.html'); @@ -317,8 +318,7 @@ function installInvoke() { // Install pip invoke into custom location, so we don't depend on system-wide // installation. executeCmd( - `"${PYTHON}" -m pip install --upgrade --no-user --target "${PIP_INVOKE_DIR}" invoke`, - /* exitOnError */ true + `"${PYTHON}" -m pip install --upgrade --no-user --target "${PIP_INVOKE_DIR}" invoke` ); } @@ -332,7 +332,7 @@ function deleteNodeLib() { fs.rmSync('node/lib', { recursive: true, force: true }); } -function buildTypescript({ force = false } = { force: false }) { +function buildTypescript({ force }) { if (!force && fs.existsSync('node/lib')) { return; } @@ -340,7 +340,16 @@ function buildTypescript({ force = false } = { force: false }) { logInfo('buildTypescript()'); deleteNodeLib(); - executeCmd('tsc'); + + executeCmd(`tsc ${args}`); +} + +function watchTypescript() { + logInfo('watchTypescript()'); + + deleteNodeLib(); + + executeCmd(`tsc --watch ${args}`); } function buildWorker() { @@ -358,8 +367,10 @@ function cleanWorkerArtifacts() { // Clean build artifacts except `mediasoup-worker`. executeCmd(`"${PYTHON}" -m invoke -r worker clean-build`); + // Clean downloaded dependencies. executeCmd(`"${PYTHON}" -m invoke -r worker clean-subprojects`); + // Clean PIP/Meson/Ninja. executeCmd(`"${PYTHON}" -m invoke -r worker clean-pip`); } @@ -470,6 +481,7 @@ function installNodeDeps() { // Install/update Node deps. executeCmd('npm ci --ignore-scripts'); + // Update package-lock.json. executeCmd('npm install --package-lock-only --ignore-scripts'); } @@ -679,19 +691,15 @@ async function getVersionChanges() { ); } -function executeCmd(command, exitOnError = true) { +function executeCmd(command) { logInfo(`executeCmd(): ${command}`); try { execSync(command, { stdio: ['ignore', process.stdout, process.stderr] }); } catch (error) { - if (exitOnError) { - logError(`executeCmd() failed, exiting: ${error}`); + logError(`executeCmd() failed, exiting: ${error}`); - exitWithError(); - } else { - logInfo(`executeCmd() failed, ignoring: ${error}`); - } + exitWithError(); } } diff --git a/package.json b/package.json index 0b8fb7d0ae..30adddf523 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,21 @@ }, "main": "node/lib/index.js", "types": "node/lib/index.d.ts", + "exports": { + ".": { + "types": "./node/lib/index.d.ts", + "default": "./node/lib/index.js" + }, + "./types": { + "types": "./node/lib/types.d.ts", + "default": "./node/lib/types.js" + } + }, "files": [ + "LICENSE", + "README.md", "node/lib", + "npm-scripts.mjs", "worker/deps/libwebrtc", "worker/fbs", "worker/fuzzer/include", @@ -36,8 +49,7 @@ "worker/test/src", "worker/meson.build", "worker/meson_options.txt", - "worker/tasks.py", - "npm-scripts.mjs" + "worker/tasks.py" ], "engines": { "node": ">=18" @@ -72,33 +84,6 @@ "release:check": "node npm-scripts.mjs release:check", "release": "node npm-scripts.mjs release" }, - "jest": { - "verbose": true, - "testEnvironment": "node", - "testRegex": "node/src/test/test-.*\\.ts", - "transform": { - "^.*\\.ts$": [ - "ts-jest", - { - "diagnostics": { - "ignoreCodes": [ - "TS151001" - ] - } - } - ] - }, - "coveragePathIgnorePatterns": [ - "node/src/fbs", - "node/src/test" - ], - "cacheDirectory": ".cache/jest", - "modulePathIgnorePatterns": [ - "worker", - "rust", - "target" - ] - }, "dependencies": { "@types/ini": "^4.1.1", "debug": "^4.4.0", diff --git a/tsconfig.json b/tsconfig.json index 1ea8a48622..a405fa95a1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,40 @@ { "compileOnSave": true, "compilerOptions": { - "lib": ["es2022"], - "target": "esnext", - "module": "commonjs", - "moduleResolution": "node", - "strict": true, + "lib": ["es2024", "dom"], + "module": "NodeNext", + "moduleResolution": "NodeNext", "outDir": "node/lib", "declaration": true, - "declarationMap": true + "declarationMap": true, + "emitDeclarationOnly": false, + "declarationDir": "node/lib", + "isolatedModules": false, + "verbatimModuleSyntax": false, + "useDefineForClassFields": true, + "esModuleInterop": false, + "allowImportingTsExtensions": false, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "alwaysStrict": true, + "exactOptionalPropertyTypes": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "strict": true, + "strictBindCallApply": true, + "strictBuiltinIteratorReturn": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "useUnknownInCatchVariables": true, + "noUncheckedSideEffectImports": true }, - "include": ["node/src"], - "watchOptions": { - "watchFile": "useFsEvents", - "watchDirectory": "useFsEvents", - "fallbackPolling": "dynamicPriority", - "synchronousWatchDirectory": true - } + "include": ["node/src"] } From 455eed979cfb8e26548985daf661280d10f62b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Baz=20Castillo?= Date: Mon, 24 Mar 2025 02:21:54 +0100 Subject: [PATCH 2/3] Add .editorconfig --- .editorconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..6f1e75efeb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://editorconfig.org + +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{ts,mts,mjs,cjs,js}] +indent_style = tab + +[*.json] +indent_style = tab + +[*.md] +indent_style = tab From 26aca8fe85789d8b545087a6dafc55e644aa5a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Baz=20Castillo?= Date: Mon, 24 Mar 2025 02:28:51 +0100 Subject: [PATCH 3/3] more --- CHANGELOG.md | 2 +- node/src/index.ts | 4 ++-- package.json | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94e983b19f..2f9ab4f3fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### NEXT - CI: Remove redundant hosts `macos-14` and `windows-2022` from `mediasoup-worker-prebuild` job ([PR #1506](https://github.com/versatica/mediasoup/pull/1506)). -- Node: Modernize code ([PR #XXXX](https://github.com/versatica/mediasoup/pull/XXXX)). +- Node: Modernize code ([PR #1513](https://github.com/versatica/mediasoup/pull/1513)). ### 3.15.6 diff --git a/node/src/index.ts b/node/src/index.ts index 031c64c5b0..fdf3ad4a38 100644 --- a/node/src/index.ts +++ b/node/src/index.ts @@ -35,7 +35,7 @@ export { observer }; /** * Full path of the mediasoup-worker binary. */ -export { workerBin }; +export { workerBin } from './Worker'; const logger = new Logger(); @@ -142,7 +142,7 @@ export function getSupportedRtpCapabilities(): RtpCapabilities { /** * Expose parseScalabilityMode() function. */ -export { parseScalabilityMode }; +export { parseScalabilityMode } from './scalabilityModesUtils'; /** * Expose extras module. diff --git a/package.json b/package.json index 30adddf523..bd95859114 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,10 @@ "./types": { "types": "./node/lib/types.d.ts", "default": "./node/lib/types.js" + }, + "./extras": { + "types": "./node/lib/extras.d.ts", + "default": "./node/lib/extras.js" } }, "files": [