blob: 90f099e4e5b32ab3917f31160c0673d5ca02f274 [file] [log] [blame]
// 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.
*/
<include src="plugin_manager.js"/>
<include src="audio_manager.js"/>
<include src="speech_recognition_manager.js"/>
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
};
});