| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview The class to Manage both offline / online speech recognition. | 6 * @fileoverview The class to Manage both offline / online speech recognition. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 <include src="plugin_manager.js"/> | 9 <include src="plugin_manager.js"/> |
| 10 <include src="audio_manager.js"/> | 10 <include src="audio_manager.js"/> |
| 11 <include src="speech_recognition_manager.js"/> | 11 <include src="speech_recognition_manager.js"/> |
| 12 | 12 |
| 13 cr.define('speech', function() { | 13 cr.define('speech', function() { |
| 14 'use strict'; | 14 'use strict'; |
| 15 | 15 |
| 16 /** | 16 /** |
| 17 * The state of speech recognition. | 17 * The state of speech recognition. |
| 18 * | 18 * |
| 19 * @enum {string} | 19 * @enum {string} |
| 20 */ | 20 */ |
| 21 var SpeechState = { | 21 var SpeechState = { |
| 22 READY: 'READY', | 22 READY: 'READY', |
| 23 HOTWORD_RECOGNIZING: 'HOTWORD_RECOGNIZING', | 23 HOTWORD_RECOGNIZING: 'HOTWORD_RECOGNIZING', |
| 24 RECOGNIZING: 'RECOGNIZING', | 24 RECOGNIZING: 'RECOGNIZING', |
| 25 IN_SPEECH: 'IN_SPEECH', |
| 25 STOPPING: 'STOPPING' | 26 STOPPING: 'STOPPING' |
| 26 }; | 27 }; |
| 27 | 28 |
| 28 /** | 29 /** |
| 29 * @constructor | 30 * @constructor |
| 30 */ | 31 */ |
| 31 function SpeechManager() { | 32 function SpeechManager() { |
| 32 this.audioManager_ = new speech.AudioManager(); | 33 this.audioManager_ = new speech.AudioManager(); |
| 33 this.audioManager_.addEventListener('audio', this.onAudioLevel_.bind(this)); | 34 this.audioManager_.addEventListener('audio', this.onAudioLevel_.bind(this)); |
| 34 if (speech.isPluginAvailable()) { | 35 if (speech.isPluginAvailable()) { |
| 35 var pluginManager = new speech.PluginManager( | 36 var pluginManager = new speech.PluginManager( |
| 36 this.onHotwordRecognizerReady_.bind(this), | 37 this.onHotwordRecognizerReady_.bind(this), |
| 37 this.onHotwordRecognized_.bind(this)); | 38 this.onHotwordRecognized_.bind(this)); |
| 38 pluginManager.scheduleInitialize( | 39 pluginManager.scheduleInitialize( |
| 39 this.audioManager_.getSampleRate(), | 40 this.audioManager_.getSampleRate(), |
| 40 'chrome://app-list/okgoogle_hotword.config'); | 41 'chrome://app-list/okgoogle_hotword.config'); |
| 41 } | 42 } |
| 43 this.shown_ = false; |
| 42 this.speechRecognitionManager_ = new speech.SpeechRecognitionManager(this); | 44 this.speechRecognitionManager_ = new speech.SpeechRecognitionManager(this); |
| 43 this.setState_(SpeechState.READY); | 45 this.setState_(SpeechState.READY); |
| 44 } | 46 } |
| 45 | 47 |
| 46 /** | 48 /** |
| 47 * Updates the state. | 49 * Updates the state. |
| 48 * | 50 * |
| 49 * @param {SpeechState} newState The new state. | 51 * @param {SpeechState} newState The new state. |
| 50 * @private | 52 * @private |
| 51 */ | 53 */ |
| 52 SpeechManager.prototype.setState_ = function(newState) { | 54 SpeechManager.prototype.setState_ = function(newState) { |
| 53 this.state = newState; | 55 this.state = newState; |
| 56 chrome.send('setSpeechRecognitionState', [this.state]); |
| 54 }; | 57 }; |
| 55 | 58 |
| 56 /** | 59 /** |
| 57 * Called with the mean audio level when audio data arrives. | 60 * Called with the mean audio level when audio data arrives. |
| 58 * | 61 * |
| 59 * @param {cr.event.Event} event The event object for the audio data. | 62 * @param {cr.event.Event} event The event object for the audio data. |
| 60 * @private | 63 * @private |
| 61 */ | 64 */ |
| 62 SpeechManager.prototype.onAudioLevel_ = function(event) { | 65 SpeechManager.prototype.onAudioLevel_ = function(event) { |
| 63 var data = event.data; | 66 var data = event.data; |
| 64 var level = 0; | 67 var level = 0; |
| 65 for (var i = 0; i < data.length; ++i) | 68 for (var i = 0; i < data.length; ++i) |
| 66 level += Math.abs(data[i]); | 69 level += Math.abs(data[i]); |
| 67 level /= data.length; | 70 level /= data.length; |
| 68 chrome.send('speechSoundLevel', [level]); | 71 chrome.send('speechSoundLevel', [level]); |
| 69 }; | 72 }; |
| 70 | 73 |
| 71 /** | 74 /** |
| 72 * Called when the hotword recognizer is ready. | 75 * Called when the hotword recognizer is ready. |
| 73 * | 76 * |
| 74 * @param {PluginManager} pluginManager The hotword plugin manager which gets | 77 * @param {PluginManager} pluginManager The hotword plugin manager which gets |
| 75 * ready. | 78 * ready. |
| 76 * @private | 79 * @private |
| 77 */ | 80 */ |
| 78 SpeechManager.prototype.onHotwordRecognizerReady_ = function(pluginManager) { | 81 SpeechManager.prototype.onHotwordRecognizerReady_ = function(pluginManager) { |
| 79 this.pluginManager_ = pluginManager; | 82 this.pluginManager_ = pluginManager; |
| 80 this.audioManager_.addEventListener( | 83 this.audioManager_.addEventListener( |
| 81 'audio', pluginManager.sendAudioData.bind(pluginManager)); | 84 'audio', pluginManager.sendAudioData.bind(pluginManager)); |
| 82 this.setState_(SpeechState.READY); | 85 if (this.shown_) { |
| 86 this.pluginManager_.startRecognizer(); |
| 87 this.audioManager_.start(); |
| 88 this.setState_(SpeechState.HOTWORD_RECOGNIZING); |
| 89 } else { |
| 90 this.setState_(SpeechState.READY); |
| 91 } |
| 83 }; | 92 }; |
| 84 | 93 |
| 85 /** | 94 /** |
| 86 * Called when the hotword is recognized. | 95 * Called when the hotword is recognized. |
| 87 * | 96 * |
| 88 * @param {number} confidence The confidence store of the recognition. | 97 * @param {number} confidence The confidence store of the recognition. |
| 89 * @private | 98 * @private |
| 90 */ | 99 */ |
| 91 SpeechManager.prototype.onHotwordRecognized_ = function(confidence) { | 100 SpeechManager.prototype.onHotwordRecognized_ = function(confidence) { |
| 92 if (this.state != SpeechState.HOTWORD_RECOGNIZING) | 101 if (this.state != SpeechState.HOTWORD_RECOGNIZING) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 106 chrome.send('speechResult', [result, isFinal]); | 115 chrome.send('speechResult', [result, isFinal]); |
| 107 if (isFinal) | 116 if (isFinal) |
| 108 this.speechRecognitionManager_.stop(); | 117 this.speechRecognitionManager_.stop(); |
| 109 }; | 118 }; |
| 110 | 119 |
| 111 /** | 120 /** |
| 112 * Called when the speech recognition has started. | 121 * Called when the speech recognition has started. |
| 113 */ | 122 */ |
| 114 SpeechManager.prototype.onSpeechRecognitionStarted = function() { | 123 SpeechManager.prototype.onSpeechRecognitionStarted = function() { |
| 115 this.setState_(SpeechState.RECOGNIZING); | 124 this.setState_(SpeechState.RECOGNIZING); |
| 116 chrome.send('setSpeechRecognitionState', ['on']); | |
| 117 }; | 125 }; |
| 118 | 126 |
| 119 /** | 127 /** |
| 120 * Called when the speech recognition has ended. | 128 * Called when the speech recognition has ended. |
| 121 */ | 129 */ |
| 122 SpeechManager.prototype.onSpeechRecognitionEnded = function() { | 130 SpeechManager.prototype.onSpeechRecognitionEnded = function() { |
| 123 // Restarts the hotword recognition. | 131 // Restarts the hotword recognition. |
| 124 if (this.state != SpeechState.STOPPING && this.pluginManager_) { | 132 if (this.state != SpeechState.STOPPING && this.pluginManager_) { |
| 125 this.pluginManager_.startRecognizer(); | 133 this.pluginManager_.startRecognizer(); |
| 126 this.audioManager_.start(); | 134 this.audioManager_.start(); |
| 127 this.setState_(SpeechState.HOTWORD_RECOGNIZING); | 135 this.setState_(SpeechState.HOTWORD_RECOGNIZING); |
| 128 } else { | 136 } else { |
| 129 this.audioManager_.stop(); | 137 this.audioManager_.stop(); |
| 130 } | 138 } |
| 131 chrome.send('setSpeechRecognitionState', ['off']); | 139 chrome.send('setSpeechRecognitionState', ['off']); |
| 132 }; | 140 }; |
| 133 | 141 |
| 134 /** | 142 /** |
| 135 * Called when a speech has started. | 143 * Called when a speech has started. |
| 136 */ | 144 */ |
| 137 SpeechManager.prototype.onSpeechStarted = function() { | 145 SpeechManager.prototype.onSpeechStarted = function() { |
| 138 if (this.state == SpeechState.RECOGNIZING) | 146 if (this.state == SpeechState.RECOGNIZING) |
| 139 chrome.send('setSpeechRecognitionState', ['in-speech']); | 147 this.setState_(SpeechState.IN_SPEECH); |
| 140 }; | 148 }; |
| 141 | 149 |
| 142 /** | 150 /** |
| 143 * Called when a speech has ended. | 151 * Called when a speech has ended. |
| 144 */ | 152 */ |
| 145 SpeechManager.prototype.onSpeechEnded = function() { | 153 SpeechManager.prototype.onSpeechEnded = function() { |
| 146 if (this.state == SpeechState.RECOGNIZING) | 154 if (this.state == SpeechState.IN_SPEECH) |
| 147 chrome.send('setSpeechRecognitionState', ['on']); | 155 this.setState_(SpeechState.RECOGNIZING); |
| 148 }; | 156 }; |
| 149 | 157 |
| 150 /** | 158 /** |
| 151 * Called when an error happened during the speech recognition. | 159 * Called when an error happened during the speech recognition. |
| 152 * | 160 * |
| 153 * @param {SpeechRecognitionError} e The error object. | 161 * @param {SpeechRecognitionError} e The error object. |
| 154 */ | 162 */ |
| 155 SpeechManager.prototype.onSpeechRecognitionError = function(e) { | 163 SpeechManager.prototype.onSpeechRecognitionError = function(e) { |
| 156 if (this.state != SpeechState.STOPPING) | 164 if (this.state != SpeechState.STOPPING) |
| 157 this.setState_(SpeechState.READY); | 165 this.setState_(SpeechState.READY); |
| 158 }; | 166 }; |
| 159 | 167 |
| 160 /** | 168 /** |
| 161 * Starts the speech recognition session. | 169 * Called when the app-list bubble is shown. |
| 162 */ | 170 */ |
| 163 SpeechManager.prototype.start = function() { | 171 SpeechManager.prototype.onShown = function() { |
| 172 this.shown_ = true; |
| 164 if (!this.pluginManager_) | 173 if (!this.pluginManager_) |
| 165 return; | 174 return; |
| 166 | 175 |
| 167 if (this.state == SpeechState.HOTWORD_RECOGNIZING) { | 176 if (this.state == SpeechState.HOTWORD_RECOGNIZING) { |
| 168 console.warn('Already in recognition state...'); | 177 console.warn('Already in recognition state...'); |
| 169 return; | 178 return; |
| 170 } | 179 } |
| 171 | 180 |
| 172 this.pluginManager_.startRecognizer(); | 181 this.pluginManager_.startRecognizer(); |
| 173 this.audioManager_.start(); | 182 this.audioManager_.start(); |
| 174 this.setState_(SpeechState.HOTWORD_RECOGNIZING); | 183 this.setState_(SpeechState.HOTWORD_RECOGNIZING); |
| 175 }; | 184 }; |
| 176 | 185 |
| 177 /** | 186 /** |
| 178 * Stops the speech recognition session. | 187 * Called when the app-list bubble is hidden. |
| 179 */ | 188 */ |
| 180 SpeechManager.prototype.stop = function() { | 189 SpeechManager.prototype.onHidden = function() { |
| 190 this.shown_ = false; |
| 181 if (this.pluginManager_) | 191 if (this.pluginManager_) |
| 182 this.pluginManager_.stopRecognizer(); | 192 this.pluginManager_.stopRecognizer(); |
| 183 | 193 |
| 184 // SpeechRecognition is asynchronous. | 194 // SpeechRecognition is asynchronous. |
| 185 this.audioManager_.stop(); | 195 this.audioManager_.stop(); |
| 186 if (this.state == SpeechState.RECOGNIZING) { | 196 if (this.state == SpeechState.RECOGNIZING || |
| 197 this.state == SpeechState.IN_SPEECH) { |
| 187 this.setState_(SpeechState.STOPPING); | 198 this.setState_(SpeechState.STOPPING); |
| 188 this.speechRecognitionManager_.stop(); | 199 this.speechRecognitionManager_.stop(); |
| 189 } else { | 200 } else { |
| 190 this.setState_(SpeechState.READY); | 201 this.setState_(SpeechState.READY); |
| 191 } | 202 } |
| 192 }; | 203 }; |
| 193 | 204 |
| 194 /** | 205 /** |
| 195 * Toggles the current state of speech recognition. | 206 * Toggles the current state of speech recognition. |
| 196 */ | 207 */ |
| 197 SpeechManager.prototype.toggleSpeechRecognition = function() { | 208 SpeechManager.prototype.toggleSpeechRecognition = function() { |
| 198 if (this.state == SpeechState.RECOGNIZING) { | 209 if (this.state == SpeechState.RECOGNIZING || |
| 210 this.state == SpeechState.IN_SPEECH) { |
| 199 this.audioManager_.stop(); | 211 this.audioManager_.stop(); |
| 200 this.speechRecognitionManager_.stop(); | 212 this.speechRecognitionManager_.stop(); |
| 201 } else { | 213 } else { |
| 202 if (this.pluginManager_) | 214 if (this.pluginManager_) |
| 203 this.pluginManager_.stopRecognizer(); | 215 this.pluginManager_.stopRecognizer(); |
| 204 if (this.audioManager_.state == speech.AudioState.STOPPED) | 216 if (this.audioManager_.state == speech.AudioState.STOPPED) |
| 205 this.audioManager_.start(); | 217 this.audioManager_.start(); |
| 206 this.speechRecognitionManager_.start(); | 218 this.speechRecognitionManager_.start(); |
| 207 } | 219 } |
| 208 }; | 220 }; |
| 209 | 221 |
| 210 return { | 222 return { |
| 211 SpeechManager: SpeechManager | 223 SpeechManager: SpeechManager |
| 212 }; | 224 }; |
| 213 }); | 225 }); |
| OLD | NEW |