blob: a5df6a9d2b21714c1fd8fcad1293b495e95fcb6e [file] [log] [blame]
Soares Chend8b19bc2017-07-19 07:44:511<!doctype html>
2<meta charset=utf-8>
3<title>RTCRtpTransceiver.prototype.setCodecPreferences</title>
4<script src="/resources/testharness.js"></script>
5<script src="/resources/testharnessreport.js"></script>
Philipp Hanckeef0384e2020-09-07 09:12:426<script src="./third_party/sdp/sdp.js"></script>
Soares Chend8b19bc2017-07-19 07:44:517<script>
8 'use strict';
9
10 // Test is based on the following editor draft:
11 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
12
13 /*
14 5.4. RTCRtpTransceiver Interface
15 interface RTCRtpTransceiver {
16 ...
17 void setCodecPreferences(sequence<RTCRtpCodecCapability> codecs);
18 };
19
20 setCodecPreferences
21 - Setting codecs to an empty sequence resets codec preferences to any
22 default value.
23
24 - The codecs sequence passed into setCodecPreferences can only contain
25 codecs that are returned by RTCRtpSender.getCapabilities(kind) or
26 RTCRtpReceiver.getCapabilities(kind), where kind is the kind of the
27 RTCRtpTransceiver on which the method is called. Additionally, the
28 RTCRtpCodecParameters dictionary members cannot be modified. If
29 codecs does not fulfill these requirements, the user agent MUST throw
Florent Castellidd2829c2019-05-08 15:36:3630 an InvalidModificationError.
Soares Chend8b19bc2017-07-19 07:44:5131 */
Philipp Hancke57cb5de2020-09-17 11:56:3532 /*
33 * Chromium note: this requires build bots with H264 support. See
34 * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
35 * for details on how to enable support.
36 */
Soares Chend8b19bc2017-07-19 07:44:5137
Philipp Hanckeef0384e2020-09-07 09:12:4238 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:5139 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:4240 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:5141 const transceiver = pc.addTransceiver('audio');
42 const capabilities = RTCRtpSender.getCapabilities('audio');
43 transceiver.setCodecPreferences(capabilities.codecs);
Soares Chend8b19bc2017-07-19 07:44:5144 }, `setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed`);
45
Philipp Hanckeef0384e2020-09-07 09:12:4246 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:5147 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:4248 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:5149 const transceiver = pc.addTransceiver('video');
50 const capabilities = RTCRtpReceiver.getCapabilities('video');
51 transceiver.setCodecPreferences(capabilities.codecs);
Soares Chend8b19bc2017-07-19 07:44:5152 }, `setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed`);
53
Philipp Hanckeef0384e2020-09-07 09:12:4254 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:5155 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:4256 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:5157 const transceiver = pc.addTransceiver('audio');
58 const capabilities1 = RTCRtpSender.getCapabilities('audio');
59 const capabilities2 = RTCRtpReceiver.getCapabilities('audio');
60 transceiver.setCodecPreferences([...capabilities1.codecs, ... capabilities2.codecs]);
Soares Chend8b19bc2017-07-19 07:44:5161 }, `setCodecPreferences() with both sender receiver codecs combined should succeed`);
62
Philipp Hanckeef0384e2020-09-07 09:12:4263 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:5164 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:4265 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:5166 const transceiver = pc.addTransceiver('audio');
67 transceiver.setCodecPreferences([]);
Soares Chend8b19bc2017-07-19 07:44:5168 }, `setCodecPreferences([]) should succeed`);
69
Philipp Hanckeef0384e2020-09-07 09:12:4270 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:5171 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:4272 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:5173 const transceiver = pc.addTransceiver('audio');
74 const capabilities = RTCRtpSender.getCapabilities('audio');
75 const { codecs } = capabilities;
76
77 if(codecs.length >= 2) {
78 const tmp = codecs[0];
79 codecs[0] = codecs[1];
80 codecs[1] = tmp;
81 }
82
83 transceiver.setCodecPreferences(codecs);
Soares Chend8b19bc2017-07-19 07:44:5184 }, `setCodecPreferences() with reordered codecs should succeed`);
85
Philipp Hanckeef0384e2020-09-07 09:12:4286 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:5187 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:4288 t.add_cleanup(() => pc.close());
Harald Alvestrand3130f022020-02-06 10:50:2789 const transceiver = pc.addTransceiver('video');
90 const capabilities = RTCRtpSender.getCapabilities('video');
91 const { codecs } = capabilities;
92 // This test verifies that the mandatory VP8 codec is present
93 // and can be set.
94 let tried = false;
95 codecs.forEach(codec => {
96 if (codec.mimeType.toLowerCase() === 'video/vp8') {
97 transceiver.setCodecPreferences([codecs[0]]);
98 tried = true;
99 }
100 });
101 assert_true(tried, 'VP8 video codec was found and tried');
youennfb8ff0872020-09-03 08:35:01102 }, `setCodecPreferences() with only VP8 should succeed`);
103
104 test(() => {
105 const pc = new RTCPeerConnection();
106 const transceiver = pc.addTransceiver('video');
107 const capabilities = RTCRtpSender.getCapabilities('video');
108 const { codecs } = capabilities;
109 // This test verifies that the mandatory H264 codec is present
110 // and can be set.
111 let tried = false;
112 codecs.forEach(codec => {
113 if (codec.mimeType.toLowerCase() === 'video/h264') {
114 transceiver.setCodecPreferences([codecs[0]]);
115 tried = true;
116 }
117 });
Philipp Hancke85617862020-09-07 13:15:29118 assert_true(tried, 'H264 video codec was found and tried');
youennfb8ff0872020-09-03 08:35:01119 }, `setCodecPreferences() with only H264 should succeed`);
120
121 async function getRTPMapLinesWithCodecAsFirst(firstCodec)
122 {
123 const capabilities = RTCRtpSender.getCapabilities('video').codecs;
124 capabilities.forEach((codec, idx) => {
125 if (codec.mimeType === firstCodec) {
126 capabilities.splice(idx, 1);
127 capabilities.unshift(codec);
128 }
129 });
130
131 const pc = new RTCPeerConnection();
132 const transceiver = pc.addTransceiver('video');
133 transceiver.setCodecPreferences(capabilities);
134 const offer = await pc.createOffer();
135
136 return offer.sdp.split('\r\n').filter(line => line.indexOf("a=rtpmap") === 0);
137 }
138
139 promise_test(async () => {
140 const lines = await getRTPMapLinesWithCodecAsFirst('video/H264');
141
142 assert_greater_than(lines.length, 1);
143 assert_true(lines[0].indexOf("H264") !== -1, "H264 should be the first codec");
144 }, `setCodecPreferences() should allow setting H264 as first codec`);
145
146 promise_test(async () => {
147 const lines = await getRTPMapLinesWithCodecAsFirst('video/VP8');
148
149 assert_greater_than(lines.length, 1);
150 assert_true(lines[0].indexOf("VP8") !== -1, "VP8 should be the first codec");
151 }, `setCodecPreferences() should allow setting VP8 as first codec`);
Harald Alvestrand3130f022020-02-06 10:50:27152
Philipp Hanckeef0384e2020-09-07 09:12:42153 test((t) => {
Harald Alvestrand3130f022020-02-06 10:50:27154 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42155 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:51156 const transceiver = pc.addTransceiver('audio');
157 const capabilities = RTCRtpSender.getCapabilities('video');
Stephen McGruerd5103042020-01-23 21:45:45158 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(capabilities.codecs));
Florent Castellidd2829c2019-05-08 15:36:36159 }, `setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidModificationError`);
160
Philipp Hanckeef0384e2020-09-07 09:12:42161 test((t) => {
Florent Castellidd2829c2019-05-08 15:36:36162 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42163 t.add_cleanup(() => pc.close());
Florent Castellidd2829c2019-05-08 15:36:36164 const transceiver = pc.addTransceiver('audio');
165 const codecs = [{
166 mimeType: 'data',
167 clockRate: 2000,
168 channels: 2,
169 sdpFmtpLine: '0-15'
170 }];
171
Stephen McGruerd5103042020-01-23 21:45:45172 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36173 }, `setCodecPreferences() with user defined codec with invalid mimeType should throw InvalidModificationError`);
Soares Chend8b19bc2017-07-19 07:44:51174
Philipp Hanckeef0384e2020-09-07 09:12:42175 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:51176 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42177 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:51178 const transceiver = pc.addTransceiver('audio');
179 const codecs = [{
180 mimeType: 'audio/piepiper',
181 clockRate: 2000,
182 channels: 2,
Florent Castellidd2829c2019-05-08 15:36:36183 sdpFmtpLine: '0-15'
Soares Chend8b19bc2017-07-19 07:44:51184 }];
185
Stephen McGruerd5103042020-01-23 21:45:45186 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36187 }, `setCodecPreferences() with user defined codec should throw InvalidModificationError`);
Soares Chend8b19bc2017-07-19 07:44:51188
Philipp Hanckeef0384e2020-09-07 09:12:42189 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:51190 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42191 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:51192 const transceiver = pc.addTransceiver('audio');
193 const capabilities = RTCRtpSender.getCapabilities('audio');
194 const codecs = [
195 ...capabilities.codecs,
196 {
197 mimeType: 'audio/piepiper',
198 clockRate: 2000,
199 channels: 2,
Florent Castellidd2829c2019-05-08 15:36:36200 sdpFmtpLine: '0-15'
Soares Chend8b19bc2017-07-19 07:44:51201 }];
202
Stephen McGruerd5103042020-01-23 21:45:45203 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36204 }, `setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidModificationError`);
205
Philipp Hanckeef0384e2020-09-07 09:12:42206 test((t) => {
Florent Castellidd2829c2019-05-08 15:36:36207 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42208 t.add_cleanup(() => pc.close());
Florent Castellidd2829c2019-05-08 15:36:36209 const transceiver = pc.addTransceiver('audio');
210 const capabilities = RTCRtpSender.getCapabilities('audio');
211 const codecs = [capabilities.codecs[0]];
212 codecs[0].clockRate = codecs[0].clockRate / 2;
213
Stephen McGruerd5103042020-01-23 21:45:45214 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36215 }, `setCodecPreferences() with modified codec clock rate should throw InvalidModificationError`);
216
Philipp Hanckeef0384e2020-09-07 09:12:42217 test((t) => {
Florent Castellidd2829c2019-05-08 15:36:36218 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42219 t.add_cleanup(() => pc.close());
Florent Castellidd2829c2019-05-08 15:36:36220 const transceiver = pc.addTransceiver('audio');
221 const capabilities = RTCRtpSender.getCapabilities('audio');
222 const codecs = [capabilities.codecs[0]];
223 codecs[0].channels = codecs[0].channels + 11;
224
Stephen McGruerd5103042020-01-23 21:45:45225 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36226 }, `setCodecPreferences() with modified codec channel count should throw InvalidModificationError`);
227
Philipp Hanckeef0384e2020-09-07 09:12:42228 test((t) => {
Florent Castellidd2829c2019-05-08 15:36:36229 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42230 t.add_cleanup(() => pc.close());
Florent Castellidd2829c2019-05-08 15:36:36231 const transceiver = pc.addTransceiver('audio');
232 const capabilities = RTCRtpSender.getCapabilities('audio');
233 const codecs = [capabilities.codecs[0]];
234 codecs[0].sdpFmtpLine = "modifiedparameter=1";
235
Stephen McGruerd5103042020-01-23 21:45:45236 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36237 }, `setCodecPreferences() with modified codec parameters should throw InvalidModificationError`);
Soares Chend8b19bc2017-07-19 07:44:51238
Philipp Hanckeef0384e2020-09-07 09:12:42239 test((t) => {
Soares Chend8b19bc2017-07-19 07:44:51240 const pc = new RTCPeerConnection();
Philipp Hanckeef0384e2020-09-07 09:12:42241 t.add_cleanup(() => pc.close());
Soares Chend8b19bc2017-07-19 07:44:51242 const transceiver = pc.addTransceiver('audio');
243 const capabilities = RTCRtpSender.getCapabilities('audio');
244
245 const { codecs } = capabilities;
246 assert_greater_than(codecs.length, 0,
247 'Expect at least one codec available');
248
249 const [ codec ] = codecs;
250 const { channels=2 } = codec;
251 codec.channels = channels+1;
252
Stephen McGruerd5103042020-01-23 21:45:45253 assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
Florent Castellidd2829c2019-05-08 15:36:36254 }, `setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidModificationError`);
Soares Chend8b19bc2017-07-19 07:44:51255
Philipp Hanckeef0384e2020-09-07 09:12:42256 promise_test(async (t) => {
257 const pc = new RTCPeerConnection();
258 t.add_cleanup(() => pc.close());
259 const transceiver = pc.addTransceiver('audio');
260 const {codecs} = RTCRtpSender.getCapabilities('audio');
261 // Reorder codecs, put PCMU/PCMA first.
262 let firstCodec;
263 let i;
264 for (i = 0; i < codecs.length; i++) {
265 const codec = codecs[i];
266 if (codec.mimeType === 'audio/PCMU' || codec.mimeType === 'audio/PCMA') {
267 codecs.splice(i, 1);
268 codecs.unshift(codec);
269 firstCodec = codec.mimeType.substr(6);
270 break;
271 }
272 }
273 assert_not_equals(firstCodec, undefined, 'PCMU or PCMA codec not found');
274 transceiver.setCodecPreferences(codecs);
275
276 const offer = await pc.createOffer();
277 const mediaSection = SDPUtils.getMediaSections(offer.sdp)[0];
278 const rtpParameters = SDPUtils.parseRtpParameters(mediaSection);
279 assert_equals(rtpParameters.codecs[0].name, firstCodec);
280 }, `setCodecPreferences() modifies the order of audio codecs in createOffer`);
281
282 promise_test(async (t) => {
283 const pc = new RTCPeerConnection();
284 t.add_cleanup(() => pc.close());
285 const transceiver = pc.addTransceiver('video');
286 const {codecs} = RTCRtpSender.getCapabilities('video');
287 // Reorder codecs, swap H264 and VP8.
288 let vp8 = -1;
289 let h264 = -1;
290 let firstCodec;
291 let i;
292 for (i = 0; i < codecs.length; i++) {
293 const codec = codecs[i];
294 if (codec.mimeType === 'video/VP8') {
295 vp8 = i;
296 if (h264 !== -1) {
297 codecs[vp8] = codecs[h264];
298 codecs[h264] = codec;
299 firstCodec = 'VP8';
300 break;
301 }
302 }
303 if (codec.mimeType === 'video/H264') {
304 h264 = i;
305 if (vp8 !== -1) {
306 codecs[h264] = codecs[vp8];
307 codecs[vp8] = codec;
308 firstCodec = 'H264';
309 break;
310 }
311 }
312 }
313 assert_not_equals(firstCodec, undefined, 'VP8 and H264 codecs not found');
314 transceiver.setCodecPreferences(codecs);
315
316 const offer = await pc.createOffer();
317 const mediaSection = SDPUtils.getMediaSections(offer.sdp)[0];
318 const rtpParameters = SDPUtils.parseRtpParameters(mediaSection);
319 assert_equals(rtpParameters.codecs[0].name, firstCodec);
320 }, `setCodecPreferences() modifies the order of video codecs in createOffer`);
321
Soares Chend8b19bc2017-07-19 07:44:51322 </script>