summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/app_list/plugin_manager.js
blob: fb8a6044f8190488a46fa2c7b61f31ec2f6d6748 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// 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
  };
});