// Copyright 2014 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. cr.define('hotword', function() { 'use strict'; /** * Class used to manage speaker training. Starts a hotwording session * if training is on, and automatically restarts the detector when a * a hotword is triggered. * @param {!hotword.StateManager} stateManager * @constructor * @extends {hotword.BaseSessionManager} */ function TrainingManager(stateManager) { /** * Chrome event listeners. Saved so that they can be de-registered when * hotwording is disabled. * @private */ this.finalizedSpeakerModelListener_ = this.handleFinalizeSpeakerModel_.bind(this); hotword.BaseSessionManager.call(this, stateManager, hotword.constants.SessionSource.TRAINING); } /** * Handles a success event on mounting the file system event and deletes * the user data files. * @param {FileSystem} fs The FileSystem object. * @private */ TrainingManager.deleteFiles_ = function(fs) { fs.root.getFile(hotword.constants.SPEAKER_MODEL_FILE_NAME, {create: false}, TrainingManager.deleteFile_, TrainingManager.fileErrorHandler_); for (var i = 0; i < hotword.constants.NUM_TRAINING_UTTERANCES; ++i) { fs.root.getFile(hotword.constants.UTTERANCE_FILE_PREFIX + i + hotword.constants.UTTERANCE_FILE_EXTENSION, {create: false}, TrainingManager.deleteFile_, TrainingManager.fileErrorHandler_); } }; /** * Deletes a file. * @param {FileEntry} fileEntry The FileEntry object. * @private */ TrainingManager.deleteFile_ = function(fileEntry) { if (fileEntry.isFile) { hotword.debug('File found: ' + fileEntry.fullPath); if (hotword.DEBUG || window.localStorage['hotword.DEBUG']) { fileEntry.getMetadata(function(md) { hotword.debug('File size: ' + md.size); }); } fileEntry.remove(function() { hotword.debug('File removed: ' + fileEntry.fullPath); }, TrainingManager.fileErrorHandler_); } }; /** * Handles a failure event on mounting the file system event. * @param {FileError} e The FileError object. * @private */ TrainingManager.fileErrorHandler_ = function(e) { hotword.debug('File error: ' + e.code); }; /** * Handles a failure event on checking for the existence of the speaker model. * @param {FileError} e The FileError object. * @private */ TrainingManager.sendNoSpeakerModelResponse_ = function(e) { chrome.hotwordPrivate.speakerModelExistsResult(false); }; /** * Handles a success event on mounting the file system and checks for the * existence of the speaker model. * @param {FileSystem} fs The FileSystem object. * @private */ TrainingManager.speakerModelExists_ = function(fs) { fs.root.getFile(hotword.constants.SPEAKER_MODEL_FILE_NAME, {create: false}, TrainingManager.sendSpeakerModelExistsResponse_, TrainingManager.sendNoSpeakerModelResponse_); }; /** * Sends a response through the HotwordPrivateApi indicating whether * the speaker model exists. * @param {FileEntry} fileEntry The FileEntry object. * @private */ TrainingManager.sendSpeakerModelExistsResponse_ = function(fileEntry) { if (fileEntry.isFile) { hotword.debug('File found: ' + fileEntry.fullPath); if (hotword.DEBUG || window.localStorage['hotword.DEBUG']) { fileEntry.getMetadata(function(md) { hotword.debug('File size: ' + md.size); }); } } chrome.hotwordPrivate.speakerModelExistsResult(fileEntry.isFile); }; /** * Handles a request to delete the speaker model. */ TrainingManager.handleDeleteSpeakerModel = function() { window.webkitRequestFileSystem(PERSISTENT, hotword.constants.FILE_SYSTEM_SIZE_BYTES, TrainingManager.deleteFiles_, TrainingManager.fileErrorHandler_); }; /** * Handles a request for the speaker model existence. */ TrainingManager.handleSpeakerModelExists = function() { window.webkitRequestFileSystem(PERSISTENT, hotword.constants.FILE_SYSTEM_SIZE_BYTES, TrainingManager.speakerModelExists_, TrainingManager.fileErrorHandler_); }; TrainingManager.prototype = { __proto__: hotword.BaseSessionManager.prototype, /** @override */ enabled: function() { return this.stateManager.isTrainingEnabled(); }, /** @override */ updateListeners: function() { hotword.BaseSessionManager.prototype.updateListeners.call(this); if (this.enabled()) { // Detect when the speaker model needs to be finalized. if (!chrome.hotwordPrivate.onFinalizeSpeakerModel.hasListener( this.finalizedSpeakerModelListener_)) { chrome.hotwordPrivate.onFinalizeSpeakerModel.addListener( this.finalizedSpeakerModelListener_); } this.startSession(hotword.constants.RecognizerStartMode.NEW_MODEL); } else { chrome.hotwordPrivate.onFinalizeSpeakerModel.removeListener( this.finalizedSpeakerModelListener_); } }, /** @override */ handleHotwordTrigger: function(log) { if (this.enabled()) { hotword.BaseSessionManager.prototype.handleHotwordTrigger.call( this, log); this.startSession(hotword.constants.RecognizerStartMode.ADAPT_MODEL); } }, /** @override */ startSession: function(opt_mode) { this.stateManager.startSession( this.sessionSource_, function() { chrome.hotwordPrivate.setHotwordSessionState(true, function() {}); }, this.handleHotwordTrigger.bind(this), this.handleSpeakerModelSaved_.bind(this), opt_mode); }, /** * Handles a hotwordPrivate.onFinalizeSpeakerModel event. * @private */ handleFinalizeSpeakerModel_: function() { if (this.enabled()) this.stateManager.finalizeSpeakerModel(); }, /** * Handles a hotwordPrivate.onFinalizeSpeakerModel event. * @private */ handleSpeakerModelSaved_: function() { if (this.enabled()) chrome.hotwordPrivate.notifySpeakerModelSaved(); }, }; return { TrainingManager: TrainingManager }; });