mediasoup-client 3.7.1 → 3.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -112
- package/lib/Consumer.d.ts +1 -1
- package/lib/Consumer.d.ts.map +1 -1
- package/lib/Consumer.js +1 -1
- package/lib/DataConsumer.d.ts +1 -1
- package/lib/DataConsumer.d.ts.map +1 -1
- package/lib/DataConsumer.js +1 -1
- package/lib/DataProducer.d.ts +1 -1
- package/lib/DataProducer.d.ts.map +1 -1
- package/lib/DataProducer.js +1 -1
- package/lib/Device.d.ts +3 -3
- package/lib/Device.d.ts.map +1 -1
- package/lib/Device.js +66 -89
- package/lib/EnhancedEventEmitter.d.ts.map +1 -1
- package/lib/Logger.d.ts.map +1 -1
- package/lib/Producer.d.ts +5 -15
- package/lib/Producer.d.ts.map +1 -1
- package/lib/Producer.js +2 -2
- package/lib/RtpParameters.d.ts.map +1 -1
- package/lib/SctpParameters.d.ts.map +1 -1
- package/lib/Transport.d.ts +21 -11
- package/lib/Transport.d.ts.map +1 -1
- package/lib/Transport.js +73 -55
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +6 -6
- package/lib/handlers/Chrome111.d.ts +4 -4
- package/lib/handlers/Chrome111.d.ts.map +1 -1
- package/lib/handlers/Chrome111.js +79 -78
- package/lib/handlers/Chrome55.d.ts +4 -4
- package/lib/handlers/Chrome55.d.ts.map +1 -1
- package/lib/handlers/Chrome55.js +88 -81
- package/lib/handlers/Chrome67.d.ts +4 -4
- package/lib/handlers/Chrome67.d.ts.map +1 -1
- package/lib/handlers/Chrome67.js +90 -84
- package/lib/handlers/Chrome70.d.ts +4 -4
- package/lib/handlers/Chrome70.d.ts.map +1 -1
- package/lib/handlers/Chrome70.js +81 -79
- package/lib/handlers/Chrome74.d.ts +4 -4
- package/lib/handlers/Chrome74.d.ts.map +1 -1
- package/lib/handlers/Chrome74.js +80 -79
- package/lib/handlers/Edge11.d.ts +1 -1
- package/lib/handlers/Edge11.d.ts.map +1 -1
- package/lib/handlers/Edge11.js +66 -78
- package/lib/handlers/FakeHandler.d.ts +3 -3
- package/lib/handlers/FakeHandler.d.ts.map +1 -1
- package/lib/handlers/FakeHandler.js +20 -22
- package/lib/handlers/Firefox60.d.ts +4 -4
- package/lib/handlers/Firefox60.d.ts.map +1 -1
- package/lib/handlers/Firefox60.js +80 -73
- package/lib/handlers/HandlerInterface.d.ts +1 -0
- package/lib/handlers/HandlerInterface.d.ts.map +1 -1
- package/lib/handlers/ReactNative.d.ts +4 -4
- package/lib/handlers/ReactNative.d.ts.map +1 -1
- package/lib/handlers/ReactNative.js +89 -83
- package/lib/handlers/ReactNativeUnifiedPlan.d.ts +4 -4
- package/lib/handlers/ReactNativeUnifiedPlan.d.ts.map +1 -1
- package/lib/handlers/ReactNativeUnifiedPlan.js +80 -79
- package/lib/handlers/Safari11.d.ts +4 -4
- package/lib/handlers/Safari11.d.ts.map +1 -1
- package/lib/handlers/Safari11.js +89 -82
- package/lib/handlers/Safari12.d.ts +4 -4
- package/lib/handlers/Safari12.d.ts.map +1 -1
- package/lib/handlers/Safari12.js +80 -78
- package/lib/handlers/ortc/edgeUtils.d.ts.map +1 -1
- package/lib/handlers/ortc/utils.d.ts.map +1 -1
- package/lib/handlers/ortc/utils.js +2 -2
- package/lib/handlers/sdp/MediaSection.d.ts +5 -5
- package/lib/handlers/sdp/MediaSection.d.ts.map +1 -1
- package/lib/handlers/sdp/MediaSection.js +296 -318
- package/lib/handlers/sdp/RemoteSdp.d.ts +5 -5
- package/lib/handlers/sdp/RemoteSdp.d.ts.map +1 -1
- package/lib/handlers/sdp/RemoteSdp.js +28 -30
- package/lib/handlers/sdp/commonUtils.d.ts +8 -5
- package/lib/handlers/sdp/commonUtils.d.ts.map +1 -1
- package/lib/handlers/sdp/commonUtils.js +71 -59
- package/lib/handlers/sdp/plainRtpUtils.d.ts +2 -2
- package/lib/handlers/sdp/plainRtpUtils.d.ts.map +1 -1
- package/lib/handlers/sdp/plainRtpUtils.js +5 -7
- package/lib/handlers/sdp/planBUtils.d.ts +2 -2
- package/lib/handlers/sdp/planBUtils.d.ts.map +1 -1
- package/lib/handlers/sdp/planBUtils.js +11 -14
- package/lib/handlers/sdp/unifiedPlanUtils.d.ts +2 -2
- package/lib/handlers/sdp/unifiedPlanUtils.d.ts.map +1 -1
- package/lib/handlers/sdp/unifiedPlanUtils.js +11 -14
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/ortc.d.ts +4 -58
- package/lib/ortc.d.ts.map +1 -1
- package/lib/ortc.js +432 -478
- package/lib/scalabilityModes.d.ts.map +1 -1
- package/lib/scalabilityModes.js +2 -2
- package/lib/{tests → test}/fakeParameters.d.ts +3 -2
- package/lib/test/fakeParameters.d.ts.map +1 -0
- package/lib/test/fakeParameters.js +654 -0
- package/lib/{tests → test}/test.d.ts.map +1 -1
- package/lib/{tests → test}/test.js +469 -496
- package/lib/test/uaTestCases.d.ts.map +1 -0
- package/lib/{tests → test}/uaTestCases.js +17 -17
- package/lib/types.d.ts.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/npm-scripts.mjs +75 -103
- package/package.json +93 -90
- package/lib/tests/fakeParameters.d.ts.map +0 -1
- package/lib/tests/fakeParameters.js +0 -662
- package/lib/tests/uaTestCases.d.ts.map +0 -1
- /package/lib/{tests → test}/test.d.ts +0 -0
- /package/lib/{tests → test}/uaTestCases.d.ts +0 -0
|
@@ -37,15 +37,108 @@ const FakeHandler_1 = require("../handlers/FakeHandler");
|
|
|
37
37
|
const fakeParameters = __importStar(require("./fakeParameters"));
|
|
38
38
|
const uaTestCases_1 = require("./uaTestCases");
|
|
39
39
|
const { Device, detectDevice, parseScalabilityMode, debug } = mediasoupClient;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
const ctx = {};
|
|
41
|
+
beforeEach(async () => {
|
|
42
|
+
ctx.device = new Device({
|
|
43
|
+
handlerFactory: FakeHandler_1.FakeHandler.createFactory(fakeParameters),
|
|
44
|
+
});
|
|
45
|
+
ctx.loadedDevice = new Device({
|
|
46
|
+
handlerFactory: FakeHandler_1.FakeHandler.createFactory(fakeParameters),
|
|
47
|
+
});
|
|
48
|
+
const routerRtpCapabilities = fakeParameters.generateRouterRtpCapabilities();
|
|
49
|
+
// Only load loadedDevice.
|
|
50
|
+
await ctx.loadedDevice.load({ routerRtpCapabilities });
|
|
51
|
+
const { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters } = fakeParameters.generateTransportRemoteParameters();
|
|
52
|
+
ctx.sendTransport = ctx.loadedDevice.createSendTransport({
|
|
53
|
+
id,
|
|
54
|
+
iceParameters,
|
|
55
|
+
iceCandidates,
|
|
56
|
+
dtlsParameters,
|
|
57
|
+
sctpParameters,
|
|
58
|
+
});
|
|
59
|
+
ctx.connectedSendTransport = ctx.loadedDevice.createSendTransport({
|
|
60
|
+
id,
|
|
61
|
+
iceParameters,
|
|
62
|
+
iceCandidates,
|
|
63
|
+
dtlsParameters,
|
|
64
|
+
sctpParameters,
|
|
65
|
+
});
|
|
66
|
+
ctx.connectedSendTransport.on('connect',
|
|
67
|
+
// eslint-disable-next-line no-shadow, @typescript-eslint/no-unused-vars
|
|
68
|
+
({ dtlsParameters }, callback /* errback */) => {
|
|
69
|
+
setTimeout(callback);
|
|
70
|
+
});
|
|
71
|
+
ctx.connectedSendTransport.on('produce',
|
|
72
|
+
// eslint-disable-next-line no-shadow, @typescript-eslint/no-unused-vars
|
|
73
|
+
({ kind, rtpParameters, appData }, callback /* errback */) => {
|
|
74
|
+
// eslint-disable-next-line no-shadow
|
|
75
|
+
const id = fakeParameters.generateProducerRemoteParameters().id;
|
|
76
|
+
setTimeout(() => callback({ id }));
|
|
77
|
+
});
|
|
78
|
+
ctx.connectedSendTransport.on('producedata', (
|
|
79
|
+
// eslint-disable-next-line no-shadow, @typescript-eslint/no-unused-vars
|
|
80
|
+
{ sctpStreamParameters, label, protocol, appData }, callback /* errback */) => {
|
|
81
|
+
// eslint-disable-next-line no-shadow
|
|
82
|
+
const id = fakeParameters.generateDataProducerRemoteParameters().id;
|
|
83
|
+
setTimeout(() => callback({ id }));
|
|
84
|
+
});
|
|
85
|
+
ctx.recvTransport = ctx.loadedDevice.createRecvTransport({
|
|
86
|
+
id,
|
|
87
|
+
iceParameters,
|
|
88
|
+
iceCandidates,
|
|
89
|
+
dtlsParameters,
|
|
90
|
+
sctpParameters,
|
|
91
|
+
});
|
|
92
|
+
ctx.connectedRecvTransport = ctx.loadedDevice.createRecvTransport({
|
|
93
|
+
id,
|
|
94
|
+
iceParameters,
|
|
95
|
+
iceCandidates,
|
|
96
|
+
dtlsParameters,
|
|
97
|
+
sctpParameters,
|
|
98
|
+
});
|
|
99
|
+
ctx.connectedRecvTransport.on('connect',
|
|
100
|
+
// eslint-disable-next-line no-shadow, @typescript-eslint/no-unused-vars
|
|
101
|
+
({ dtlsParameters }, callback /* errback */) => {
|
|
102
|
+
setTimeout(callback);
|
|
103
|
+
});
|
|
104
|
+
const audioTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
105
|
+
ctx.audioProducer = await ctx.connectedSendTransport.produce({
|
|
106
|
+
track: audioTrack,
|
|
107
|
+
stopTracks: false,
|
|
108
|
+
});
|
|
109
|
+
const videoTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'video' });
|
|
110
|
+
ctx.videoProducer = await ctx.connectedSendTransport.produce({
|
|
111
|
+
track: videoTrack,
|
|
112
|
+
});
|
|
113
|
+
const audioConsumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
114
|
+
codecMimeType: 'audio/opus',
|
|
115
|
+
});
|
|
116
|
+
ctx.audioConsumer = await ctx.connectedRecvTransport.consume({
|
|
117
|
+
id: audioConsumerRemoteParameters.id,
|
|
118
|
+
producerId: audioConsumerRemoteParameters.producerId,
|
|
119
|
+
kind: audioConsumerRemoteParameters.kind,
|
|
120
|
+
rtpParameters: audioConsumerRemoteParameters.rtpParameters,
|
|
121
|
+
});
|
|
122
|
+
const videoConsumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
123
|
+
codecMimeType: 'video/VP8',
|
|
124
|
+
});
|
|
125
|
+
ctx.videoConsumer = await ctx.connectedRecvTransport.consume({
|
|
126
|
+
id: videoConsumerRemoteParameters.id,
|
|
127
|
+
producerId: videoConsumerRemoteParameters.producerId,
|
|
128
|
+
kind: videoConsumerRemoteParameters.kind,
|
|
129
|
+
rtpParameters: videoConsumerRemoteParameters.rtpParameters,
|
|
130
|
+
});
|
|
131
|
+
ctx.dataProducer = await ctx.connectedSendTransport.produceData({
|
|
132
|
+
ordered: false,
|
|
133
|
+
maxPacketLifeTime: 5555,
|
|
134
|
+
});
|
|
135
|
+
const dataConsumerRemoteParameters = fakeParameters.generateDataConsumerRemoteParameters();
|
|
136
|
+
ctx.dataConsumer = await ctx.connectedRecvTransport.consumeData({
|
|
137
|
+
id: dataConsumerRemoteParameters.id,
|
|
138
|
+
dataProducerId: dataConsumerRemoteParameters.dataProducerId,
|
|
139
|
+
sctpStreamParameters: dataConsumerRemoteParameters.sctpStreamParameters,
|
|
140
|
+
});
|
|
141
|
+
});
|
|
49
142
|
test('mediasoup-client exposes debug dependency', () => {
|
|
50
143
|
expect(typeof debug).toBe('function');
|
|
51
144
|
}, 500);
|
|
@@ -53,102 +146,89 @@ test('detectDevice() returns nothing in Node', () => {
|
|
|
53
146
|
expect(detectDevice()).toBe(undefined);
|
|
54
147
|
});
|
|
55
148
|
test('create a Device in Node without custom handlerName/handlerFactory throws UnsupportedError', () => {
|
|
56
|
-
expect(() => new Device())
|
|
57
|
-
.toThrow(errors_1.UnsupportedError);
|
|
149
|
+
expect(() => new Device()).toThrow(errors_1.UnsupportedError);
|
|
58
150
|
});
|
|
59
151
|
test('create a Device with an unknown handlerName string throws TypeError', () => {
|
|
60
152
|
// @ts-ignore
|
|
61
|
-
expect(() => new Device({ handlerName: 'FooBrowser666' }))
|
|
62
|
-
.toThrow(TypeError);
|
|
153
|
+
expect(() => new Device({ handlerName: 'FooBrowser666' })).toThrow(TypeError);
|
|
63
154
|
});
|
|
64
155
|
test('create a Device in Node with a valid handlerFactory succeeds', () => {
|
|
65
|
-
device = new Device({
|
|
156
|
+
const device = new Device({
|
|
157
|
+
handlerFactory: FakeHandler_1.FakeHandler.createFactory(fakeParameters),
|
|
158
|
+
});
|
|
66
159
|
expect(typeof device).toBe('object');
|
|
67
160
|
expect(device.handlerName).toBe('FakeHandler');
|
|
68
161
|
expect(device.loaded).toBe(false);
|
|
69
162
|
});
|
|
70
163
|
test('device.rtpCapabilities getter throws InvalidStateError if not loaded', () => {
|
|
71
|
-
expect(() => device.rtpCapabilities)
|
|
72
|
-
.toThrow(errors_1.InvalidStateError);
|
|
164
|
+
expect(() => ctx.device.rtpCapabilities).toThrow(errors_1.InvalidStateError);
|
|
73
165
|
});
|
|
74
166
|
test('device.sctpCapabilities getter throws InvalidStateError if not loaded', () => {
|
|
75
|
-
expect(() => device.sctpCapabilities)
|
|
76
|
-
.toThrow(errors_1.InvalidStateError);
|
|
167
|
+
expect(() => ctx.device.sctpCapabilities).toThrow(errors_1.InvalidStateError);
|
|
77
168
|
});
|
|
78
169
|
test('device.canProduce() throws InvalidStateError if not loaded', () => {
|
|
79
|
-
expect(() => device.canProduce('audio'))
|
|
80
|
-
.toThrow(errors_1.InvalidStateError);
|
|
170
|
+
expect(() => ctx.device.canProduce('audio')).toThrow(errors_1.InvalidStateError);
|
|
81
171
|
});
|
|
82
172
|
test('device.createSendTransport() throws InvalidStateError if not loaded', () => {
|
|
83
173
|
const { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters } = fakeParameters.generateTransportRemoteParameters();
|
|
84
|
-
expect(() => device.createSendTransport({
|
|
174
|
+
expect(() => ctx.device.createSendTransport({
|
|
85
175
|
id,
|
|
86
176
|
iceParameters,
|
|
87
177
|
iceCandidates,
|
|
88
178
|
dtlsParameters,
|
|
89
|
-
sctpParameters
|
|
90
|
-
}))
|
|
91
|
-
.toThrow(errors_1.InvalidStateError);
|
|
179
|
+
sctpParameters,
|
|
180
|
+
})).toThrow(errors_1.InvalidStateError);
|
|
92
181
|
});
|
|
93
182
|
test('device.load() without routerRtpCapabilities rejects with TypeError', async () => {
|
|
94
183
|
// @ts-ignore
|
|
95
|
-
await expect(device.load({}))
|
|
96
|
-
|
|
97
|
-
.toThrow(TypeError);
|
|
98
|
-
expect(device.loaded).toBe(false);
|
|
184
|
+
await expect(ctx.device.load({})).rejects.toThrow(TypeError);
|
|
185
|
+
expect(ctx.device.loaded).toBe(false);
|
|
99
186
|
}, 500);
|
|
100
187
|
test('device.load() with invalid routerRtpCapabilities rejects with TypeError', async () => {
|
|
101
|
-
//
|
|
188
|
+
// Clone fake router RTP capabilities to make them invalid.
|
|
102
189
|
const routerRtpCapabilities = utils.clone(fakeParameters.generateRouterRtpCapabilities());
|
|
103
190
|
for (const codec of routerRtpCapabilities.codecs) {
|
|
104
191
|
// @ts-ignore
|
|
105
192
|
delete codec.mimeType;
|
|
106
193
|
}
|
|
107
|
-
await expect(device.load({ routerRtpCapabilities }))
|
|
108
|
-
|
|
109
|
-
.toThrow(TypeError);
|
|
110
|
-
expect(device.loaded).toBe(false);
|
|
194
|
+
await expect(ctx.device.load({ routerRtpCapabilities })).rejects.toThrow(TypeError);
|
|
195
|
+
expect(ctx.device.loaded).toBe(false);
|
|
111
196
|
}, 500);
|
|
112
197
|
test('device.load() succeeds', async () => {
|
|
113
198
|
// Assume we get the router RTP capabilities.
|
|
114
199
|
const routerRtpCapabilities = fakeParameters.generateRouterRtpCapabilities();
|
|
115
|
-
await expect(device.load({ routerRtpCapabilities }))
|
|
116
|
-
|
|
117
|
-
.toBe(undefined);
|
|
118
|
-
expect(device.loaded).toBe(true);
|
|
200
|
+
await expect(ctx.device.load({ routerRtpCapabilities })).resolves.toBe(undefined);
|
|
201
|
+
expect(ctx.device.loaded).toBe(true);
|
|
119
202
|
}, 500);
|
|
120
203
|
test('device.load() rejects with InvalidStateError if already loaded', async () => {
|
|
121
|
-
|
|
122
|
-
await expect(
|
|
123
|
-
|
|
124
|
-
.toThrow(errors_1.InvalidStateError);
|
|
125
|
-
expect(device.loaded).toBe(true);
|
|
204
|
+
const routerRtpCapabilities = fakeParameters.generateRouterRtpCapabilities();
|
|
205
|
+
await expect(ctx.loadedDevice.load({ routerRtpCapabilities })).rejects.toThrow(errors_1.InvalidStateError);
|
|
206
|
+
expect(ctx.loadedDevice.loaded).toBe(true);
|
|
126
207
|
}, 500);
|
|
127
208
|
test('device.rtpCapabilities getter succeeds', () => {
|
|
128
|
-
expect(typeof
|
|
209
|
+
expect(typeof ctx.loadedDevice.rtpCapabilities).toBe('object');
|
|
129
210
|
});
|
|
130
211
|
test('device.sctpCapabilities getter succeeds', () => {
|
|
131
|
-
expect(typeof
|
|
212
|
+
expect(typeof ctx.loadedDevice.sctpCapabilities).toBe('object');
|
|
132
213
|
});
|
|
133
214
|
test('device.canProduce() with "audio"/"video" kind returns true', () => {
|
|
134
|
-
expect(
|
|
135
|
-
expect(
|
|
215
|
+
expect(ctx.loadedDevice.canProduce('audio')).toBe(true);
|
|
216
|
+
expect(ctx.loadedDevice.canProduce('video')).toBe(true);
|
|
136
217
|
});
|
|
137
218
|
test('device.canProduce() with invalid kind throws TypeError', () => {
|
|
138
219
|
// @ts-ignore
|
|
139
|
-
expect(() =>
|
|
140
|
-
.toThrow(TypeError);
|
|
220
|
+
expect(() => ctx.loadedDevice.canProduce('chicken')).toThrow(TypeError);
|
|
141
221
|
});
|
|
142
222
|
test('device.createSendTransport() for sending media succeeds', () => {
|
|
143
223
|
// Assume we create a transport in the server and get its remote parameters.
|
|
144
224
|
const { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters } = fakeParameters.generateTransportRemoteParameters();
|
|
145
|
-
sendTransport =
|
|
225
|
+
const sendTransport = ctx.loadedDevice.createSendTransport({
|
|
146
226
|
id,
|
|
147
227
|
iceParameters,
|
|
148
228
|
iceCandidates,
|
|
149
229
|
dtlsParameters,
|
|
150
230
|
sctpParameters,
|
|
151
|
-
appData: { foo: 123 }
|
|
231
|
+
appData: { foo: 123 },
|
|
152
232
|
});
|
|
153
233
|
expect(typeof sendTransport).toBe('object');
|
|
154
234
|
expect(sendTransport.id).toBe(id);
|
|
@@ -162,12 +242,12 @@ test('device.createSendTransport() for sending media succeeds', () => {
|
|
|
162
242
|
test('device.createRecvTransport() for receiving media succeeds', () => {
|
|
163
243
|
// Assume we create a transport in the server and get its remote parameters.
|
|
164
244
|
const { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters } = fakeParameters.generateTransportRemoteParameters();
|
|
165
|
-
recvTransport =
|
|
245
|
+
const recvTransport = ctx.loadedDevice.createRecvTransport({
|
|
166
246
|
id,
|
|
167
247
|
iceParameters,
|
|
168
248
|
iceCandidates,
|
|
169
249
|
dtlsParameters,
|
|
170
|
-
sctpParameters
|
|
250
|
+
sctpParameters,
|
|
171
251
|
});
|
|
172
252
|
expect(typeof recvTransport).toBe('object');
|
|
173
253
|
expect(recvTransport.id).toBe(id);
|
|
@@ -180,95 +260,59 @@ test('device.createRecvTransport() for receiving media succeeds', () => {
|
|
|
180
260
|
});
|
|
181
261
|
test('device.createSendTransport() with missing remote Transport parameters throws TypeError', () => {
|
|
182
262
|
// @ts-ignore
|
|
183
|
-
expect(() =>
|
|
184
|
-
|
|
263
|
+
expect(() => ctx.loadedDevice.createSendTransport({ id: '1234' })).toThrow(TypeError);
|
|
264
|
+
expect(() =>
|
|
185
265
|
// @ts-ignore
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
expect(() => device.createSendTransport({
|
|
266
|
+
ctx.loadedDevice.createSendTransport({ id: '1234', iceParameters: {} })).toThrow(TypeError);
|
|
267
|
+
expect(() => ctx.loadedDevice.createSendTransport({
|
|
189
268
|
id: '1234',
|
|
190
269
|
// @ts-ignore
|
|
191
270
|
iceParameters: {},
|
|
192
|
-
iceCandidates: []
|
|
193
|
-
}))
|
|
194
|
-
.toThrow(TypeError);
|
|
271
|
+
iceCandidates: [],
|
|
272
|
+
})).toThrow(TypeError);
|
|
195
273
|
});
|
|
196
274
|
test('device.createRecvTransport() with a non object appData throws TypeError', () => {
|
|
197
275
|
const { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters } = fakeParameters.generateTransportRemoteParameters();
|
|
198
|
-
expect(() =>
|
|
276
|
+
expect(() => ctx.loadedDevice.createRecvTransport({
|
|
199
277
|
id,
|
|
200
278
|
iceParameters,
|
|
201
279
|
iceCandidates,
|
|
202
280
|
dtlsParameters,
|
|
203
281
|
sctpParameters,
|
|
204
282
|
// @ts-ignore
|
|
205
|
-
appData: 1234
|
|
206
|
-
}))
|
|
207
|
-
.toThrow(TypeError);
|
|
283
|
+
appData: 1234,
|
|
284
|
+
})).toThrow(TypeError);
|
|
208
285
|
});
|
|
209
|
-
test('transport.produce() without "
|
|
286
|
+
test('transport.produce() without "produce" listener rejects', async () => {
|
|
210
287
|
const audioTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
.toThrow(Error);
|
|
288
|
+
ctx.sendTransport.removeAllListeners('produce');
|
|
289
|
+
await expect(ctx.sendTransport.produce({ track: audioTrack })).rejects.toThrow(Error);
|
|
214
290
|
}, 500);
|
|
215
291
|
test('transport.produce() succeeds', async () => {
|
|
216
292
|
const audioTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
217
293
|
const videoTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'video' });
|
|
218
|
-
let audioProducerId;
|
|
219
|
-
let videoProducerId;
|
|
220
294
|
let connectEventNumTimesCalled = 0;
|
|
221
295
|
let produceEventNumTimesCalled = 0;
|
|
222
|
-
// eslint-disable-next-line no-unused-vars
|
|
223
|
-
sendTransport.on('connect', ({ dtlsParameters }, callback /* errback */) => {
|
|
224
|
-
connectEventNumTimesCalled++;
|
|
225
|
-
expect(typeof dtlsParameters).toBe('object');
|
|
226
|
-
// Emulate communication with the server and success response (no response
|
|
227
|
-
// data needed).
|
|
228
|
-
setTimeout(callback);
|
|
229
|
-
});
|
|
230
|
-
// eslint-disable-next-line no-unused-vars
|
|
231
|
-
sendTransport.on('produce', ({ kind, rtpParameters, appData }, callback /* errback */) => {
|
|
232
|
-
produceEventNumTimesCalled++;
|
|
233
|
-
expect(typeof kind).toBe('string');
|
|
234
|
-
expect(typeof rtpParameters).toBe('object');
|
|
235
|
-
let id;
|
|
236
|
-
switch (kind) {
|
|
237
|
-
case 'audio':
|
|
238
|
-
{
|
|
239
|
-
expect(appData).toEqual({ foo: 'FOO' });
|
|
240
|
-
id = fakeParameters.generateProducerRemoteParameters().id;
|
|
241
|
-
audioProducerId = id;
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
case 'video':
|
|
245
|
-
{
|
|
246
|
-
expect(appData).toEqual({});
|
|
247
|
-
id = fakeParameters.generateProducerRemoteParameters().id;
|
|
248
|
-
videoProducerId = id;
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
default:
|
|
252
|
-
{
|
|
253
|
-
throw new Error('unknown kind');
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
// Emulate communication with the server and success response with Producer
|
|
257
|
-
// remote parameters.
|
|
258
|
-
setTimeout(() => callback({ id }));
|
|
259
|
-
});
|
|
260
296
|
let codecs;
|
|
261
297
|
let headerExtensions;
|
|
262
298
|
let encodings;
|
|
263
299
|
let rtcp;
|
|
264
300
|
// Pause the audio track before creating its Producer.
|
|
265
301
|
audioTrack.enabled = false;
|
|
302
|
+
ctx.connectedSendTransport.prependListener('connect', () => ++connectEventNumTimesCalled);
|
|
303
|
+
ctx.connectedSendTransport.prependListener('produce', () => ++produceEventNumTimesCalled);
|
|
266
304
|
// Use stopTracks: false.
|
|
267
|
-
audioProducer = await
|
|
268
|
-
|
|
305
|
+
const audioProducer = await ctx.connectedSendTransport.produce({
|
|
306
|
+
track: audioTrack,
|
|
307
|
+
stopTracks: false,
|
|
308
|
+
appData: { foo: 'FOO' },
|
|
309
|
+
});
|
|
310
|
+
// 'connect' event should not have been called since it was in beforeEach
|
|
311
|
+
// already.
|
|
312
|
+
expect(connectEventNumTimesCalled).toBe(0);
|
|
269
313
|
expect(produceEventNumTimesCalled).toBe(1);
|
|
270
314
|
expect(typeof audioProducer).toBe('object');
|
|
271
|
-
expect(audioProducer.id).toBe(
|
|
315
|
+
expect(typeof audioProducer.id).toBe('string');
|
|
272
316
|
expect(audioProducer.closed).toBe(false);
|
|
273
317
|
expect(audioProducer.kind).toBe('audio');
|
|
274
318
|
expect(audioProducer.track).toBe(audioTrack);
|
|
@@ -281,13 +325,11 @@ test('transport.produce() succeeds', async () => {
|
|
|
281
325
|
payloadType: 111,
|
|
282
326
|
clockRate: 48000,
|
|
283
327
|
channels: 2,
|
|
284
|
-
rtcpFeedback: [
|
|
285
|
-
{ type: 'transport-cc', parameter: '' }
|
|
286
|
-
],
|
|
328
|
+
rtcpFeedback: [{ type: 'transport-cc', parameter: '' }],
|
|
287
329
|
parameters: {
|
|
288
330
|
minptime: 10,
|
|
289
|
-
useinbandfec: 1
|
|
290
|
-
}
|
|
331
|
+
useinbandfec: 1,
|
|
332
|
+
},
|
|
291
333
|
});
|
|
292
334
|
headerExtensions = audioProducer.rtpParameters.headerExtensions;
|
|
293
335
|
expect(headerExtensions).toEqual([
|
|
@@ -295,14 +337,14 @@ test('transport.produce() succeeds', async () => {
|
|
|
295
337
|
uri: 'urn:ietf:params:rtp-hdrext:sdes:mid',
|
|
296
338
|
id: 1,
|
|
297
339
|
encrypt: false,
|
|
298
|
-
parameters: {}
|
|
340
|
+
parameters: {},
|
|
299
341
|
},
|
|
300
342
|
{
|
|
301
343
|
uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
|
|
302
344
|
id: 10,
|
|
303
345
|
encrypt: false,
|
|
304
|
-
parameters: {}
|
|
305
|
-
}
|
|
346
|
+
parameters: {},
|
|
347
|
+
},
|
|
306
348
|
]);
|
|
307
349
|
encodings = audioProducer.rtpParameters.encodings;
|
|
308
350
|
expect(Array.isArray(encodings)).toBe(true);
|
|
@@ -318,22 +360,19 @@ test('transport.produce() succeeds', async () => {
|
|
|
318
360
|
expect(audioProducer.appData).toEqual({ foo: 'FOO' });
|
|
319
361
|
// Reset the audio paused state.
|
|
320
362
|
audioProducer.resume();
|
|
321
|
-
const videoEncodings = [
|
|
322
|
-
|
|
323
|
-
{ maxBitrate: 500000 }
|
|
324
|
-
];
|
|
325
|
-
// Note that stopTracks is not give so it's true by default.
|
|
363
|
+
const videoEncodings = [{ maxBitrate: 100000 }, { maxBitrate: 500000 }];
|
|
364
|
+
// Note that stopTracks is not given so it's true by default.
|
|
326
365
|
// Use disableTrackOnPause: false and zeroRtpOnPause: true
|
|
327
|
-
videoProducer = await
|
|
366
|
+
const videoProducer = await ctx.connectedSendTransport.produce({
|
|
328
367
|
track: videoTrack,
|
|
329
368
|
encodings: videoEncodings,
|
|
330
369
|
disableTrackOnPause: false,
|
|
331
|
-
zeroRtpOnPause: true
|
|
370
|
+
zeroRtpOnPause: true,
|
|
332
371
|
});
|
|
333
|
-
expect(connectEventNumTimesCalled).toBe(
|
|
372
|
+
expect(connectEventNumTimesCalled).toBe(0);
|
|
334
373
|
expect(produceEventNumTimesCalled).toBe(2);
|
|
335
374
|
expect(typeof videoProducer).toBe('object');
|
|
336
|
-
expect(videoProducer.id).toBe(
|
|
375
|
+
expect(typeof videoProducer.id).toBe('string');
|
|
337
376
|
expect(videoProducer.closed).toBe(false);
|
|
338
377
|
expect(videoProducer.kind).toBe('video');
|
|
339
378
|
expect(videoProducer.track).toBe(videoTrack);
|
|
@@ -350,11 +389,11 @@ test('transport.produce() succeeds', async () => {
|
|
|
350
389
|
{ type: 'transport-cc', parameter: '' },
|
|
351
390
|
{ type: 'ccm', parameter: 'fir' },
|
|
352
391
|
{ type: 'nack', parameter: '' },
|
|
353
|
-
{ type: 'nack', parameter: 'pli' }
|
|
392
|
+
{ type: 'nack', parameter: 'pli' },
|
|
354
393
|
],
|
|
355
394
|
parameters: {
|
|
356
|
-
baz: '1234abcd'
|
|
357
|
-
}
|
|
395
|
+
baz: '1234abcd',
|
|
396
|
+
},
|
|
358
397
|
});
|
|
359
398
|
expect(codecs[1]).toEqual({
|
|
360
399
|
mimeType: 'video/rtx',
|
|
@@ -362,8 +401,8 @@ test('transport.produce() succeeds', async () => {
|
|
|
362
401
|
clockRate: 90000,
|
|
363
402
|
rtcpFeedback: [],
|
|
364
403
|
parameters: {
|
|
365
|
-
apt: 96
|
|
366
|
-
}
|
|
404
|
+
apt: 96,
|
|
405
|
+
},
|
|
367
406
|
});
|
|
368
407
|
headerExtensions = videoProducer.rtpParameters.headerExtensions;
|
|
369
408
|
expect(headerExtensions).toEqual([
|
|
@@ -371,32 +410,32 @@ test('transport.produce() succeeds', async () => {
|
|
|
371
410
|
uri: 'urn:ietf:params:rtp-hdrext:sdes:mid',
|
|
372
411
|
id: 1,
|
|
373
412
|
encrypt: false,
|
|
374
|
-
parameters: {}
|
|
413
|
+
parameters: {},
|
|
375
414
|
},
|
|
376
415
|
{
|
|
377
416
|
uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
|
|
378
417
|
id: 3,
|
|
379
418
|
encrypt: false,
|
|
380
|
-
parameters: {}
|
|
419
|
+
parameters: {},
|
|
381
420
|
},
|
|
382
421
|
{
|
|
383
422
|
uri: 'http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01',
|
|
384
423
|
id: 5,
|
|
385
424
|
encrypt: false,
|
|
386
|
-
parameters: {}
|
|
425
|
+
parameters: {},
|
|
387
426
|
},
|
|
388
427
|
{
|
|
389
428
|
uri: 'urn:3gpp:video-orientation',
|
|
390
429
|
id: 4,
|
|
391
430
|
encrypt: false,
|
|
392
|
-
parameters: {}
|
|
431
|
+
parameters: {},
|
|
393
432
|
},
|
|
394
433
|
{
|
|
395
434
|
uri: 'urn:ietf:params:rtp-hdrext:toffset',
|
|
396
435
|
id: 2,
|
|
397
436
|
encrypt: false,
|
|
398
|
-
parameters: {}
|
|
399
|
-
}
|
|
437
|
+
parameters: {},
|
|
438
|
+
},
|
|
400
439
|
]);
|
|
401
440
|
encodings = videoProducer.rtpParameters.encodings;
|
|
402
441
|
expect(Array.isArray(encodings)).toBe(true);
|
|
@@ -417,58 +456,48 @@ test('transport.produce() succeeds', async () => {
|
|
|
417
456
|
expect(videoProducer.paused).toBe(false);
|
|
418
457
|
expect(videoProducer.maxSpatialLayer).toBe(undefined);
|
|
419
458
|
expect(videoProducer.appData).toEqual({});
|
|
420
|
-
sendTransport.removeAllListeners('connect');
|
|
421
|
-
sendTransport.removeAllListeners('produce');
|
|
422
459
|
}, 500);
|
|
423
460
|
test('transport.produce() without track rejects with TypeError', async () => {
|
|
424
|
-
await expect(sendTransport.produce({}))
|
|
425
|
-
.rejects
|
|
426
|
-
.toThrow(TypeError);
|
|
461
|
+
await expect(ctx.sendTransport.produce({})).rejects.toThrow(TypeError);
|
|
427
462
|
}, 500);
|
|
428
463
|
test('transport.produce() in a receiving Transport rejects with UnsupportedError', async () => {
|
|
429
464
|
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
430
|
-
await expect(recvTransport.produce({ track }))
|
|
431
|
-
.rejects
|
|
432
|
-
.toThrow(errors_1.UnsupportedError);
|
|
465
|
+
await expect(ctx.recvTransport.produce({ track })).rejects.toThrow(errors_1.UnsupportedError);
|
|
433
466
|
}, 500);
|
|
434
467
|
test('transport.produce() with an ended track rejects with InvalidStateError', async () => {
|
|
435
468
|
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
436
469
|
track.stop();
|
|
437
|
-
await expect(sendTransport.produce({ track }))
|
|
438
|
-
.rejects
|
|
439
|
-
.toThrow(errors_1.InvalidStateError);
|
|
470
|
+
await expect(ctx.sendTransport.produce({ track })).rejects.toThrow(errors_1.InvalidStateError);
|
|
440
471
|
}, 500);
|
|
441
472
|
test('transport.produce() with a non object appData rejects with TypeError', async () => {
|
|
442
473
|
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
474
|
+
await expect(
|
|
443
475
|
// @ts-ignore
|
|
444
|
-
|
|
445
|
-
.rejects
|
|
446
|
-
.toThrow(TypeError);
|
|
476
|
+
ctx.sendTransport.produce({ track, appData: true })).rejects.toThrow(TypeError);
|
|
447
477
|
}, 500);
|
|
448
478
|
test('transport.consume() succeeds', async () => {
|
|
449
|
-
const audioConsumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
450
|
-
|
|
451
|
-
let connectEventNumTimesCalled = 0;
|
|
452
|
-
// eslint-disable-next-line no-unused-vars
|
|
453
|
-
recvTransport.on('connect', ({ dtlsParameters }, callback /* errback */) => {
|
|
454
|
-
connectEventNumTimesCalled++;
|
|
455
|
-
expect(typeof dtlsParameters).toBe('object');
|
|
456
|
-
// Emulate communication with the server and success response (no response
|
|
457
|
-
// data needed).
|
|
458
|
-
setTimeout(callback);
|
|
479
|
+
const audioConsumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
480
|
+
codecMimeType: 'audio/opus',
|
|
459
481
|
});
|
|
482
|
+
const videoConsumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
483
|
+
codecMimeType: 'video/VP8',
|
|
484
|
+
});
|
|
485
|
+
let connectEventNumTimesCalled = 0;
|
|
460
486
|
let codecs;
|
|
461
487
|
let headerExtensions;
|
|
462
488
|
let encodings;
|
|
463
489
|
let rtcp;
|
|
464
|
-
|
|
490
|
+
ctx.connectedRecvTransport.prependListener('connect', () => ++connectEventNumTimesCalled);
|
|
491
|
+
const audioConsumer = await ctx.connectedRecvTransport.consume({
|
|
465
492
|
id: audioConsumerRemoteParameters.id,
|
|
466
493
|
producerId: audioConsumerRemoteParameters.producerId,
|
|
467
494
|
kind: audioConsumerRemoteParameters.kind,
|
|
468
495
|
rtpParameters: audioConsumerRemoteParameters.rtpParameters,
|
|
469
|
-
appData: { bar: 'BAR' }
|
|
496
|
+
appData: { bar: 'BAR' },
|
|
470
497
|
});
|
|
471
|
-
|
|
498
|
+
// 'connect' event should not have been called since it was in beforeEach
|
|
499
|
+
// already.
|
|
500
|
+
expect(connectEventNumTimesCalled).toBe(0);
|
|
472
501
|
expect(typeof audioConsumer).toBe('object');
|
|
473
502
|
expect(audioConsumer.id).toBe(audioConsumerRemoteParameters.id);
|
|
474
503
|
expect(audioConsumer.producerId).toBe(audioConsumerRemoteParameters.producerId);
|
|
@@ -484,13 +513,11 @@ test('transport.consume() succeeds', async () => {
|
|
|
484
513
|
payloadType: 100,
|
|
485
514
|
clockRate: 48000,
|
|
486
515
|
channels: 2,
|
|
487
|
-
rtcpFeedback: [
|
|
488
|
-
{ type: 'transport-cc', parameter: '' }
|
|
489
|
-
],
|
|
516
|
+
rtcpFeedback: [{ type: 'transport-cc', parameter: '' }],
|
|
490
517
|
parameters: {
|
|
491
518
|
useinbandfec: 1,
|
|
492
|
-
foo: 'bar'
|
|
493
|
-
}
|
|
519
|
+
foo: 'bar',
|
|
520
|
+
},
|
|
494
521
|
});
|
|
495
522
|
headerExtensions = audioConsumer.rtpParameters.headerExtensions;
|
|
496
523
|
expect(headerExtensions).toEqual([
|
|
@@ -498,20 +525,20 @@ test('transport.consume() succeeds', async () => {
|
|
|
498
525
|
uri: 'urn:ietf:params:rtp-hdrext:sdes:mid',
|
|
499
526
|
id: 1,
|
|
500
527
|
encrypt: false,
|
|
501
|
-
parameters: {}
|
|
528
|
+
parameters: {},
|
|
502
529
|
},
|
|
503
530
|
{
|
|
504
531
|
uri: 'http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01',
|
|
505
532
|
id: 5,
|
|
506
533
|
encrypt: false,
|
|
507
|
-
parameters: {}
|
|
534
|
+
parameters: {},
|
|
508
535
|
},
|
|
509
536
|
{
|
|
510
537
|
uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
|
|
511
538
|
id: 10,
|
|
512
539
|
encrypt: false,
|
|
513
|
-
parameters: {}
|
|
514
|
-
}
|
|
540
|
+
parameters: {},
|
|
541
|
+
},
|
|
515
542
|
]);
|
|
516
543
|
encodings = audioConsumer.rtpParameters.encodings;
|
|
517
544
|
expect(Array.isArray(encodings)).toBe(true);
|
|
@@ -519,18 +546,18 @@ test('transport.consume() succeeds', async () => {
|
|
|
519
546
|
expect(typeof encodings?.[0]).toBe('object');
|
|
520
547
|
expect(Object.keys(encodings[0])).toEqual(['ssrc', 'dtx']);
|
|
521
548
|
expect(typeof encodings[0].ssrc).toBe('number');
|
|
522
|
-
rtcp =
|
|
549
|
+
rtcp = audioConsumer.rtpParameters.rtcp;
|
|
523
550
|
expect(typeof rtcp).toBe('object');
|
|
524
551
|
expect(typeof rtcp?.cname).toBe('string');
|
|
525
552
|
expect(audioConsumer.paused).toBe(false);
|
|
526
553
|
expect(audioConsumer.appData).toEqual({ bar: 'BAR' });
|
|
527
|
-
videoConsumer = await
|
|
554
|
+
const videoConsumer = await ctx.connectedRecvTransport.consume({
|
|
528
555
|
id: videoConsumerRemoteParameters.id,
|
|
529
556
|
producerId: videoConsumerRemoteParameters.producerId,
|
|
530
557
|
kind: videoConsumerRemoteParameters.kind,
|
|
531
|
-
rtpParameters: videoConsumerRemoteParameters.rtpParameters
|
|
558
|
+
rtpParameters: videoConsumerRemoteParameters.rtpParameters,
|
|
532
559
|
});
|
|
533
|
-
expect(connectEventNumTimesCalled).toBe(
|
|
560
|
+
expect(connectEventNumTimesCalled).toBe(0);
|
|
534
561
|
expect(typeof videoConsumer).toBe('object');
|
|
535
562
|
expect(videoConsumer.id).toBe(videoConsumerRemoteParameters.id);
|
|
536
563
|
expect(videoConsumer.producerId).toBe(videoConsumerRemoteParameters.producerId);
|
|
@@ -550,11 +577,11 @@ test('transport.consume() succeeds', async () => {
|
|
|
550
577
|
{ type: 'nack', parameter: 'pli' },
|
|
551
578
|
{ type: 'ccm', parameter: 'fir' },
|
|
552
579
|
{ type: 'goog-remb', parameter: '' },
|
|
553
|
-
{ type: 'transport-cc', parameter: '' }
|
|
580
|
+
{ type: 'transport-cc', parameter: '' },
|
|
554
581
|
],
|
|
555
582
|
parameters: {
|
|
556
|
-
'x-google-start-bitrate': 1500
|
|
557
|
-
}
|
|
583
|
+
'x-google-start-bitrate': 1500,
|
|
584
|
+
},
|
|
558
585
|
});
|
|
559
586
|
expect(codecs[1]).toEqual({
|
|
560
587
|
mimeType: 'video/rtx',
|
|
@@ -562,8 +589,8 @@ test('transport.consume() succeeds', async () => {
|
|
|
562
589
|
clockRate: 90000,
|
|
563
590
|
rtcpFeedback: [],
|
|
564
591
|
parameters: {
|
|
565
|
-
apt: 101
|
|
566
|
-
}
|
|
592
|
+
apt: 101,
|
|
593
|
+
},
|
|
567
594
|
});
|
|
568
595
|
headerExtensions = videoConsumer.rtpParameters.headerExtensions;
|
|
569
596
|
expect(headerExtensions).toEqual([
|
|
@@ -571,32 +598,32 @@ test('transport.consume() succeeds', async () => {
|
|
|
571
598
|
uri: 'urn:ietf:params:rtp-hdrext:sdes:mid',
|
|
572
599
|
id: 1,
|
|
573
600
|
encrypt: false,
|
|
574
|
-
parameters: {}
|
|
601
|
+
parameters: {},
|
|
575
602
|
},
|
|
576
603
|
{
|
|
577
604
|
uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
|
|
578
605
|
id: 4,
|
|
579
606
|
encrypt: false,
|
|
580
|
-
parameters: {}
|
|
607
|
+
parameters: {},
|
|
581
608
|
},
|
|
582
609
|
{
|
|
583
610
|
uri: 'http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01',
|
|
584
611
|
id: 5,
|
|
585
612
|
encrypt: false,
|
|
586
|
-
parameters: {}
|
|
613
|
+
parameters: {},
|
|
587
614
|
},
|
|
588
615
|
{
|
|
589
616
|
uri: 'urn:3gpp:video-orientation',
|
|
590
617
|
id: 11,
|
|
591
618
|
encrypt: false,
|
|
592
|
-
parameters: {}
|
|
619
|
+
parameters: {},
|
|
593
620
|
},
|
|
594
621
|
{
|
|
595
622
|
uri: 'urn:ietf:params:rtp-hdrext:toffset',
|
|
596
623
|
id: 12,
|
|
597
624
|
encrypt: false,
|
|
598
|
-
parameters: {}
|
|
599
|
-
}
|
|
625
|
+
parameters: {},
|
|
626
|
+
},
|
|
600
627
|
]);
|
|
601
628
|
encodings = videoConsumer.rtpParameters.encodings;
|
|
602
629
|
expect(Array.isArray(encodings)).toBe(true);
|
|
@@ -612,15 +639,19 @@ test('transport.consume() succeeds', async () => {
|
|
|
612
639
|
expect(typeof rtcp?.cname).toBe('string');
|
|
613
640
|
expect(videoConsumer.paused).toBe(false);
|
|
614
641
|
expect(videoConsumer.appData).toEqual({});
|
|
615
|
-
recvTransport.removeAllListeners('connect');
|
|
616
642
|
}, 500);
|
|
617
643
|
test('transport.consume() batches consumers created in same macrotask into the same task', async () => {
|
|
618
|
-
const videoConsumerRemoteParameters1 = fakeParameters.generateConsumerRemoteParameters({
|
|
619
|
-
|
|
620
|
-
|
|
644
|
+
const videoConsumerRemoteParameters1 = fakeParameters.generateConsumerRemoteParameters({
|
|
645
|
+
codecMimeType: 'video/VP8',
|
|
646
|
+
});
|
|
647
|
+
const videoConsumerRemoteParameters2 = fakeParameters.generateConsumerRemoteParameters({
|
|
648
|
+
codecMimeType: 'video/VP8',
|
|
649
|
+
});
|
|
650
|
+
// @ts-ignore
|
|
651
|
+
const pushSpy = jest.spyOn(ctx.connectedRecvTransport._awaitQueue, 'push');
|
|
621
652
|
const waitForConsumer = (id) => {
|
|
622
|
-
return new Promise(
|
|
623
|
-
|
|
653
|
+
return new Promise(resolve => {
|
|
654
|
+
ctx.connectedRecvTransport.observer.on('newconsumer', consumer => {
|
|
624
655
|
if (consumer.id === id) {
|
|
625
656
|
resolve();
|
|
626
657
|
}
|
|
@@ -629,114 +660,95 @@ test('transport.consume() batches consumers created in same macrotask into the s
|
|
|
629
660
|
};
|
|
630
661
|
const allConsumersCreated = Promise.all([
|
|
631
662
|
waitForConsumer(videoConsumerRemoteParameters1.id),
|
|
632
|
-
waitForConsumer(videoConsumerRemoteParameters2.id)
|
|
663
|
+
waitForConsumer(videoConsumerRemoteParameters2.id),
|
|
633
664
|
]);
|
|
634
665
|
await Promise.all([
|
|
635
|
-
|
|
666
|
+
ctx.connectedRecvTransport.consume({
|
|
636
667
|
id: videoConsumerRemoteParameters1.id,
|
|
637
668
|
producerId: videoConsumerRemoteParameters1.producerId,
|
|
638
669
|
kind: videoConsumerRemoteParameters1.kind,
|
|
639
|
-
rtpParameters: videoConsumerRemoteParameters1.rtpParameters
|
|
670
|
+
rtpParameters: videoConsumerRemoteParameters1.rtpParameters,
|
|
640
671
|
}),
|
|
641
|
-
|
|
672
|
+
ctx.connectedRecvTransport.consume({
|
|
642
673
|
id: videoConsumerRemoteParameters2.id,
|
|
643
674
|
producerId: videoConsumerRemoteParameters2.producerId,
|
|
644
675
|
kind: videoConsumerRemoteParameters2.kind,
|
|
645
|
-
rtpParameters: videoConsumerRemoteParameters2.rtpParameters
|
|
646
|
-
})
|
|
676
|
+
rtpParameters: videoConsumerRemoteParameters2.rtpParameters,
|
|
677
|
+
}),
|
|
647
678
|
]);
|
|
648
679
|
await allConsumersCreated;
|
|
649
680
|
expect(pushSpy).toBeCalledTimes(1);
|
|
650
681
|
}, 500);
|
|
651
682
|
test('transport.consume() without remote Consumer parameters rejects with TypeError', async () => {
|
|
652
683
|
// @ts-ignore
|
|
653
|
-
await expect(recvTransport.consume({}))
|
|
654
|
-
.rejects
|
|
655
|
-
.toThrow(TypeError);
|
|
684
|
+
await expect(ctx.recvTransport.consume({})).rejects.toThrow(TypeError);
|
|
656
685
|
}, 500);
|
|
657
686
|
test('transport.consume() with missing remote Consumer parameters rejects with TypeError', async () => {
|
|
658
687
|
// @ts-ignore
|
|
659
|
-
await expect(recvTransport.consume({ id: '1234' }))
|
|
660
|
-
|
|
661
|
-
.toThrow(TypeError);
|
|
688
|
+
await expect(ctx.recvTransport.consume({ id: '1234' })).rejects.toThrow(TypeError);
|
|
689
|
+
await expect(
|
|
662
690
|
// @ts-ignore
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
.toThrow(TypeError);
|
|
666
|
-
await expect(recvTransport.consume(
|
|
691
|
+
ctx.recvTransport.consume({ id: '1234', producerId: '4444' })).rejects.toThrow(TypeError);
|
|
692
|
+
await expect(ctx.recvTransport.consume(
|
|
667
693
|
// @ts-ignore
|
|
668
694
|
{
|
|
669
695
|
id: '1234',
|
|
670
696
|
producerId: '4444',
|
|
671
|
-
kind: 'audio'
|
|
672
|
-
}))
|
|
673
|
-
|
|
674
|
-
.toThrow(TypeError);
|
|
675
|
-
await expect(recvTransport.consume(
|
|
697
|
+
kind: 'audio',
|
|
698
|
+
})).rejects.toThrow(TypeError);
|
|
699
|
+
await expect(ctx.recvTransport.consume(
|
|
676
700
|
// @ts-ignore
|
|
677
701
|
{
|
|
678
702
|
id: '1234',
|
|
679
703
|
producerId: '4444',
|
|
680
|
-
kind: 'audio'
|
|
681
|
-
}))
|
|
682
|
-
.rejects
|
|
683
|
-
.toThrow(TypeError);
|
|
704
|
+
kind: 'audio',
|
|
705
|
+
})).rejects.toThrow(TypeError);
|
|
684
706
|
}, 500);
|
|
685
707
|
test('transport.consume() in a sending Transport rejects with UnsupportedError', async () => {
|
|
686
|
-
const { id, producerId, kind, rtpParameters } = fakeParameters.generateConsumerRemoteParameters({
|
|
687
|
-
|
|
708
|
+
const { id, producerId, kind, rtpParameters } = fakeParameters.generateConsumerRemoteParameters({
|
|
709
|
+
codecMimeType: 'audio/opus',
|
|
710
|
+
});
|
|
711
|
+
await expect(ctx.sendTransport.consume({
|
|
688
712
|
id,
|
|
689
713
|
producerId,
|
|
690
714
|
kind,
|
|
691
|
-
rtpParameters
|
|
692
|
-
}))
|
|
693
|
-
.rejects
|
|
694
|
-
.toThrow(errors_1.UnsupportedError);
|
|
715
|
+
rtpParameters,
|
|
716
|
+
})).rejects.toThrow(errors_1.UnsupportedError);
|
|
695
717
|
}, 500);
|
|
696
718
|
test('transport.consume() with unsupported rtpParameters rejects with UnsupportedError', async () => {
|
|
697
|
-
const { id, producerId, kind, rtpParameters } = fakeParameters.generateConsumerRemoteParameters({
|
|
698
|
-
|
|
719
|
+
const { id, producerId, kind, rtpParameters } = fakeParameters.generateConsumerRemoteParameters({
|
|
720
|
+
codecMimeType: 'audio/ISAC',
|
|
721
|
+
});
|
|
722
|
+
await expect(ctx.sendTransport.consume({
|
|
699
723
|
id,
|
|
700
724
|
producerId,
|
|
701
725
|
kind,
|
|
702
|
-
rtpParameters
|
|
703
|
-
}))
|
|
704
|
-
.rejects
|
|
705
|
-
.toThrow(errors_1.UnsupportedError);
|
|
726
|
+
rtpParameters,
|
|
727
|
+
})).rejects.toThrow(errors_1.UnsupportedError);
|
|
706
728
|
}, 500);
|
|
707
729
|
test('transport.consume() with a non object appData rejects with TypeError', async () => {
|
|
708
|
-
const consumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
730
|
+
const consumerRemoteParameters = fakeParameters.generateConsumerRemoteParameters({
|
|
731
|
+
codecMimeType: 'audio/opus',
|
|
732
|
+
});
|
|
733
|
+
await expect(
|
|
709
734
|
// @ts-ignore
|
|
710
|
-
|
|
711
|
-
.rejects
|
|
712
|
-
.toThrow(TypeError);
|
|
735
|
+
ctx.recvTransport.consume({ consumerRemoteParameters, appData: true })).rejects.toThrow(TypeError);
|
|
713
736
|
}, 500);
|
|
714
737
|
test('transport.produceData() succeeds', async () => {
|
|
715
|
-
let dataProducerId;
|
|
716
738
|
let produceDataEventNumTimesCalled = 0;
|
|
717
|
-
|
|
718
|
-
sendTransport.on('producedata', ({ sctpStreamParameters, label, protocol, appData }, callback /* errback */) => {
|
|
739
|
+
ctx.connectedSendTransport.prependListener('producedata', () => {
|
|
719
740
|
produceDataEventNumTimesCalled++;
|
|
720
|
-
expect(typeof sctpStreamParameters).toBe('object');
|
|
721
|
-
expect(label).toBe('FOO');
|
|
722
|
-
expect(protocol).toBe('BAR');
|
|
723
|
-
expect(appData).toEqual({ foo: 'FOO' });
|
|
724
|
-
const id = fakeParameters.generateDataProducerRemoteParameters().id;
|
|
725
|
-
dataProducerId = id;
|
|
726
|
-
// Emulate communication with the server and success response with Producer
|
|
727
|
-
// remote parameters.
|
|
728
|
-
setTimeout(() => callback({ id }));
|
|
729
741
|
});
|
|
730
|
-
dataProducer = await
|
|
742
|
+
const dataProducer = await ctx.connectedSendTransport.produceData({
|
|
731
743
|
ordered: false,
|
|
732
744
|
maxPacketLifeTime: 5555,
|
|
733
745
|
label: 'FOO',
|
|
734
746
|
protocol: 'BAR',
|
|
735
|
-
appData: { foo: 'FOO' }
|
|
747
|
+
appData: { foo: 'FOO' },
|
|
736
748
|
});
|
|
737
749
|
expect(produceDataEventNumTimesCalled).toBe(1);
|
|
738
750
|
expect(typeof dataProducer).toBe('object');
|
|
739
|
-
expect(dataProducer.id).toBe(
|
|
751
|
+
expect(typeof dataProducer.id).toBe('string');
|
|
740
752
|
expect(dataProducer.closed).toBe(false);
|
|
741
753
|
expect(typeof dataProducer.sctpStreamParameters).toBe('object');
|
|
742
754
|
expect(typeof dataProducer.sctpStreamParameters.streamId).toBe('number');
|
|
@@ -745,28 +757,24 @@ test('transport.produceData() succeeds', async () => {
|
|
|
745
757
|
expect(dataProducer.sctpStreamParameters.maxRetransmits).toBe(undefined);
|
|
746
758
|
expect(dataProducer.label).toBe('FOO');
|
|
747
759
|
expect(dataProducer.protocol).toBe('BAR');
|
|
748
|
-
sendTransport.removeAllListeners('producedata');
|
|
749
760
|
}, 500);
|
|
750
761
|
test('transport.produceData() in a receiving Transport rejects with UnsupportedError', async () => {
|
|
751
|
-
await expect(recvTransport.produceData({}))
|
|
752
|
-
.rejects
|
|
753
|
-
.toThrow(errors_1.UnsupportedError);
|
|
762
|
+
await expect(ctx.recvTransport.produceData({})).rejects.toThrow(errors_1.UnsupportedError);
|
|
754
763
|
}, 500);
|
|
755
764
|
test('transport.produceData() with a non object appData rejects with TypeError', async () => {
|
|
765
|
+
await expect(
|
|
756
766
|
// @ts-ignore
|
|
757
|
-
|
|
758
|
-
.rejects
|
|
759
|
-
.toThrow(TypeError);
|
|
767
|
+
ctx.sendTransport.produceData({ appData: true })).rejects.toThrow(TypeError);
|
|
760
768
|
}, 500);
|
|
761
769
|
test('transport.consumeData() succeeds', async () => {
|
|
762
770
|
const dataConsumerRemoteParameters = fakeParameters.generateDataConsumerRemoteParameters();
|
|
763
|
-
dataConsumer = await
|
|
771
|
+
const dataConsumer = await ctx.connectedRecvTransport.consumeData({
|
|
764
772
|
id: dataConsumerRemoteParameters.id,
|
|
765
773
|
dataProducerId: dataConsumerRemoteParameters.dataProducerId,
|
|
766
774
|
sctpStreamParameters: dataConsumerRemoteParameters.sctpStreamParameters,
|
|
767
775
|
label: 'FOO',
|
|
768
776
|
protocol: 'BAR',
|
|
769
|
-
appData: { bar: 'BAR' }
|
|
777
|
+
appData: { bar: 'BAR' },
|
|
770
778
|
});
|
|
771
779
|
expect(typeof dataConsumer).toBe('object');
|
|
772
780
|
expect(dataConsumer.id).toBe(dataConsumerRemoteParameters.id);
|
|
@@ -779,66 +787,52 @@ test('transport.consumeData() succeeds', async () => {
|
|
|
779
787
|
}, 500);
|
|
780
788
|
test('transport.consumeData() without remote DataConsumer parameters rejects with TypeError', async () => {
|
|
781
789
|
// @ts-ignore
|
|
782
|
-
await expect(recvTransport.consumeData({}))
|
|
783
|
-
.rejects
|
|
784
|
-
.toThrow(TypeError);
|
|
790
|
+
await expect(ctx.recvTransport.consumeData({})).rejects.toThrow(TypeError);
|
|
785
791
|
}, 500);
|
|
786
792
|
test('transport.consumeData() with missing remote DataConsumer parameters rejects with TypeError', async () => {
|
|
787
793
|
// @ts-ignore
|
|
788
|
-
await expect(recvTransport.consumeData({ id: '1234' }))
|
|
789
|
-
|
|
790
|
-
.toThrow(TypeError);
|
|
794
|
+
await expect(ctx.recvTransport.consumeData({ id: '1234' })).rejects.toThrow(TypeError);
|
|
795
|
+
await expect(
|
|
791
796
|
// @ts-ignore
|
|
792
|
-
|
|
793
|
-
.rejects
|
|
794
|
-
.toThrow(TypeError);
|
|
797
|
+
ctx.recvTransport.consumeData({ id: '1234', dataProducerId: '4444' })).rejects.toThrow(TypeError);
|
|
795
798
|
}, 500);
|
|
796
799
|
test('transport.consumeData() in a sending Transport rejects with UnsupportedError', async () => {
|
|
797
800
|
const { id, dataProducerId, sctpStreamParameters } = fakeParameters.generateDataConsumerRemoteParameters();
|
|
798
|
-
await expect(sendTransport.consumeData({
|
|
801
|
+
await expect(ctx.sendTransport.consumeData({
|
|
799
802
|
id,
|
|
800
803
|
dataProducerId,
|
|
801
|
-
sctpStreamParameters
|
|
802
|
-
}))
|
|
803
|
-
.rejects
|
|
804
|
-
.toThrow(errors_1.UnsupportedError);
|
|
804
|
+
sctpStreamParameters,
|
|
805
|
+
})).rejects.toThrow(errors_1.UnsupportedError);
|
|
805
806
|
}, 500);
|
|
806
807
|
test('transport.consumeData() with a non object appData rejects with TypeError', async () => {
|
|
807
808
|
const dataConsumerRemoteParameters = fakeParameters.generateDataConsumerRemoteParameters();
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
809
|
+
await expect(ctx.recvTransport.consumeData({
|
|
810
|
+
dataConsumerRemoteParameters,
|
|
811
|
+
// @ts-ignore
|
|
812
|
+
appData: true,
|
|
813
|
+
})).rejects.toThrow(TypeError);
|
|
812
814
|
}, 500);
|
|
813
815
|
test('transport.getStats() succeeds', async () => {
|
|
814
|
-
const stats = await sendTransport.getStats();
|
|
816
|
+
const stats = await ctx.sendTransport.getStats();
|
|
815
817
|
expect(typeof stats).toBe('object');
|
|
816
818
|
}, 500);
|
|
817
819
|
test('transport.restartIce() succeeds', async () => {
|
|
818
|
-
await expect(sendTransport.restartIce({
|
|
820
|
+
await expect(ctx.sendTransport.restartIce({
|
|
819
821
|
iceParameters: {
|
|
820
822
|
usernameFragment: 'foo',
|
|
821
|
-
password: 'xxx'
|
|
822
|
-
}
|
|
823
|
-
}))
|
|
824
|
-
.resolves
|
|
825
|
-
.toBe(undefined);
|
|
823
|
+
password: 'xxx',
|
|
824
|
+
},
|
|
825
|
+
})).resolves.toBe(undefined);
|
|
826
826
|
}, 500);
|
|
827
827
|
test('transport.restartIce() without remote iceParameters rejects with TypeError', async () => {
|
|
828
828
|
// @ts-ignore
|
|
829
|
-
await expect(sendTransport.restartIce({}))
|
|
830
|
-
.rejects
|
|
831
|
-
.toThrow(TypeError);
|
|
829
|
+
await expect(ctx.sendTransport.restartIce({})).rejects.toThrow(TypeError);
|
|
832
830
|
}, 500);
|
|
833
831
|
test('transport.updateIceServers() succeeds', async () => {
|
|
834
|
-
await expect(sendTransport.updateIceServers({ iceServers: [] }))
|
|
835
|
-
.resolves
|
|
836
|
-
.toBe(undefined);
|
|
832
|
+
await expect(ctx.sendTransport.updateIceServers({ iceServers: [] })).resolves.toBe(undefined);
|
|
837
833
|
}, 500);
|
|
838
834
|
test('transport.updateIceServers() without iceServers rejects with TypeError', async () => {
|
|
839
|
-
await expect(sendTransport.updateIceServers({}))
|
|
840
|
-
.rejects
|
|
841
|
-
.toThrow(TypeError);
|
|
835
|
+
await expect(ctx.sendTransport.updateIceServers({})).rejects.toThrow(TypeError);
|
|
842
836
|
}, 500);
|
|
843
837
|
test('ICE gathering state change fires "icegatheringstatechange" in live Transport', () => {
|
|
844
838
|
// NOTE: These tests are a bit flaky and we should isolate them. FakeHandler
|
|
@@ -846,341 +840,284 @@ test('ICE gathering state change fires "icegatheringstatechange" in live Transpo
|
|
|
846
840
|
// private setupTransport() method is called (which has happens many times in
|
|
847
841
|
// tests above already). So here we have to reset it manually to test things.
|
|
848
842
|
// @ts-ignore
|
|
849
|
-
sendTransport.handler.setIceGatheringState('new');
|
|
843
|
+
ctx.sendTransport.handler.setIceGatheringState('new');
|
|
850
844
|
// @ts-ignore
|
|
851
|
-
sendTransport.handler.setConnectionState('new');
|
|
845
|
+
ctx.sendTransport.handler.setConnectionState('new');
|
|
852
846
|
let iceGatheringStateChangeEventNumTimesCalled = 0;
|
|
853
847
|
let connectionStateChangeEventNumTimesCalled = 0;
|
|
854
|
-
sendTransport.on('icegatheringstatechange',
|
|
848
|
+
ctx.sendTransport.on('icegatheringstatechange', iceGatheringState => {
|
|
855
849
|
iceGatheringStateChangeEventNumTimesCalled++;
|
|
856
850
|
expect(iceGatheringState).toBe('complete');
|
|
857
|
-
expect(sendTransport.iceGatheringState).toBe('complete');
|
|
858
|
-
expect(sendTransport.connectionState).toBe('new');
|
|
851
|
+
expect(ctx.sendTransport.iceGatheringState).toBe('complete');
|
|
852
|
+
expect(ctx.sendTransport.connectionState).toBe('new');
|
|
859
853
|
});
|
|
860
854
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
861
|
-
sendTransport.on('connectionstatechange',
|
|
855
|
+
ctx.sendTransport.on('connectionstatechange', connectionState => {
|
|
862
856
|
connectionStateChangeEventNumTimesCalled++;
|
|
863
857
|
});
|
|
864
858
|
// @ts-ignore
|
|
865
|
-
sendTransport.handler.setIceGatheringState('complete');
|
|
859
|
+
ctx.sendTransport.handler.setIceGatheringState('complete');
|
|
866
860
|
expect(iceGatheringStateChangeEventNumTimesCalled).toBe(1);
|
|
867
861
|
expect(connectionStateChangeEventNumTimesCalled).toBe(0);
|
|
868
|
-
expect(sendTransport.iceGatheringState).toBe('complete');
|
|
869
|
-
expect(sendTransport.connectionState).toBe('new');
|
|
870
|
-
sendTransport.removeAllListeners('icegatheringstatechange');
|
|
871
|
-
sendTransport.removeAllListeners('connectionstatechange');
|
|
862
|
+
expect(ctx.sendTransport.iceGatheringState).toBe('complete');
|
|
863
|
+
expect(ctx.sendTransport.connectionState).toBe('new');
|
|
872
864
|
});
|
|
873
865
|
test('connection state change fires "connectionstatechange" in live Transport', () => {
|
|
874
866
|
let connectionStateChangeEventNumTimesCalled = 0;
|
|
875
|
-
sendTransport.on('connectionstatechange',
|
|
867
|
+
ctx.sendTransport.on('connectionstatechange', connectionState => {
|
|
876
868
|
connectionStateChangeEventNumTimesCalled++;
|
|
877
869
|
expect(connectionState).toBe('completed');
|
|
878
870
|
});
|
|
879
871
|
// @ts-ignore
|
|
880
|
-
sendTransport.handler.setConnectionState('completed');
|
|
872
|
+
ctx.sendTransport.handler.setConnectionState('completed');
|
|
881
873
|
expect(connectionStateChangeEventNumTimesCalled).toBe(1);
|
|
882
|
-
expect(sendTransport.connectionState).toBe('completed');
|
|
883
|
-
sendTransport.removeAllListeners('connectionstatechange');
|
|
874
|
+
expect(ctx.sendTransport.connectionState).toBe('completed');
|
|
884
875
|
});
|
|
885
876
|
test('producer.pause() succeeds', () => {
|
|
886
|
-
videoProducer.pause();
|
|
887
|
-
expect(videoProducer.paused).toBe(true);
|
|
888
|
-
|
|
889
|
-
expect(videoProducer.track?.enabled).toBe(true);
|
|
877
|
+
ctx.videoProducer.pause();
|
|
878
|
+
expect(ctx.videoProducer.paused).toBe(true);
|
|
879
|
+
expect(ctx.videoProducer.track?.enabled).toBe(false);
|
|
890
880
|
});
|
|
891
881
|
test('producer.resume() succeeds', () => {
|
|
892
|
-
videoProducer.resume();
|
|
893
|
-
expect(videoProducer.paused).toBe(false);
|
|
894
|
-
expect(videoProducer.track?.enabled).toBe(true);
|
|
882
|
+
ctx.videoProducer.resume();
|
|
883
|
+
expect(ctx.videoProducer.paused).toBe(false);
|
|
884
|
+
expect(ctx.videoProducer.track?.enabled).toBe(true);
|
|
895
885
|
});
|
|
896
886
|
test('producer.replaceTrack() with a new track succeeds', async () => {
|
|
897
887
|
// Have the audio Producer paused.
|
|
898
|
-
audioProducer.pause();
|
|
899
|
-
const audioProducerPreviousTrack = audioProducer.track;
|
|
888
|
+
ctx.audioProducer.pause();
|
|
889
|
+
const audioProducerPreviousTrack = ctx.audioProducer.track;
|
|
900
890
|
const newAudioTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
901
|
-
await expect(audioProducer.replaceTrack({ track: newAudioTrack }))
|
|
902
|
-
.resolves
|
|
903
|
-
.toBe(undefined);
|
|
891
|
+
await expect(ctx.audioProducer.replaceTrack({ track: newAudioTrack })).resolves.toBe(undefined);
|
|
904
892
|
// Previous track must be 'live' due to stopTracks: false.
|
|
905
893
|
expect(audioProducerPreviousTrack?.readyState).toBe('live');
|
|
906
|
-
expect(audioProducer.track?.readyState).toBe('live');
|
|
907
|
-
expect(audioProducer.track).not.toBe(audioProducerPreviousTrack);
|
|
908
|
-
expect(audioProducer.track).toBe(newAudioTrack);
|
|
894
|
+
expect(ctx.audioProducer.track?.readyState).toBe('live');
|
|
895
|
+
expect(ctx.audioProducer.track).not.toBe(audioProducerPreviousTrack);
|
|
896
|
+
expect(ctx.audioProducer.track).toBe(newAudioTrack);
|
|
909
897
|
// Producer was already paused.
|
|
910
|
-
expect(audioProducer.paused).toBe(true);
|
|
898
|
+
expect(ctx.audioProducer.paused).toBe(true);
|
|
911
899
|
// Reset the audio paused state.
|
|
912
|
-
audioProducer.resume();
|
|
913
|
-
const videoProducerPreviousTrack = videoProducer.track;
|
|
900
|
+
ctx.audioProducer.resume();
|
|
901
|
+
const videoProducerPreviousTrack = ctx.videoProducer.track;
|
|
914
902
|
const newVideoTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'video' });
|
|
915
|
-
await expect(videoProducer.replaceTrack({ track: newVideoTrack }))
|
|
916
|
-
.resolves
|
|
917
|
-
.toBe(undefined);
|
|
903
|
+
await expect(ctx.videoProducer.replaceTrack({ track: newVideoTrack })).resolves.toBe(undefined);
|
|
918
904
|
// Previous track must be 'ended' due to stopTracks: true.
|
|
919
905
|
expect(videoProducerPreviousTrack?.readyState).toBe('ended');
|
|
920
|
-
expect(videoProducer.track).not.toBe(videoProducerPreviousTrack);
|
|
921
|
-
expect(videoProducer.track).toBe(newVideoTrack);
|
|
922
|
-
expect(videoProducer.paused).toBe(false);
|
|
906
|
+
expect(ctx.videoProducer.track).not.toBe(videoProducerPreviousTrack);
|
|
907
|
+
expect(ctx.videoProducer.track).toBe(newVideoTrack);
|
|
908
|
+
expect(ctx.videoProducer.paused).toBe(false);
|
|
923
909
|
}, 500);
|
|
924
910
|
test('producer.replaceTrack() with null succeeds', async () => {
|
|
925
911
|
// Have the audio Producer paused.
|
|
926
|
-
audioProducer.pause();
|
|
927
|
-
const audioProducerPreviousTrack = audioProducer.track;
|
|
928
|
-
await expect(audioProducer.replaceTrack({ track: null }))
|
|
929
|
-
.resolves
|
|
930
|
-
.toBe(undefined);
|
|
912
|
+
ctx.audioProducer.pause();
|
|
913
|
+
const audioProducerPreviousTrack = ctx.audioProducer.track;
|
|
914
|
+
await expect(ctx.audioProducer.replaceTrack({ track: null })).resolves.toBe(undefined);
|
|
931
915
|
// Previous track must be 'live' due to stopTracks: false.
|
|
932
916
|
expect(audioProducerPreviousTrack?.readyState).toBe('live');
|
|
933
|
-
expect(audioProducer.track).toBeNull();
|
|
917
|
+
expect(ctx.audioProducer.track).toBeNull();
|
|
934
918
|
// Producer was already paused.
|
|
935
|
-
expect(audioProducer.paused).toBe(true);
|
|
919
|
+
expect(ctx.audioProducer.paused).toBe(true);
|
|
936
920
|
// Reset the audio paused state.
|
|
937
|
-
audioProducer.resume();
|
|
938
|
-
expect(audioProducer.paused).toBe(false);
|
|
921
|
+
ctx.audioProducer.resume();
|
|
922
|
+
expect(ctx.audioProducer.paused).toBe(false);
|
|
939
923
|
// Manually "mute" the original audio track.
|
|
940
924
|
audioProducerPreviousTrack.enabled = false;
|
|
941
925
|
// Set the original audio track back.
|
|
942
|
-
await expect(audioProducer.replaceTrack({ track: audioProducerPreviousTrack }))
|
|
943
|
-
.resolves
|
|
944
|
-
.toBe(undefined);
|
|
926
|
+
await expect(ctx.audioProducer.replaceTrack({ track: audioProducerPreviousTrack })).resolves.toBe(undefined);
|
|
945
927
|
// The given audio track was muted but the Producer was not, so the track
|
|
946
928
|
// must not be muted now.
|
|
947
|
-
expect(audioProducer.paused).toBe(false);
|
|
929
|
+
expect(ctx.audioProducer.paused).toBe(false);
|
|
948
930
|
expect(audioProducerPreviousTrack?.enabled).toBe(true);
|
|
949
931
|
// Reset the audio paused state.
|
|
950
|
-
audioProducer.resume();
|
|
932
|
+
ctx.audioProducer.resume();
|
|
951
933
|
}, 500);
|
|
952
934
|
test('producer.replaceTrack() with an ended track rejects with InvalidStateError', async () => {
|
|
953
935
|
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
954
936
|
track.stop();
|
|
955
|
-
await expect(videoProducer.replaceTrack({ track }))
|
|
956
|
-
.rejects
|
|
957
|
-
.toThrow(errors_1.InvalidStateError);
|
|
937
|
+
await expect(ctx.videoProducer.replaceTrack({ track })).rejects.toThrow(errors_1.InvalidStateError);
|
|
958
938
|
expect(track.readyState).toBe('ended');
|
|
959
|
-
expect(videoProducer.track?.readyState).toBe('live');
|
|
939
|
+
expect(ctx.videoProducer.track?.readyState).toBe('live');
|
|
960
940
|
}, 500);
|
|
961
941
|
test('producer.replaceTrack() with the same track succeeds', async () => {
|
|
962
|
-
await expect(audioProducer.replaceTrack({ track: audioProducer.track }))
|
|
963
|
-
|
|
964
|
-
.toBe(undefined);
|
|
965
|
-
expect(audioProducer.track?.readyState).toBe('live');
|
|
942
|
+
await expect(ctx.audioProducer.replaceTrack({ track: ctx.audioProducer.track })).resolves.toBe(undefined);
|
|
943
|
+
expect(ctx.audioProducer.track?.readyState).toBe('live');
|
|
966
944
|
}, 500);
|
|
967
945
|
test('producer.setMaxSpatialLayer() succeeds', async () => {
|
|
968
|
-
await expect(videoProducer.setMaxSpatialLayer(0))
|
|
969
|
-
|
|
970
|
-
.toBe(undefined);
|
|
971
|
-
expect(videoProducer.maxSpatialLayer).toBe(0);
|
|
946
|
+
await expect(ctx.videoProducer.setMaxSpatialLayer(0)).resolves.toBe(undefined);
|
|
947
|
+
expect(ctx.videoProducer.maxSpatialLayer).toBe(0);
|
|
972
948
|
}, 500);
|
|
973
949
|
test('producer.setMaxSpatialLayer() in an audio Producer rejects with UnsupportedError', async () => {
|
|
974
|
-
await expect(audioProducer.setMaxSpatialLayer(1))
|
|
975
|
-
|
|
976
|
-
.toThrow(errors_1.UnsupportedError);
|
|
977
|
-
expect(audioProducer.maxSpatialLayer).toBe(undefined);
|
|
950
|
+
await expect(ctx.audioProducer.setMaxSpatialLayer(1)).rejects.toThrow(errors_1.UnsupportedError);
|
|
951
|
+
expect(ctx.audioProducer.maxSpatialLayer).toBe(undefined);
|
|
978
952
|
}, 500);
|
|
979
953
|
test('producer.setMaxSpatialLayer() with invalid spatialLayer rejects with TypeError', async () => {
|
|
954
|
+
await expect(
|
|
980
955
|
// @ts-ignore
|
|
981
|
-
|
|
982
|
-
.rejects
|
|
983
|
-
.toThrow(TypeError);
|
|
956
|
+
ctx.videoProducer.setMaxSpatialLayer('chicken')).rejects.toThrow(TypeError);
|
|
984
957
|
}, 500);
|
|
985
958
|
test('producer.setMaxSpatialLayer() without spatialLayer rejects with TypeError', async () => {
|
|
986
959
|
// @ts-ignore
|
|
987
|
-
await expect(videoProducer.setMaxSpatialLayer())
|
|
988
|
-
.rejects
|
|
989
|
-
.toThrow(TypeError);
|
|
960
|
+
await expect(ctx.videoProducer.setMaxSpatialLayer()).rejects.toThrow(TypeError);
|
|
990
961
|
}, 500);
|
|
991
962
|
test('producer.setRtpEncodingParameters() succeeds', async () => {
|
|
992
|
-
await expect(videoProducer.setRtpEncodingParameters({ scaleResolutionDownBy: 2 }))
|
|
993
|
-
.resolves
|
|
994
|
-
.toBe(undefined);
|
|
995
|
-
expect(videoProducer.maxSpatialLayer).toBe(0);
|
|
963
|
+
await expect(ctx.videoProducer.setRtpEncodingParameters({ scaleResolutionDownBy: 2 })).resolves.toBe(undefined);
|
|
996
964
|
}, 500);
|
|
997
965
|
test('producer.getStats() succeeds', async () => {
|
|
998
|
-
const stats = await videoProducer.getStats();
|
|
966
|
+
const stats = await ctx.videoProducer.getStats();
|
|
999
967
|
expect(typeof stats).toBe('object');
|
|
1000
968
|
}, 500);
|
|
1001
969
|
test('consumer.resume() succeeds', () => {
|
|
1002
|
-
videoConsumer.resume();
|
|
1003
|
-
expect(videoConsumer.paused).toBe(false);
|
|
970
|
+
ctx.videoConsumer.resume();
|
|
971
|
+
expect(ctx.videoConsumer.paused).toBe(false);
|
|
1004
972
|
});
|
|
1005
973
|
test('consumer.pause() succeeds', () => {
|
|
1006
|
-
videoConsumer.pause();
|
|
1007
|
-
expect(videoConsumer.paused).toBe(true);
|
|
974
|
+
ctx.videoConsumer.pause();
|
|
975
|
+
expect(ctx.videoConsumer.paused).toBe(true);
|
|
1008
976
|
});
|
|
1009
977
|
test('consumer.getStats() succeeds', async () => {
|
|
1010
|
-
const stats = await videoConsumer.getStats();
|
|
978
|
+
const stats = await ctx.videoConsumer.getStats();
|
|
1011
979
|
expect(typeof stats).toBe('object');
|
|
1012
980
|
}, 500);
|
|
1013
981
|
test('producer.close() succeed', () => {
|
|
1014
|
-
audioProducer.close();
|
|
1015
|
-
expect(audioProducer.closed).toBe(true);
|
|
982
|
+
ctx.audioProducer.close();
|
|
983
|
+
expect(ctx.audioProducer.closed).toBe(true);
|
|
1016
984
|
// Track will be still 'live' due to stopTracks: false.
|
|
1017
|
-
expect(audioProducer.track?.readyState).toBe('live');
|
|
985
|
+
expect(ctx.audioProducer.track?.readyState).toBe('live');
|
|
1018
986
|
});
|
|
1019
987
|
test('producer.replaceTrack() rejects with InvalidStateError if closed', async () => {
|
|
1020
988
|
const audioTrack = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
.toThrow(errors_1.InvalidStateError);
|
|
989
|
+
ctx.audioProducer.close();
|
|
990
|
+
await expect(ctx.audioProducer.replaceTrack({ track: audioTrack })).rejects.toThrow(errors_1.InvalidStateError);
|
|
1024
991
|
expect(audioTrack.readyState).toBe('live');
|
|
1025
992
|
}, 500);
|
|
1026
993
|
test('producer.getStats() rejects with InvalidStateError if closed', async () => {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
.toThrow(errors_1.InvalidStateError);
|
|
994
|
+
ctx.audioProducer.close();
|
|
995
|
+
await expect(ctx.audioProducer.getStats()).rejects.toThrow(errors_1.InvalidStateError);
|
|
1030
996
|
}, 500);
|
|
1031
997
|
test('consumer.close() succeed', () => {
|
|
1032
|
-
audioConsumer.close();
|
|
1033
|
-
expect(audioConsumer.closed).toBe(true);
|
|
1034
|
-
expect(audioConsumer.track.readyState).toBe('ended');
|
|
998
|
+
ctx.audioConsumer.close();
|
|
999
|
+
expect(ctx.audioConsumer.closed).toBe(true);
|
|
1000
|
+
expect(ctx.audioConsumer.track.readyState).toBe('ended');
|
|
1035
1001
|
});
|
|
1036
1002
|
test('consumer.getStats() rejects with InvalidStateError if closed', async () => {
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1003
|
+
ctx.audioConsumer.close();
|
|
1004
|
+
await expect(ctx.audioConsumer.getStats()).rejects.toThrow(errors_1.InvalidStateError);
|
|
1040
1005
|
}, 500);
|
|
1041
1006
|
test('dataProducer.close() succeed', () => {
|
|
1042
|
-
dataProducer.close();
|
|
1043
|
-
expect(dataProducer.closed).toBe(true);
|
|
1007
|
+
ctx.dataProducer.close();
|
|
1008
|
+
expect(ctx.dataProducer.closed).toBe(true);
|
|
1044
1009
|
});
|
|
1045
1010
|
test('dataConsumer.close() succeed', () => {
|
|
1046
|
-
dataConsumer.close();
|
|
1047
|
-
expect(dataConsumer.closed).toBe(true);
|
|
1011
|
+
ctx.dataConsumer.close();
|
|
1012
|
+
expect(ctx.dataConsumer.closed).toBe(true);
|
|
1048
1013
|
});
|
|
1049
1014
|
test('remotetely stopped track fires "trackended" in live Producers/Consumers', () => {
|
|
1050
1015
|
let audioProducerTrackendedEventCalled = false;
|
|
1051
1016
|
let videoProducerTrackendedEventCalled = false;
|
|
1052
1017
|
let audiosConsumerTrackendedEventCalled = false;
|
|
1053
1018
|
let videoConsumerTrackendedEventCalled = false;
|
|
1054
|
-
audioProducer.on('trackended', () => {
|
|
1019
|
+
ctx.audioProducer.on('trackended', () => {
|
|
1055
1020
|
audioProducerTrackendedEventCalled = true;
|
|
1056
1021
|
});
|
|
1057
|
-
videoProducer.on('trackended', () => {
|
|
1022
|
+
ctx.videoProducer.on('trackended', () => {
|
|
1058
1023
|
videoProducerTrackendedEventCalled = true;
|
|
1059
1024
|
});
|
|
1060
|
-
audioConsumer.on('trackended', () => {
|
|
1025
|
+
ctx.audioConsumer.on('trackended', () => {
|
|
1061
1026
|
audiosConsumerTrackendedEventCalled = true;
|
|
1062
1027
|
});
|
|
1063
|
-
videoConsumer.on('trackended', () => {
|
|
1028
|
+
ctx.videoConsumer.on('trackended', () => {
|
|
1064
1029
|
videoConsumerTrackendedEventCalled = true;
|
|
1065
1030
|
});
|
|
1066
1031
|
// @ts-ignore
|
|
1067
|
-
audioProducer.track.remoteStop();
|
|
1068
|
-
|
|
1069
|
-
|
|
1032
|
+
ctx.audioProducer.track.remoteStop();
|
|
1033
|
+
expect(audioProducerTrackendedEventCalled).toBe(true);
|
|
1034
|
+
// Let's close the video producer.
|
|
1035
|
+
ctx.videoProducer.close();
|
|
1070
1036
|
// @ts-ignore
|
|
1071
|
-
videoProducer.track.remoteStop();
|
|
1072
|
-
expect(videoProducerTrackendedEventCalled).toBe(
|
|
1037
|
+
ctx.videoProducer.track.remoteStop();
|
|
1038
|
+
expect(videoProducerTrackendedEventCalled).toBe(false);
|
|
1073
1039
|
// @ts-ignore
|
|
1074
|
-
audioConsumer.track.remoteStop();
|
|
1075
|
-
|
|
1076
|
-
expect(audiosConsumerTrackendedEventCalled).toBe(false);
|
|
1040
|
+
ctx.audioConsumer.track.remoteStop();
|
|
1041
|
+
expect(audiosConsumerTrackendedEventCalled).toBe(true);
|
|
1077
1042
|
// @ts-ignore
|
|
1078
|
-
videoConsumer.track.remoteStop();
|
|
1043
|
+
ctx.videoConsumer.track.remoteStop();
|
|
1079
1044
|
expect(videoConsumerTrackendedEventCalled).toBe(true);
|
|
1080
|
-
audioProducer.removeAllListeners();
|
|
1081
|
-
videoProducer.removeAllListeners();
|
|
1082
|
-
audioConsumer.removeAllListeners();
|
|
1083
|
-
videoConsumer.removeAllListeners();
|
|
1084
1045
|
});
|
|
1085
1046
|
test('transport.close() fires "transportclose" in live Producers/Consumers', () => {
|
|
1086
1047
|
let audioProducerTransportcloseEventCalled = false;
|
|
1087
1048
|
let videoProducerTransportcloseEventCalled = false;
|
|
1088
1049
|
let audioConsumerTransportcloseEventCalled = false;
|
|
1089
1050
|
let videoConsumerTransportcloseEventCalled = false;
|
|
1090
|
-
audioProducer.on('transportclose', () => {
|
|
1051
|
+
ctx.audioProducer.on('transportclose', () => {
|
|
1091
1052
|
audioProducerTransportcloseEventCalled = true;
|
|
1092
1053
|
});
|
|
1093
|
-
videoProducer.on('transportclose', () => {
|
|
1054
|
+
ctx.videoProducer.on('transportclose', () => {
|
|
1094
1055
|
videoProducerTransportcloseEventCalled = true;
|
|
1095
1056
|
});
|
|
1096
|
-
audioConsumer.on('transportclose', () => {
|
|
1057
|
+
ctx.audioConsumer.on('transportclose', () => {
|
|
1097
1058
|
audioConsumerTransportcloseEventCalled = true;
|
|
1098
1059
|
});
|
|
1099
|
-
videoConsumer.on('transportclose', () => {
|
|
1060
|
+
ctx.videoConsumer.on('transportclose', () => {
|
|
1100
1061
|
videoConsumerTransportcloseEventCalled = true;
|
|
1101
1062
|
});
|
|
1102
|
-
|
|
1103
|
-
expect(
|
|
1104
|
-
expect(videoProducer.closed).toBe(
|
|
1105
|
-
|
|
1106
|
-
expect(sendTransport.closed).toBe(true);
|
|
1107
|
-
expect(videoProducer.closed).toBe(true);
|
|
1108
|
-
// Audio Producer was already closed.
|
|
1109
|
-
expect(audioProducerTransportcloseEventCalled).toBe(false);
|
|
1063
|
+
ctx.connectedSendTransport.close();
|
|
1064
|
+
expect(ctx.connectedSendTransport.closed).toBe(true);
|
|
1065
|
+
expect(ctx.videoProducer.closed).toBe(true);
|
|
1066
|
+
expect(audioProducerTransportcloseEventCalled).toBe(true);
|
|
1110
1067
|
expect(videoProducerTransportcloseEventCalled).toBe(true);
|
|
1111
|
-
//
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
expect(
|
|
1116
|
-
expect(
|
|
1117
|
-
|
|
1118
|
-
expect(audioConsumerTransportcloseEventCalled).toBe(false);
|
|
1119
|
-
expect(videoConsumerTransportcloseEventCalled).toBe(true);
|
|
1120
|
-
audioProducer.removeAllListeners();
|
|
1121
|
-
videoProducer.removeAllListeners();
|
|
1122
|
-
audioConsumer.removeAllListeners();
|
|
1123
|
-
videoConsumer.removeAllListeners();
|
|
1068
|
+
// Let's close the video consumer.
|
|
1069
|
+
ctx.videoConsumer.close();
|
|
1070
|
+
ctx.connectedRecvTransport.close();
|
|
1071
|
+
expect(ctx.connectedRecvTransport.closed).toBe(true);
|
|
1072
|
+
expect(ctx.videoConsumer.closed).toBe(true);
|
|
1073
|
+
expect(audioConsumerTransportcloseEventCalled).toBe(true);
|
|
1074
|
+
expect(videoConsumerTransportcloseEventCalled).toBe(false);
|
|
1124
1075
|
});
|
|
1125
1076
|
test('transport.produce() rejects with InvalidStateError if closed', async () => {
|
|
1126
1077
|
const track = new fake_mediastreamtrack_1.FakeMediaStreamTrack({ kind: 'audio' });
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
await expect(sendTransport.produce({ track, stopTracks: false }))
|
|
1130
|
-
.rejects
|
|
1131
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1078
|
+
ctx.connectedSendTransport.close();
|
|
1079
|
+
await expect(ctx.connectedSendTransport.produce({ track, stopTracks: false })).rejects.toThrow(errors_1.InvalidStateError);
|
|
1132
1080
|
// The track must be 'live' due to stopTracks: false.
|
|
1133
1081
|
expect(track.readyState).toBe('live');
|
|
1134
|
-
sendTransport.removeAllListeners('produce');
|
|
1135
1082
|
}, 500);
|
|
1136
1083
|
test('transport.consume() rejects with InvalidStateError if closed', async () => {
|
|
1084
|
+
ctx.connectedRecvTransport.close();
|
|
1137
1085
|
// @ts-ignore
|
|
1138
|
-
await expect(
|
|
1139
|
-
.rejects
|
|
1140
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1141
|
-
recvTransport.removeAllListeners();
|
|
1086
|
+
await expect(ctx.connectedRecvTransport.consume({})).rejects.toThrow(errors_1.InvalidStateError);
|
|
1142
1087
|
}, 500);
|
|
1143
1088
|
test('transport.produceData() rejects with InvalidStateError if closed', async () => {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
await expect(sendTransport.produceData({}))
|
|
1147
|
-
.rejects
|
|
1148
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1149
|
-
sendTransport.removeAllListeners('producedata');
|
|
1089
|
+
ctx.connectedSendTransport.close();
|
|
1090
|
+
await expect(ctx.connectedSendTransport.produceData({})).rejects.toThrow(errors_1.InvalidStateError);
|
|
1150
1091
|
}, 500);
|
|
1151
1092
|
test('transport.consumeData() rejects with InvalidStateError if closed', async () => {
|
|
1093
|
+
ctx.connectedRecvTransport.close();
|
|
1152
1094
|
// @ts-ignore
|
|
1153
|
-
await expect(
|
|
1154
|
-
.rejects
|
|
1155
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1095
|
+
await expect(ctx.connectedRecvTransport.consumeData({})).rejects.toThrow(errors_1.InvalidStateError);
|
|
1156
1096
|
}, 500);
|
|
1157
1097
|
test('transport.getStats() rejects with InvalidStateError if closed', async () => {
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1098
|
+
ctx.connectedSendTransport.close();
|
|
1099
|
+
await expect(ctx.connectedSendTransport.getStats()).rejects.toThrow(errors_1.InvalidStateError);
|
|
1161
1100
|
}, 500);
|
|
1162
1101
|
test('transport.restartIce() rejects with InvalidStateError if closed', async () => {
|
|
1102
|
+
ctx.connectedSendTransport.close();
|
|
1103
|
+
await expect(
|
|
1163
1104
|
// @ts-ignore
|
|
1164
|
-
|
|
1165
|
-
.rejects
|
|
1166
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1105
|
+
ctx.connectedSendTransport.restartIce({ ieParameters: {} })).rejects.toThrow(errors_1.InvalidStateError);
|
|
1167
1106
|
}, 500);
|
|
1168
1107
|
test('transport.updateIceServers() rejects with InvalidStateError if closed', async () => {
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
.toThrow(errors_1.InvalidStateError);
|
|
1108
|
+
ctx.connectedSendTransport.close();
|
|
1109
|
+
await expect(ctx.connectedSendTransport.updateIceServers({ iceServers: [] })).rejects.toThrow(errors_1.InvalidStateError);
|
|
1172
1110
|
}, 500);
|
|
1173
1111
|
test('connection state change does not fire "connectionstatechange" in closed Transport', () => {
|
|
1174
1112
|
let connectionStateChangeEventNumTimesCalled = 0;
|
|
1175
|
-
|
|
1176
|
-
sendTransport.on('connectionstatechange', ( /* connectionState */) => {
|
|
1113
|
+
ctx.connectedSendTransport.on('connectionstatechange', ( /* connectionState */) => {
|
|
1177
1114
|
connectionStateChangeEventNumTimesCalled++;
|
|
1178
1115
|
});
|
|
1116
|
+
ctx.connectedSendTransport.close();
|
|
1179
1117
|
// @ts-ignore
|
|
1180
|
-
|
|
1118
|
+
ctx.connectedSendTransport.handler.setConnectionState('disconnected');
|
|
1181
1119
|
expect(connectionStateChangeEventNumTimesCalled).toBe(0);
|
|
1182
|
-
expect(
|
|
1183
|
-
sendTransport.removeAllListeners('connectionstatechange');
|
|
1120
|
+
expect(ctx.connectedSendTransport.connectionState).toBe('disconnected');
|
|
1184
1121
|
});
|
|
1185
1122
|
test('RemoteSdp properly handles multiple streams of the same type in planB', async () => {
|
|
1186
1123
|
let sdp = undefined;
|
|
@@ -1189,9 +1126,11 @@ test('RemoteSdp properly handles multiple streams of the same type in planB', as
|
|
|
1189
1126
|
await remoteSdp.receive({
|
|
1190
1127
|
mid: 'video',
|
|
1191
1128
|
kind: 'video',
|
|
1192
|
-
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1129
|
+
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1130
|
+
codecMimeType: 'video/VP8',
|
|
1131
|
+
}).rtpParameters,
|
|
1193
1132
|
streamId: 'streamId-1',
|
|
1194
|
-
trackId: 'trackId-1'
|
|
1133
|
+
trackId: 'trackId-1',
|
|
1195
1134
|
});
|
|
1196
1135
|
sdp = remoteSdp.getSdp();
|
|
1197
1136
|
sdpObject = sdpTransform.parse(sdp);
|
|
@@ -1206,9 +1145,11 @@ test('RemoteSdp properly handles multiple streams of the same type in planB', as
|
|
|
1206
1145
|
await remoteSdp.receive({
|
|
1207
1146
|
mid: 'video',
|
|
1208
1147
|
kind: 'video',
|
|
1209
|
-
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1148
|
+
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1149
|
+
codecMimeType: 'video/H264',
|
|
1150
|
+
}).rtpParameters,
|
|
1210
1151
|
streamId: 'streamId-2',
|
|
1211
|
-
trackId: 'trackId-2'
|
|
1152
|
+
trackId: 'trackId-2',
|
|
1212
1153
|
});
|
|
1213
1154
|
sdp = remoteSdp.getSdp();
|
|
1214
1155
|
sdpObject = sdpTransform.parse(sdp);
|
|
@@ -1226,7 +1167,9 @@ test('RemoteSdp properly handles multiple streams of the same type in planB', as
|
|
|
1226
1167
|
expect(sdpObject.media[0].ssrcs?.length).toBe(8);
|
|
1227
1168
|
await remoteSdp.planBStopReceiving({
|
|
1228
1169
|
mid: 'video',
|
|
1229
|
-
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1170
|
+
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1171
|
+
codecMimeType: 'video/H264',
|
|
1172
|
+
}).rtpParameters,
|
|
1230
1173
|
});
|
|
1231
1174
|
sdp = remoteSdp.getSdp();
|
|
1232
1175
|
sdpObject = sdpTransform.parse(sdp);
|
|
@@ -1250,9 +1193,11 @@ test('RemoteSdp does not duplicate codec descriptions', async () => {
|
|
|
1250
1193
|
await remoteSdp.receive({
|
|
1251
1194
|
mid: 'video',
|
|
1252
1195
|
kind: 'video',
|
|
1253
|
-
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1196
|
+
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1197
|
+
codecMimeType: 'video/VP8',
|
|
1198
|
+
}).rtpParameters,
|
|
1254
1199
|
streamId: 'streamId-1',
|
|
1255
|
-
trackId: 'trackId-1'
|
|
1200
|
+
trackId: 'trackId-1',
|
|
1256
1201
|
});
|
|
1257
1202
|
sdp = remoteSdp.getSdp();
|
|
1258
1203
|
sdpObject = sdpTransform.parse(sdp);
|
|
@@ -1267,9 +1212,11 @@ test('RemoteSdp does not duplicate codec descriptions', async () => {
|
|
|
1267
1212
|
await remoteSdp.receive({
|
|
1268
1213
|
mid: 'video',
|
|
1269
1214
|
kind: 'video',
|
|
1270
|
-
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1215
|
+
offerRtpParameters: fakeParameters.generateConsumerRemoteParameters({
|
|
1216
|
+
codecMimeType: 'video/VP8',
|
|
1217
|
+
}).rtpParameters,
|
|
1271
1218
|
streamId: 'streamId-1',
|
|
1272
|
-
trackId: 'trackId-1'
|
|
1219
|
+
trackId: 'trackId-1',
|
|
1273
1220
|
});
|
|
1274
1221
|
sdp = remoteSdp.getSdp();
|
|
1275
1222
|
sdpObject = sdpTransform.parse(sdp);
|
|
@@ -1283,25 +1230,51 @@ test('RemoteSdp does not duplicate codec descriptions', async () => {
|
|
|
1283
1230
|
expect(sdpObject.media[0].ssrcs?.length).toBe(8);
|
|
1284
1231
|
}, 500);
|
|
1285
1232
|
test('parseScalabilityMode() works', () => {
|
|
1286
|
-
expect(parseScalabilityMode('L1T3')).toEqual({
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
expect(parseScalabilityMode()).toEqual({
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
expect(parseScalabilityMode('
|
|
1233
|
+
expect(parseScalabilityMode('L1T3')).toEqual({
|
|
1234
|
+
spatialLayers: 1,
|
|
1235
|
+
temporalLayers: 3,
|
|
1236
|
+
});
|
|
1237
|
+
expect(parseScalabilityMode('L3T2_KEY')).toEqual({
|
|
1238
|
+
spatialLayers: 3,
|
|
1239
|
+
temporalLayers: 2,
|
|
1240
|
+
});
|
|
1241
|
+
expect(parseScalabilityMode('S2T3')).toEqual({
|
|
1242
|
+
spatialLayers: 2,
|
|
1243
|
+
temporalLayers: 3,
|
|
1244
|
+
});
|
|
1245
|
+
expect(parseScalabilityMode('foo')).toEqual({
|
|
1246
|
+
spatialLayers: 1,
|
|
1247
|
+
temporalLayers: 1,
|
|
1248
|
+
});
|
|
1249
|
+
expect(parseScalabilityMode()).toEqual({
|
|
1250
|
+
spatialLayers: 1,
|
|
1251
|
+
temporalLayers: 1,
|
|
1252
|
+
});
|
|
1253
|
+
expect(parseScalabilityMode('S0T3')).toEqual({
|
|
1254
|
+
spatialLayers: 1,
|
|
1255
|
+
temporalLayers: 1,
|
|
1256
|
+
});
|
|
1257
|
+
expect(parseScalabilityMode('S1T0')).toEqual({
|
|
1258
|
+
spatialLayers: 1,
|
|
1259
|
+
temporalLayers: 1,
|
|
1260
|
+
});
|
|
1261
|
+
expect(parseScalabilityMode('L20T3')).toEqual({
|
|
1262
|
+
spatialLayers: 20,
|
|
1263
|
+
temporalLayers: 3,
|
|
1264
|
+
});
|
|
1265
|
+
expect(parseScalabilityMode('S200T3')).toEqual({
|
|
1266
|
+
spatialLayers: 1,
|
|
1267
|
+
temporalLayers: 1,
|
|
1268
|
+
});
|
|
1295
1269
|
});
|
|
1296
1270
|
describe('detectDevice() assigns proper handler based on UserAgent', () => {
|
|
1297
1271
|
const originalNavigator = global.navigator;
|
|
1298
1272
|
for (const uaTestCase of uaTestCases_1.uaTestCases) {
|
|
1299
1273
|
test(uaTestCase.desc, () => {
|
|
1300
1274
|
// @ts-ignore
|
|
1301
|
-
global.navigator =
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
};
|
|
1275
|
+
global.navigator = {
|
|
1276
|
+
userAgent: uaTestCase.ua,
|
|
1277
|
+
};
|
|
1305
1278
|
const originalRTCRtpTransceiver = global.RTCRtpTransceiver;
|
|
1306
1279
|
if (uaTestCase.expect === 'Safari12') {
|
|
1307
1280
|
global.RTCRtpTransceiver = class Dummy {
|