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 }