diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-04 20:33:47 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-04 20:33:47 +0000 |
commit | 67599659c5bc4f29b4b3b79c6af13c9e54099ea8 (patch) | |
tree | d28606cf0ad7402d225ced907df3d97d29e133a8 | |
parent | c45250451180afaa0412eb71aaa7f5a41c087474 (diff) | |
download | chromium_src-67599659c5bc4f29b4b3b79c6af13c9e54099ea8.zip chromium_src-67599659c5bc4f29b4b3b79c6af13c9e54099ea8.tar.gz chromium_src-67599659c5bc4f29b4b3b79c6af13c9e54099ea8.tar.bz2 |
Removes the dependency between AudioManager and PluginManager.
Now AudioManager can listen the audio without hotword recognition.
The mean volume level would be useful to the speech UI.
BUG=313904
R=xiyuan@chromium.org
TEST=manually
Review URL: https://codereview.chromium.org/92863004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238753 0039d316-1c4b-4281-b951-d872f2087c98
4 files changed, 89 insertions, 74 deletions
diff --git a/chrome/browser/resources/app_list/audio_manager.js b/chrome/browser/resources/app_list/audio_manager.js index 4f2a301..9862ac4 100644 --- a/chrome/browser/resources/app_list/audio_manager.js +++ b/chrome/browser/resources/app_list/audio_manager.js @@ -3,7 +3,7 @@ // found in the LICENSE file. /** - * @fileoverview The manager of audio streams and interaction with the plugin. + * @fileoverview The manager of audio streams. */ cr.define('speech', function() { @@ -15,38 +15,21 @@ cr.define('speech', function() { * @enum {number} */ var AudioState = { - UNINITIALIZED: 0, - READY: 1, - RECOGNIZING: 2 + STOPPED: 0, + LISTENING: 1 }; /** * @constructor + * @extends {cr.EventTarget} */ - function AudioManager(onReady, onRecognizing, onRecognized) { - this.state = AudioState.UNINITIALIZED; - if (!speech.isPluginAvailable()) - return; - this.onReady_ = onReady; - this.onRecognizing_ = onRecognizing; - this.pluginManager_ = new speech.PluginManager( - this.onPluginReady_.bind(this), onRecognized); + function AudioManager() { this.audioContext_ = new window.webkitAudioContext(); this.audioProc_ = null; - this.pluginManager_.scheduleInitialize( - this.audioContext_.sampleRate, - 'chrome://app-list/okgoogle_hotword.config'); + this.state = AudioState.STOPPED; }; - /** - * Called when the plugin is ready. - * - * @private - */ - AudioManager.prototype.onPluginReady_ = function() { - this.state = AudioState.READY; - this.onReady_(); - }; + AudioManager.prototype.__proto__ = cr.EventTarget.prototype; /** * Called when the audio data arrives. @@ -59,7 +42,9 @@ cr.define('speech', function() { var intData = new Int16Array(data.length); for (var i = 0; i < data.length; ++i) intData[i] = Math.round(data[i] * 32767); - this.pluginManager_.sendAudioData(intData.buffer); + var event = new Event('audio'); + event.data = intData; + this.dispatchEvent(event); }; /** @@ -76,27 +61,27 @@ cr.define('speech', function() { audioIn.connect(this.audioProc_); this.audioProc_.connect(this.audioContext_.destination); - this.state = AudioState.RECOGNIZING; - this.onRecognizing_(); + this.state = AudioState.LISTENING; }; /** - * Starts the audio recognition with the plugin. + * Returns the sampling rate of the current audio context. + * @return {number} The sampling rate. + */ + AudioManager.prototype.getSampleRate = function() { + return this.audioContext_.sampleRate; + }; + + /** + * Starts the audio processing. */ AudioManager.prototype.start = function() { - // Not yet initialized. - if (this.state != AudioState.READY) - return; - if (this.pluginManager_.state < speech.PluginState.READY) + if (this.state == AudioState.LISTENING) return; - if (this.pluginManager_.state == speech.PluginState.READY) - this.pluginManager_.startRecognizer(); - if (this.audioProc_) { this.audioProc_.connect(this.audioContext_.destination); - this.state = AudioState.RECOGNIZING; - this.onRecognizing_(); + this.state = AudioState.LISTENING; return; } @@ -107,17 +92,17 @@ cr.define('speech', function() { }; /** - * Stops the audio recognition. + * Stops the audio processing. */ AudioManager.prototype.stop = function() { - if (this.state <= AudioState.READY) + if (this.state != AudioState.LISTENING) return; this.audioProc_.disconnect(); - this.pluginManager_.stopRecognizer(); - this.state = AudioState.READY; + this.state = AudioState.STOPPED; }; return { - AudioManager: AudioManager + AudioManager: AudioManager, + AudioState: AudioState }; }); diff --git a/chrome/browser/resources/app_list/plugin_manager.js b/chrome/browser/resources/app_list/plugin_manager.js index 0bce749..fb8a604 100644 --- a/chrome/browser/resources/app_list/plugin_manager.js +++ b/chrome/browser/resources/app_list/plugin_manager.js @@ -75,7 +75,7 @@ cr.define('speech', function() { if (messageEvent.data == 'audio') { if (this.state < PluginState.READY) - this.onReady_(); + this.onReady_(this); this.state = PluginState.RECOGNIZING; } else if (messageEvent.data == 'stopped') { this.state = PluginState.READY; @@ -133,23 +133,26 @@ cr.define('speech', function() { * Asks the plugin to start recognizing the hotword. */ PluginManager.prototype.startRecognizer = function() { - $('recognizer').postMessage(pluginCommands.START_RECOGNIZING); + if (this.state == PluginState.READY) + $('recognizer').postMessage(pluginCommands.START_RECOGNIZING); }; /** * Asks the plugin to stop recognizing the hotword. */ PluginManager.prototype.stopRecognizer = function() { - $('recognizer').postMessage(pluginCommands.STOP_RECOGNIZING); + if (this.state == PluginState.RECOGNIZING) + $('recognizer').postMessage(pluginCommands.STOP_RECOGNIZING); }; /** * Sends the actual audio wave data. * - * @param {ArrayBuffer} data The audio data to be recognized. + * @param {cr.event.Event} event The event for the audio data. */ - PluginManager.prototype.sendAudioData = function(data) { - $('recognizer').postMessage(data); + PluginManager.prototype.sendAudioData = function(event) { + if (this.state == PluginState.RECOGNIZING) + $('recognizer').postMessage(event.data.buffer); }; return { diff --git a/chrome/browser/resources/app_list/speech_manager.js b/chrome/browser/resources/app_list/speech_manager.js index 08284be..c55eab7 100644 --- a/chrome/browser/resources/app_list/speech_manager.js +++ b/chrome/browser/resources/app_list/speech_manager.js @@ -19,7 +19,6 @@ cr.define('speech', function() { * @enum {string} */ var SpeechState = { - UNINITIALIZED: 'UNINITIALIZED', READY: 'READY', HOTWORD_RECOGNIZING: 'HOTWORD_RECOGNIZING', RECOGNIZING: 'RECOGNIZING' @@ -29,12 +28,18 @@ cr.define('speech', function() { * @constructor */ function SpeechManager() { - this.audioManager_ = new speech.AudioManager( - this.onHotwordRecognizerReady_.bind(this), - this.onHotwordRecognizing_.bind(this), - this.onHotwordRecognized_.bind(this)); + this.audioManager_ = new speech.AudioManager(); + this.audioManager_.addEventListener('audio', this.onAudioLevel_.bind(this)); + if (speech.isPluginAvailable()) { + var pluginManager = new speech.PluginManager( + this.onHotwordRecognizerReady_.bind(this), + this.onHotwordRecognized_.bind(this)); + pluginManager.scheduleInitialize( + this.audioManager_.getSampleRate(), + 'chrome://app-list/okgoogle_hotword.config'); + } this.speechRecognitionManager_ = new speech.SpeechRecognitionManager(this); - this.setState_(SpeechState.UNINITIALIZED); + this.setState_(SpeechState.READY); } /** @@ -49,11 +54,32 @@ cr.define('speech', function() { }; /** + * Called with the mean audio level when audio data arrives. + * + * @param {cr.event.Event} event The event object for the audio data. + * @private + */ + SpeechManager.prototype.onAudioLevel_ = function(event) { + var data = event.data; + var level = 0; + for (var i = 0; i < data.length; ++i) + level += Math.abs(data[i]); + level /= data.length; + // TODO(mukai): use the result to make the audio feedback during the speech + // recognition. + }; + + /** * Called when the hotword recognizer is ready. * + * @param {PluginManager} pluginManager The hotword plugin manager which gets + * ready. * @private */ - SpeechManager.prototype.onHotwordRecognizerReady_ = function() { + SpeechManager.prototype.onHotwordRecognizerReady_ = function(pluginManager) { + this.pluginManager_ = pluginManager; + this.audioManager_.addEventListener( + 'audio', pluginManager.sendAudioData.bind(pluginManager)); this.setState_(SpeechState.READY); }; @@ -66,21 +92,12 @@ cr.define('speech', function() { SpeechManager.prototype.onHotwordRecognized_ = function(confidence) { if (this.state != SpeechState.HOTWORD_RECOGNIZING) return; - this.audioManager_.stop(); this.setState_(SpeechState.READY); + this.pluginManager_.stopRecognizer(); this.speechRecognitionManager_.start(); }; /** - * Called when the hotword recognition has started. - * - * @private - */ - SpeechManager.prototype.onHotwordRecognizing_ = function() { - this.setState_(SpeechState.HOTWORD_RECOGNIZING); - }; - - /** * Called when the speech recognition has happened. * * @param {string} result The speech recognition result. @@ -108,7 +125,13 @@ cr.define('speech', function() { */ SpeechManager.prototype.onSpeechRecognitionEnded = function() { // Restarts the hotword recognition. - this.audioManager_.start(); + if (this.pluginManager_) { + this.pluginManager_.startRecognizer(); + this.audioManager_.start(); + this.setState_(SpeechState.HOTWORD_RECOGNIZING); + } else { + this.audioManager_.stop(); + } chrome.send('setSpeechRecognitionState', [false]); }; @@ -118,33 +141,32 @@ cr.define('speech', function() { * @param {SpeechRecognitionError} e The error object. */ SpeechManager.prototype.onSpeechRecognitionError = function(e) { - this.setState_(SpeechState.UNINITIALIZED); + this.setState_(SpeechState.READY); }; /** * Starts the speech recognition session. */ SpeechManager.prototype.start = function() { - if (this.state == SpeechState.UNINITIALIZED) { - console.warn('hotword recognizer is not yet initialized'); + if (!this.pluginManager_) return; - } if (this.state != SpeechState.READY) { console.warn('Already in recognition state...'); return; } + this.pluginManager_.startRecognizer(); this.audioManager_.start(); + this.setState_(SpeechState.HOTWORD_RECOGNIZING); }; /** * Stops the speech recognition session. */ SpeechManager.prototype.stop = function() { - if (this.state == SpeechState.UNINITIALIZED) - return; - + if (this.pluginManager_) + this.pluginManager_.stopRecognizer(); this.audioManager_.stop(); this.speechRecognitionManager_.stop(); this.setState_(SpeechState.READY); @@ -155,9 +177,13 @@ cr.define('speech', function() { */ SpeechManager.prototype.toggleSpeechRecognition = function() { if (this.state == SpeechState.RECOGNIZING) { + this.audioManager_.stop(); this.speechRecognitionManager_.stop(); } else { - this.audioManager_.stop(); + if (this.pluginManager_) + this.pluginManager_.stopRecognizer(); + if (this.audioManager_.state == speech.AudioState.STOPPED) + this.audioManager_.start(); this.speechRecognitionManager_.start(); } }; diff --git a/chrome/browser/resources/app_list/start_page.html b/chrome/browser/resources/app_list/start_page.html index 47a9167..2ff0961 100644 --- a/chrome/browser/resources/app_list/start_page.html +++ b/chrome/browser/resources/app_list/start_page.html @@ -5,6 +5,7 @@ <link rel="stylesheet" href="chrome://app-list/start_page.css"> <script src="chrome://resources/js/load_time_data.js"></script> <script src="chrome://resources/js/cr.js"></script> + <script src="chrome://resources/js/cr/event_target.js"></script> <script src="chrome://resources/js/cr/ui.js"></script> <script src="chrome://resources/js/util.js"></script> <script src="chrome://app-list/strings.js"></script> |