tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

setParameters-encodings.https.html (19258B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>RTCPeerConnection Simulcast Tests - setParameters/encodings</title>
      4 <meta name="timeout" content="long">
      5 <script src="../third_party/sdp/sdp.js"></script>
      6 <script src="simulcast.js"></script>
      7 <script src="../RTCPeerConnection-helper.js"></script>
      8 <script src="/resources/testharness.js"></script>
      9 <script src="/resources/testharnessreport.js"></script>
     10 <script src="/resources/testdriver.js"></script>
     11 <script src="/resources/testdriver-vendor.js"></script>
     12 <script src="../../mediacapture-streams/permission-helper.js"></script>
     13 <script>
     14 
     15 promise_test(async t => {
     16  const pc1 = new RTCPeerConnection();
     17  t.add_cleanup(() => pc1.close());
     18  const pc2 = new RTCPeerConnection();
     19  t.add_cleanup(() => pc2.close());
     20 
     21  const {sender} = pc1.addTransceiver("video", {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
     22 
     23  await doOfferToSendSimulcast(pc1, pc2);
     24 
     25  await pc2.setLocalDescription();
     26  const simulcastAnswer = midToRid(pc2.localDescription, pc1.localDescription, ["foo"]);
     27 
     28  const parameters = sender.getParameters();
     29  parameters.encodings[1].scaleResolutionDownBy = 3.3;
     30  const answerDone = pc1.setRemoteDescription({type: "answer", sdp: simulcastAnswer});
     31  await sender.setParameters(parameters);
     32  await answerDone;
     33 
     34  assert_equals(pc1.getTransceivers().length, 1);
     35  const {encodings} = sender.getParameters();
     36  const rids = encodings.map(({rid}) => rid);
     37  assert_array_equals(rids, ["foo"]);
     38 }, 'sRD(simulcast answer) can narrow the simulcast envelope when interrupted by a setParameters');
     39 
     40 promise_test(async t => {
     41  const pc1 = new RTCPeerConnection();
     42  t.add_cleanup(() => pc1.close());
     43  const pc2 = new RTCPeerConnection();
     44  t.add_cleanup(() => pc2.close());
     45 
     46  const {sender} = pc1.addTransceiver("video", {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
     47 
     48  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
     49 
     50  assert_equals(pc1.getTransceivers().length, 1);
     51  let encodings = sender.getParameters().encodings;
     52  let rids = encodings.map(({rid}) => rid);
     53  assert_array_equals(rids, ["foo", "bar"]);
     54 
     55  const reoffer = await pc2.createOffer();
     56  const simulcastSdp = midToRid(reoffer, pc1.localDescription, ["foo"]);
     57 
     58  const parameters = sender.getParameters();
     59  parameters.encodings[1].scaleResolutionDownBy = 3.3;
     60  const reofferDone = pc1.setRemoteDescription({type: "offer", sdp: simulcastSdp});
     61  await sender.setParameters(parameters);
     62  await reofferDone;
     63  await pc1.setLocalDescription();
     64 
     65  encodings = sender.getParameters().encodings;
     66  rids = encodings.map(({rid}) => rid);
     67  assert_array_equals(rids, ["foo"]);
     68 }, 'sRD(simulcast offer) can narrow the simulcast envelope when interrupted by a setParameters');
     69 
     70 promise_test(async t => {
     71  const pc1 = new RTCPeerConnection();
     72  t.add_cleanup(() => pc1.close());
     73  const pc2 = new RTCPeerConnection();
     74  t.add_cleanup(() => pc2.close());
     75 
     76  const {sender} = pc1.addTransceiver("video", {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
     77 
     78  const parameters = sender.getParameters();
     79  parameters.encodings[0].scaleResolutionDownBy = 2.3;
     80  parameters.encodings[1].scaleResolutionDownBy = 3.3;
     81  await sender.setParameters(parameters);
     82 
     83  await doOfferToSendSimulcast(pc1, pc2);
     84  await doAnswerToRecvSimulcast(pc1, pc2, []);
     85 
     86  assert_equals(pc1.getTransceivers().length, 1);
     87  const encodings = sender.getParameters().encodings;
     88  const rids = encodings.map(({rid}) => rid);
     89  assert_array_equals(rids, ["foo"]);
     90  assert_equals(encodings[0].scaleResolutionDownBy, 2.3);
     91 }, 'a simulcast setParameters followed by a sRD(unicast answer) results in keeping the first encoding');
     92 
     93 promise_test(async t => {
     94  const pc1 = new RTCPeerConnection();
     95  t.add_cleanup(() => pc1.close());
     96  const pc2 = new RTCPeerConnection();
     97  t.add_cleanup(() => pc2.close());
     98 
     99  const {sender} = pc1.addTransceiver("video", {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    100  await doOfferToSendSimulcast(pc1, pc2);
    101 
    102  await pc2.setLocalDescription();
    103  const unicastAnswer = midToRid(pc2.localDescription, pc1.localDescription, []);
    104 
    105  const parameters = sender.getParameters();
    106  parameters.encodings[0].scaleResolutionDownBy = 2.3;
    107  parameters.encodings[1].scaleResolutionDownBy = 3.3;
    108  const answerDone = pc1.setRemoteDescription({type: "answer", sdp: unicastAnswer});
    109  await sender.setParameters(parameters);
    110  await answerDone;
    111 
    112  assert_equals(pc1.getTransceivers().length, 1);
    113  const encodings = sender.getParameters().encodings;
    114  const rids = encodings.map(({rid}) => rid);
    115  assert_array_equals(rids, ["foo"]);
    116  assert_equals(encodings[0].scaleResolutionDownBy, 2.3);
    117 }, 'sRD(unicast answer) interrupted by setParameters(simulcast) results in keeping the first encoding');
    118 
    119 promise_test(async t => {
    120  const pc1 = new RTCPeerConnection();
    121  t.add_cleanup(() => pc1.close());
    122  const pc2 = new RTCPeerConnection();
    123  t.add_cleanup(() => pc2.close());
    124 
    125  const {sender} = pc1.addTransceiver("video", {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    126 
    127  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
    128  assert_equals(pc1.getTransceivers().length, 1);
    129  let encodings = sender.getParameters().encodings;
    130  let rids = encodings.map(({rid}) => rid);
    131  assert_array_equals(rids, ["foo", "bar"]);
    132 
    133  const reoffer = await pc2.createOffer();
    134  const unicastSdp = midToRid(reoffer, pc1.localDescription, []);
    135  const parameters = sender.getParameters();
    136  parameters.encodings[0].scaleResolutionDownBy = 2.3;
    137  parameters.encodings[1].scaleResolutionDownBy = 3.3;
    138  const reofferDone = pc1.setRemoteDescription({type: "offer", sdp: unicastSdp});
    139  await sender.setParameters(parameters);
    140  await reofferDone;
    141  await pc1.setLocalDescription();
    142 
    143  encodings = sender.getParameters().encodings;
    144  rids = encodings.map(({rid}) => rid);
    145  assert_array_equals(rids, ["foo"]);
    146  assert_equals(encodings[0].scaleResolutionDownBy, 2.3);
    147 }, 'sRD(unicast reoffer) interrupted by setParameters(simulcast) results in keeping the first encoding');
    148 
    149 promise_test(async t => {
    150  const pc1 = new RTCPeerConnection();
    151  t.add_cleanup(() => pc1.close());
    152  const pc2 = new RTCPeerConnection();
    153  t.add_cleanup(() => pc2.close());
    154 
    155  const {sender} = pc1.addTransceiver("video", {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    156 
    157  await doOfferToSendSimulcast(pc1, pc2);
    158  await pc2.setLocalDescription();
    159  const simulcastAnswer = midToRid(pc2.localDescription, pc1.localDescription, ["foo"]);
    160  const parameters = sender.getParameters();
    161  parameters.encodings[0].scaleResolutionDownBy = 3.3;
    162  const answerDone = pc1.setRemoteDescription({type: "answer", sdp: simulcastAnswer});
    163  await sender.setParameters(parameters);
    164  await answerDone;
    165 
    166  const {encodings} = sender.getParameters();
    167  assert_equals(encodings.length, 1);
    168  assert_equals(encodings[0].scaleResolutionDownBy, 3.3);
    169 }, 'sRD(simulcast answer) interrupted by a setParameters does not result in losing modifications from the setParameters to the encodings that remain');
    170 
    171 const simulcastOffer = `v=0
    172 o=- 3840232462471583827 0 IN IP4 127.0.0.1
    173 s=-
    174 t=0 0
    175 a=group:BUNDLE 0
    176 a=msid-semantic: WMS
    177 m=video 9 UDP/TLS/RTP/SAVPF 96
    178 c=IN IP4 0.0.0.0
    179 a=rtcp:9 IN IP4 0.0.0.0
    180 a=ice-ufrag:Li6+
    181 a=ice-pwd:3C05CTZBRQVmGCAq7hVasHlT
    182 a=ice-options:trickle
    183 a=fingerprint:sha-256 5B:D3:8E:66:0E:7D:D3:F3:8E:E6:80:28:19:FC:55:AD:58:5D:B9:3D:A8:DE:45:4A:E7:87:02:F8:3C:0B:3B:B3
    184 a=setup:actpass
    185 a=mid:0
    186 a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
    187 a=extmap:2 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
    188 a=recvonly
    189 a=rtcp-mux
    190 a=rtpmap:96 VP8/90000
    191 a=rtcp-fb:96 goog-remb
    192 a=rtcp-fb:96 transport-cc
    193 a=rtcp-fb:96 ccm fir
    194 a=rid:foo recv
    195 a=rid:bar recv
    196 a=simulcast:recv foo;bar
    197 `;
    198 
    199 promise_test(async t => {
    200  const pc1 = new RTCPeerConnection();
    201  t.add_cleanup(() => pc1.close());
    202 
    203  const stream = await getNoiseStream({video: true});
    204  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    205  const sender = pc1.addTrack(stream.getTracks()[0]);
    206  const parameters = sender.getParameters();
    207  parameters.encodings[0].scaleResolutionDownBy = 3.0;
    208  await sender.setParameters(parameters);
    209 
    210  await pc1.setRemoteDescription({type: "offer", sdp: simulcastOffer});
    211 
    212  const {encodings} = sender.getParameters();
    213  const rids = encodings.map(({rid}) => rid);
    214  assert_array_equals(rids, ["foo", "bar"]);
    215  assert_equals(encodings[0].scaleResolutionDownBy, 2.0);
    216  assert_equals(encodings[1].scaleResolutionDownBy, 1.0);
    217 }, 'addTrack, then a unicast setParameters, then sRD(simulcast offer) results in simulcast without the settings from setParameters');
    218 
    219 promise_test(async t => {
    220  const pc1 = new RTCPeerConnection();
    221  t.add_cleanup(() => pc1.close());
    222 
    223  const stream = await getNoiseStream({video: true});
    224  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    225  const sender = pc1.addTrack(stream.getTracks()[0]);
    226  const parameters = sender.getParameters();
    227  parameters.encodings[0].scaleResolutionDownBy = 3.0;
    228 
    229  const offerDone = pc1.setRemoteDescription({type: "offer", sdp: simulcastOffer});
    230  await sender.setParameters(parameters);
    231  await offerDone;
    232 
    233  const {encodings} = sender.getParameters();
    234  const rids = encodings.map(({rid}) => rid);
    235  assert_array_equals(rids, ["foo", "bar"]);
    236  assert_equals(encodings[0].scaleResolutionDownBy, 2.0);
    237  assert_equals(encodings[1].scaleResolutionDownBy, 1.0);
    238 }, 'addTrack, then sRD(simulcast offer) interrupted by a unicast setParameters results in simulcast without the settings from setParameters');
    239 
    240 promise_test(async t => {
    241  const pc1 = new RTCPeerConnection();
    242  const pc2 = new RTCPeerConnection();
    243  t.add_cleanup(() => pc1.close());
    244  t.add_cleanup(() => pc2.close());
    245 
    246  const stream = await getNoiseStream({video: true});
    247  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    248  const {sender} = pc1.addTransceiver(stream.getTracks()[0], {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    249  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
    250  pc2.getTransceivers()[0].direction = "sendrecv";
    251  pc2.getTransceivers()[1].direction = "sendrecv";
    252 
    253  await doOfferToRecvSimulcast(pc2, pc1, []);
    254  // Race simulcast setParameters against sLD(unicast reanswer)
    255  const answer = await pc1.createAnswer();
    256  const aTask = queueAWebrtcTask();
    257  // This also queues a task to clear [[LastReturnedParameters]]
    258  const parameters = sender.getParameters();
    259  // This might or might not queue a task right away (it might do some
    260  // microtask stuff first), but it doesn't really matter.
    261  const sLDDone = pc1.setLocalDescription(answer);
    262  await aTask;
    263  // Task queue should now have the task that clears
    264  // [[LastReturnedParameters]], _then_ the success task for sLD.
    265  // setParameters should succeed because [[LastReturnedParameters]] has not
    266  // yet been cleared, and the steps in the success task for sLD have not run
    267  // either.
    268  await sender.setParameters(parameters);
    269  await sLDDone;
    270 
    271  assert_equals(pc1.getTransceivers().length, 1);
    272  const {encodings} = sender.getParameters();
    273  const rids = encodings.map(({rid}) => rid);
    274  assert_array_equals(rids, ["foo"]);
    275 }, 'getParameters, then sLD(unicast answer) interrupted by a simulcast setParameters results in unicast');
    276 
    277 promise_test(async t => {
    278  const pc1 = new RTCPeerConnection();
    279  const pc2 = new RTCPeerConnection();
    280  t.add_cleanup(() => pc1.close());
    281  t.add_cleanup(() => pc2.close());
    282 
    283  const stream = await getNoiseStream({video: true});
    284  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    285  const {sender} = pc1.addTransceiver(stream.getTracks()[0], {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    286  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
    287  pc2.getTransceivers()[0].direction = "sendrecv";
    288  pc2.getTransceivers()[1].direction = "sendrecv";
    289 
    290  await doOfferToRecvSimulcast(pc2, pc1, []);
    291  const answer = await pc1.createAnswer();
    292 
    293  // The timing on this is very difficult. We want to ensure that our
    294  // getParameters call happens after the initial steps in sLD, but
    295  // before the queued task that sLD runs when it completes.
    296  const aTask = queueAWebrtcTask();
    297  const sLDDone = pc1.setLocalDescription(answer);
    298  // We now have a queued task (aTask). We might also have the success task for
    299  // sLD, but maybe not. Allowing aTask to finish gives us our best chance that
    300  // the success task for sLD is queued, but not run yet.
    301  await aTask;
    302  const parameters = sender.getParameters();
    303  // Hopefully we now have the success task for sLD, followed by the
    304  // success task for getParameters.
    305  await sLDDone;
    306  // Success task for getParameters should not have run yet.
    307  await promise_rejects_dom(t, 'InvalidStateError', sender.setParameters(parameters));
    308 },'Success task for setLocalDescription(answer) clears [[LastReturnedParameters]]');
    309 
    310 promise_test(async t => {
    311  const pc1 = new RTCPeerConnection();
    312  const pc2 = new RTCPeerConnection();
    313  t.add_cleanup(() => pc1.close());
    314  t.add_cleanup(() => pc2.close());
    315 
    316  const stream = await getNoiseStream({video: true});
    317  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    318  const {sender} = pc1.addTransceiver(stream.getTracks()[0], {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    319  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
    320  pc2.getTransceivers()[0].direction = "sendrecv";
    321  pc2.getTransceivers()[1].direction = "sendrecv";
    322 
    323  await pc2.setLocalDescription();
    324  const simulcastOffer = midToRid(
    325    pc2.localDescription,
    326    pc1.localDescription,
    327    []
    328  );
    329 
    330  // The timing on this is very difficult. We need to ensure that our
    331  // getParameters call happens after the initial steps in sRD, but
    332  // before the queued task that sRD runs when it completes.
    333  const aTask = queueAWebrtcTask();
    334  const sRDDone = pc1.setRemoteDescription({ type: "offer", sdp: simulcastOffer });
    335 
    336  await aTask;
    337  const parameters = sender.getParameters();
    338  await sRDDone;
    339  await promise_rejects_dom(t, 'InvalidStateError', sender.setParameters(parameters));
    340 },'Success task for setRemoteDescription(offer) clears [[LastReturnedParameters]]');
    341 
    342 promise_test(async t => {
    343  const pc1 = new RTCPeerConnection();
    344  const pc2 = new RTCPeerConnection();
    345  t.add_cleanup(() => pc1.close());
    346  t.add_cleanup(() => pc2.close());
    347 
    348  const stream = await getNoiseStream({video: true});
    349  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    350  const {sender} = pc1.addTransceiver(stream.getTracks()[0], {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    351  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
    352  pc2.getTransceivers()[0].direction = "sendrecv";
    353  pc2.getTransceivers()[1].direction = "sendrecv";
    354 
    355  await doOfferToSendSimulcast(pc1, pc2);
    356  await pc2.setLocalDescription();
    357  const simulcastAnswer = midToRid(
    358    pc2.localDescription,
    359    pc1.localDescription,
    360    []
    361  );
    362 
    363  // The timing on this is very difficult. We need to ensure that our
    364  // getParameters call happens after the initial steps in sRD, but
    365  // before the queued task that sRD runs when it completes.
    366  const aTask = queueAWebrtcTask();
    367  const sRDDone = pc1.setRemoteDescription({ type: "answer", sdp: simulcastAnswer });
    368  await aTask;
    369 
    370  const parameters = sender.getParameters();
    371  await sRDDone;
    372  await promise_rejects_dom(t, 'InvalidStateError', sender.setParameters(parameters));
    373 },'Success task for setRemoteDescription(answer) clears [[LastReturnedParameters]]');
    374 
    375 promise_test(async t => {
    376  const pc1 = new RTCPeerConnection();
    377  t.add_cleanup(() => pc1.close());
    378  const pc2 = new RTCPeerConnection();
    379  t.add_cleanup(() => pc2.close());
    380 
    381  const stream = await getNoiseStream({video: true});
    382  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    383  const sender = pc1.addTrack(stream.getTracks()[0]);
    384  pc2.addTrack(stream.getTracks()[0]);
    385 
    386  await doOfferToRecvSimulcast(pc2, pc1, ["foo", "bar"]);
    387  let parameters = sender.getParameters();
    388  let rids = parameters.encodings.map(({rid}) => rid);
    389  assert_array_equals(rids, ["foo", "bar"]);
    390  parameters.encodings[0].scaleResolutionDownBy = 3;
    391  parameters.encodings[1].scaleResolutionDownBy = 5;
    392  await sender.setParameters(parameters);
    393 
    394  await pc1.setRemoteDescription({sdp: "", type: "rollback"});
    395 
    396  parameters = sender.getParameters();
    397  rids = parameters.encodings.map(({rid}) => rid);
    398  assert_array_equals(rids, [undefined]);
    399  assert_equals(parameters.encodings[0].scaleResolutionDownBy, 1);
    400 }, 'addTrack, then rollback of sRD(simulcast offer), brings us back to having a single encoding without any previously set parameters');
    401 
    402 promise_test(async t => {
    403  const pc1 = new RTCPeerConnection();
    404  t.add_cleanup(() => pc1.close());
    405  const pc2 = new RTCPeerConnection();
    406  t.add_cleanup(() => pc2.close());
    407 
    408  const stream = await getNoiseStream({video: true});
    409  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    410  const {sender} = pc1.addTransceiver(stream.getTracks()[0], {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
    411 
    412  await doOfferToSendSimulcastAndAnswer(pc1, pc2, ["foo", "bar"]);
    413  let parameters = sender.getParameters();
    414  let rids = parameters.encodings.map(({rid}) => rid);
    415  assert_array_equals(rids, ["foo", "bar"]);
    416  parameters.encodings[0].scaleResolutionDownBy = 3;
    417  parameters.encodings[1].scaleResolutionDownBy = 5;
    418  await sender.setParameters(parameters);
    419 
    420  await doOfferToRecvSimulcast(pc2, pc1, []);
    421  parameters = sender.getParameters();
    422  rids = parameters.encodings.map(({rid}) => rid);
    423  assert_array_equals(rids, ["foo", "bar"]);
    424 
    425  await pc1.setRemoteDescription({sdp: "", type: "rollback"});
    426  parameters = sender.getParameters();
    427  rids = parameters.encodings.map(({rid}) => rid);
    428  assert_array_equals(rids, ["foo", "bar"]);
    429  assert_equals(parameters.encodings[0].scaleResolutionDownBy, 3);
    430  assert_equals(parameters.encodings[1].scaleResolutionDownBy, 5);
    431 }, 'rollback of a remote offer that disabled a previously negotiated simulcast should restore simulcast along with any previously set parameters');
    432 
    433 promise_test(async t => {
    434  const pc1 = new RTCPeerConnection();
    435  t.add_cleanup(() => pc1.close());
    436  const pc2 = new RTCPeerConnection();
    437  t.add_cleanup(() => pc2.close());
    438 
    439  const stream = await getNoiseStream({video: true});
    440  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
    441  const sender = pc1.addTrack(stream.getTracks()[0]);
    442  pc2.addTrack(stream.getTracks()[0]);
    443 
    444  await doOfferToRecvSimulcast(pc2, pc1, ["foo", "bar"]);
    445  const aTask = queueAWebrtcTask();
    446  let parameters = sender.getParameters();
    447  let rids = parameters.encodings.map(({rid}) => rid);
    448  assert_array_equals(rids, ["foo", "bar"]);
    449  parameters.encodings[0].scaleResolutionDownBy = 3;
    450  parameters.encodings[1].scaleResolutionDownBy = 5;
    451 
    452  const rollbackDone = pc1.setRemoteDescription({sdp: "", type: "rollback"});
    453  await aTask;
    454  await sender.setParameters(parameters);
    455  await rollbackDone;
    456 
    457  parameters = sender.getParameters();
    458  rids = parameters.encodings.map(({rid}) => rid);
    459  assert_array_equals(rids, [undefined]);
    460  assert_equals(parameters.encodings[0].scaleResolutionDownBy, 1);
    461 }, 'rollback of sRD(simulcast offer) interrupted by setParameters(simulcast) brings us back to having a single encoding without any previously set parameters');
    462 
    463 </script>