blob: 58712770be03e169f71a3f649ce1142555b36cfe [file] [log] [blame]
Soares Chen172fe9d2017-07-18 09:30:181<!doctype html>
2<meta charset=utf-8>
3<title>RTCRtpParameters encodings</title>
4<script src="/resources/testharness.js"></script>
5<script src="/resources/testharnessreport.js"></script>
6<script src="dictionary-helper.js"></script>
7<script src="RTCRtpParameters-helper.js"></script>
8<script>
9 'use strict';
10
11 // Test is based on the following editor draft:
12 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
13
14 // The following helper functions are called from RTCRtpParameters-helper.js:
15 // validateSenderRtpParameters
16
17 /*
18 5.1. RTCPeerConnection Interface Extensions
19 partial interface RTCPeerConnection {
20 RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
21 optional RTCRtpTransceiverInit init);
22 ...
23 };
24
25 dictionary RTCRtpTransceiverInit {
26 RTCRtpTransceiverDirection direction = "sendrecv";
27 sequence<MediaStream> streams;
28 sequence<RTCRtpEncodingParameters> sendEncodings;
29 };
30
31 5.2. RTCRtpSender Interface
32 interface RTCRtpSender {
33 Promise<void> setParameters(optional RTCRtpParameters parameters);
34 RTCRtpParameters getParameters();
35 };
36
37 dictionary RTCRtpParameters {
38 DOMString transactionId;
39 sequence<RTCRtpEncodingParameters> encodings;
40 sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
41 RTCRtcpParameters rtcp;
42 sequence<RTCRtpCodecParameters> codecs;
43 RTCDegradationPreference degradationPreference;
44 };
45
46 dictionary RTCRtpEncodingParameters {
47 [readonly]
48 unsigned long ssrc;
49
50 [readonly]
51 RTCRtpRtxParameters rtx;
52
53 [readonly]
54 RTCRtpFecParameters fec;
55
56 RTCDtxStatus dtx;
57 boolean active;
58 RTCPriorityType priority;
59 unsigned long ptime;
60 unsigned long maxBitrate;
61 double maxFramerate;
62
63 [readonly]
64 DOMString rid;
65
66 double scaleResolutionDownBy;
67 };
68
69 dictionary RTCRtpRtxParameters {
70 [readonly]
71 unsigned long ssrc;
72 };
73
74 dictionary RTCRtpFecParameters {
75 [readonly]
76 unsigned long ssrc;
77 };
78
79 enum RTCDtxStatus {
80 "disabled",
81 "enabled"
82 };
83
84 enum RTCPriorityType {
85 "very-low",
86 "low",
87 "medium",
88 "high"
89 };
90
91 getParameters
92 - encodings is set to the value of the [[send encodings]] internal slot.
93 */
94
95 // Get the first encoding in param.encodings.
96 // Asserts that param.encodings has at least one element.
97 function getFirstEncoding(param) {
98 const { encodings } = param;
99 assert_equals(encodings.length, 1);
100 return encodings[0];
101 }
102
103 /*
104 5.1. addTransceiver
105 7. Create an RTCRtpSender with track, streams and sendEncodings and let sender
106 be the result.
107
108 5.2. create an RTCRtpSender
109 5. Let sender have a [[send encodings]] internal slot, representing a list
110 of RTCRtpEncodingParameters dictionaries.
111 6. If sendEncodings is given as input to this algorithm, and is non-empty,
112 set the [[send encodings]] slot to sendEncodings.
113
114 Otherwise, set it to a list containing a single RTCRtpEncodingParameters
115 with active set to true.
116 */
117 test(() => {
118 const pc = new RTCPeerConnection();
119 const transceiver = pc.addTransceiver('audio');
120 const param = transceiver.sender.getParameters();
121 validateSenderRtpParameters(param);
122 const { encodings } = param;
123 const encoding = getFirstEncoding(param);
124
125 assert_equals(encoding.active, true);
126 }, 'addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true');
127
128 test(() => {
129 const pc = new RTCPeerConnection();
130 const transceiver = pc.addTransceiver('audio', { sendEncodings: [] });
131
132 const param = transceiver.sender.getParameters();
133 validateSenderRtpParameters(param);
134 const { encodings } = param;
135 const encoding = getFirstEncoding(param);
136
137 assert_equals(encoding.active, true);
138 }, 'addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true');
139
140 /*
141 5.2. create an RTCRtpSender
142 To create an RTCRtpSender with a MediaStreamTrack , track, a list of MediaStream
143 objects, streams, and optionally a list of RTCRtpEncodingParameters objects,
144 sendEncodings, run the following steps:
145 5. Let sender have a [[send encodings]] internal slot, representing a list
146 of RTCRtpEncodingParameters dictionaries.
147
148 6. If sendEncodings is given as input to this algorithm, and is non-empty,
149 set the [[send encodings]] slot to sendEncodings.
150
151 5.2. getParameters
152 - encodings is set to the value of the [[send encodings]] internal slot.
153 */
154 test(() => {
155 const pc = new RTCPeerConnection();
156 const { sender } = pc.addTransceiver('audio', {
157 sendEncodings: [{
158 dtx: 'enabled',
159 active: false,
160 priority: 'low',
161 ptime: 5,
162 maxBitrate: 8,
163 maxFramerate: 25,
164 rid: 'foo'
165 }]
166 });
167
168 const param = sender.getParameters();
169 validateSenderRtpParameters(param);
170 const encoding = getFirstEncoding(param);
171
172 assert_equals(encoding.dtx, 'enabled');
173 assert_equals(encoding.active, false);
174 assert_equals(encoding.priority, 'low');
175 assert_equals(encoding.ptime, 5);
176 assert_equals(encoding.maxBitrate, 8);
177 assert_equals(encoding.maxFramerate, 25);
178 assert_equals(encoding.rid, 'foo');
179
180 }, `sender.getParameters() should return sendEncodings set by addTransceiver()`);
181
182 /*
183 5.2. setParameters
184 3. Let N be the number of RTCRtpEncodingParameters stored in sender's internal
185 [[send encodings]] slot.
186 7. If parameters.encodings.length is different from N, or if any parameter
187 in the parameters argument, marked as a Read-only parameter, has a value
188 that is different from the corresponding parameter value returned from
189 sender.getParameters(), abort these steps and return a promise rejected
190 with a newly created InvalidModificationError. Note that this also applies
191 to transactionId.
192 */
193 promise_test(t => {
194 const pc = new RTCPeerConnection();
195 const { sender } = pc.addTransceiver('audio');
196 const param = sender.getParameters();
197 validateSenderRtpParameters(param);
198
199 const { encodings } = param;
200 assert_equals(encodings.length, 1);
201
202 // {} is valid RTCRtpEncodingParameters because all fields are optional
203 encodings.push({});
204 assert_equals(param.encodings.length, 2);
205
206 return promise_rejects(t, 'InvalidModificationError',
207 sender.setParameters(param));
208
209 }, `sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError`);
210
211 promise_test(t => {
212 const pc = new RTCPeerConnection();
213 const { sender } = pc.addTransceiver('audio');
214 const param = sender.getParameters();
215 validateSenderRtpParameters(param);
216
217 param.encodings = undefined;
218
219 return promise_rejects(t, 'InvalidModificationError',
220 sender.setParameters(param));
221
222 }, `sender.setParameters() with encodings unset should reject with InvalidModificationError`);
223
224 promise_test(t => {
225 const pc = new RTCPeerConnection();
226 const { sender } = pc.addTransceiver('audio');
227
228 const param = sender.getParameters();
229 validateSenderRtpParameters(param);
230 const encoding = getFirstEncoding(param);
231 const { ssrc } = encoding;
232
233 // ssrc may not be set since it is optional
234 if(ssrc === undefined) {
235 encoding.ssrc = 2;
236 } else {
237 // If it is set, increase the number by 1 to make it different from original
238 encoding.ssrc = ssrc + 1;
239 }
240
241 return promise_rejects(t, 'InvalidModificationError',
242 sender.setParameters(param));
243
244 }, `setParameters() with modified encoding.ssrc field should reject with InvalidModificationError`);
245
246 promise_test(t => {
247 const pc = new RTCPeerConnection();
248 const { sender } = pc.addTransceiver('audio');
249
250 const param = sender.getParameters();
251 validateSenderRtpParameters(param);
252 const encoding = getFirstEncoding(param);
253 const { rtx } = encoding;
254
255 if(rtx === undefined) {
256 encoding.rtx = { ssrc: 2 };
257 } else if(rtx.ssrc === undefined) {
258 rtx.ssrc = 2;
259 } else {
260 rtx.ssrc += 1;
261 }
262
263 return promise_rejects(t, 'InvalidModificationError',
264 sender.setParameters(param));
265
266 }, `setParameters() with modified encoding.rtx field should reject with InvalidModificationError`);
267
268 promise_test(t => {
269 const pc = new RTCPeerConnection();
270 const { sender } = pc.addTransceiver('audio');
271
272 const param = sender.getParameters();
273 validateSenderRtpParameters(param);
274 const encoding = getFirstEncoding(param);
275 const { fec } = encoding;
276
277 if(fec === undefined) {
278 encoding.fec = { ssrc: 2 };
279 } else if(fec.ssrc === undefined) {
280 fec.ssrc = 2;
281 } else {
282 fec.ssrc += 1;
283 }
284
285 return promise_rejects(t, 'InvalidModificationError',
286 sender.setParameters(param));
287
288 }, `setParameters() with modified encoding.rtx field should reject with InvalidModificationError`);
289
290 promise_test(t => {
291 const pc = new RTCPeerConnection();
292 const { sender } = pc.addTransceiver('audio', {
293 sendEncodings: [{ rid: 'foo' }],
294 });
295
296 const param = sender.getParameters();
297 validateSenderRtpParameters(param);
298 const encoding = getFirstEncoding(param);
299
300 assert_equals(encoding.rid, 'foo');
301
302 encoding.rid = 'bar';
303 return promise_rejects(t, 'InvalidModificationError',
304 sender.setParameters(param));
305
306 }, `setParameters() with modified encoding.rid field should reject with InvalidModificationError`);
307
308 /*
309 5.2. setParameters
310 8. If the scaleResolutionDownBy parameter in the parameters argument has a
311 value less than 1.0, abort these steps and return a promise rejected with
312 a newly created RangeError.
313 */
314 promise_test(t => {
315 const pc = new RTCPeerConnection();
316 const { sender } = pc.addTransceiver('audio');
317
318 const param = sender.getParameters();
319 validateSenderRtpParameters(param);
320 const encoding = getFirstEncoding(param);
321
322 encoding.scaleResolutionDownBy = 0.5;
323 return promise_rejects(t, 'RangeError',
324 sender.setParameters(param));
325
326 }, `setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError`);
327
328 promise_test(t => {
329 const pc = new RTCPeerConnection();
330 const { sender } = pc.addTransceiver('audio');
331
332 const param = sender.getParameters();
333 validateSenderRtpParameters(param);
334 const encoding = getFirstEncoding(param);
335
336 encoding.scaleResolutionDownBy = 1.5;
337 return sender.setParameters(param)
338 .then(() => {
339 const param = sender.getParameters();
340 validateSenderRtpParameters(param);
341 const encoding = getFirstEncoding(param);
342
343 assert_approx_equals(encoding.scaleResolutionDownBy, 1.5, 0.01);
344 });
345
346 }, `setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed`);
347
348 // Helper function to test that modifying an encoding field should succeed
349 function test_modified_encoding(field, value1, value2, desc) {
350 promise_test(t => {
351 const pc = new RTCPeerConnection();
352 const { sender } = pc.addTransceiver('audio', {
353 sendEncodings: [{
354 [field]: value1
355 }]
356 });
357
358 const param = sender.getParameters();
359 validateSenderRtpParameters(param);
360 const encoding = getFirstEncoding(param);
361
362 assert_equals(encoding[field], value1);
363 encoding[field] = value2;
364
365 return sender.setParameters(param)
366 .then(() => {
367 const param = sender.getParameters();
368 validateSenderRtpParameters(param);
369 const encoding = getFirstEncoding(param);
370 assert_equals(encoding[field], value2);
371 });
372 }, desc);
373 }
374
375 test_modified_encoding('dtx', 'enabled', 'disabled',
376 'setParameters() with modified encoding.dtx should succeed');
377
378 test_modified_encoding('dtx', 'enabled', undefined,
379 'setParameters() with unset encoding.dtx should succeed');
380
381 test_modified_encoding('active', true, false,
382 'setParameters() with modified encoding.active should succeed');
383
384 test_modified_encoding('priority', 'very-low', 'high',
385 'setParameters() with modified encoding.priority should succeed');
386
387 test_modified_encoding('ptime', 2, 4,
388 'setParameters() with modified encoding.ptime should succeed');
389
390 test_modified_encoding('maxBitrate', 2, 4,
391 'setParameters() with modified encoding.maxBitrate should succeed');
392
393 test_modified_encoding('maxBitrate', 24, 16,
394 'setParameters() with modified encoding.maxFramerate should succeed');
395
396</script>