Testing new OfflineAudioContext

This commit is contained in:
Richard Davey 2024-08-26 12:20:14 +01:00
parent 378838a011
commit 75ebcea0ac
No known key found for this signature in database
3 changed files with 102 additions and 44 deletions

View file

@ -78,7 +78,7 @@ var AudioFile = new Class({
var _this = this; var _this = this;
// interesting read https://github.com/WebAudio/web-audio-api/issues/1305 // interesting read https://github.com/WebAudio/web-audio-api/issues/1305
this.config.context.decodeAudioData(this.xhrLoader.response, this.config.offlineContext.decodeAudioData(this.xhrLoader.response,
function (audioBuffer) function (audioBuffer)
{ {
_this.data = audioBuffer; _this.data = audioBuffer;

View file

@ -45,7 +45,7 @@ var WebAudioSound = new Class({
if (!this.audioBuffer) if (!this.audioBuffer)
{ {
throw new Error('Audio key "' + key + '" not found in cache'); throw new Error('Audio key not found: ' + key);
} }
/** /**

View file

@ -37,6 +37,15 @@ var WebAudioSoundManager = new Class({
function WebAudioSoundManager (game) function WebAudioSoundManager (game)
{ {
/**
* The OfflineAudioContext used for audio decoding and state management.
*
* @name Phaser.Sound.WebAudioSoundManager#offlineContext
* @type {OfflineAudioContext}
* @since 3.85.0
*/
this.offlineContext = new OfflineAudioContext(2, 1, 8000);
/** /**
* The AudioContext being used for playback. * The AudioContext being used for playback.
* *
@ -44,7 +53,7 @@ var WebAudioSoundManager = new Class({
* @type {AudioContext} * @type {AudioContext}
* @since 3.0.0 * @since 3.0.0
*/ */
this.context = this.createAudioContext(game); this.context = null;
/** /**
* Gain node responsible for controlling global muting. * Gain node responsible for controlling global muting.
@ -53,7 +62,7 @@ var WebAudioSoundManager = new Class({
* @type {GainNode} * @type {GainNode}
* @since 3.0.0 * @since 3.0.0
*/ */
this.masterMuteNode = this.context.createGain(); this.masterMuteNode = null;
/** /**
* Gain node responsible for controlling global volume. * Gain node responsible for controlling global volume.
@ -62,11 +71,7 @@ var WebAudioSoundManager = new Class({
* @type {GainNode} * @type {GainNode}
* @since 3.0.0 * @since 3.0.0
*/ */
this.masterVolumeNode = this.context.createGain(); this.masterVolumeNode = null;
this.masterMuteNode.connect(this.masterVolumeNode);
this.masterVolumeNode.connect(this.context.destination);
/** /**
* Destination node for connecting individual sounds to. * Destination node for connecting individual sounds to.
@ -75,19 +80,31 @@ var WebAudioSoundManager = new Class({
* @type {AudioNode} * @type {AudioNode}
* @since 3.0.0 * @since 3.0.0
*/ */
this.destination = this.masterMuteNode; this.destination = null;
this.locked = this.context.state === 'suspended' && ('ontouchstart' in window || 'onclick' in window); this._volume = 1;
this._mute = false;
BaseSoundManager.call(this, game); BaseSoundManager.call(this, game);
if (this.locked && game.isBooted) this.locked = this.offlineContext.state === 'suspended';
console.log('SM locked', this.locked);
if (this.locked)
{ {
this.unlock(); if (game.isBooted)
{
this.unlock();
}
else
{
game.events.once(GameEvents.BOOT, this.unlock, this);
}
} }
else else
{ {
game.events.once(GameEvents.BOOT, this.unlock, this); this.createAudioContext();
} }
}, },
@ -101,29 +118,35 @@ var WebAudioSoundManager = new Class({
* @method Phaser.Sound.WebAudioSoundManager#createAudioContext * @method Phaser.Sound.WebAudioSoundManager#createAudioContext
* @since 3.0.0 * @since 3.0.0
* *
* @param {Phaser.Game} game - Reference to the current game instance.
*
* @return {AudioContext} The AudioContext instance to be used for playback. * @return {AudioContext} The AudioContext instance to be used for playback.
*/ */
createAudioContext: function (game) createAudioContext: function ()
{ {
var audioConfig = game.config.audio; console.log('createAudioContext');
var audioConfig = this.game.config.audio;
var context;
if (audioConfig.context) if (audioConfig.context)
{ {
audioConfig.context.resume(); audioConfig.context.resume();
return audioConfig.context; context = audioConfig.context;
} }
else if (window.hasOwnProperty('AudioContext'))
if (window.hasOwnProperty('AudioContext'))
{ {
return new AudioContext(); context = new AudioContext();
} }
else if (window.hasOwnProperty('webkitAudioContext')) else if (window.hasOwnProperty('webkitAudioContext'))
{ {
return new window.webkitAudioContext(); context = new window.webkitAudioContext();
} }
this.setAudioContext(context);
this.locked = this.context.state === 'suspended';
return context;
}, },
/** /**
@ -167,6 +190,9 @@ var WebAudioSoundManager = new Class({
this.destination = this.masterMuteNode; this.destination = this.masterMuteNode;
this.setVolume(this._volume);
this.setMute(this._mute);
return this; return this;
}, },
@ -214,6 +240,8 @@ var WebAudioSoundManager = new Class({
*/ */
decodeAudio: function (audioKey, audioData) decodeAudio: function (audioKey, audioData)
{ {
console.log('decodeAudio', audioKey);
var audioFiles; var audioFiles;
if (!Array.isArray(audioKey)) if (!Array.isArray(audioKey))
@ -306,12 +334,21 @@ var WebAudioSoundManager = new Class({
*/ */
unlock: function () unlock: function ()
{ {
console.log('SM unlock');
var _this = this; var _this = this;
var body = document.body; var body = document.body;
var unlockHandler = function unlockHandler () var unlockHandler = function unlockHandler ()
{ {
console.log('SM unlockHandler invoked');
// if (!_this.context)
// {
// _this.createAudioContext();
// }
if (_this.context && body) if (_this.context && body)
{ {
var bodyRemove = body.removeEventListener.bind(body); var bodyRemove = body.removeEventListener.bind(body);
@ -353,7 +390,7 @@ var WebAudioSoundManager = new Class({
*/ */
onBlur: function () onBlur: function ()
{ {
if (!this.locked) if (!this.locked && this.context)
{ {
this.context.suspend(); this.context.suspend();
} }
@ -392,20 +429,23 @@ var WebAudioSoundManager = new Class({
*/ */
update: function (time, delta) update: function (time, delta)
{ {
var listener = this.context.listener; if (this.context)
if (listener && listener.positionX !== undefined)
{ {
var x = GetFastValue(this.listenerPosition, 'x', null); var listener = this.context.listener;
var y = GetFastValue(this.listenerPosition, 'y', null);
if (x && x !== this._spatialx) if (listener && listener.positionX !== undefined)
{ {
this._spatialx = listener.positionX.value = x; var x = GetFastValue(this.listenerPosition, 'x', null);
} var y = GetFastValue(this.listenerPosition, 'y', null);
if (y && y !== this._spatialy)
{ if (x && x !== this._spatialx)
this._spatialy = listener.positionY.value = y; {
this._spatialx = listener.positionX.value = x;
}
if (y && y !== this._spatialy)
{
this._spatialy = listener.positionY.value = y;
}
} }
} }
@ -428,16 +468,24 @@ var WebAudioSoundManager = new Class({
destroy: function () destroy: function ()
{ {
this.destination = null; this.destination = null;
this.masterVolumeNode.disconnect();
this.masterVolumeNode = null; if (this.masterVolumeNode)
this.masterMuteNode.disconnect(); {
this.masterMuteNode = null; this.masterVolumeNode.disconnect();
this.masterVolumeNode = null;
}
if (this.masterMuteNode)
{
this.masterMuteNode.disconnect();
this.masterMuteNode = null;
}
if (this.game.config.audio.context) if (this.game.config.audio.context)
{ {
this.context.suspend(); this.context.suspend();
} }
else else if (this.context)
{ {
var _this = this; var _this = this;
@ -478,12 +526,17 @@ var WebAudioSoundManager = new Class({
get: function () get: function ()
{ {
return (this.masterMuteNode.gain.value === 0); return this._mute;
}, },
set: function (value) set: function (value)
{ {
this.masterMuteNode.gain.setValueAtTime(value ? 0 : 1, 0); this._mute = value;
if (this.masterMuteNode)
{
this.masterMuteNode.gain.setValueAtTime(value ? 0 : 1, 0);
}
this.emit(Events.GLOBAL_MUTE, this, value); this.emit(Events.GLOBAL_MUTE, this, value);
} }
@ -518,12 +571,17 @@ var WebAudioSoundManager = new Class({
get: function () get: function ()
{ {
return this.masterVolumeNode.gain.value; return this._volume;
}, },
set: function (value) set: function (value)
{ {
this.masterVolumeNode.gain.setValueAtTime(value, 0); this._volume = value;
if (this.masterVolumeNode)
{
this.masterVolumeNode.gain.setValueAtTime(value, 0);
}
this.emit(Events.GLOBAL_VOLUME, this, value); this.emit(Events.GLOBAL_VOLUME, this, value);
} }