chromium/third_party/google_input_tools/src/chrome/os/sounds/soundcontroller.js

// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
// limitations under the License.
// See the License for the specific language governing permissions and
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// distributed under the License is distributed on an "AS-IS" BASIS,
// Unless required by applicable law or agreed to in writing, software
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// You may obtain a copy of the License at
// you may not use this file except in compliance with the License.
// Licensed under the Apache License, Version 2.0 (the "License");
//
goog.provide('i18n.input.chrome.sounds.SoundController');

goog.require('goog.Disposable');
goog.require('goog.dom');
goog.require('i18n.input.chrome.ElementType');
goog.require('i18n.input.chrome.sounds.Sounds');

goog.scope(function() {
var Sounds = i18n.input.chrome.sounds.Sounds;
var ElementType = i18n.input.chrome.ElementType;
var keyToSoundIdOnKeyUp = {};
var keyToSoundIdOnKeyRepeat = {};



/**
 * Sound controller for the keyboard.
 *
 * @param {!boolean} enabled Whether sounds is enabled by default.
 * @param {?number=} opt_volume The default volume for sound tracks.
 * @constructor
 * @extends {goog.Disposable}
 */
i18n.input.chrome.sounds.SoundController = function(enabled, opt_volume) {

  /**
   * Collection of all the sound pools.
   *
   * @private {!Object.<string, !Object>}
   */
  this.sounds_ = {};

  /** @private {boolean} */
  this.enabled_ = enabled;

  /**
   * The default volume for all audio tracks. Tracks with volume 0 will be
   * skipped.
   *
   * @private {number}
   */
  this.volume_ = opt_volume || this.DEFAULT_VOLUME;

  if (enabled) {
    this.initialize();
  }
};
goog.inherits(i18n.input.chrome.sounds.SoundController, goog.Disposable);


var Controller = i18n.input.chrome.sounds.SoundController;


/**
 * @define {number}  The size of the pool to use for playing audio sounds.
 */
Controller.prototype.POOL_SIZE = 10;


/**
 * @define {number}  The default audio track volume.
 */
Controller.prototype.DEFAULT_VOLUME = 0.6;


/** @private {boolean} */
Controller.prototype.initialized_ = false;


/**
 * Initializes the sound controller.
 */
Controller.prototype.initialize = function() {
  if (!this.initialized_) {
    for (var sound in Sounds) {
      this.addSound_(Sounds[sound]);
    }
    keyToSoundIdOnKeyUp[ElementType.BACKSPACE_KEY] = Sounds.NONE;
    keyToSoundIdOnKeyUp[ElementType.ENTER_KEY] = Sounds.RETURN;
    keyToSoundIdOnKeyUp[ElementType.SPACE_KEY] = Sounds.SPACEBAR;
    keyToSoundIdOnKeyRepeat[ElementType.BACKSPACE_KEY] = Sounds.DELETE;
    this.initialized_ = true;
  }
};


/**
 * Caches the specified sound on the keyboard.
 *
 * @param {string} soundId The name of the .wav file in the "sounds"
     directory.
 * @private
 */
Controller.prototype.addSound_ = function(soundId) {
  if (soundId == Sounds.NONE || this.sounds_[soundId])
    return;
  var pool = [];
  // Create sound pool.
  for (var i = 0; i < this.POOL_SIZE; i++) {
    var audio = goog.dom.createDom('audio', {
      preload: 'auto',
      id: soundId,
      src: 'sounds/' + soundId + '.wav',
      volume: this.volume_
    });
    pool.push(audio);
  }
  this.sounds_[soundId] = pool;
};


/**
 * Sets the volume for the specified sound.
 *
 * @param {string} soundId The id of the sound.
 * @param {number} volume The volume to set.
 */
Controller.prototype.setVolume = function(soundId, volume) {
  var pool = this.sounds_[soundId];
  if (!pool) {
    console.error('Cannot find sound: ' + soundId);
    return;
  }
  // Change volume for all sounds in the pool.
  for (var i = 0; i < pool.length; i++) {
    pool[i].volume = volume;
  }
};


/**
 * Enables or disable playing sounds on keypress.
 * @param {!boolean} enabled
 */
Controller.prototype.setEnabled = function(enabled) {
  this.enabled_ = enabled;
  if (this.enabled_) {
    this.initialize();
  }
};


/**
 * Gets the flag whether sound controller is enabled or not.
 *
 * @return {!boolean}
 */
Controller.prototype.getEnabled = function() {
  return this.enabled_;
};


/**
 * Sets the volume for all sounds on the keyboard.
 *
 * @param {number} volume The volume of the sounds.
 */
Controller.prototype.setMasterVolume = function(volume) {
  this.volume_ = volume;
  for (var id in this.sounds_) {
    this.setVolume(id, volume);
  }
};


/**
 * Plays the specified sound.
 *
 * @param {string} soundId The id of the audio tag.
 * @param {boolean=} opt_force Force to play sound whatever the enabled flags is
 *     turned on.
 */
Controller.prototype.playSound = function(soundId, opt_force) {
  if (opt_force) {
    this.initialize();
  }
  // If master volume is zero, ignore the request.
  if (!opt_force && !this.enabled_ || this.volume_ == 0 ||
      soundId == Sounds.NONE) {
    return;
  }
  var pool = this.sounds_[soundId];
  if (!pool) {
    console.error('Cannot find sound: ' + soundId);
    return;
  }
  // Search the sound pool for a free resource.
  for (var i = 0; i < pool.length; i++) {
    if (pool[i].paused) {
      pool[i].play();
      return;
    }
  }
};


/**
 * On key up.
 *
 * @param {ElementType} key The key released.
 */
Controller.prototype.onKeyUp = function(key) {
  var sound = keyToSoundIdOnKeyUp[key] || Sounds.STANDARD;
  this.playSound(sound);
};


/**
 * On key repeat.
 *
 * @param {ElementType} key The key that is being repeated.
 */
Controller.prototype.onKeyRepeat = function(key) {
  var sound = keyToSoundIdOnKeyRepeat[key] || Sounds.NONE;
  this.playSound(sound);
};


/** @override */
Controller.prototype.disposeInternal = function() {
  for (var soundId in this.sounds_) {
    var pool = this.sounds_[soundId];
    for (var i = 0; i < pool.length; i++) {
      var tag = pool[i];
      if (tag && tag.loaded) {
        tag.pause();
        tag.autoplay = false;
        tag.loop = false;
        tag.currentTime = 0;
      }
    }
    delete this.sounds_[soundId];
  }
  this.sounds_ = {};
  keyToSoundIdOnKeyUp = {};
  keyToSoundIdOnKeyRepeat = {};
  goog.base(this, 'disposeInternal');
};

});  // goog.scope