Source code

Revision control

Copy as Markdown

Other Tools

'use strict';
// Test is based on the following editor draft:
// Code using this helper should also include RTCPeerConnection-helper.js
// in the main HTML file
// The following helper functions are called from RTCPeerConnection-helper.js:
// getTrackFromUserMedia
// exchangeOfferAnswer
// Create a RTCDTMFSender using getUserMedia()
// Connect the PeerConnection to another PC and wait until it is
// properly connected, so that DTMF can be sent.
function createDtmfSender(pc = new RTCPeerConnection()) {
let dtmfSender;
return getTrackFromUserMedia('audio')
.then(([track, mediaStream]) => {
const sender = pc.addTrack(track, mediaStream);
dtmfSender = sender.dtmf;
assert_true(dtmfSender instanceof RTCDTMFSender,
'Expect audio sender.dtmf to be set to a RTCDTMFSender');
// on whether sending should be possible before negotiation.
const pc2 = new RTCPeerConnection();
Object.defineProperty(pc, 'otherPc', { value: pc2 });
exchangeIceCandidates(pc, pc2);
return exchangeOfferAnswer(pc, pc2);
}).then(() => {
if (!('canInsertDTMF' in dtmfSender)) {
return Promise.resolve();
}
// Wait until dtmfSender.canInsertDTMF becomes true.
// Up to 150 ms has been observed in test. Wait 1 second
// in steps of 10 ms.
// Note: Using a short timeout and rejected promise in order to
// make test return a clear error message on failure.
return new Promise((resolve, reject) => {
let counter = 0;
step_timeout(function checkCanInsertDTMF() {
if (dtmfSender.canInsertDTMF) {
resolve();
} else {
if (counter >= 100) {
reject('Waited too long for canInsertDTMF');
return;
}
++counter;
step_timeout(checkCanInsertDTMF, 10);
}
}, 0);
});
}).then(() => {
return dtmfSender;
});
}
/*
Create an RTCDTMFSender and test tonechange events on it.
testFunc
Test function that is going to manipulate the DTMFSender.
It will be called with:
t - the test object
sender - the created RTCDTMFSender
pc - the associated RTCPeerConnection as second argument.
toneChanges
Array of expected tonechange events fired. The elements
are array of 3 items:
expectedTone
The expected character in event.tone
expectedToneBuffer
The expected new value of dtmfSender.toneBuffer
expectedDuration
The rough time since beginning or last tonechange event
was fired.
desc
Test description.
*/
function test_tone_change_events(testFunc, toneChanges, desc) {
// Convert to cumulative time
let cumulativeTime = 0;
const cumulativeToneChanges = toneChanges.map(c => {
cumulativeTime += c[2];
return [c[0], c[1], cumulativeTime];
});
// Wait for same duration as last expected duration + 100ms
// before passing test in case there are new tone events fired,
// in which case the test should fail.
const lastWait = toneChanges.pop()[2] + 100;
promise_test(async t => {
const pc = new RTCPeerConnection();
const dtmfSender = await createDtmfSender(pc);
const start = Date.now();
const allEventsReceived = new Promise(resolve => {
const onToneChange = t.step_func(ev => {
assert_true(ev instanceof RTCDTMFToneChangeEvent,
'Expect tone change event object to be an RTCDTMFToneChangeEvent');
const { tone } = ev;
assert_equals(typeof tone, 'string',
'Expect event.tone to be the tone string');
assert_greater_than(cumulativeToneChanges.length, 0,
'More tonechange event is fired than expected');
const [
expectedTone, expectedToneBuffer, expectedTime
] = cumulativeToneChanges.shift();
assert_equals(tone, expectedTone,
`Expect current event.tone to be ${expectedTone}`);
assert_equals(dtmfSender.toneBuffer, expectedToneBuffer,
`Expect dtmfSender.toneBuffer to be updated to ${expectedToneBuffer}`);
// We check that the cumulative delay is at least the expected one.
// Note that as a UA optimization events can fire a bit (<1ms) early,
// and system load may cause random delays. We therefore allow events
// to be 1ms early and do not put any realistic expectation on the upper
// bound of their timing.
assert_between_inclusive(Date.now() - start, Math.max(0, expectedTime - 1),
expectedTime + 4000,
`Expect tonechange event for "${tone}" to be fired approximately after ${expectedTime} milliseconds`);
if (cumulativeToneChanges.length === 0) {
resolve();
}
});
dtmfSender.addEventListener('tonechange', onToneChange);
});
testFunc(t, dtmfSender, pc);
await allEventsReceived;
const wait = ms => new Promise(resolve => t.step_timeout(resolve, ms));
await wait(lastWait);
}, desc);
}
// Get the one and only tranceiver from pc.getTransceivers().
// Assumes that there is only one tranceiver in pc.
function getTransceiver(pc) {
const transceivers = pc.getTransceivers();
assert_equals(transceivers.length, 1,
'Expect there to be only one tranceiver in pc');
return transceivers[0];
}