| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 1 | <!DOCTYPE html> | 
|  | 2 | <meta charset="utf-8"> | 
|  | 3 | <title>RTCRtpEncodingParameters codec property</title> | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 4 | <meta name="timeout" content="long"> | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 5 | <script src="/resources/testharness.js"></script> | 
|  | 6 | <script src="/resources/testharnessreport.js"></script> | 
|  | 7 | <script src="../webrtc/RTCPeerConnection-helper.js"></script> | 
|  | 8 | <script src="../webrtc/third_party/sdp/sdp.js"></script> | 
|  | 9 | <script src="../webrtc/simulcast/simulcast.js"></script> | 
|  | 10 | <script> | 
|  | 11 | 'use strict'; | 
|  | 12 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 13 | function arrayEquals(a, b) { | 
|  | 14 | return Array.isArray(a) && Array.isArray(b) && | 
|  | 15 | a.length === b.length && | 
|  | 16 | a.every((val, i) => val === b[i]); | 
|  | 17 | } | 
|  | 18 |  | 
|  | 19 | async function sleep(timeout) { | 
|  | 20 | return new Promise(resolve => { | 
|  | 21 | step_timeout(() => { | 
|  | 22 | resolve(); | 
|  | 23 | }, timeout); | 
|  | 24 | }); | 
|  | 25 | } | 
|  | 26 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 27 | function findFirstCodec(name) { | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 28 | return RTCRtpReceiver.getCapabilities(name.split('/')[0]).codecs.filter(c => c.mimeType.localeCompare(name, undefined, { sensitivity: 'base' }) === 0)[0]; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 29 | } | 
|  | 30 |  | 
|  | 31 | function codecsNotMatching(mimeType) { | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 32 | return RTCRtpReceiver.getCapabilities(mimeType.split('/')[0]).codecs.filter(c => c.mimeType.localeCompare(mimeType, undefined, {sensitivity: 'base'}) !== 0); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 33 | } | 
|  | 34 |  | 
|  | 35 | function assertCodecEquals(a, b) { | 
|  | 36 | assert_equals(a.mimeType, b.mimeType); | 
|  | 37 | assert_equals(a.clockRate, b.clockRate); | 
|  | 38 | assert_equals(a.channels, b.channels); | 
|  | 39 | assert_equals(a.sdpFmtpLine, b.sdpFmtpLine); | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | async function codecsForSender(sender) { | 
|  | 43 | const rids = sender.getParameters().encodings.map(e => e.rid); | 
|  | 44 | const stats = await sender.getStats(); | 
|  | 45 | const codecs = [...stats] | 
|  | 46 | .filter(([k, v]) => v.type === 'outbound-rtp') | 
|  | 47 | .sort(([k, v], [k2, v2]) => rids.indexOf(v.rid) - rids.indexOf(v2.rid)) | 
|  | 48 | .map(([k, v]) => stats.get(v.codecId).mimeType); | 
|  | 49 | return codecs; | 
|  | 50 | } | 
|  | 51 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 52 | async function waitForAllLayers(t, sender) { | 
|  | 53 | const encodings_count = sender.getParameters().encodings.length; | 
|  | 54 | return step_wait_async(t, async () => { | 
|  | 55 | const stats = await sender.getStats(); | 
|  | 56 | return [...stats] | 
|  | 57 | .filter(([k, v]) => v.type === 'outbound-rtp').length == encodings_count; | 
|  | 58 | }, `Wait for ${encodings_count} layers to start`); | 
|  | 59 | } | 
|  | 60 |  | 
|  | 61 | function step_wait_async(t, cond, description, timeout=3000, interval=100) { | 
|  | 62 | return new Promise(resolve => { | 
|  | 63 | var timeout_full = timeout * t.timeout_multiplier; | 
|  | 64 | var remaining = Math.ceil(timeout_full / interval); | 
|  | 65 |  | 
|  | 66 | var wait_for_inner = t.step_func(async () => { | 
|  | 67 | if (await cond()) { | 
|  | 68 | resolve(); | 
|  | 69 | } else { | 
|  | 70 | if(remaining === 0) { | 
|  | 71 | assert(false, "step_wait_async", description, | 
|  | 72 | "Timed out waiting on condition"); | 
|  | 73 | } | 
|  | 74 | remaining--; | 
|  | 75 | await sleep(interval); | 
|  | 76 | wait_for_inner(); | 
|  | 77 | } | 
|  | 78 | }); | 
|  | 79 |  | 
|  | 80 | wait_for_inner(); | 
|  | 81 | }); | 
|  | 82 | } | 
|  | 83 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 84 | promise_test(async t => { | 
|  | 85 | const pc = new RTCPeerConnection(); | 
|  | 86 | t.add_cleanup(() => pc.close()); | 
|  | 87 |  | 
|  | 88 | const { sender } = pc.addTransceiver('audio'); | 
|  | 89 |  | 
|  | 90 | let param = sender.getParameters(); | 
|  | 91 | let encoding = param.encodings[0]; | 
|  | 92 |  | 
|  | 93 | assert_equals(encoding.codec, undefined); | 
|  | 94 | }, `Codec should be undefined by default on audio encodings`); | 
|  | 95 |  | 
|  | 96 | promise_test(async t => { | 
|  | 97 | const pc = new RTCPeerConnection(); | 
|  | 98 | t.add_cleanup(() => pc.close()); | 
|  | 99 |  | 
|  | 100 | const { sender } = pc.addTransceiver('video'); | 
|  | 101 |  | 
|  | 102 | let param = sender.getParameters(); | 
|  | 103 | let encoding = param.encodings[0]; | 
|  | 104 |  | 
|  | 105 | assert_equals(encoding.codec, undefined); | 
|  | 106 | }, `Codec should be undefined by default on video encodings`); | 
|  | 107 |  | 
|  | 108 | promise_test(async t => { | 
|  | 109 | const pc = new RTCPeerConnection(); | 
|  | 110 | t.add_cleanup(() => pc.close()); | 
|  | 111 |  | 
|  | 112 | const opus = findFirstCodec('audio/opus'); | 
|  | 113 |  | 
|  | 114 | const { sender } = pc.addTransceiver('audio', { | 
|  | 115 | sendEncodings: [{codec: opus}], | 
|  | 116 | }); | 
|  | 117 |  | 
|  | 118 | let param = sender.getParameters(); | 
|  | 119 | let encoding = param.encodings[0]; | 
|  | 120 |  | 
|  | 121 | assertCodecEquals(opus, encoding.codec); | 
|  | 122 | }, `Creating an audio sender with addTransceiver and codec should work`); | 
|  | 123 |  | 
|  | 124 | promise_test(async t => { | 
|  | 125 | const pc = new RTCPeerConnection(); | 
|  | 126 | t.add_cleanup(() => pc.close()); | 
|  | 127 |  | 
|  | 128 | const vp8 = findFirstCodec('video/VP8'); | 
|  | 129 |  | 
|  | 130 | const { sender } = pc.addTransceiver('video', { | 
|  | 131 | sendEncodings: [{codec: vp8}], | 
|  | 132 | }); | 
|  | 133 |  | 
|  | 134 | let param = sender.getParameters(); | 
|  | 135 | let encoding = param.encodings[0]; | 
|  | 136 |  | 
|  | 137 | assertCodecEquals(vp8, encoding.codec); | 
|  | 138 | }, `Creating a video sender with addTransceiver and codec should work`); | 
|  | 139 |  | 
|  | 140 | promise_test(async t => { | 
|  | 141 | const pc = new RTCPeerConnection(); | 
|  | 142 | t.add_cleanup(() => pc.close()); | 
|  | 143 |  | 
|  | 144 | const opus = findFirstCodec('audio/opus'); | 
|  | 145 |  | 
|  | 146 | const { sender } = pc.addTransceiver('audio'); | 
|  | 147 |  | 
|  | 148 | let param = sender.getParameters(); | 
|  | 149 | let encoding = param.encodings[0]; | 
|  | 150 |  | 
|  | 151 | encoding.codec = opus; | 
|  | 152 | await sender.setParameters(param); | 
|  | 153 | param = sender.getParameters(); | 
|  | 154 | encoding = param.encodings[0]; | 
|  | 155 |  | 
|  | 156 | assertCodecEquals(opus, encoding.codec); | 
|  | 157 |  | 
|  | 158 | delete encoding.codec; | 
|  | 159 | await sender.setParameters(param); | 
|  | 160 | param = sender.getParameters(); | 
|  | 161 | encoding = param.encodings[0]; | 
|  | 162 |  | 
|  | 163 | assert_equals(encoding.codec, undefined); | 
|  | 164 | }, `Setting codec on an audio sender with setParameters should work`); | 
|  | 165 |  | 
|  | 166 | promise_test(async t => { | 
|  | 167 | const pc = new RTCPeerConnection(); | 
|  | 168 | t.add_cleanup(() => pc.close()); | 
|  | 169 |  | 
|  | 170 | const vp8 = findFirstCodec('video/VP8'); | 
|  | 171 |  | 
|  | 172 | const { sender } = pc.addTransceiver('video'); | 
|  | 173 |  | 
|  | 174 | let param = sender.getParameters(); | 
|  | 175 | let encoding = param.encodings[0]; | 
|  | 176 |  | 
|  | 177 | encoding.codec = vp8; | 
|  | 178 | await sender.setParameters(param); | 
|  | 179 | param = sender.getParameters(); | 
|  | 180 | encoding = param.encodings[0]; | 
|  | 181 |  | 
|  | 182 | assertCodecEquals(vp8, encoding.codec); | 
|  | 183 |  | 
|  | 184 | delete encoding.codec; | 
|  | 185 | await sender.setParameters(param); | 
|  | 186 | param = sender.getParameters(); | 
|  | 187 | encoding = param.encodings[0]; | 
|  | 188 |  | 
|  | 189 | assert_equals(encoding.codec, undefined); | 
|  | 190 | }, `Setting codec on a video sender with setParameters should work`); | 
|  | 191 |  | 
|  | 192 | promise_test(async t => { | 
|  | 193 | const pc = new RTCPeerConnection(); | 
|  | 194 | t.add_cleanup(() => pc.close()); | 
|  | 195 |  | 
|  | 196 | const newCodec = { | 
|  | 197 | mimeType: "audio/newCodec", | 
|  | 198 | clockRate: 90000, | 
|  | 199 | channel: 2, | 
|  | 200 | }; | 
|  | 201 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 202 | assert_throws_dom('OperationError', () => pc.addTransceiver('audio', { | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 203 | sendEncodings: [{codec: newCodec}], | 
|  | 204 | })); | 
|  | 205 | }, `Creating an audio sender with addTransceiver and non-existing codec should throw OperationError`); | 
|  | 206 |  | 
|  | 207 | promise_test(async t => { | 
|  | 208 | const pc = new RTCPeerConnection(); | 
|  | 209 | t.add_cleanup(() => pc.close()); | 
|  | 210 |  | 
|  | 211 | const newCodec = { | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 212 | mimeType: "dummy/newCodec", | 
|  | 213 | clockRate: 90000, | 
|  | 214 | channel: 2, | 
|  | 215 | }; | 
|  | 216 |  | 
|  | 217 | assert_throws_dom('OperationError', () => pc.addTransceiver('audio', { | 
|  | 218 | sendEncodings: [{codec: newCodec}], | 
|  | 219 | })); | 
|  | 220 | }, `Creating an audio sender with addTransceiver and non-existing codec type should throw OperationError`); | 
|  | 221 |  | 
|  | 222 | promise_test(async t => { | 
|  | 223 | const pc = new RTCPeerConnection(); | 
|  | 224 | t.add_cleanup(() => pc.close()); | 
|  | 225 |  | 
|  | 226 | const newCodec = { | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 227 | mimeType: "video/newCodec", | 
|  | 228 | clockRate: 90000, | 
|  | 229 | }; | 
|  | 230 |  | 
|  | 231 | assert_throws_dom('OperationError', () => pc.addTransceiver('video', { | 
|  | 232 | sendEncodings: [{codec: newCodec}], | 
|  | 233 | })); | 
|  | 234 | }, `Creating a video sender with addTransceiver and non-existing codec should throw OperationError`); | 
|  | 235 |  | 
|  | 236 | promise_test(async t => { | 
|  | 237 | const pc = new RTCPeerConnection(); | 
|  | 238 | t.add_cleanup(() => pc.close()); | 
|  | 239 |  | 
|  | 240 | const newCodec = { | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 241 | mimeType: "dummy/newCodec", | 
|  | 242 | clockRate: 90000, | 
|  | 243 | }; | 
|  | 244 |  | 
|  | 245 | assert_throws_dom('OperationError', () => pc.addTransceiver('video', { | 
|  | 246 | sendEncodings: [{codec: newCodec}], | 
|  | 247 | })); | 
|  | 248 | }, `Creating a video sender with addTransceiver and non-existing codec type should throw OperationError`); | 
|  | 249 |  | 
|  | 250 | promise_test(async t => { | 
|  | 251 | const pc = new RTCPeerConnection(); | 
|  | 252 | t.add_cleanup(() => pc.close()); | 
|  | 253 |  | 
|  | 254 | const newCodec = { | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 255 | mimeType: "audio/newCodec", | 
|  | 256 | clockRate: 90000, | 
|  | 257 | channel: 2, | 
|  | 258 | }; | 
|  | 259 |  | 
|  | 260 | const { sender } = pc.addTransceiver('audio'); | 
|  | 261 |  | 
|  | 262 | let param = sender.getParameters(); | 
|  | 263 | let encoding = param.encodings[0]; | 
|  | 264 |  | 
|  | 265 | encoding.codec = newCodec; | 
|  | 266 | await promise_rejects_dom(t, "InvalidModificationError", sender.setParameters(param)); | 
|  | 267 | }, `Setting a non-existing codec on an audio sender with setParameters should throw InvalidModificationError`); | 
|  | 268 |  | 
|  | 269 | promise_test(async t => { | 
|  | 270 | const pc = new RTCPeerConnection(); | 
|  | 271 | t.add_cleanup(() => pc.close()); | 
|  | 272 |  | 
|  | 273 | const newCodec = { | 
|  | 274 | mimeType: "video/newCodec", | 
|  | 275 | clockRate: 90000, | 
|  | 276 | }; | 
|  | 277 |  | 
|  | 278 | const { sender } = pc.addTransceiver('video'); | 
|  | 279 |  | 
|  | 280 | let param = sender.getParameters(); | 
|  | 281 | let encoding = param.encodings[0]; | 
|  | 282 |  | 
|  | 283 | encoding.codec = newCodec; | 
|  | 284 | await promise_rejects_dom(t, "InvalidModificationError", sender.setParameters(param)); | 
|  | 285 | }, `Setting a non-existing codec on a video sender with setParameters should throw InvalidModificationError`); | 
|  | 286 |  | 
|  | 287 | promise_test(async t => { | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 288 | const pc1 = new RTCPeerConnection(); | 
|  | 289 | t.add_cleanup(() => pc1.close()); | 
|  | 290 | const pc2 = new RTCPeerConnection(); | 
|  | 291 | t.add_cleanup(() => pc2.close()); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 292 |  | 
|  | 293 | const opus = findFirstCodec('audio/opus'); | 
|  | 294 | const nonOpus = codecsNotMatching(opus.mimeType); | 
|  | 295 |  | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 296 | const transceiver = pc1.addTransceiver('audio'); | 
|  | 297 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 298 | const negotiated = exchangeOfferAnswer(pc1, pc2); | 
|  | 299 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 300 | trackEvent.transceiver.setCodecPreferences(nonOpus); | 
|  | 301 | await negotiated; | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 302 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 303 | const sender = transceiver.sender; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 304 | let param = sender.getParameters(); | 
|  | 305 | let encoding = param.encodings[0]; | 
|  | 306 |  | 
|  | 307 | encoding.codec = opus; | 
|  | 308 | await promise_rejects_dom(t, "InvalidModificationError", sender.setParameters(param)); | 
|  | 309 | }, `Setting a non-preferred codec on an audio sender with setParameters should throw InvalidModificationError`); | 
|  | 310 |  | 
|  | 311 | promise_test(async t => { | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 312 | const pc1 = new RTCPeerConnection(); | 
|  | 313 | t.add_cleanup(() => pc1.close()); | 
|  | 314 | const pc2 = new RTCPeerConnection(); | 
|  | 315 | t.add_cleanup(() => pc2.close()); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 316 |  | 
|  | 317 | const vp8 = findFirstCodec('video/VP8'); | 
|  | 318 | const nonVP8 = codecsNotMatching(vp8.mimeType); | 
|  | 319 |  | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 320 | const transceiver = pc1.addTransceiver('video'); | 
|  | 321 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 322 | const negotiated = exchangeOfferAnswer(pc1, pc2); | 
|  | 323 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 324 | trackEvent.transceiver.setCodecPreferences(nonVP8); | 
|  | 325 | await negotiated; | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 326 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 327 | const sender = transceiver.sender; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 328 | let param = sender.getParameters(); | 
|  | 329 | let encoding = param.encodings[0]; | 
|  | 330 |  | 
|  | 331 | encoding.codec = vp8; | 
|  | 332 | await promise_rejects_dom(t, "InvalidModificationError", sender.setParameters(param)); | 
|  | 333 | }, `Setting a non-preferred codec on a video sender with setParameters should throw InvalidModificationError`); | 
|  | 334 |  | 
|  | 335 | promise_test(async (t) => { | 
|  | 336 | const pc1 = new RTCPeerConnection(); | 
|  | 337 | const pc2 = new RTCPeerConnection(); | 
|  | 338 | t.add_cleanup(() => pc1.close()); | 
|  | 339 | t.add_cleanup(() => pc2.close()); | 
|  | 340 |  | 
|  | 341 | const opus = findFirstCodec('audio/opus'); | 
|  | 342 | const nonOpus = codecsNotMatching(opus.mimeType); | 
|  | 343 |  | 
|  | 344 | const transceiver = pc1.addTransceiver('audio'); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 345 |  | 
|  | 346 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 347 | const negotiated = exchangeOfferAnswer(pc1, pc2); | 
|  | 348 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 349 | trackEvent.transceiver.setCodecPreferences(nonOpus); | 
|  | 350 | await negotiated; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 351 |  | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 352 | const sender = transceiver.sender; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 353 | let param = sender.getParameters(); | 
|  | 354 | let encoding = param.encodings[0]; | 
|  | 355 |  | 
|  | 356 | encoding.codec = opus; | 
|  | 357 | await promise_rejects_dom(t, "InvalidModificationError", sender.setParameters(param)); | 
|  | 358 | }, `Setting a non-negotiated codec on an audio sender with setParameters should throw InvalidModificationError`); | 
|  | 359 |  | 
|  | 360 | promise_test(async (t) => { | 
|  | 361 | const pc1 = new RTCPeerConnection(); | 
|  | 362 | const pc2 = new RTCPeerConnection(); | 
|  | 363 | t.add_cleanup(() => pc1.close()); | 
|  | 364 | t.add_cleanup(() => pc2.close()); | 
|  | 365 |  | 
|  | 366 | const vp8 = findFirstCodec('video/VP8'); | 
|  | 367 | const nonVP8 = codecsNotMatching(vp8.mimeType); | 
|  | 368 |  | 
|  | 369 | const transceiver = pc1.addTransceiver('video'); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 370 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 371 | const negotiated = exchangeOfferAnswer(pc1, pc2); | 
|  | 372 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 373 | trackEvent.transceiver.setCodecPreferences(nonVP8); | 
|  | 374 | await negotiated; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 375 |  | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 376 | const sender = transceiver.sender; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 377 | let param = sender.getParameters(); | 
|  | 378 | let encoding = param.encodings[0]; | 
|  | 379 |  | 
|  | 380 | encoding.codec = vp8; | 
|  | 381 | await promise_rejects_dom(t, "InvalidModificationError", sender.setParameters(param)); | 
|  | 382 | }, `Setting a non-negotiated codec on a video sender with setParameters should throw InvalidModificationError`); | 
|  | 383 |  | 
|  | 384 | promise_test(async (t) => { | 
|  | 385 | const pc1 = new RTCPeerConnection(); | 
|  | 386 | const pc2 = new RTCPeerConnection(); | 
|  | 387 | t.add_cleanup(() => pc1.close()); | 
|  | 388 | t.add_cleanup(() => pc2.close()); | 
|  | 389 |  | 
|  | 390 | const opus = findFirstCodec('audio/opus'); | 
|  | 391 | const nonOpus = codecsNotMatching(opus.mimeType); | 
|  | 392 |  | 
|  | 393 | const transceiver = pc1.addTransceiver('audio', { | 
|  | 394 | sendEncodings: [{codec: opus}], | 
|  | 395 | }); | 
|  | 396 | const sender = transceiver.sender; | 
|  | 397 |  | 
|  | 398 | exchangeIceCandidates(pc1, pc2); | 
|  | 399 | await exchangeOfferAnswer(pc1, pc2); | 
|  | 400 |  | 
|  | 401 | let param = sender.getParameters(); | 
|  | 402 | let encoding = param.encodings[0]; | 
|  | 403 |  | 
|  | 404 | assertCodecEquals(opus, encoding.codec); | 
|  | 405 |  | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 406 | pc2.getTransceivers()[0].setCodecPreferences(nonOpus); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 407 | await exchangeOfferAnswer(pc1, pc2); | 
|  | 408 |  | 
|  | 409 | param = sender.getParameters(); | 
|  | 410 | encoding = param.encodings[0]; | 
|  | 411 |  | 
|  | 412 | assert_equals(encoding.codec, undefined); | 
|  | 413 | }, `Codec should be undefined after negotiating away the currently set codec on an audio sender`); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 414 | promise_test(async (t) => { | 
|  | 415 | const pc1 = new RTCPeerConnection(); | 
|  | 416 | const pc2 = new RTCPeerConnection(); | 
|  | 417 | t.add_cleanup(() => pc1.close()); | 
|  | 418 | t.add_cleanup(() => pc2.close()); | 
|  | 419 |  | 
|  | 420 | const vp8 = findFirstCodec('video/VP8'); | 
|  | 421 | const nonVP8 = codecsNotMatching(vp8.mimeType); | 
|  | 422 |  | 
|  | 423 | const transceiver = pc1.addTransceiver('video', { | 
|  | 424 | sendEncodings: [{codec: vp8}], | 
|  | 425 | }); | 
|  | 426 | const sender = transceiver.sender; | 
|  | 427 |  | 
|  | 428 | exchangeIceCandidates(pc1, pc2); | 
|  | 429 | await exchangeOfferAnswer(pc1, pc2); | 
|  | 430 |  | 
|  | 431 | let param = sender.getParameters(); | 
|  | 432 | let encoding = param.encodings[0]; | 
|  | 433 |  | 
|  | 434 | assertCodecEquals(vp8, encoding.codec); | 
|  | 435 |  | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 436 | pc2.getTransceivers()[0].setCodecPreferences(nonVP8); | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 437 | await exchangeOfferAnswer(pc1, pc2); | 
|  | 438 |  | 
|  | 439 | param = sender.getParameters(); | 
|  | 440 | encoding = param.encodings[0]; | 
|  | 441 |  | 
|  | 442 | assert_equals(encoding.codec, undefined); | 
|  | 443 | }, `Codec should be undefined after negotiating away the currently set codec on a video sender`); | 
|  | 444 |  | 
|  | 445 | promise_test(async (t) => { | 
|  | 446 | const pc1 = new RTCPeerConnection(); | 
|  | 447 | const pc2 = new RTCPeerConnection(); | 
|  | 448 | t.add_cleanup(() => pc1.close()); | 
|  | 449 | t.add_cleanup(() => pc2.close()); | 
|  | 450 | const stream = await getNoiseStream({audio:true}); | 
|  | 451 | t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); | 
|  | 452 |  | 
|  | 453 | const opus = findFirstCodec('audio/opus'); | 
|  | 454 | const nonOpus = codecsNotMatching(opus.mimeType); | 
|  | 455 |  | 
|  | 456 | const transceiver = pc1.addTransceiver(stream.getTracks()[0]); | 
|  | 457 | const sender = transceiver.sender; | 
|  | 458 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 459 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 460 | const negotiated = exchangeOfferAnswer(pc1, pc2); | 
|  | 461 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 462 | trackEvent.transceiver.setCodecPreferences(nonOpus.concat([opus])); | 
|  | 463 | await negotiated; | 
|  | 464 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 465 |  | 
|  | 466 | let codecs = await codecsForSender(sender); | 
|  | 467 | assert_not_equals(codecs[0], opus.mimeType); | 
|  | 468 |  | 
|  | 469 | let param = sender.getParameters(); | 
|  | 470 | let encoding = param.encodings[0]; | 
|  | 471 | encoding.codec = opus; | 
|  | 472 |  | 
|  | 473 | await sender.setParameters(param); | 
|  | 474 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 475 | await step_wait_async(t, async () => { | 
|  | 476 | let old_codecs = codecs; | 
|  | 477 | codecs = await codecsForSender(sender); | 
|  | 478 | return !arrayEquals(codecs, old_codecs); | 
|  | 479 | }, 'Waiting for current codecs to change', 5000, 200); | 
|  | 480 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 481 | assert_array_equals(codecs, [opus.mimeType]); | 
|  | 482 | }, `Stats output-rtp should match the selected codec in non-simulcast usecase on an audio sender`); | 
|  | 483 |  | 
|  | 484 | promise_test(async (t) => { | 
|  | 485 | const pc1 = new RTCPeerConnection(); | 
|  | 486 | const pc2 = new RTCPeerConnection(); | 
|  | 487 | t.add_cleanup(() => pc1.close()); | 
|  | 488 | t.add_cleanup(() => pc2.close()); | 
|  | 489 | const stream = await getNoiseStream({video:true}); | 
|  | 490 | t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); | 
|  | 491 |  | 
|  | 492 | const vp8 = findFirstCodec('video/VP8'); | 
|  | 493 | const nonVP8 = codecsNotMatching(vp8.mimeType); | 
|  | 494 |  | 
|  | 495 | const transceiver = pc1.addTransceiver(stream.getTracks()[0]); | 
|  | 496 | const sender = transceiver.sender; | 
|  | 497 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 498 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 499 | const negotiated = exchangeOfferAnswer(pc1, pc2); | 
|  | 500 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 501 | trackEvent.transceiver.setCodecPreferences(nonVP8.concat([vp8])); | 
|  | 502 | await negotiated; | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 503 |  | 
|  | 504 | let codecs = await codecsForSender(sender); | 
|  | 505 | assert_not_equals(codecs[0], vp8.mimeType); | 
|  | 506 |  | 
|  | 507 | let param = sender.getParameters(); | 
|  | 508 | let encoding = param.encodings[0]; | 
|  | 509 | encoding.codec = vp8; | 
|  | 510 |  | 
|  | 511 | await sender.setParameters(param); | 
|  | 512 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 513 | await step_wait_async(t, async () => { | 
|  | 514 | let old_codecs = codecs; | 
|  | 515 | codecs = await codecsForSender(sender); | 
|  | 516 | return !arrayEquals(codecs, old_codecs); | 
|  | 517 | }, 'Waiting for current codecs to change', 5000, 200); | 
|  | 518 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 519 | assert_array_equals(codecs, [vp8.mimeType]); | 
|  | 520 | }, `Stats output-rtp should match the selected codec in non-simulcast usecase on a video sender`); | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 521 |  | 
|  | 522 | promise_test(async (t) => { | 
|  | 523 | const pc1 = new RTCPeerConnection(); | 
|  | 524 | const pc2 = new RTCPeerConnection(); | 
|  | 525 | t.add_cleanup(() => pc1.close()); | 
|  | 526 | t.add_cleanup(() => pc2.close()); | 
|  | 527 | const stream = await getNoiseStream({video:true}); | 
|  | 528 | t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); | 
|  | 529 |  | 
|  | 530 | const vp8 = findFirstCodec('video/VP8'); | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 531 | const h264 = findFirstCodec('video/H264'); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 532 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 533 | const transceiver = pc1.addTransceiver(stream.getTracks()[0], { | 
|  | 534 | sendEncodings: [{rid: '0'}, {rid: '1'}, {rid: '2'}], | 
|  | 535 | }); | 
|  | 536 | const sender = transceiver.sender; | 
|  | 537 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 538 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 539 | const negotiated = doOfferToSendSimulcastAndAnswer(pc1, pc2, ['0', '1', '2']); | 
|  | 540 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 541 | trackEvent.transceiver.setCodecPreferences([h264, vp8]); | 
|  | 542 | await negotiated; | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 543 |  | 
|  | 544 | await waitForAllLayers(t, sender); | 
|  | 545 |  | 
|  | 546 | let codecs = await codecsForSender(sender); | 
|  | 547 | assert_not_equals(codecs[0], vp8.mimeType); | 
|  | 548 | assert_not_equals(codecs[1], vp8.mimeType); | 
|  | 549 | assert_not_equals(codecs[2], vp8.mimeType); | 
|  | 550 |  | 
|  | 551 | let param = sender.getParameters(); | 
|  | 552 | param.encodings[0].codec = vp8; | 
|  | 553 | param.encodings[1].codec = vp8; | 
|  | 554 | param.encodings[2].codec = vp8; | 
|  | 555 |  | 
|  | 556 | await sender.setParameters(param); | 
|  | 557 |  | 
|  | 558 | // Waiting for 10s as ramp-up time can be slow in the runners. | 
|  | 559 | await step_wait_async(t, async () => { | 
|  | 560 | let old_codecs = codecs; | 
|  | 561 | codecs = await codecsForSender(sender); | 
|  | 562 | return !arrayEquals(codecs, old_codecs); | 
|  | 563 | }, 'Waiting for current codecs to change', 10000, 200); | 
|  | 564 |  | 
|  | 565 | assert_array_equals(codecs, [vp8.mimeType, vp8.mimeType, vp8.mimeType]); | 
|  | 566 | }, `Stats output-rtp should match the selected codec in simulcast usecase on a video sender`); | 
|  | 567 |  | 
|  | 568 | promise_test(async (t) => { | 
|  | 569 | const pc1 = new RTCPeerConnection(); | 
|  | 570 | const pc2 = new RTCPeerConnection(); | 
|  | 571 | t.add_cleanup(() => pc1.close()); | 
|  | 572 | t.add_cleanup(() => pc2.close()); | 
|  | 573 | const stream = await getNoiseStream({video:true}); | 
|  | 574 | t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); | 
|  | 575 |  | 
|  | 576 | const vp8 = findFirstCodec('video/VP8'); | 
| Philipp Hancke | eeb00b0 | 2024-02-12 10:56:41 | [diff] [blame] | 577 | const h264 = findFirstCodec('video/H264'); | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 578 |  | 
|  | 579 | const transceiver = pc1.addTransceiver(stream.getTracks()[0], { | 
|  | 580 | sendEncodings: [{rid: '0'}, {rid: '1'}, {rid: '2'}], | 
|  | 581 | }); | 
|  | 582 | const sender = transceiver.sender; | 
|  | 583 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 584 | exchangeIceCandidates(pc1, pc2); | 
| Dan Baker | ee22853 | 2024-05-13 20:35:27 | [diff] [blame^] | 585 | const negotiated = doOfferToSendSimulcastAndAnswer(pc1, pc2, ['0', '1', '2']); | 
|  | 586 | const trackEvent = await new Promise(r => pc2.ontrack = r); | 
|  | 587 | trackEvent.transceiver.setCodecPreferences([h264, vp8]); | 
|  | 588 | await negotiated; | 
|  | 589 |  | 
| Blink WPT Bot | 396bc8e | 2023-09-01 20:33:46 | [diff] [blame] | 590 |  | 
|  | 591 | await waitForAllLayers(t, sender); | 
|  | 592 |  | 
|  | 593 | let codecs = await codecsForSender(sender); | 
|  | 594 | assert_not_equals(codecs[0], vp8.mimeType); | 
|  | 595 | assert_not_equals(codecs[1], vp8.mimeType); | 
|  | 596 | assert_not_equals(codecs[2], vp8.mimeType); | 
|  | 597 |  | 
|  | 598 | let param = sender.getParameters(); | 
|  | 599 | param.encodings[1].codec = vp8; | 
|  | 600 |  | 
|  | 601 | await sender.setParameters(param); | 
|  | 602 |  | 
|  | 603 | await step_wait_async(t, async () => { | 
|  | 604 | let old_codecs = codecs; | 
|  | 605 | codecs = await codecsForSender(sender); | 
|  | 606 | return !arrayEquals(codecs, old_codecs); | 
|  | 607 | }, 'Waiting for current codecs to change', 5000, 200); | 
|  | 608 |  | 
|  | 609 | assert_not_equals(codecs[0], vp8.mimeType); | 
|  | 610 | assert_equals(codecs[1], vp8.mimeType); | 
|  | 611 | assert_not_equals(codecs[2], vp8.mimeType); | 
|  | 612 | }, `Stats output-rtp should match the selected mixed codecs in simulcast usecase on a video sender`); | 
|  | 613 |  | 
| Florent Castelli | 9f783ba | 2023-05-16 13:09:15 | [diff] [blame] | 614 | </script> |