diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCDTMFSender-ontonechange.https.html')
-rw-r--r-- | testing/web-platform/tests/webrtc/RTCDTMFSender-ontonechange.https.html | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCDTMFSender-ontonechange.https.html b/testing/web-platform/tests/webrtc/RTCDTMFSender-ontonechange.https.html new file mode 100644 index 0000000000..08dd6ada32 --- /dev/null +++ b/testing/web-platform/tests/webrtc/RTCDTMFSender-ontonechange.https.html @@ -0,0 +1,294 @@ +<!doctype html> +<meta charset=utf-8> +<title>RTCDTMFSender.prototype.ontonechange</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="RTCPeerConnection-helper.js"></script> +<script src="RTCDTMFSender-helper.js"></script> +<script> + 'use strict'; + + // Test is based on the following editor draft: + // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html + + // The following helper functions are called from RTCPeerConnection-helper.js + // generateAnswer + + // The following helper functions are called from RTCDTMFSender-helper.js + // test_tone_change_events + // getTransceiver + + /* + 7. Peer-to-peer DTMF + partial interface RTCRtpSender { + readonly attribute RTCDTMFSender? dtmf; + }; + + interface RTCDTMFSender : EventTarget { + void insertDTMF(DOMString tones, + optional unsigned long duration = 100, + optional unsigned long interToneGap = 70); + attribute EventHandler ontonechange; + readonly attribute DOMString toneBuffer; + }; + + [Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)] + interface RTCDTMFToneChangeEvent : Event { + readonly attribute DOMString tone; + }; + */ + + /* + 7.2. insertDTMF + 11. If a Playout task is scheduled to be run; abort these steps; otherwise queue + a task that runs the following steps (Playout task): + 3. If toneBuffer is an empty string, fire an event named tonechange with an + empty string at the RTCDTMFSender object and abort these steps. + 4. Remove the first character from toneBuffer and let that character be tone. + 6. Queue a task to be executed in duration + interToneGap ms from now that + runs the steps labelled Playout task. + 7. Fire an event named tonechange with a string consisting of tone at the + RTCDTMFSender object. + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.insertDTMF('123'); + }, [ + ['1', '23', 0], + ['2', '3', 170], + ['3', '', 170], + ['', '', 170] + ], 'insertDTMF() with default duration and intertoneGap should fire tonechange events at the expected time'); + + test_tone_change_events((t, dtmfSender) => { + dtmfSender.insertDTMF('abc', 100, 70); + }, [ + ['A', 'BC', 0], + ['B', 'C', 170], + ['C', '', 170], + ['', '', 170] + ], 'insertDTMF() with explicit duration and intertoneGap should fire tonechange events at the expected time'); + + /* + 7.2. insertDTMF + 10. If toneBuffer is an empty string, abort these steps. + */ + async_test(t => { + createDtmfSender() + .then(dtmfSender => { + dtmfSender.addEventListener('tonechange', + t.unreached_func('Expect no tonechange event to be fired')); + + dtmfSender.insertDTMF('', 100, 70); + + t.step_timeout(t.step_func_done(), 300); + }) + .catch(t.step_func(err => { + assert_unreached(`Unexpected promise rejection: ${err}`); + })); + }, `insertDTMF('') should not fire any tonechange event, including for '' tone`); + + /* + 7.2. insertDTMF + 8. If the value of the duration parameter is less than 40, set it to 40. + If, on the other hand, the value is greater than 6000, set it to 6000. + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.insertDTMF('ABC', 10, 70); + }, [ + ['A', 'BC', 0], + ['B', 'C', 110], + ['C', '', 110], + ['', '', 110] + ], 'insertDTMF() with duration less than 40 should be clamped to 40'); + + /* + 7.2. insertDTMF + 9. If the value of the interToneGap parameter is less than 30, set it to 30. + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.insertDTMF('ABC', 100, 10); + }, [ + ['A', 'BC', 0], + ['B', 'C', 130], + ['C', '', 130], + ['', '', 130] + ], + 'insertDTMF() with interToneGap less than 30 should be clamped to 30'); + + /* + [w3c/webrtc-pc#1373] + This step is added to handle the "," character correctly. "," supposed to delay the next + tonechange event by 2000ms. + + 7.2. insertDTMF + 11.5. If tone is "," delay sending tones for 2000 ms on the associated RTP media + stream, and queue a task to be executed in 2000 ms from now that runs the + steps labelled Playout task. + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.insertDTMF('A,B', 100, 70); + + }, [ + ['A', ',B', 0], + [',', 'B', 170], + ['B', '', 2000], + ['', '', 170] + ], 'insertDTMF with comma should delay next tonechange event for a constant 2000ms'); + + /* + 7.2. insertDTMF + 11.1. If transceiver.stopped is true, abort these steps. + */ + test_tone_change_events((t, dtmfSender, pc) => { + const transceiver = getTransceiver(pc); + dtmfSender.addEventListener('tonechange', ev => { + if(ev.tone === 'B') { + transceiver.stop(); + } + }); + + dtmfSender.insertDTMF('ABC', 100, 70); + }, [ + ['A', 'BC', 0], + ['B', 'C', 170] + ], 'insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing'); + + /* + 7.2. insertDTMF + 3. If a Playout task is scheduled to be run, abort these steps; + otherwise queue a task that runs the following steps (Playout task): + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.addEventListener('tonechange', ev => { + if(ev.tone === 'B') { + dtmfSender.insertDTMF('12', 100, 70); + } + }); + + dtmfSender.insertDTMF('ABC', 100, 70); + }, [ + ['A', 'BC', 0], + ['B', 'C', 170], + ['1', '2', 170], + ['2', '', 170], + ['', '', 170] + ], 'Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones'); + + + /* + 7.2. insertDTMF + 3. If a Playout task is scheduled to be run, abort these steps; + otherwise queue a task that runs the following steps (Playout task): + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.addEventListener('tonechange', ev => { + if(ev.tone === 'B') { + dtmfSender.insertDTMF('12', 100, 70); + dtmfSender.insertDTMF('34', 100, 70); + } + }); + + dtmfSender.insertDTMF('ABC', 100, 70); + }, [ + ['A', 'BC', 0], + ['B', 'C', 170], + ['3', '4', 170], + ['4', '', 170], + ['', '', 170] + ], 'Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones'); + + /* + 7.2. insertDTMF + 3. If a Playout task is scheduled to be run, abort these steps; + otherwise queue a task that runs the following steps (Playout task): + */ + test_tone_change_events((t, dtmfSender) => { + dtmfSender.addEventListener('tonechange', ev => { + if(ev.tone === 'B') { + dtmfSender.insertDTMF(''); + } + }); + + dtmfSender.insertDTMF('ABC', 100, 70); + }, [ + ['A', 'BC', 0], + ['B', 'C', 170], + ['', '', 170] + ], `Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing`); + + /* + 7.2. insertDTMF + 11.2. If transceiver.currentDirection is recvonly or inactive, abort these steps. + */ + promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const dtmfSender = await createDtmfSender(pc); + const pc2 = pc.otherPc; + assert_true(pc2 instanceof RTCPeerConnection, + 'Expect pc2 to be a RTCPeerConnection'); + t.add_cleanup(() => pc2.close()); + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.sender.dtmf, dtmfSender); + + // Since setRemoteDescription happens in parallel with tonechange event, + // We use a flag and allow tonechange events to be fired as long as + // the promise returned by setRemoteDescription is not yet resolved. + let remoteDescriptionIsSet = false; + + // We only do basic tone verification and not check timing here + let expectedTones = ['A', 'B', 'C', 'D', '']; + + const firstTone = new Promise(resolve => { + const onToneChange = t.step_func(ev => { + assert_false(remoteDescriptionIsSet, + 'Expect no tonechange event to be fired after currentDirection is changed to recvonly'); + + const { tone } = ev; + const expectedTone = expectedTones.shift(); + assert_equals(tone, expectedTone, + `Expect fired event.tone to be ${expectedTone}`); + + if(tone === 'A') { + resolve(); + } + }); + dtmfSender.addEventListener('tonechange', onToneChange); + }); + + dtmfSender.insertDTMF('ABCD', 100, 70); + await firstTone; + + // Only change transceiver.direction after the first + // tonechange event, to make sure that tonechange is triggered + // then stopped + transceiver.direction = 'recvonly'; + await exchangeOfferAnswer(pc, pc2); + assert_equals(transceiver.currentDirection, 'inactive'); + remoteDescriptionIsSet = true; + + await new Promise(resolve => t.step_timeout(resolve, 300)); + }, `Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing`); + + /* Section 7.3 - Tone change event */ + test(t => { + let ev = new RTCDTMFToneChangeEvent('tonechange', {'tone': '1'}); + assert_equals(ev.type, 'tonechange'); + assert_equals(ev.tone, '1'); + }, 'Tone change event constructor works'); + + test(t => { + let ev = new RTCDTMFToneChangeEvent('worngname', {}); + }, 'Tone change event with unexpected name should not crash'); + + test(t => { + const ev1 = new RTCDTMFToneChangeEvent('tonechange', {}); + assert_equals(ev1.tone, ''); + + assert_equals(RTCDTMFToneChangeEvent.constructor.length, 1); + const ev2 = new RTCDTMFToneChangeEvent('tonechange'); + assert_equals(ev2.tone, ''); + }, 'Tone change event init optional parameters'); + +</script> |