tor-browser

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

test_peerConnection_getParameters.html (16935B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 
      4 <head>
      5  <script type="application/javascript" src="pc.js"></script>
      6  <script type="application/javascript" src="sdpUtils.js"></script>
      7  <script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
      8 </head>
      9 
     10 <body>
     11  <pre id="test">
     12 <script type="application/javascript">
     13  createHTML({
     14    bug: "1534687",
     15    title: "getParameters tests (that we can't do in wpt)",
     16    visible: true
     17  });
     18 
     19  function compareCodecParam(observed, expected) {
     20    info(`Comparing ${JSON.stringify(observed)} to ${JSON.stringify(expected)}`);
     21    is(observed.payloadType, expected.payloadType);
     22    is(observed.clockRate, expected.clockRate);
     23    is(observed.channels, expected.channels);
     24    is(observed.mimeType.toLowerCase(), expected.mimeType.toLowerCase());
     25    if (expected.hasOwnProperty('sdpFmtpLine')) {
     26      is(observed.sdpFmtpLine, expected.sdpFmtpLine);
     27    }
     28  }
     29 
     30  function buildExpectedCodecs(msection) {
     31    const rtpParameters = SDPUtils.parseRtpParameters(msection);
     32    const {kind} = SDPUtils.parseMLine(msection);
     33    const sdpCodecs = new Map;
     34    for (const fromSdp of rtpParameters.codecs) {
     35      const expected = {
     36        payloadType: fromSdp.payloadType,
     37        clockRate: fromSdp.clockRate,
     38        mimeType: `${kind}/${fromSdp.name}`,
     39      };
     40      if (kind == 'audio') {
     41        expected.channels = fromSdp.channels;
     42      }
     43      const fmtps = SDPUtils.matchPrefixAndTrim(msection, `a=fmtp:${fromSdp.payloadType}`);
     44      if (fmtps.length == 1) {
     45        expected.sdpFmtpLine = fmtps[0];
     46      } else {
     47        // compareCodecParam will check if observed.sdpFmtpLine is undefined if we
     48        // set this, but will not perform any checks if we do not.
     49        expected.sdpFmtpLine = undefined;
     50      }
     51      ok(!sdpCodecs.has(expected.payloadType), "payload types must be unique");
     52      sdpCodecs.set(expected.payloadType, expected);
     53    }
     54    return sdpCodecs;
     55  }
     56 
     57  // Does not support disregarding unsupported codecs in the SDP, so is not
     58  // suitable for all test-cases.
     59  function checkCodecsAgainstSDP(codecs, msection) {
     60    const expectedCodecs = Array.from(buildExpectedCodecs(msection).values());
     61    is(codecs.length, expectedCodecs.length);
     62    isnot(codecs.length, 0);
     63    for (let i = 0; i < codecs.length; ++i) {
     64      compareCodecParam(codecs[i], expectedCodecs[i]);
     65    }
     66  }
     67 
     68  function checkCodecsAgainstSDPUnordered(codecs, msection) {
     69    const expectedCodecsMap = buildExpectedCodecs(msection);
     70    is(codecs.length, expectedCodecsMap.size);
     71    isnot(codecs.length, 0);
     72    for (const observed of codecs) {
     73      compareCodecParam(observed, expectedCodecsMap.get(observed.payloadType));
     74    }
     75  }
     76 
     77  async function getNumExpectedH264SendCodecs() {
     78    const h264Support = await checkPlatformH264CodecPrefs();
     79    if (h264Support.webrtc) {
     80      // Constrained Baseline and Baseline multiplied with packetization-mode 0 and 1.
     81      return 4;
     82    }
     83    ok(h264Support.platform, "There should always be some H264 support");
     84    // packetization-mode=0 is not supported with MediaDataEncoder.
     85    return 2;
     86  }
     87 
     88 // SDP with unusual values in fmtp, but in the same formatting that Firefox
     89 // typically uses. This lets us check that we're putting the right param values
     90 // in sdpFmtpLine, if not what appears in the SDP verbatim.
     91  const audioSdp = `v=0
     92 o=- 1878890426675213188 2 IN IP4 127.0.0.1
     93 s=-
     94 t=0 0
     95 a=fingerprint:sha-256 EB:74:E9:5F:EB:FB:79:D4:36:3A:06:89:DD:49:D0:C7:A5:EA:2A:B2:38:74:C8:AF:E4:A0:5A:EF:A9:58:B5:1A
     96 m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101
     97 c=IN IP4 0.0.0.0
     98 a=sendrecv
     99 a=fmtp:109 maxplaybackrate=48001;stereo=0;useinbandfec=0
    100 a=fmtp:101 0-14
    101 a=ice-pwd:60840251a559417c253d68478b0020fb
    102 a=ice-ufrag:741347dd
    103 a=mid:0
    104 a=msid:{0df6a81e-d3f8-4d0f-ab93-892762bd2af7} {b15b10a1-061b-4685-9ca4-99e110744b2e}
    105 a=rtcp-mux
    106 a=rtpmap:109 opus/48000/2
    107 a=rtpmap:9 G722/8000/1
    108 a=rtpmap:0 PCMU/8000
    109 a=rtpmap:8 PCMA/8000
    110 a=rtpmap:101 telephone-event/8000/1
    111 a=setup:passive
    112 `;
    113 
    114  let videoSdp;
    115  if (navigator.userAgent.includes("Android")) {
    116    // Alternate form with no packetization-mode=0 h264
    117    videoSdp  = `v=0
    118 o=- 1878890426675213188 2 IN IP4 127.0.0.1
    119 s=-
    120 t=0 0
    121 a=fingerprint:sha-256 EB:74:E9:5F:EB:FB:79:D4:36:3A:06:89:DD:49:D0:C7:A5:EA:2A:B2:38:74:C8:AF:E4:A0:5A:EF:A9:58:B5:1A
    122 m=video 9 UDP/TLS/RTP/SAVPF 121 125 120 124 126 127 105 106 123 122 119
    123 c=IN IP4 0.0.0.0
    124 a=sendonly
    125 a=fmtp:126 profile-level-id=42e00b;level-asymmetry-allowed=1;packetization-mode=1
    126 a=fmtp:105 profile-level-id=420015;level-asymmetry-allowed=1;packetization-mode=1
    127 a=fmtp:121 max-fs=12277;max-fr=50
    128 a=fmtp:125 apt=121
    129 a=fmtp:127 apt=126
    130 a=fmtp:106 apt=105
    131 a=fmtp:120 max-fs=12266;max-fr=40
    132 a=fmtp:124 apt=120
    133 a=fmtp:119 apt=122
    134 a=ice-pwd:60840251a559417c253d68478b0020fb
    135 a=ice-ufrag:741347dd
    136 a=mid:0
    137 a=msid:{debeb004-97f0-44ca-b6b2-a6bd8e42ddb2} {7fcd72c7-b112-49b4-892c-feee2cc9525d}
    138 a=rtcp-mux
    139 a=rtcp-rsize
    140 a=rtpmap:121 VP9/90000
    141 a=rtpmap:125 rtx/90000
    142 a=rtpmap:120 VP8/90000
    143 a=rtpmap:124 rtx/90000
    144 a=rtpmap:126 H264/90000
    145 a=rtpmap:127 rtx/90000
    146 a=rtpmap:105 H264/90000
    147 a=rtpmap:106 rtx/90000
    148 a=rtpmap:123 ulpfec/90000
    149 a=rtpmap:122 red/90000
    150 a=rtpmap:119 rtx/90000
    151 a=setup:passive
    152 `;
    153  } else {
    154    videoSdp  = `v=0
    155 o=- 1878890426675213188 2 IN IP4 127.0.0.1
    156 s=-
    157 t=0 0
    158 a=fingerprint:sha-256 EB:74:E9:5F:EB:FB:79:D4:36:3A:06:89:DD:49:D0:C7:A5:EA:2A:B2:38:74:C8:AF:E4:A0:5A:EF:A9:58:B5:1A
    159 m=video 9 UDP/TLS/RTP/SAVPF 121 125 120 124 126 127 97 98 105 106 103 104 123 122 119
    160 c=IN IP4 0.0.0.0
    161 a=sendonly
    162 a=fmtp:126 profile-level-id=42e00b;level-asymmetry-allowed=1;packetization-mode=1
    163 a=fmtp:97 profile-level-id=42e00b;level-asymmetry-allowed=1
    164 a=fmtp:105 profile-level-id=420015;level-asymmetry-allowed=1;packetization-mode=1
    165 a=fmtp:103 profile-level-id=420015;level-asymmetry-allowed=1
    166 a=fmtp:121 max-fs=12277;max-fr=50
    167 a=fmtp:125 apt=121
    168 a=fmtp:120 max-fs=12266;max-fr=40
    169 a=fmtp:124 apt=120
    170 a=fmtp:127 apt=126
    171 a=fmtp:98 apt=97
    172 a=fmtp:106 apt=105
    173 a=fmtp:104 apt=103
    174 a=fmtp:100 apt=99
    175 a=fmtp:119 apt=122
    176 a=ice-pwd:60840251a559417c253d68478b0020fb
    177 a=ice-ufrag:741347dd
    178 a=mid:0
    179 a=msid:{debeb004-97f0-44ca-b6b2-a6bd8e42ddb2} {7fcd72c7-b112-49b4-892c-feee2cc9525d}
    180 a=rtcp-mux
    181 a=rtcp-rsize
    182 a=rtpmap:121 VP9/90000
    183 a=rtpmap:125 rtx/90000
    184 a=rtpmap:120 VP8/90000
    185 a=rtpmap:124 rtx/90000
    186 a=rtpmap:126 H264/90000
    187 a=rtpmap:127 rtx/90000
    188 a=rtpmap:97 H264/90000
    189 a=rtpmap:98 rtx/90000
    190 a=rtpmap:105 H264/90000
    191 a=rtpmap:106 rtx/90000
    192 a=rtpmap:103 H264/90000
    193 a=rtpmap:104 rtx/90000
    194 a=rtpmap:123 ulpfec/90000
    195 a=rtpmap:122 red/90000
    196 a=rtpmap:119 rtx/90000
    197 a=setup:passive
    198 `;
    199  }
    200 
    201  let tests = [
    202    // fmtp testing in wpt requires a verbatim match, which we do not support
    203    // yet (see bug 1751671). These test that we have a semantic match at least,
    204    // because the sdp's fmtps use the same formatting that Firefox uses.
    205    // TODO(https://bugzilla.mozilla.org/show_bug.cgi?id=1751671)
    206    async function checkSenderFmtpAudioAnswerer() {
    207      const pc = new RTCPeerConnection();
    208      await pc.setRemoteDescription({sdp: audioSdp, type: 'offer'});
    209      await pc.setLocalDescription();
    210      const {codecs} = pc.getSenders()[0].getParameters();
    211      const sections = SDPUtils.splitSections(audioSdp);
    212      checkCodecsAgainstSDP(codecs, sections[1]);
    213    },
    214 
    215    async function checkSenderFmtpVideoAnswerer() {
    216      const pc = new RTCPeerConnection();
    217      await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
    218      await pc.setLocalDescription();
    219      const {codecs} = pc.getSenders()[0].getParameters();
    220      const sections = SDPUtils.splitSections(videoSdp);
    221      checkCodecsAgainstSDP(codecs, sections[1]);
    222    },
    223 
    224    async function checkSenderFmtpAudioOfferer() {
    225      const pc = new RTCPeerConnection();
    226      pc.addTransceiver('audio', { direction: 'sendrecv' });
    227      await pc.setLocalDescription();
    228      await pc.setRemoteDescription({sdp: audioSdp, type: 'answer'});
    229      const {codecs} = pc.getSenders()[0].getParameters();
    230      const sections = SDPUtils.splitSections(audioSdp);
    231      checkCodecsAgainstSDP(codecs, sections[1]);
    232    },
    233 
    234    async function checkSenderFmtpVideoOfferer() {
    235      const pc = new RTCPeerConnection();
    236      pc.addTransceiver('video', { direction: 'sendrecv' });
    237      await pc.setLocalDescription();
    238      await pc.setRemoteDescription({sdp: videoSdp, type: 'answer'});
    239      const {codecs} = pc.getSenders()[0].getParameters();
    240      const sections = SDPUtils.splitSections(videoSdp);
    241      checkCodecsAgainstSDP(codecs, sections[1]);
    242    },
    243 
    244    // wpt does not allow us to test that .codecs omits things that the pref
    245    // system has disabled
    246    async function checkRedUlpfecDisabled() {
    247      await withPrefs([["media.navigator.video.red_ulpfec_enabled", false]], async () => {
    248          const pc = new RTCPeerConnection();
    249          await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
    250          await pc.setLocalDescription();
    251          const {codecs} = pc.getSenders()[0].getParameters();
    252          // Control
    253          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp8'), true);
    254          // No red or ulpfec
    255          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/red'), false);
    256          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/ulpfec'), false);
    257        }
    258      );
    259    },
    260 
    261    async function checkRtxDisabled() {
    262      await withPrefs([["media.peerconnection.video.use_rtx", false]], async () => {
    263          const pc = new RTCPeerConnection();
    264          await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
    265          await pc.setLocalDescription();
    266          const {codecs} = pc.getSenders()[0].getParameters();
    267          // Control
    268          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp8'), true);
    269          // No rtx
    270          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/rtx'), false);
    271        }
    272      );
    273    },
    274 
    275    async function checkVP9Disabled() {
    276      await withPrefs([["media.peerconnection.video.vp9_enabled", false]], async () => {
    277          const pc = new RTCPeerConnection();
    278          await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
    279          await pc.setLocalDescription();
    280          const {codecs} = pc.getSenders()[0].getParameters();
    281          // Control
    282          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp8'), true);
    283          // No VP9
    284          is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp9'), false);
    285        }
    286      );
    287    },
    288 
    289    async function checkH264Sender() {
    290      const numExpectedH264Codecs = await getNumExpectedH264SendCodecs();
    291      const pc1 = new RTCPeerConnection();
    292      const pc2 = new RTCPeerConnection();
    293      const {sender} = pc1.addTransceiver('video');
    294      await pc1.setLocalDescription();
    295      await pc2.setRemoteDescription(pc1.localDescription);
    296      await pc2.setLocalDescription();
    297      await pc1.setRemoteDescription(pc2.localDescription);
    298      {
    299        const {codecs} = pc1.getSenders()[0].getParameters();
    300        info("pc1 codecs: " + JSON.stringify(codecs, null, 2));
    301        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    302        const sections = SDPUtils.splitSections(pc1.remoteDescription.sdp);
    303        info("pc1 msection: " + sections[1].replace(/\r\n/g, "\n"));
    304        checkCodecsAgainstSDP(codecs, sections[1]);
    305      }
    306 
    307      {
    308        const {codecs} = pc2.getSenders()[0].getParameters();
    309        info("pc2 codecs: " + JSON.stringify(codecs, null, 2));
    310        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    311        const sections = SDPUtils.splitSections(pc2.remoteDescription.sdp);
    312        info("pc2 msection: " + sections[1].replace(/\r\n/g, "\n"));
    313        checkCodecsAgainstSDP(codecs, sections[1]);
    314      }
    315    },
    316 
    317    async function checkH264Receiver() {
    318      const numExpectedH264Codecs = await getNumExpectedH264SendCodecs();
    319      const pc1 = new RTCPeerConnection();
    320      const pc2 = new RTCPeerConnection();
    321      pc1.addTransceiver('video');
    322      await pc1.setLocalDescription();
    323      await pc2.setRemoteDescription(pc1.localDescription);
    324      await pc2.setLocalDescription();
    325      await pc1.setRemoteDescription(pc2.localDescription);
    326      {
    327        const {codecs} = pc1.getReceivers()[0].getParameters();
    328        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    329        const sections = SDPUtils.splitSections(pc1.localDescription.sdp);
    330        checkCodecsAgainstSDP(codecs, sections[1]);
    331      }
    332 
    333      {
    334        const {codecs} = pc2.getReceivers()[0].getParameters();
    335        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    336        const sections = SDPUtils.splitSections(pc2.localDescription.sdp);
    337        checkCodecsAgainstSDP(codecs, sections[1]);
    338      }
    339    },
    340 
    341    async function checkH264Unidirectional() {
    342      const numExpectedH264Codecs = await getNumExpectedH264SendCodecs();
    343      const pc1 = new RTCPeerConnection();
    344      const pc2 = new RTCPeerConnection();
    345      pc1.addTransceiver('video', {direction: 'recvonly'});
    346      await pc1.setLocalDescription();
    347      {
    348        const sections = SDPUtils.splitSections(pc1.localDescription.sdp);
    349        const {codecs} = SDPUtils.parseRtpParameters(sections[1]);
    350        is(codecs.filter(c => c.name.toLowerCase() == 'h264').length, 4);
    351      }
    352 
    353      await pc2.setRemoteDescription(pc1.localDescription);
    354      pc2.getTransceivers()[0].direction = 'sendonly';
    355      await pc2.setLocalDescription();
    356      await pc1.setRemoteDescription(pc2.localDescription);
    357      {
    358        const {codecs} = pc1.getReceivers()[0].getParameters();
    359        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, 4);
    360        const sections = SDPUtils.splitSections(pc1.localDescription.sdp);
    361        checkCodecsAgainstSDPUnordered(codecs, sections[1]);
    362      }
    363 
    364      {
    365        const {codecs} = pc2.getSenders()[0].getParameters();
    366        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    367        const sections = SDPUtils.splitSections(pc2.localDescription.sdp);
    368        checkCodecsAgainstSDP(codecs, sections[1]);
    369      }
    370    },
    371 
    372    async function checkH264NoLevelAsymmetryInOffer() {
    373      const numExpectedH264Codecs = await getNumExpectedH264SendCodecs();
    374      const pc1 = new RTCPeerConnection();
    375      const pc2 = new RTCPeerConnection();
    376      pc1.addTransceiver('video');
    377      await pc1.setLocalDescription();
    378      const mungedOffer = {
    379        sdp: pc1.localDescription.sdp.replace(/level-asymmetry-allowed=1/g, 'level-asymmetry-allowed=0'),
    380        type: 'offer'
    381      };
    382      await pc2.setRemoteDescription(mungedOffer);
    383      await pc2.setLocalDescription();
    384      {
    385        const {codecs} = pc2.getSenders()[0].getParameters();
    386        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    387        const sections = SDPUtils.splitSections(pc2.remoteDescription.sdp);
    388        checkCodecsAgainstSDP(codecs, sections[1]);
    389      }
    390 
    391      {
    392        const {codecs} = pc2.getReceivers()[0].getParameters();
    393        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    394        const sections = SDPUtils.splitSections(pc2.localDescription.sdp);
    395        checkCodecsAgainstSDP(codecs, sections[1]);
    396      }
    397    },
    398 
    399    async function checkH264NoLevelAsymmetryInAnswer() {
    400      const numExpectedH264Codecs = await getNumExpectedH264SendCodecs();
    401      const pc1 = new RTCPeerConnection();
    402      const pc2 = new RTCPeerConnection();
    403      pc1.addTransceiver('video');
    404      await pc1.setLocalDescription();
    405      await pc2.setRemoteDescription(pc1.localDescription);
    406      await pc2.setLocalDescription();
    407      const mungedAnswer = {
    408        sdp: pc2.localDescription.sdp.replace(/level-asymmetry-allowed=1/g, 'level-asymmetry-allowed=0'),
    409        type: 'answer'
    410      };
    411      await pc1.setRemoteDescription(mungedAnswer);
    412      {
    413        const {codecs} = pc1.getSenders()[0].getParameters();
    414        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    415        const sections = SDPUtils.splitSections(pc1.remoteDescription.sdp);
    416        checkCodecsAgainstSDP(codecs, sections[1]);
    417      }
    418 
    419      {
    420        const {codecs} = pc1.getReceivers()[0].getParameters();
    421        is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
    422        const sections = SDPUtils.splitSections(pc1.localDescription.sdp);
    423        checkCodecsAgainstSDP(codecs, sections[1]);
    424      }
    425    },
    426  ];
    427 
    428  runNetworkTest(async () => {
    429    await SpecialPowers.pushPrefEnv({ set: [["media.navigator.video.disable_h264_baseline", false]] });
    430    for (const test of tests) {
    431      info(`Running test: ${test.name}`);
    432      await test();
    433      info(`Done running test: ${test.name}`);
    434    }
    435  });
    436 
    437 </script>
    438 </pre>
    439 </body>
    440 </html>