tor-browser

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

RTCDTMFSender-helper.js (5483B)


      1 'use strict';
      2 
      3 // Test is based on the following editor draft:
      4 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
      5 
      6 // Code using this helper should also include RTCPeerConnection-helper.js
      7 // in the main HTML file
      8 
      9 // The following helper functions are called from RTCPeerConnection-helper.js:
     10 //   getTrackFromUserMedia
     11 //   exchangeOfferAnswer
     12 
     13 // Create a RTCDTMFSender using getUserMedia()
     14 // Connect the PeerConnection to another PC and wait until it is
     15 // properly connected, so that DTMF can be sent.
     16 function createDtmfSender(pc = new RTCPeerConnection()) {
     17  let dtmfSender;
     18  return getTrackFromUserMedia('audio')
     19  .then(([track, mediaStream]) => {
     20    const sender = pc.addTrack(track, mediaStream);
     21    dtmfSender = sender.dtmf;
     22    assert_true(dtmfSender instanceof RTCDTMFSender,
     23                'Expect audio sender.dtmf to be set to a RTCDTMFSender');
     24    // Note: spec bug open - https://github.com/w3c/webrtc-pc/issues/1774
     25    // on whether sending should be possible before negotiation.
     26    const pc2 = new RTCPeerConnection();
     27    Object.defineProperty(pc, 'otherPc', { value: pc2 });
     28    exchangeIceCandidates(pc, pc2);
     29    return exchangeOfferAnswer(pc, pc2);
     30  }).then(() => {
     31    if (!('canInsertDTMF' in dtmfSender)) {
     32      return Promise.resolve();
     33    }
     34    // Wait until dtmfSender.canInsertDTMF becomes true.
     35    // Up to 150 ms has been observed in test. Wait 1 second
     36    // in steps of 10 ms.
     37    // Note: Using a short timeout and rejected promise in order to
     38    // make test return a clear error message on failure.
     39    return new Promise((resolve, reject) => {
     40      let counter = 0;
     41      step_timeout(function checkCanInsertDTMF() {
     42        if (dtmfSender.canInsertDTMF) {
     43          resolve();
     44        } else {
     45          if (counter >= 100) {
     46            reject('Waited too long for canInsertDTMF');
     47            return;
     48          }
     49          ++counter;
     50          step_timeout(checkCanInsertDTMF, 10);
     51        }
     52      }, 0);
     53    });
     54  }).then(() => {
     55    return dtmfSender;
     56  });
     57 }
     58 
     59 /*
     60  Create an RTCDTMFSender and test tonechange events on it.
     61    testFunc
     62      Test function that is going to manipulate the DTMFSender.
     63      It will be called with:
     64        t - the test object
     65        sender - the created RTCDTMFSender
     66        pc - the associated RTCPeerConnection as second argument.
     67    toneChanges
     68      Array of expected tonechange events fired. The elements
     69      are array of 3 items:
     70        expectedTone
     71          The expected character in event.tone
     72        expectedToneBuffer
     73          The expected new value of dtmfSender.toneBuffer
     74        expectedDuration
     75          The rough time since beginning or last tonechange event
     76          was fired.
     77    desc
     78      Test description.
     79 */
     80 function test_tone_change_events(testFunc, toneChanges, desc) {
     81  // Convert to cumulative time
     82  let cumulativeTime = 0;
     83  const cumulativeToneChanges = toneChanges.map(c => {
     84    cumulativeTime += c[2];
     85    return [c[0], c[1], cumulativeTime];
     86  });
     87 
     88  // Wait for same duration as last expected duration + 100ms
     89  // before passing test in case there are new tone events fired,
     90  // in which case the test should fail.
     91  const lastWait = toneChanges.pop()[2] + 100;
     92 
     93  promise_test(async t => {
     94    const pc = new RTCPeerConnection();
     95    const dtmfSender = await createDtmfSender(pc);
     96    const start = Date.now();
     97 
     98    const allEventsReceived = new Promise(resolve => {
     99      const onToneChange = t.step_func(ev => {
    100        assert_true(ev instanceof RTCDTMFToneChangeEvent,
    101          'Expect tone change event object to be an RTCDTMFToneChangeEvent');
    102 
    103        const { tone } = ev;
    104        assert_equals(typeof tone, 'string',
    105          'Expect event.tone to be the tone string');
    106 
    107        assert_greater_than(cumulativeToneChanges.length, 0,
    108          'More tonechange event is fired than expected');
    109 
    110        const [
    111          expectedTone, expectedToneBuffer, expectedTime
    112        ] = cumulativeToneChanges.shift();
    113 
    114        assert_equals(tone, expectedTone,
    115          `Expect current event.tone to be ${expectedTone}`);
    116 
    117        assert_equals(dtmfSender.toneBuffer, expectedToneBuffer,
    118          `Expect dtmfSender.toneBuffer to be updated to ${expectedToneBuffer}`);
    119 
    120        // We check that the cumulative delay is at least the expected one.
    121        // Note that as a UA optimization events can fire a bit (<1ms) early,
    122        // and system load may cause random delays. We therefore allow events
    123        // to be 1ms early and do not put any realistic expectation on the upper
    124        // bound of their timing.
    125        assert_between_inclusive(Date.now() - start, Math.max(0, expectedTime - 1),
    126                                 expectedTime + 4000,
    127          `Expect tonechange event for "${tone}" to be fired approximately after ${expectedTime} milliseconds`);
    128        if (cumulativeToneChanges.length === 0) {
    129          resolve();
    130        }
    131      });
    132 
    133      dtmfSender.addEventListener('tonechange', onToneChange);
    134    });
    135 
    136    testFunc(t, dtmfSender, pc);
    137    await allEventsReceived;
    138    const wait = ms => new Promise(resolve => t.step_timeout(resolve, ms));
    139    await wait(lastWait);
    140  }, desc);
    141 }
    142 
    143 // Get the one and only tranceiver from pc.getTransceivers().
    144 // Assumes that there is only one tranceiver in pc.
    145 function getTransceiver(pc) {
    146  const transceivers = pc.getTransceivers();
    147  assert_equals(transceivers.length, 1,
    148    'Expect there to be only one tranceiver in pc');
    149 
    150  return transceivers[0];
    151 }