diff --git a/node/src/test/test-WebRtcTransport.ts b/node/src/test/test-WebRtcTransport.ts index b08b32c342..8f45bff000 100644 --- a/node/src/test/test-WebRtcTransport.ts +++ b/node/src/test/test-WebRtcTransport.ts @@ -2,77 +2,74 @@ import * as pickPort from 'pick-port'; import * as flatbuffers from 'flatbuffers'; import * as mediasoup from '../'; +import * as utils from '../utils'; +import { serializeProtocol, TransportTuple } from '../Transport'; import { Notification, Body as NotificationBody, Event } from '../fbs/notification'; import * as FbsTransport from '../fbs/transport'; import * as FbsWebRtcTransport from '../fbs/web-rtc-transport'; -import { serializeProtocol, TransportTuple } from '../Transport'; - -let worker: mediasoup.types.Worker; -let router: mediasoup.types.Router; -let transport: mediasoup.types.WebRtcTransport; -const mediaCodecs: mediasoup.types.RtpCodecCapability[] = -[ - { - kind : 'audio', - mimeType : 'audio/opus', - clockRate : 48000, - channels : 2, - parameters : - { - useinbandfec : 1, - foo : 'bar' - } - }, - { - kind : 'video', - mimeType : 'video/VP8', - clockRate : 90000 - }, - { - kind : 'video', - mimeType : 'video/H264', - clockRate : 90000, - parameters : - { - 'level-asymmetry-allowed' : 1, - 'packetization-mode' : 1, - 'profile-level-id' : '4d0032', - foo : 'bar' - } - } -]; - -beforeAll(async () => +type TestContext = { - worker = await mediasoup.createWorker(); - router = await worker.createRouter({ mediaCodecs }); -}); + mediaCodecs: mediasoup.types.RtpCodecCapability[]; + worker?: mediasoup.types.Worker; + router?: mediasoup.types.Router; +}; -afterAll(() => worker.close()); +const ctx: TestContext = +{ + mediaCodecs : utils.deepFreeze( + [ + { + kind : 'audio', + mimeType : 'audio/opus', + clockRate : 48000, + channels : 2, + parameters : + { + useinbandfec : 1, + foo : 'bar' + } + }, + { + kind : 'video', + mimeType : 'video/VP8', + clockRate : 90000 + }, + { + kind : 'video', + mimeType : 'video/H264', + clockRate : 90000, + parameters : + { + 'level-asymmetry-allowed' : 1, + 'packetization-mode' : 1, + 'profile-level-id' : '4d0032', + foo : 'bar' + } + } + ] + ) +}; beforeEach(async () => { - transport = await router.createWebRtcTransport( - { - listenInfos : [ { protocol: 'udp', ip: '127.0.0.1', announcedIp: '9.9.9.1' } ] - }); + ctx.worker = await mediasoup.createWorker(); + ctx.router = await ctx.worker.createRouter({ mediaCodecs: ctx.mediaCodecs }); }); -afterEach(() => transport.close()); +afterEach(() => +{ + ctx.worker?.close(); +}); test('router.createWebRtcTransport() succeeds', async () => { - await expect(router.dump()) - .resolves - .toMatchObject({ transportIds: [ transport.id ] }); - const onObserverNewTransport = jest.fn(); - router.observer.once('newtransport', onObserverNewTransport); + ctx.router!.observer.once('newtransport', onObserverNewTransport); // Create a separate transport here. - const transport1 = await router.createWebRtcTransport( + const webRtcTransport = await ctx.router!.createWebRtcTransport( { listenInfos : [ @@ -91,27 +88,31 @@ test('router.createWebRtcTransport() succeeds', async () => appData : { foo: 'bar' } }); + await expect(ctx.router!.dump()) + .resolves + .toMatchObject({ transportIds: [ webRtcTransport.id ] }); + expect(onObserverNewTransport).toHaveBeenCalledTimes(1); - expect(onObserverNewTransport).toHaveBeenCalledWith(transport1); - expect(typeof transport1.id).toBe('string'); - expect(transport1.closed).toBe(false); - expect(transport1.appData).toEqual({ foo: 'bar' }); - expect(transport1.iceRole).toBe('controlled'); - expect(typeof transport1.iceParameters).toBe('object'); - expect(transport1.iceParameters.iceLite).toBe(true); - expect(typeof transport1.iceParameters.usernameFragment).toBe('string'); - expect(typeof transport1.iceParameters.password).toBe('string'); - expect(transport1.sctpParameters).toMatchObject( + expect(onObserverNewTransport).toHaveBeenCalledWith(webRtcTransport); + expect(typeof webRtcTransport.id).toBe('string'); + expect(webRtcTransport.closed).toBe(false); + expect(webRtcTransport.appData).toEqual({ foo: 'bar' }); + expect(webRtcTransport.iceRole).toBe('controlled'); + expect(typeof webRtcTransport.iceParameters).toBe('object'); + expect(webRtcTransport.iceParameters.iceLite).toBe(true); + expect(typeof webRtcTransport.iceParameters.usernameFragment).toBe('string'); + expect(typeof webRtcTransport.iceParameters.password).toBe('string'); + expect(webRtcTransport.sctpParameters).toMatchObject( { port : 5000, OS : 2048, MIS : 2048, maxMessageSize : 1000000 }); - expect(Array.isArray(transport1.iceCandidates)).toBe(true); - expect(transport1.iceCandidates.length).toBe(6); + expect(Array.isArray(webRtcTransport.iceCandidates)).toBe(true); + expect(webRtcTransport.iceCandidates.length).toBe(6); - const iceCandidates = transport1.iceCandidates; + const iceCandidates = webRtcTransport.iceCandidates; expect(iceCandidates[0].ip).toBe('9.9.9.1'); expect(iceCandidates[0].protocol).toBe('udp'); @@ -143,67 +144,61 @@ test('router.createWebRtcTransport() succeeds', async () => expect(iceCandidates[3].priority).toBeGreaterThan(iceCandidates[4].priority); expect(iceCandidates[4].priority).toBeGreaterThan(iceCandidates[5].priority); - expect(transport1.iceState).toBe('new'); - expect(transport1.iceSelectedTuple).toBeUndefined(); - expect(typeof transport1.dtlsParameters).toBe('object'); - expect(Array.isArray(transport1.dtlsParameters.fingerprints)).toBe(true); - expect(transport1.dtlsParameters.role).toBe('auto'); - expect(transport1.dtlsState).toBe('new'); - expect(transport1.dtlsRemoteCert).toBeUndefined(); - expect(transport1.sctpState).toBe('new'); - - const data1 = await transport1.dump(); - - expect(data1.id).toBe(transport1.id); - expect(data1.direct).toBe(false); - expect(data1.producerIds).toEqual([]); - expect(data1.consumerIds).toEqual([]); - expect(data1.iceRole).toBe(transport1.iceRole); - expect(data1.iceParameters).toEqual(transport1.iceParameters); - expect(data1.iceCandidates).toEqual(transport1.iceCandidates); - expect(data1.iceState).toBe(transport1.iceState); - expect(data1.iceSelectedTuple).toEqual(transport1.iceSelectedTuple); - expect(data1.dtlsParameters).toEqual(transport1.dtlsParameters); - expect(data1.dtlsState).toBe(transport1.dtlsState); - expect(data1.sctpParameters).toEqual(transport1.sctpParameters); - expect(data1.sctpState).toBe(transport1.sctpState); - expect(data1.recvRtpHeaderExtensions).toBeDefined(); - expect(typeof data1.rtpListener).toBe('object'); - - transport1.close(); - expect(transport1.closed).toBe(true); - - const anotherTransport = await router.createWebRtcTransport( - { - listenInfos : [ { protocol: 'udp', ip: '127.0.0.1' } ] - }); + expect(webRtcTransport.iceState).toBe('new'); + expect(webRtcTransport.iceSelectedTuple).toBeUndefined(); + expect(typeof webRtcTransport.dtlsParameters).toBe('object'); + expect(Array.isArray(webRtcTransport.dtlsParameters.fingerprints)).toBe(true); + expect(webRtcTransport.dtlsParameters.role).toBe('auto'); + expect(webRtcTransport.dtlsState).toBe('new'); + expect(webRtcTransport.dtlsRemoteCert).toBeUndefined(); + expect(webRtcTransport.sctpState).toBe('new'); + + const dump = await webRtcTransport.dump(); + + expect(dump.id).toBe(webRtcTransport.id); + expect(dump.direct).toBe(false); + expect(dump.producerIds).toEqual([]); + expect(dump.consumerIds).toEqual([]); + expect(dump.iceRole).toBe(webRtcTransport.iceRole); + expect(dump.iceParameters).toEqual(webRtcTransport.iceParameters); + expect(dump.iceCandidates).toEqual(webRtcTransport.iceCandidates); + expect(dump.iceState).toBe(webRtcTransport.iceState); + expect(dump.iceSelectedTuple).toEqual(webRtcTransport.iceSelectedTuple); + expect(dump.dtlsParameters).toEqual(webRtcTransport.dtlsParameters); + expect(dump.dtlsState).toBe(webRtcTransport.dtlsState); + expect(dump.sctpParameters).toEqual(webRtcTransport.sctpParameters); + expect(dump.sctpState).toBe(webRtcTransport.sctpState); + expect(dump.recvRtpHeaderExtensions).toBeDefined(); + expect(typeof dump.rtpListener).toBe('object'); + + webRtcTransport.close(); - expect(typeof anotherTransport).toBe('object'); + expect(webRtcTransport.closed).toBe(true); }, 2000); test('router.createWebRtcTransport() with wrong arguments rejects with TypeError', async () => { // @ts-ignore - await expect(router.createWebRtcTransport({})) + await expect(ctx.router!.createWebRtcTransport({})) .rejects .toThrow(TypeError); // @ts-ignore - await expect(router.createWebRtcTransport({ listenIps: [ 123 ] })) + await expect(ctx.router!.createWebRtcTransport({ listenIps: [ 123 ] })) .rejects .toThrow(TypeError); // @ts-ignore - await expect(router.createWebRtcTransport({ listenInfos: '127.0.0.1' })) + await expect(ctx.router!.createWebRtcTransport({ listenInfos: '127.0.0.1' })) .rejects .toThrow(TypeError); // @ts-ignore - await expect(router.createWebRtcTransport({ listenIps: '127.0.0.1' })) + await expect(ctx.router!.createWebRtcTransport({ listenIps: '127.0.0.1' })) .rejects .toThrow(TypeError); - await expect(router.createWebRtcTransport( + await expect(ctx.router!.createWebRtcTransport( { listenIps : [ '127.0.0.1' ], // @ts-ignore @@ -212,7 +207,7 @@ test('router.createWebRtcTransport() with wrong arguments rejects with TypeError .rejects .toThrow(TypeError); - await expect(router.createWebRtcTransport( + await expect(ctx.router!.createWebRtcTransport( { listenIps : [ '127.0.0.1' ], enableSctp : true, @@ -225,7 +220,7 @@ test('router.createWebRtcTransport() with wrong arguments rejects with TypeError test('router.createWebRtcTransport() with non bindable IP rejects with Error', async () => { - await expect(router.createWebRtcTransport( + await expect(ctx.router!.createWebRtcTransport( { listenInfos : [ { protocol: 'udp', ip: '8.8.8.8' } ] })) @@ -235,37 +230,53 @@ test('router.createWebRtcTransport() with non bindable IP rejects with Error', a test('webRtcTransport.getStats() succeeds', async () => { - const data = await transport.getStats(); - - expect(Array.isArray(data)).toBe(true); - expect(data.length).toBe(1); - expect(data[0].type).toBe('webrtc-transport'); - expect(data[0].transportId).toBe(transport.id); - expect(typeof data[0].timestamp).toBe('number'); - expect(data[0].iceRole).toBe('controlled'); - expect(data[0].iceState).toBe('new'); - expect(data[0].dtlsState).toBe('new'); - expect(data[0].sctpState).toBeUndefined(); - expect(data[0].bytesReceived).toBe(0); - expect(data[0].recvBitrate).toBe(0); - expect(data[0].bytesSent).toBe(0); - expect(data[0].sendBitrate).toBe(0); - expect(data[0].rtpBytesReceived).toBe(0); - expect(data[0].rtpRecvBitrate).toBe(0); - expect(data[0].rtpBytesSent).toBe(0); - expect(data[0].rtpSendBitrate).toBe(0); - expect(data[0].rtxBytesReceived).toBe(0); - expect(data[0].rtxRecvBitrate).toBe(0); - expect(data[0].rtxBytesSent).toBe(0); - expect(data[0].rtxSendBitrate).toBe(0); - expect(data[0].probationBytesSent).toBe(0); - expect(data[0].probationSendBitrate).toBe(0); - expect(data[0].iceSelectedTuple).toBeUndefined(); - expect(data[0].maxIncomingBitrate).toBeUndefined(); + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { + listenInfos : + [ + { protocol: 'udp', ip: '127.0.0.1', announcedIp: '9.9.9.1' } + ] + }); + + const stats = await webRtcTransport.getStats(); + + 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(); }, 2000); test('webRtcTransport.connect() succeeds', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { + listenInfos : + [ + { protocol: 'udp', ip: '127.0.0.1', announcedIp: '9.9.9.1' } + ] + }); + const dtlsRemoteParameters: mediasoup.types.DtlsParameters = { fingerprints : @@ -278,29 +289,32 @@ test('webRtcTransport.connect() succeeds', async () => role : 'client' }; - await expect(transport.connect({ dtlsParameters: dtlsRemoteParameters })) + await expect(webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })) .resolves .toBeUndefined(); // Must fail if connected. - await expect(transport.connect({ dtlsParameters: dtlsRemoteParameters })) + await expect(webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })) .rejects .toThrow(Error); - expect(transport.dtlsParameters.role).toBe('server'); + expect(webRtcTransport.dtlsParameters.role).toBe('server'); }, 2000); -/** - * When are we going to rely on the type system in the API? - * We are testing invalid type values which adds extra checks in the code that should be - * simply guarded by the type system. - */ test('webRtcTransport.connect() with wrong arguments rejects with TypeError', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { + listenInfos : + [ + { protocol: 'udp', ip: '127.0.0.1', announcedIp: '9.9.9.1' } + ] + }); + let dtlsRemoteParameters: mediasoup.types.DtlsParameters; // @ts-ignore - await expect(transport.connect({})) + await expect(webRtcTransport.connect({})) .rejects .toThrow(TypeError); @@ -317,7 +331,7 @@ test('webRtcTransport.connect() with wrong arguments rejects with TypeError', as role : 'client' }; - await expect(transport.connect({ dtlsParameters: dtlsRemoteParameters })) + await expect(webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })) .rejects .toThrow(TypeError); @@ -334,7 +348,7 @@ test('webRtcTransport.connect() with wrong arguments rejects with TypeError', as role : 'chicken' }; - await expect(transport.connect({ dtlsParameters: dtlsRemoteParameters })) + await expect(webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })) .rejects .toThrow(TypeError); @@ -344,91 +358,120 @@ test('webRtcTransport.connect() with wrong arguments rejects with TypeError', as role : 'client' }; - await expect(transport.connect({ dtlsParameters: dtlsRemoteParameters })) + await expect(webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })) .rejects .toThrow(TypeError); - await expect(transport.connect({ dtlsParameters: dtlsRemoteParameters })) + await expect(webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })) .rejects .toThrow(TypeError); - expect(transport.dtlsParameters.role).toBe('auto'); + expect(webRtcTransport.dtlsParameters.role).toBe('auto'); }, 2000); test('webRtcTransport.setMaxIncomingBitrate() succeeds', async () => { - await expect(transport.setMaxIncomingBitrate(1000000)) + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { + listenInfos : + [ + { protocol: 'udp', ip: '127.0.0.1', announcedIp: '9.9.9.1' } + ] + }); + + await expect(webRtcTransport.setMaxIncomingBitrate(1000000)) .resolves .toBeUndefined(); // Remove limit. - await expect(transport.setMaxIncomingBitrate(0)) + await expect(webRtcTransport.setMaxIncomingBitrate(0)) .resolves .toBeUndefined(); }, 2000); test('webRtcTransport.setMaxOutgoingBitrate() succeeds', async () => { - await expect(transport.setMaxOutgoingBitrate(2000000)) + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + + await expect(webRtcTransport.setMaxOutgoingBitrate(2000000)) .resolves .toBeUndefined(); // Remove limit. - await expect(transport.setMaxOutgoingBitrate(0)) + await expect(webRtcTransport.setMaxOutgoingBitrate(0)) .resolves .toBeUndefined(); }, 2000); test('webRtcTransport.setMinOutgoingBitrate() succeeds', async () => { - await expect(transport.setMinOutgoingBitrate(100000)) + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + + await expect(webRtcTransport.setMinOutgoingBitrate(100000)) .resolves .toBeUndefined(); // Remove limit. - await expect(transport.setMinOutgoingBitrate(0)) + await expect(webRtcTransport.setMinOutgoingBitrate(0)) .resolves .toBeUndefined(); }, 2000); test('webRtcTransport.setMaxOutgoingBitrate() fails if value is lower than current min limit', async () => { - await expect(transport.setMinOutgoingBitrate(3000000)) + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + + await expect(webRtcTransport.setMinOutgoingBitrate(3000000)) .resolves .toBeUndefined(); - await expect(transport.setMaxOutgoingBitrate(2000000)) + await expect(webRtcTransport.setMaxOutgoingBitrate(2000000)) .rejects .toThrow(Error); // Remove limit. - await expect(transport.setMinOutgoingBitrate(0)) + await expect(webRtcTransport.setMinOutgoingBitrate(0)) .resolves .toBeUndefined(); }, 2000); test('webRtcTransport.setMinOutgoingBitrate() fails if value is higher than current max limit', async () => { - await expect(transport.setMaxOutgoingBitrate(2000000)) + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + + await expect(webRtcTransport.setMaxOutgoingBitrate(2000000)) .resolves .toBeUndefined(); - await expect(transport.setMinOutgoingBitrate(3000000)) + await expect(webRtcTransport.setMinOutgoingBitrate(3000000)) .rejects .toThrow(Error); // Remove limit. - await expect(transport.setMaxOutgoingBitrate(0)) + await expect(webRtcTransport.setMaxOutgoingBitrate(0)) .resolves .toBeUndefined(); }, 2000); test('webRtcTransport.restartIce() succeeds', async () => { - const previousIceUsernameFragment = transport.iceParameters.usernameFragment; - const previousIcePassword = transport.iceParameters.password; + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + + const previousIceUsernameFragment = + webRtcTransport.iceParameters.usernameFragment; + const previousIcePassword = webRtcTransport.iceParameters.password; - await expect(transport.restartIce()) + await expect(webRtcTransport.restartIce()) .resolves .toMatchObject( { @@ -437,72 +480,85 @@ test('webRtcTransport.restartIce() succeeds', async () => iceLite : true }); - expect(typeof transport.iceParameters.usernameFragment).toBe('string'); - expect(typeof transport.iceParameters.password).toBe('string'); - expect(transport.iceParameters.usernameFragment) + expect(typeof webRtcTransport.iceParameters.usernameFragment).toBe('string'); + expect(typeof webRtcTransport.iceParameters.password).toBe('string'); + expect(webRtcTransport.iceParameters.usernameFragment) .not.toBe(previousIceUsernameFragment); - expect(transport.iceParameters.password).not.toBe(previousIcePassword); + expect(webRtcTransport.iceParameters.password).not.toBe(previousIcePassword); }, 2000); test('transport.enableTraceEvent() succeed', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + // @ts-ignore - await transport.enableTraceEvent([ 'foo', 'probation' ]); - await expect(transport.dump()) + await webRtcTransport.enableTraceEvent([ 'foo', 'probation' ]); + await expect(webRtcTransport.dump()) .resolves .toMatchObject({ traceEventTypes: [ 'probation' ] }); - await transport.enableTraceEvent([]); - await expect(transport.dump()) + await webRtcTransport.enableTraceEvent([]); + await expect(webRtcTransport.dump()) .resolves .toMatchObject({ traceEventTypes: [] }); // @ts-ignore - await transport.enableTraceEvent([ 'probation', 'FOO', 'bwe', 'BAR' ]); - await expect(transport.dump()) + await webRtcTransport.enableTraceEvent([ 'probation', 'FOO', 'bwe', 'BAR' ]); + await expect(webRtcTransport.dump()) .resolves .toMatchObject({ traceEventTypes: [ 'probation', 'bwe' ] }); - await transport.enableTraceEvent(); - await expect(transport.dump()) + await webRtcTransport.enableTraceEvent(); + await expect(webRtcTransport.dump()) .resolves .toMatchObject({ traceEventTypes: [] }); }, 2000); test('transport.enableTraceEvent() with wrong arguments rejects with TypeError', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + // @ts-ignore - await expect(transport.enableTraceEvent(123)) + await expect(webRtcTransport.enableTraceEvent(123)) .rejects .toThrow(TypeError); // @ts-ignore - await expect(transport.enableTraceEvent('probation')) + await expect(webRtcTransport.enableTraceEvent('probation')) .rejects .toThrow(TypeError); // @ts-ignore - await expect(transport.enableTraceEvent([ 'probation', 123.123 ])) + await expect(webRtcTransport.enableTraceEvent([ 'probation', 123.123 ])) .rejects .toThrow(TypeError); }, 2000); test('WebRtcTransport events succeed', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + // Private API. - const channel = transport.channelForTesting; + const channel = webRtcTransport.channelForTesting; const onIceStateChange = jest.fn(); - transport.on('icestatechange', onIceStateChange); + webRtcTransport.on('icestatechange', onIceStateChange); - // Simulate a 'iceselectedtuplechange' notification coming through the channel. + // Simulate a 'iceselectedtuplechange' notification coming through the + // channel. const builder = new flatbuffers.Builder(); const iceStateChangeNotification = new FbsWebRtcTransport.IceStateChangeNotificationT( FbsWebRtcTransport.IceState.COMPLETED); let notificationOffset = Notification.createNotification( builder, - builder.createString(transport.id), + builder.createString(webRtcTransport.id), Event.WEBRTCTRANSPORT_ICE_STATE_CHANGE, NotificationBody.WebRtcTransport_IceStateChangeNotification, iceStateChangeNotification.pack(builder) @@ -511,13 +567,18 @@ test('WebRtcTransport events succeed', async () => builder.finish(notificationOffset); let notification = Notification.getRootAsNotification( - new flatbuffers.ByteBuffer(builder.asUint8Array())); + new flatbuffers.ByteBuffer(builder.asUint8Array()) + ); - channel.emit(transport.id, Event.WEBRTCTRANSPORT_ICE_STATE_CHANGE, notification); + channel.emit( + webRtcTransport.id, + Event.WEBRTCTRANSPORT_ICE_STATE_CHANGE, + notification + ); expect(onIceStateChange).toHaveBeenCalledTimes(1); expect(onIceStateChange).toHaveBeenCalledWith('completed'); - expect(transport.iceState).toBe('completed'); + expect(webRtcTransport.iceState).toBe('completed'); builder.clear(); @@ -531,7 +592,7 @@ test('WebRtcTransport events succeed', async () => protocol : 'udp' }; - transport.on('iceselectedtuplechange', onIceSelectedTuple); + webRtcTransport.on('iceselectedtuplechange', onIceSelectedTuple); // Simulate a 'icestatechange' notification coming through the channel. const iceSelectedTupleChangeNotification = @@ -541,12 +602,13 @@ test('WebRtcTransport events succeed', async () => iceSelectedTuple.localPort, iceSelectedTuple.remoteIp, iceSelectedTuple.remotePort, - serializeProtocol(iceSelectedTuple.protocol)) + serializeProtocol(iceSelectedTuple.protocol) + ) ); notificationOffset = Notification.createNotification( builder, - builder.createString(transport.id), + builder.createString(webRtcTransport.id), Event.WEBRTCTRANSPORT_ICE_SELECTED_TUPLE_CHANGE, NotificationBody.WebRtcTransport_IceSelectedTupleChangeNotification, iceSelectedTupleChangeNotification.pack(builder) @@ -555,20 +617,24 @@ test('WebRtcTransport events succeed', async () => builder.finish(notificationOffset); notification = Notification.getRootAsNotification( - new flatbuffers.ByteBuffer(builder.asUint8Array())); + new flatbuffers.ByteBuffer(builder.asUint8Array()) + ); channel.emit( - transport.id, Event.WEBRTCTRANSPORT_ICE_SELECTED_TUPLE_CHANGE, notification); + webRtcTransport.id, + Event.WEBRTCTRANSPORT_ICE_SELECTED_TUPLE_CHANGE, + notification + ); expect(onIceSelectedTuple).toHaveBeenCalledTimes(1); expect(onIceSelectedTuple).toHaveBeenCalledWith(iceSelectedTuple); - expect(transport.iceSelectedTuple).toEqual(iceSelectedTuple); + expect(webRtcTransport.iceSelectedTuple).toEqual(iceSelectedTuple); builder.clear(); const onDtlsStateChange = jest.fn(); - transport.on('dtlsstatechange', onDtlsStateChange); + webRtcTransport.on('dtlsstatechange', onDtlsStateChange); // Simulate a 'dtlsstatechange' notification coming through the channel. const dtlsStateChangeNotification = new FbsWebRtcTransport.DtlsStateChangeNotificationT( @@ -576,7 +642,7 @@ test('WebRtcTransport events succeed', async () => notificationOffset = Notification.createNotification( builder, - builder.createString(transport.id), + builder.createString(webRtcTransport.id), Event.WEBRTCTRANSPORT_DTLS_STATE_CHANGE, NotificationBody.WebRtcTransport_DtlsStateChangeNotification, dtlsStateChangeNotification.pack(builder) @@ -587,62 +653,69 @@ test('WebRtcTransport events succeed', async () => notification = Notification.getRootAsNotification( new flatbuffers.ByteBuffer(builder.asUint8Array())); - channel.emit(transport.id, Event.WEBRTCTRANSPORT_DTLS_STATE_CHANGE, notification); + channel.emit( + webRtcTransport.id, + Event.WEBRTCTRANSPORT_DTLS_STATE_CHANGE, + notification + ); expect(onDtlsStateChange).toHaveBeenCalledTimes(1); expect(onDtlsStateChange).toHaveBeenCalledWith('connecting'); - expect(transport.dtlsState).toBe('connecting'); + expect(webRtcTransport.dtlsState).toBe('connecting'); }, 2000); test('WebRtcTransport methods reject if closed', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + const onObserverClose = jest.fn(); - transport.observer.once('close', onObserverClose); - transport.close(); + webRtcTransport.observer.once('close', onObserverClose); + webRtcTransport.close(); expect(onObserverClose).toHaveBeenCalledTimes(1); - expect(transport.closed).toBe(true); - expect(transport.iceState).toBe('closed'); - expect(transport.iceSelectedTuple).toBeUndefined(); - expect(transport.dtlsState).toBe('closed'); - expect(transport.sctpState).toBeUndefined(); + expect(webRtcTransport.closed).toBe(true); + expect(webRtcTransport.iceState).toBe('closed'); + expect(webRtcTransport.iceSelectedTuple).toBeUndefined(); + expect(webRtcTransport.dtlsState).toBe('closed'); + expect(webRtcTransport.sctpState).toBeUndefined(); - await expect(transport.dump()) + await expect(webRtcTransport.dump()) .rejects .toThrow(Error); - await expect(transport.getStats()) + await expect(webRtcTransport.getStats()) .rejects .toThrow(Error); // @ts-ignore - await expect(transport.connect({})) + await expect(webRtcTransport.connect({})) .rejects .toThrow(Error); - await expect(transport.setMaxIncomingBitrate(200000)) + await expect(webRtcTransport.setMaxIncomingBitrate(200000)) .rejects .toThrow(Error); - await expect(transport.setMaxOutgoingBitrate(200000)) + await expect(webRtcTransport.setMaxOutgoingBitrate(200000)) .rejects .toThrow(Error); - await expect(transport.setMinOutgoingBitrate(100000)) + await expect(webRtcTransport.setMinOutgoingBitrate(100000)) .rejects .toThrow(Error); - await expect(transport.restartIce()) + await expect(webRtcTransport.restartIce()) .rejects .toThrow(Error); }, 2000); test('router.createWebRtcTransport() with fixed port succeeds', async () => { - const port = await pickPort({ type: 'tcp', ip: '127.0.0.1', reserveTimeout: 0 }); - const webRtcTransport = await router.createWebRtcTransport( + const webRtcTransport = await ctx.router!.createWebRtcTransport( { listenInfos : [ @@ -658,47 +731,50 @@ test('router.createWebRtcTransport() with fixed port succeeds', async () => test('WebRtcTransport emits "routerclose" if Router is closed', async () => { - // We need different Router and WebRtcTransport instances here. - const router2 = await worker.createRouter({ mediaCodecs }); - const transport2 = await router2.createWebRtcTransport( - { - listenIps : [ '127.0.0.1' ], - enableSctp : true - }); + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenIps: [ '127.0.0.1' ], enableSctp: true } + ); + const onObserverClose = jest.fn(); - transport2.observer.once('close', onObserverClose); + webRtcTransport.observer.once('close', onObserverClose); await new Promise((resolve) => { - transport2.on('routerclose', resolve); - router2.close(); + webRtcTransport.on('routerclose', resolve); + + ctx.router!.close(); }); expect(onObserverClose).toHaveBeenCalledTimes(1); - expect(transport2.closed).toBe(true); - expect(transport2.iceState).toBe('closed'); - expect(transport2.iceSelectedTuple).toBeUndefined(); - expect(transport2.dtlsState).toBe('closed'); - expect(transport2.sctpState).toBe('closed'); + expect(webRtcTransport.closed).toBe(true); + expect(webRtcTransport.iceState).toBe('closed'); + expect(webRtcTransport.iceSelectedTuple).toBeUndefined(); + expect(webRtcTransport.dtlsState).toBe('closed'); + expect(webRtcTransport.sctpState).toBe('closed'); }, 2000); test('WebRtcTransport emits "routerclose" if Worker is closed', async () => { + const webRtcTransport = await ctx.router!.createWebRtcTransport( + { listenInfos: [ { protocol: 'udp', ip: '127.0.0.1' } ] } + ); + const onObserverClose = jest.fn(); - transport.observer.once('close', onObserverClose); + webRtcTransport.observer.once('close', onObserverClose); await new Promise((resolve) => { - transport.on('routerclose', resolve); - worker.close(); + webRtcTransport.on('routerclose', resolve); + + ctx.worker!.close(); }); expect(onObserverClose).toHaveBeenCalledTimes(1); - expect(transport.closed).toBe(true); - expect(transport.iceState).toBe('closed'); - expect(transport.iceSelectedTuple).toBeUndefined(); - expect(transport.dtlsState).toBe('closed'); - expect(transport.sctpState).toBeUndefined(); + expect(webRtcTransport.closed).toBe(true); + expect(webRtcTransport.iceState).toBe('closed'); + expect(webRtcTransport.iceSelectedTuple).toBeUndefined(); + expect(webRtcTransport.dtlsState).toBe('closed'); + expect(webRtcTransport.sctpState).toBeUndefined(); }, 2000);