// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview The class to Manage both offline / online speech recognition. */ cr.define('speech', function() { 'use strict'; /** * The state of speech recognition. * * @enum {string} */ var SpeechState = { READY: 'READY', HOTWORD_RECOGNIZING: 'HOTWORD_RECOGNIZING', RECOGNIZING: 'RECOGNIZING', STOPPING: 'STOPPING' }; /** * @constructor */ function SpeechManager() { 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.READY); } /** * Updates the state. * * @param {SpeechState} newState The new state. * @private */ SpeechManager.prototype.setState_ = function(newState) { this.state = newState; }; /** * 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; chrome.send('speechSoundLevel', [level]); }; /** * Called when the hotword recognizer is ready. * * @param {PluginManager} pluginManager The hotword plugin manager which gets * ready. * @private */ SpeechManager.prototype.onHotwordRecognizerReady_ = function(pluginManager) { this.pluginManager_ = pluginManager; this.audioManager_.addEventListener( 'audio', pluginManager.sendAudioData.bind(pluginManager)); this.setState_(SpeechState.READY); }; /** * Called when the hotword is recognized. * * @param {number} confidence The confidence store of the recognition. * @private */ SpeechManager.prototype.onHotwordRecognized_ = function(confidence) { if (this.state != SpeechState.HOTWORD_RECOGNIZING) return; this.setState_(SpeechState.READY); this.pluginManager_.stopRecognizer(); this.speechRecognitionManager_.start(); }; /** * Called when the speech recognition has happened. * * @param {string} result The speech recognition result. * @param {boolean} isFinal Whether the result is final or not. */ SpeechManager.prototype.onSpeechRecognized = function(result, isFinal) { chrome.send('speechResult', [result, isFinal]); if (isFinal) this.speechRecognitionManager_.stop(); }; /** * Called when the speech recognition has started. */ SpeechManager.prototype.onSpeechRecognitionStarted = function() { this.setState_(SpeechState.RECOGNIZING); chrome.send('setSpeechRecognitionState', ['on']); }; /** * Called when the speech recognition has ended. */ SpeechManager.prototype.onSpeechRecognitionEnded = function() { // Restarts the hotword recognition. if (this.state != SpeechState.STOPPING && this.pluginManager_) { this.pluginManager_.startRecognizer(); this.audioManager_.start(); this.setState_(SpeechState.HOTWORD_RECOGNIZING); } else { this.audioManager_.stop(); } chrome.send('setSpeechRecognitionState', ['off']); }; /** * Called when a speech has started. */ SpeechManager.prototype.onSpeechStarted = function() { if (this.state == SpeechState.RECOGNIZING) chrome.send('setSpeechRecognitionState', ['in-speech']); }; /** * Called when a speech has ended. */ SpeechManager.prototype.onSpeechEnded = function() { if (this.state == SpeechState.RECOGNIZING) chrome.send('setSpeechRecognitionState', ['on']); }; /** * Called when an error happened during the speech recognition. * * @param {SpeechRecognitionError} e The error object. */ SpeechManager.prototype.onSpeechRecognitionError = function(e) { if (this.state != SpeechState.STOPPING) this.setState_(SpeechState.READY); }; /** * Starts the speech recognition session. */ SpeechManager.prototype.start = function() { if (!this.pluginManager_) return; if (this.state == SpeechState.HOTWORD_RECOGNIZING) { 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.pluginManager_) this.pluginManager_.stopRecognizer(); // SpeechRecognition is asynchronous. this.audioManager_.stop(); if (this.state == SpeechState.RECOGNIZING) { this.setState_(SpeechState.STOPPING); this.speechRecognitionManager_.stop(); } else { this.setState_(SpeechState.READY); } }; /** * Toggles the current state of speech recognition. */ SpeechManager.prototype.toggleSpeechRecognition = function() { if (this.state == SpeechState.RECOGNIZING) { this.audioManager_.stop(); this.speechRecognitionManager_.stop(); } else { if (this.pluginManager_) this.pluginManager_.stopRecognizer(); if (this.audioManager_.state == speech.AudioState.STOPPED) this.audioManager_.start(); this.speechRecognitionManager_.start(); } }; return { SpeechManager: SpeechManager }; });