phaser/src/sound/html5/HTML5AudioSound.js
2018-01-12 15:23:39 +01:00

286 lines
8.9 KiB
JavaScript

var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var SoundEvent = require('../SoundEvent');
var SoundValueEvent = require('../SoundValueEvent');
var HTML5AudioSound = new Class({
Extends: BaseSound,
initialize: function HTML5AudioSound(manager, key, config) {
if (config === void 0) { config = {}; }
/**
* An array containing all HTML5 Audio tags that could be used for individual
* sound's playback. Number of instances depends on the config value passed
* to the Loader#audio method call, default is 1.
*
* @private
* @property {HTMLAudioElement[]} tags
*/
this.tags = manager.game.cache.audio.get(key);
if (!this.tags) {
console.error('No audio loaded in cache with key: \'' + key + '\'!');
return;
}
/**
* Reference to an HTML5 Audio tag used for playing sound.
*
* @private
* @property {HTMLAudioElement} audio
* @default null
*/
this.audio = null;
/**
* Timestamp as generated by the Request Animation Frame or SetTimeout
* representing the time at which the delayed sound playback should start.
* Set to 0 if sound playback is not delayed.
*
* @private
* @property {number} startTime
* @default 0
*/
this.startTime = 0;
this.duration = this.tags[0].duration;
this.totalDuration = this.tags[0].duration;
BaseSound.call(this, manager, key, config);
},
play: function (markerName, config) {
if (!BaseSound.prototype.play.call(this, markerName, config)) {
return false;
}
// \/\/\/ isPlaying = true, isPaused = false \/\/\/
if (!this.pickAndPlayAudioTag()) {
return false;
}
this.events.dispatch(new SoundEvent(this, 'SOUND_PLAY'));
return true;
},
pause: function () {
if (this.startTime > 0) {
return false;
}
if (!BaseSound.prototype.pause.call(this)) {
return false;
}
// \/\/\/ isPlaying = false, isPaused = true \/\/\/
this.currentConfig.seek = this.audio.currentTime
- (this.currentMarker ? this.currentMarker.start : 0);
this.stopAndReleaseAudioTag();
this.events.dispatch(new SoundEvent(this, 'SOUND_PAUSE'));
return true;
},
resume: function () {
if (this.startTime > 0) {
return false;
}
if (!BaseSound.prototype.resume.call(this)) {
return false;
}
// \/\/\/ isPlaying = true, isPaused = false \/\/\/
if (!this.pickAndPlayAudioTag()) {
return false;
}
this.events.dispatch(new SoundEvent(this, 'SOUND_RESUME'));
return true;
},
stop: function () {
if (!BaseSound.prototype.stop.call(this)) {
return false;
}
// \/\/\/ isPlaying = false, isPaused = false \/\/\/
this.stopAndReleaseAudioTag();
this.events.dispatch(new SoundEvent(this, 'SOUND_STOP'));
return true;
},
pickAndPlayAudioTag: function () {
if (!this.pickAudioTag()) {
this.reset();
return false;
}
var seek = this.currentConfig.seek;
var delay = this.currentConfig.delay;
var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
this.audio.currentTime = offset;
this.applyConfig();
if (delay === 0) {
this.startTime = 0;
if (this.audio.paused) {
this.audio.play();
}
}
else {
this.startTime = window.performance.now() + delay;
if (!this.audio.paused) {
this.audio.pause();
}
}
this.resetConfig();
return true;
},
pickAudioTag: function () {
if (!this.audio) {
for (var i = 0; i < this.tags.length; i++) {
var audio = this.tags[i];
if (audio.dataset.used === 'false') {
audio.dataset.used = 'true';
this.audio = audio;
return true;
}
}
if (!this.manager.override) {
return false;
}
var otherSounds_1 = [];
this.manager.forEachActiveSound(function (sound) {
if (sound.key === this.key && sound.isPlaying) {
otherSounds_1.push(sound);
}
});
otherSounds_1.sort(function (a1, a2) {
if (a1.loop === a2.loop) {
return a2.seek - a1.seek;
}
return a1.loop ? 1 : -1;
});
var selectedSound = otherSounds_1[0];
this.audio = selectedSound.audio;
selectedSound.reset();
selectedSound.audio = null;
selectedSound.startTime = 0;
}
return true;
},
stopAndReleaseAudioTag: function () {
this.audio.pause();
this.audio.dataset.used = 'false';
this.audio = null;
this.startTime = 0;
},
reset: function () {
BaseSound.prototype.stop.call(this);
},
update: function (time, delta) {
if (this.isPlaying) {
// handling delayed playback
if (this.startTime > 0) {
if (this.startTime < time) {
this.audio.currentTime += (time - this.startTime) / 1000;
this.startTime = 0;
this.audio.play();
}
return;
}
// handle looping
var startTime = (this.currentMarker ? this.currentMarker.start : 0);
var endTime = startTime + this.duration;
var currentTime = this.audio.currentTime;
if (currentTime >= endTime) {
if (this.currentConfig.loop) {
this.audio.currentTime = startTime + (currentTime - endTime);
}
}
}
},
destroy: function () {
BaseSound.prototype.destroy.call(this);
// TODO release all HTML5 Audio tag related stuff
},
setMute: function () {
if (this.audio) {
this.audio.muted = this.currentConfig.mute || this.manager.mute;
}
},
setVolume: function () {
if (this.audio) {
this.audio.volume = this.currentConfig.volume * this.manager.volume;
}
},
setRate: function () {
BaseSound.prototype.setRate.call(this);
if (this.audio) {
this.audio.playbackRate = this.totalRate;
}
}
});
/**
* Mute setting.
*
* @name Phaser.Sound.HTML5AudioSound#mute
* @property {boolean} mute
*/
Object.defineProperty(HTML5AudioSound.prototype, 'mute', {
get: function () {
return this.currentConfig.mute;
},
set: function (value) {
this.currentConfig.mute = value;
this.setMute();
this.events.dispatch(new SoundValueEvent(this, 'SOUND_MUTE', value));
}
});
/**
* Volume setting.
*
* @name Phaser.Sound.HTML5AudioSound#volume
* @property {number} volume
*/
Object.defineProperty(HTML5AudioSound.prototype, 'volume', {
get: function () {
return this.currentConfig.volume;
},
set: function (value) {
this.currentConfig.volume = value;
this.setVolume();
this.events.dispatch(new SoundValueEvent(this, 'SOUND_VOLUME', value));
}
});
/**
* Current position of playing sound.
*
* @name Phaser.Sound.HTML5AudioSound#seek
* @property {number} seek
*/
Object.defineProperty(HTML5AudioSound.prototype, 'seek', {
get: function () {
if (this.isPlaying) {
return this.audio.currentTime;
}
else if (this.isPaused) {
return this.currentConfig.seek;
}
else {
return 0;
}
},
set: function (value) {
if (this.startTime > 0) {
return;
}
if (this.isPlaying || this.isPaused) {
value = Math.min(Math.max(0, value), this.duration);
if (this.isPlaying) {
this.audio.currentTime = value;
}
else if (this.isPaused) {
this.currentConfig.seek = value;
}
this.events.dispatch(new SoundValueEvent(this, 'SOUND_SEEK', value));
}
}
});
/**
* Property indicating whether or not
* the sound or current sound marker will loop.
*
* @name Phaser.Sound.HTML5AudioSound#loop
* @property {boolean} loop
*/
Object.defineProperty(HTML5AudioSound.prototype, 'loop', {
get: function () {
return this.currentConfig.loop;
},
set: function (value) {
this.currentConfig.loop = value;
if (this.audio) {
this.audio.loop = value;
}
}
});
module.exports = HTML5AudioSound;