blob: fb8a6044f8190488a46fa2c7b61f31ec2f6d6748 [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 manager of offline hotword speech recognizer plugin.
*/
cr.define('speech', function() {
'use strict';
/**
* The type of the plugin state.
** @enum {number}
*/
var PluginState = {
UNINITIALIZED: 0,
LOADED: 1,
SAMPLING_RATE_READY: 2,
READY: 3,
RECOGNIZING: 4
};
/**
* The command names of the plugin.
* @enum {string}
*/
var pluginCommands = {
SET_SAMPLING_RATE: 'h',
SET_CONFIG: 'm',
START_RECOGNIZING: 'r',
STOP_RECOGNIZING: 's'
};
/**
* The regexp pattern of the hotword recognition result.
*/
var recognitionPattern = /^HotwordFiredEvent: \[(.*)\] confidence: (.*)/;
/**
* Checks the availability of the plugin.
* @return {boolean} True only if the plugin is available.
*/
function isPluginAvailable() {
return !!($('recognizer') && $('recognizer').postMessage);
}
/**
* @constructor
*/
function PluginManager(onReady, onRecognized) {
this.state = PluginState.UNINITIALIZED;
this.onReady_ = onReady;
this.onRecognized_ = onRecognized;
this.samplingRate_ = null;
this.config_ = null;
if (isPluginAvailable()) {
$('recognizer').addEventListener('message', this.onMessage_.bind(this));
$('recognizer').addEventListener('load', this.onLoad_.bind(this));
}
};
/**
* The event handler of the plugin status.
*
* @param {Event} messageEvent the event object from the plugin.
* @private
*/
PluginManager.prototype.onMessage_ = function(messageEvent) {
if (this.state == PluginState.LOADED) {
if (messageEvent.data == 'stopped')
this.state = PluginState.SAMPLING_RATE_READY;
return;
}
if (messageEvent.data == 'audio') {
if (this.state < PluginState.READY)
this.onReady_(this);
this.state = PluginState.RECOGNIZING;
} else if (messageEvent.data == 'stopped') {
this.state = PluginState.READY;
} else {
var matched = recognitionPattern.exec(messageEvent.data);
if (matched && matched[1] == 'hotword_ok_google')
this.onRecognized_(Number(matched[2]));
}
};
/**
* The event handler when the plugin is loaded.
*
* @private
*/
PluginManager.prototype.onLoad_ = function() {
if (this.state == PluginState.UNINITIALIZED) {
this.state = PluginState.LOADED;
if (this.samplingRate_ && this.config_)
this.initialize_(this.samplingRate_, this.config_);
}
};
/**
* Sends the initialization messages to the plugin. This method is private.
* The initialization will happen from onLoad_ or scheduleInitialize.
*
* @param {number} samplingRate the sampling rate the plugin accepts.
* @param {string} config the url of the config file.
* @private
*/
PluginManager.prototype.initialize_ = function(samplingRate, config) {
$('recognizer').postMessage(
pluginCommands.SET_SAMPLING_RATE + samplingRate);
$('recognizer').postMessage(pluginCommands.SET_CONFIG + config);
};
/**
* Initializes the plugin with the specified parameter, or schedules the
* initialization if the plugin is not ready.
*
* @param {number} samplingRate the sampling rate the plugin accepts.
* @param {string} config the url of the config file.
*/
PluginManager.prototype.scheduleInitialize = function(samplingRate, config) {
if (this.state == PluginState.UNINITIALIZED) {
this.samplingRate_ = samplingRate;
this.config_ = config;
} else {
this.initialize_(samplingRate, config);
}
};
/**
* Asks the plugin to start recognizing the hotword.
*/
PluginManager.prototype.startRecognizer = function() {
if (this.state == PluginState.READY)
$('recognizer').postMessage(pluginCommands.START_RECOGNIZING);
};
/**
* Asks the plugin to stop recognizing the hotword.
*/
PluginManager.prototype.stopRecognizer = function() {
if (this.state == PluginState.RECOGNIZING)
$('recognizer').postMessage(pluginCommands.STOP_RECOGNIZING);
};
/**
* Sends the actual audio wave data.
*
* @param {cr.event.Event} event The event for the audio data.
*/
PluginManager.prototype.sendAudioData = function(event) {
if (this.state == PluginState.RECOGNIZING)
$('recognizer').postMessage(event.data.buffer);
};
return {
PluginManager: PluginManager,
PluginState: PluginState,
isPluginAvailable: isPluginAvailable
};
});