head.js (5033B)
1 "use strict"; 2 3 const DEFAULT_AUDIO_SAMPLE_FILE = "hello.ogg"; 4 const SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC = 5 "SpeechRecognitionTest:RequestEvent"; 6 const SPEECH_RECOGNITION_TEST_END_TOPIC = "SpeechRecognitionTest:End"; 7 8 var errorCodes = { 9 NO_SPEECH: "no-speech", 10 ABORTED: "aborted", 11 AUDIO_CAPTURE: "audio-capture", 12 NETWORK: "network", 13 NOT_ALLOWED: "not-allowed", 14 SERVICE_NOT_ALLOWED: "service-not-allowed", 15 BAD_GRAMMAR: "bad-grammar", 16 LANGUAGE_NOT_SUPPORTED: "language-not-supported", 17 }; 18 19 var Services = SpecialPowers.Services; 20 21 function EventManager(sr) { 22 var self = this; 23 var nEventsExpected = 0; 24 self.eventsReceived = []; 25 26 var allEvents = [ 27 "audiostart", 28 "soundstart", 29 "speechstart", 30 "speechend", 31 "soundend", 32 "audioend", 33 "result", 34 "nomatch", 35 "error", 36 "start", 37 "end", 38 ]; 39 40 var eventDependencies = { 41 speechend: "speechstart", 42 soundend: "soundstart", 43 audioend: "audiostart", 44 }; 45 46 var isDone = false; 47 48 // set up grammar 49 var sgl = new SpeechGrammarList(); 50 sgl.addFromString("#JSGF V1.0; grammar test; public <simple> = hello ;", 1); 51 sr.grammars = sgl; 52 53 // AUDIO_DATA events are asynchronous, 54 // so we queue events requested while they are being 55 // issued to make them seem synchronous 56 var isSendingAudioData = false; 57 var queuedEventRequests = []; 58 59 // register default handlers 60 for (var i = 0; i < allEvents.length; i++) { 61 (function (eventName) { 62 sr["on" + eventName] = function (evt) { 63 var message = "unexpected event: " + eventName; 64 if (eventName == "error") { 65 message += " -- " + evt.message; 66 } 67 68 ok(false, message); 69 if (self.doneFunc && !isDone) { 70 isDone = true; 71 self.doneFunc(); 72 } 73 }; 74 })(allEvents[i]); 75 } 76 77 self.expect = function EventManager_expect(eventName, cb) { 78 nEventsExpected++; 79 80 sr["on" + eventName] = function (evt) { 81 self.eventsReceived.push(eventName); 82 ok(true, "received event " + eventName); 83 84 var dep = eventDependencies[eventName]; 85 if (dep) { 86 ok( 87 self.eventsReceived.includes(dep), 88 eventName + " must come after " + dep 89 ); 90 } 91 92 cb && cb(evt, sr); 93 if ( 94 self.doneFunc && 95 !isDone && 96 nEventsExpected === self.eventsReceived.length 97 ) { 98 isDone = true; 99 self.doneFunc(); 100 } 101 }; 102 }; 103 104 self.start = function EventManager_start() { 105 isSendingAudioData = true; 106 var audioTag = document.createElement("audio"); 107 audioTag.src = self.audioSampleFile; 108 109 var stream = audioTag.mozCaptureStreamUntilEnded(); 110 audioTag.addEventListener("ended", function () { 111 info("Sample stream ended, requesting queued events"); 112 isSendingAudioData = false; 113 while (queuedEventRequests.length) { 114 self.requestFSMEvent(queuedEventRequests.shift()); 115 } 116 }); 117 118 audioTag.play(); 119 sr.start(stream); 120 }; 121 122 self.requestFSMEvent = function EventManager_requestFSMEvent(eventName) { 123 if (isSendingAudioData) { 124 info( 125 "Queuing event " + eventName + " until we're done sending audio data" 126 ); 127 queuedEventRequests.push(eventName); 128 return; 129 } 130 131 info("requesting " + eventName); 132 Services.obs.notifyObservers( 133 null, 134 SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC, 135 eventName 136 ); 137 }; 138 139 self.requestTestEnd = function EventManager_requestTestEnd() { 140 Services.obs.notifyObservers(null, SPEECH_RECOGNITION_TEST_END_TOPIC); 141 }; 142 } 143 144 function buildResultCallback(transcript) { 145 return function (evt) { 146 is(evt.results[0][0].transcript, transcript, "expect correct transcript"); 147 }; 148 } 149 150 function buildErrorCallback(errcode) { 151 return function (err) { 152 is(err.error, errcode, "expect correct error code"); 153 }; 154 } 155 156 function performTest(options) { 157 var prefs = options.prefs; 158 159 prefs.unshift( 160 ["media.webspeech.recognition.enable", true], 161 ["media.webspeech.test.enable", true] 162 ); 163 164 SpecialPowers.pushPrefEnv({ set: prefs }, function () { 165 var sr; 166 if (!options.webkit) { 167 sr = new SpeechRecognition(); 168 } else { 169 sr = new webkitSpeechRecognition(); 170 var grammar = new webkitSpeechGrammar(); 171 var speechrecognitionlist = new webkitSpeechGrammarList(); 172 speechrecognitionlist.addFromString("", 1); 173 sr.grammars = speechrecognitionlist; 174 } 175 var em = new EventManager(sr); 176 177 for (var eventName in options.expectedEvents) { 178 var cb = options.expectedEvents[eventName]; 179 em.expect(eventName, cb); 180 } 181 182 em.doneFunc = function () { 183 em.requestTestEnd(); 184 if (options.doneFunc) { 185 options.doneFunc(); 186 } 187 }; 188 189 em.audioSampleFile = DEFAULT_AUDIO_SAMPLE_FILE; 190 if (options.audioSampleFile) { 191 em.audioSampleFile = options.audioSampleFile; 192 } 193 194 em.start(); 195 196 for (var i = 0; i < options.eventsToRequest.length; i++) { 197 em.requestFSMEvent(options.eventsToRequest[i]); 198 } 199 }); 200 }