RTCDTMFSender-insertDTMF.https.html (6345B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>RTCDTMFSender.prototype.insertDTMF</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="RTCPeerConnection-helper.js"></script> 7 <script src="RTCDTMFSender-helper.js"></script> 8 <script> 9 'use strict'; 10 11 // Test is based on the following editor draft: 12 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html 13 14 // The following helper functions are called from RTCPeerConnection-helper.js 15 // generateAnswer 16 17 // The following helper functions are called from RTCDTMFSender-helper.js 18 // createDtmfSender 19 // test_tone_change_events 20 // getTransceiver 21 22 /* 23 7. Peer-to-peer DTMF 24 partial interface RTCRtpSender { 25 readonly attribute RTCDTMFSender? dtmf; 26 }; 27 28 interface RTCDTMFSender : EventTarget { 29 void insertDTMF(DOMString tones, 30 optional unsigned long duration = 100, 31 optional unsigned long interToneGap = 70); 32 attribute EventHandler ontonechange; 33 readonly attribute DOMString toneBuffer; 34 }; 35 */ 36 37 /* 38 7.2. insertDTMF 39 The tones parameter is treated as a series of characters. 40 41 The characters 0 through 9, A through D, #, and * generate the associated 42 DTMF tones. 43 44 The characters a to d MUST be normalized to uppercase on entry and are 45 equivalent to A to D. 46 47 As noted in [RTCWEB-AUDIO] Section 3, support for the characters 0 through 9, 48 A through D, #, and * are required. 49 50 The character ',' MUST be supported, and indicates a delay of 2 seconds 51 before processing the next character in the tones parameter. 52 53 All other characters (and only those other characters) MUST be considered 54 unrecognized. 55 */ 56 promise_test(async t => { 57 const dtmfSender = await createDtmfSender(); 58 dtmfSender.insertDTMF(''); 59 dtmfSender.insertDTMF('012345689'); 60 dtmfSender.insertDTMF('ABCD'); 61 dtmfSender.insertDTMF('abcd'); 62 dtmfSender.insertDTMF('#*'); 63 dtmfSender.insertDTMF(','); 64 dtmfSender.insertDTMF('0123456789ABCDabcd#*,'); 65 }, 'insertDTMF() should succeed if tones contains valid DTMF characters'); 66 67 68 /* 69 7.2. insertDTMF 70 6. If tones contains any unrecognized characters, throw an 71 InvalidCharacterError. 72 */ 73 promise_test(async t => { 74 const dtmfSender = await createDtmfSender(); 75 assert_throws_dom('InvalidCharacterError', () => 76 // 'F' is invalid 77 dtmfSender.insertDTMF('123FFABC')); 78 79 assert_throws_dom('InvalidCharacterError', () => 80 // 'E' is invalid 81 dtmfSender.insertDTMF('E')); 82 83 assert_throws_dom('InvalidCharacterError', () => 84 // ' ' is invalid 85 dtmfSender.insertDTMF('# *')); 86 }, 'insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters'); 87 88 /* 89 7.2. insertDTMF 90 3. If transceiver.stopped is true, throw an InvalidStateError. 91 */ 92 test(t => { 93 const pc = new RTCPeerConnection(); 94 const transceiver = pc.addTransceiver('audio'); 95 const dtmfSender = transceiver.sender.dtmf; 96 97 transceiver.stop(); 98 assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF('')); 99 100 }, 'insertDTMF() should throw InvalidStateError if transceiver is stopped'); 101 102 /* 103 7.2. insertDTMF 104 4. If transceiver.currentDirection is recvonly or inactive, throw an InvalidStateError. 105 */ 106 promise_test(async t => { 107 const caller = new RTCPeerConnection(); 108 t.add_cleanup(() => caller.close()); 109 const callee = new RTCPeerConnection(); 110 t.add_cleanup(() => callee.close()); 111 const transceiver = 112 caller.addTransceiver('audio', { direction: 'recvonly' }); 113 const dtmfSender = transceiver.sender.dtmf; 114 115 const offer = await caller.createOffer(); 116 await caller.setLocalDescription(offer); 117 await callee.setRemoteDescription(offer); 118 const stream = await getNoiseStream({audio: true}); 119 t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); 120 const [track] = stream.getTracks(); 121 callee.addTrack(track, stream); 122 const answer = await callee.createAnswer(); 123 await callee.setLocalDescription(answer); 124 await caller.setRemoteDescription(answer); 125 assert_equals(transceiver.currentDirection, 'recvonly'); 126 assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF('')); 127 }, 'insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly'); 128 129 promise_test(async t => { 130 const pc = new RTCPeerConnection(); 131 t.add_cleanup(() => pc.close()); 132 const transceiver = 133 pc.addTransceiver('audio', { direction: 'inactive' }); 134 const dtmfSender = transceiver.sender.dtmf; 135 136 const offer = await pc.createOffer(); 137 await pc.setLocalDescription(offer); 138 const answer = await generateAnswer(offer); 139 await pc.setRemoteDescription(answer); 140 assert_equals(transceiver.currentDirection, 'inactive'); 141 assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF('')); 142 }, 'insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive'); 143 144 /* 145 7.2. insertDTMF 146 The characters a to d MUST be normalized to uppercase on entry and are 147 equivalent to A to D. 148 149 7. Set the object's toneBuffer attribute to tones. 150 */ 151 promise_test(async t => { 152 const dtmfSender = await createDtmfSender(); 153 dtmfSender.insertDTMF('123'); 154 assert_equals(dtmfSender.toneBuffer, '123'); 155 156 dtmfSender.insertDTMF('ABC'); 157 assert_equals(dtmfSender.toneBuffer, 'ABC'); 158 159 dtmfSender.insertDTMF('bcd'); 160 assert_equals(dtmfSender.toneBuffer, 'BCD'); 161 }, 'insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden'); 162 163 promise_test(async t => { 164 const pc = new RTCPeerConnection(); 165 t.add_cleanup(() => pc.close()); 166 const [track, mediaStream] = await getTrackFromUserMedia('audio'); 167 const sender = pc.addTrack(track, mediaStream); 168 await pc.setLocalDescription(await pc.createOffer()); 169 const dtmfSender = sender.dtmf; 170 pc.removeTrack(sender); 171 pc.close(); 172 assert_throws_dom('InvalidStateError', () => 173 dtmfSender.insertDTMF('123')); 174 }, 'insertDTMF() after remove and close should reject'); 175 176 </script>