Skip to content

Commit

Permalink
audio-manager: Refactor stop() method and re-added emitter
Browse files Browse the repository at this point in the history
  • Loading branch information
timothyhale committed Mar 7, 2024
1 parent 8449ab0 commit 9a8c9af
Showing 1 changed file with 36 additions and 26 deletions.
62 changes: 36 additions & 26 deletions src/audio-manager.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {_audioContext} from './audio-listener.js';
import {Emitter, ListenerCallback} from '@wonderlandengine/api';
import {Emitter} from '@wonderlandengine/api';

/* Ramp times of 0 cause a click, 5 ms should be sufficient */
const MIN_RAMP_TIME = 5 / 1000;
/* Needed because WebAudio volumes don't accept 0 as valid volume */
const MIN_VOLUME = 0.001;

export enum PlayState {
/* The source is ready to be played */
READY,
/* The source has started playing */
PLAYING,
/* The source has been stopped */
STOPPED,
/* The source has reached the end of playback */
ENDED,
}

/**
Expand Down Expand Up @@ -129,7 +135,8 @@ class PlayableNode {
private _audioNode: AudioBufferSourceNode = new AudioBufferSourceNode(_audioContext);
private _destroy: boolean = false;
private _rampTime: number = MIN_RAMP_TIME;
private _callback: ((state?: PlayState) => void) | undefined;
// @todo: Find out how costly this is to have per node
private _emitter: Emitter<[PlayState]> = new Emitter<[PlayState]>();

/**
* Constructs a PlayableNode.
Expand All @@ -145,8 +152,7 @@ class PlayableNode {
this._audioManager = audioManager;
this._source = src;
this._gainNode.connect(_audioContext.destination);
// @todo: why is this necessary
this.stop = this.stop.bind(this);
this._emitter.notify(PlayState.READY);
}

/**
Expand Down Expand Up @@ -227,40 +233,40 @@ class PlayableNode {
throw 'playable-node: Invalid configuration for play()';
}
}
this._audioNode.addEventListener('ended', this.stop);
this._audioNode.addEventListener('ended', () => {
this._handleEndedEvent();
/* If node was stopped, isPlaying will be false already */
if(this._isPlaying) {
this._isPlaying = false;
this._emitter.notify(PlayState.ENDED)
}
});
this._audioNode.start();
this._isPlaying = true;
if (this._callback) {
this._callback(PlayState.PLAYING);
}
}

set listener(listener: (state?: PlayState) => void) {
this._callback = listener;
this._emitter.notify(PlayState.PLAYING);
}

/**
* Stops the playback, and if set to destroy, removes associated audio file.
*/
stop() {
if (this.isPlaying) {
this._audioNode.removeEventListener('ended', this.stop);
this._audioNode.stop();
}
if (this._audioNode !== undefined) {
private _handleEndedEvent() {
if (this._audioNode) {
this._audioNode.disconnect();
}
if (this._pannerNode !== undefined) {
if (this._pannerNode) {
this._pannerNode.disconnect();
}
this._isPlaying = false;
if (this._destroy) {
this._audioManager._remove(this._source);
this._gainNode.disconnect();
}
if (this._callback) {
this._callback(PlayState.STOPPED);
}
}

/**
* Stops the playback, and if set to destroy, removes associated audio file.
*/
stop() {
this._isPlaying = false
/* This triggers the 'ended' listener and frees the resources */
this._audioNode.stop();
this._emitter.notify(PlayState.STOPPED);
}

/**
Expand Down Expand Up @@ -289,6 +295,10 @@ class PlayableNode {
}, duration * 1000);
}

get emitter(): Emitter<[PlayState]> {
return this._emitter;
}

/**
* Checks if the audio node is currently playing.
*/
Expand Down

0 comments on commit 9a8c9af

Please sign in to comment.