UNPKG

mediasoup

Version:

Cutting Edge WebRTC Video Conferencing

245 lines (244 loc) 11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const mediasoup = require("../"); const enhancedEvents_1 = require("../enhancedEvents"); const utils = require("../utils"); const ctx = { dataProducerOptions1: utils.deepFreeze({ sctpStreamParameters: { streamId: 666, }, label: 'foo', protocol: 'bar', appData: { foo: 1, bar: '2' }, }), dataProducerOptions2: utils.deepFreeze({ sctpStreamParameters: { streamId: 777, maxRetransmits: 3, }, label: 'foo', protocol: 'bar', paused: true, appData: { foo: 1, bar: '2' }, }), }; beforeEach(async () => { ctx.worker = await mediasoup.createWorker(); ctx.router = await ctx.worker.createRouter(); ctx.webRtcTransport1 = await ctx.router.createWebRtcTransport({ listenIps: ['127.0.0.1'], enableSctp: true, }); ctx.webRtcTransport2 = await ctx.router.createWebRtcTransport({ listenIps: ['127.0.0.1'], enableSctp: true, }); }); afterEach(async () => { ctx.worker?.close(); if (ctx.worker?.subprocessClosed === false) { await (0, enhancedEvents_1.enhancedOnce)(ctx.worker, 'subprocessclose'); } }); test('webRtcTransport1.produceData() succeeds', async () => { const onObserverNewDataProducer = jest.fn(); ctx.webRtcTransport1.observer.once('newdataproducer', onObserverNewDataProducer); const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); expect(onObserverNewDataProducer).toHaveBeenCalledTimes(1); expect(onObserverNewDataProducer).toHaveBeenCalledWith(dataProducer1); expect(typeof dataProducer1.id).toBe('string'); expect(dataProducer1.closed).toBe(false); expect(dataProducer1.type).toBe('sctp'); expect(typeof dataProducer1.sctpStreamParameters).toBe('object'); expect(dataProducer1.sctpStreamParameters?.streamId).toBe(666); expect(dataProducer1.sctpStreamParameters?.ordered).toBe(true); expect(dataProducer1.sctpStreamParameters?.maxPacketLifeTime).toBeUndefined(); expect(dataProducer1.sctpStreamParameters?.maxRetransmits).toBeUndefined(); expect(dataProducer1.label).toBe('foo'); expect(dataProducer1.protocol).toBe('bar'); expect(dataProducer1.paused).toBe(false); expect(dataProducer1.appData).toEqual({ foo: 1, bar: '2' }); const dump = await ctx.router.dump(); expect(dump.mapDataProducerIdDataConsumerIds).toEqual(expect.arrayContaining([{ key: dataProducer1.id, values: [] }])); expect(dump.mapDataConsumerIdDataProducerId.length).toBe(0); await expect(ctx.webRtcTransport1.dump()).resolves.toMatchObject({ id: ctx.webRtcTransport1.id, dataProducerIds: [dataProducer1.id], dataConsumerIds: [], }); }, 2000); test('webRtcTransport2.produceData() succeeds', async () => { const onObserverNewDataProducer = jest.fn(); ctx.webRtcTransport2.observer.once('newdataproducer', onObserverNewDataProducer); const dataProducer2 = await ctx.webRtcTransport2.produceData(ctx.dataProducerOptions2); expect(onObserverNewDataProducer).toHaveBeenCalledTimes(1); expect(onObserverNewDataProducer).toHaveBeenCalledWith(dataProducer2); expect(typeof dataProducer2.id).toBe('string'); expect(dataProducer2.closed).toBe(false); expect(dataProducer2.type).toBe('sctp'); expect(typeof dataProducer2.sctpStreamParameters).toBe('object'); expect(dataProducer2.sctpStreamParameters?.streamId).toBe(777); expect(dataProducer2.sctpStreamParameters?.ordered).toBe(false); expect(dataProducer2.sctpStreamParameters?.maxPacketLifeTime).toBeUndefined(); expect(dataProducer2.sctpStreamParameters?.maxRetransmits).toBe(3); expect(dataProducer2.label).toBe('foo'); expect(dataProducer2.protocol).toBe('bar'); expect(dataProducer2.paused).toBe(true); expect(dataProducer2.appData).toEqual({ foo: 1, bar: '2' }); const dump = await ctx.router.dump(); expect(dump.mapDataProducerIdDataConsumerIds).toEqual(expect.arrayContaining([{ key: dataProducer2.id, values: [] }])); expect(dump.mapDataConsumerIdDataProducerId.length).toBe(0); await expect(ctx.webRtcTransport2.dump()).resolves.toMatchObject({ id: ctx.webRtcTransport2.id, dataProducerIds: [dataProducer2.id], dataConsumerIds: [], }); }, 2000); test('webRtcTransport1.produceData() with wrong arguments rejects with TypeError', async () => { await expect(ctx.webRtcTransport1.produceData({})).rejects.toThrow(TypeError); // Missing or empty sctpStreamParameters.streamId. await expect(ctx.webRtcTransport1.produceData({ // @ts-expect-error --- Testing purposes. sctpStreamParameters: { foo: 'foo' }, })).rejects.toThrow(TypeError); }, 2000); test('transport.produceData() with already used streamId rejects with Error', async () => { await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); await expect(ctx.webRtcTransport1.produceData({ sctpStreamParameters: { streamId: 666, }, })).rejects.toThrow(Error); }, 2000); test('transport.produceData() with ordered and maxPacketLifeTime rejects with TypeError', async () => { await expect(ctx.webRtcTransport1.produceData({ sctpStreamParameters: { streamId: 999, ordered: true, maxPacketLifeTime: 4000, }, })).rejects.toThrow(TypeError); }, 2000); test('dataProducer.dump() succeeds', async () => { const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); const dump1 = await dataProducer1.dump(); expect(dump1.id).toBe(dataProducer1.id); expect(dump1.type).toBe('sctp'); expect(typeof dump1.sctpStreamParameters).toBe('object'); expect(dump1.sctpStreamParameters.streamId).toBe(666); expect(dump1.sctpStreamParameters.ordered).toBe(true); expect(dump1.sctpStreamParameters.maxPacketLifeTime).toBeUndefined(); expect(dump1.sctpStreamParameters.maxRetransmits).toBeUndefined(); expect(dump1.label).toBe('foo'); expect(dump1.protocol).toBe('bar'); expect(dump1.paused).toBe(false); const dataProducer2 = await ctx.webRtcTransport2.produceData(ctx.dataProducerOptions2); const dump2 = await dataProducer2.dump(); expect(dump2.id).toBe(dataProducer2.id); expect(dump2.type).toBe('sctp'); expect(typeof dump2.sctpStreamParameters).toBe('object'); expect(dump2.sctpStreamParameters.streamId).toBe(777); expect(dump2.sctpStreamParameters.ordered).toBe(false); expect(dump2.sctpStreamParameters.maxPacketLifeTime).toBeUndefined(); expect(dump2.sctpStreamParameters.maxRetransmits).toBe(3); expect(dump2.label).toBe('foo'); expect(dump2.protocol).toBe('bar'); expect(dump2.paused).toBe(true); }, 2000); test('dataProducer.getStats() succeeds', async () => { const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); await expect(dataProducer1.getStats()).resolves.toMatchObject([ { type: 'data-producer', label: dataProducer1.label, protocol: dataProducer1.protocol, messagesReceived: 0, bytesReceived: 0, }, ]); const dataProducer2 = await ctx.webRtcTransport2.produceData(ctx.dataProducerOptions2); await expect(dataProducer2.getStats()).resolves.toMatchObject([ { type: 'data-producer', label: dataProducer2.label, protocol: dataProducer2.protocol, messagesReceived: 0, bytesReceived: 0, }, ]); }, 2000); test('dataProducer.pause() and resume() succeed', async () => { const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); const onObserverPause = jest.fn(); const onObserverResume = jest.fn(); dataProducer1.observer.on('pause', onObserverPause); dataProducer1.observer.on('resume', onObserverResume); await dataProducer1.pause(); expect(dataProducer1.paused).toBe(true); const dump1 = await dataProducer1.dump(); expect(dump1.paused).toBe(true); await dataProducer1.resume(); expect(dataProducer1.paused).toBe(false); const dump2 = await dataProducer1.dump(); expect(dump2.paused).toBe(false); // Even if we don't await for pause()/resume() completion, the observer must // fire 'pause' and 'resume' events if state was the opposite. void dataProducer1.pause(); void dataProducer1.resume(); void dataProducer1.pause(); void dataProducer1.pause(); void dataProducer1.pause(); await dataProducer1.resume(); expect(onObserverPause).toHaveBeenCalledTimes(3); expect(onObserverResume).toHaveBeenCalledTimes(3); }, 2000); test('producer.pause() and resume() emit events', async () => { const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); const promises = []; const events = []; dataProducer1.observer.once('resume', () => { events.push('resume'); }); dataProducer1.observer.once('pause', () => { events.push('pause'); }); promises.push(dataProducer1.pause()); promises.push(dataProducer1.resume()); await Promise.all(promises); expect(events).toEqual(['pause', 'resume']); expect(dataProducer1.paused).toBe(false); }, 2000); test('dataProducer.close() succeeds', async () => { const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); const onObserverClose = jest.fn(); dataProducer1.observer.once('close', onObserverClose); dataProducer1.close(); expect(onObserverClose).toHaveBeenCalledTimes(1); expect(dataProducer1.closed).toBe(true); await expect(ctx.router.dump()).resolves.toMatchObject({ mapDataProducerIdDataConsumerIds: {}, mapDataConsumerIdDataProducerId: {}, }); await expect(ctx.webRtcTransport1.dump()).resolves.toMatchObject({ id: ctx.webRtcTransport1.id, dataProducerIds: [], dataConsumerIds: [], }); }, 2000); test('DataProducer methods reject if closed', async () => { const dataProducer1 = await ctx.webRtcTransport1.produceData(ctx.dataProducerOptions1); dataProducer1.close(); await expect(dataProducer1.dump()).rejects.toThrow(Error); await expect(dataProducer1.getStats()).rejects.toThrow(Error); }, 2000); test('DataProducer emits "transportclose" if Transport is closed', async () => { const dataProducer2 = await ctx.webRtcTransport2.produceData(ctx.dataProducerOptions2); const onObserverClose = jest.fn(); dataProducer2.observer.once('close', onObserverClose); const promise = (0, enhancedEvents_1.enhancedOnce)(dataProducer2, 'transportclose'); ctx.webRtcTransport2.close(); await promise; expect(onObserverClose).toHaveBeenCalledTimes(1); expect(dataProducer2.closed).toBe(true); }, 2000);