Skip to content

Commit

Permalink
✨ [Sound] Manually emit ended event on .stop() but never started
Browse files Browse the repository at this point in the history
  • Loading branch information
beefchimi committed Dec 20, 2023
1 parent 6fc43cf commit 0925bf7
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 5 deletions.
23 changes: 18 additions & 5 deletions src/Sound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export class Sound extends EmittenCommon<SoundEventMap> {
this.#source.connect(this.#gainNode).connect(this.destination);
this.#gainNode.gain.setValueAtTime(this._volume, this.context.currentTime);

// We could `emit` a "created" event, but it wouldn't get caught
// by any listeners, since those cannot be attached until after creation.
// The `ended` event is fired either when the sound has played its full duration,
// or the `.stop()` method has been called.
this.#source.addEventListener('ended', this.#handleEnded, {once: true});
}

Expand Down Expand Up @@ -129,7 +129,16 @@ export class Sound extends EmittenCommon<SoundEventMap> {

stop() {
this.#setState('stopping');
if (this.#started) this.#source.stop();

if (this.#started) {
this.#source.stop();
} else {
// Required to manually emit the `ended` event for "un-started" sounds.
this.#handleEnded();
}

// Should `disconnect` and `empty` be moved into `#handleEnded`?
// Would this actually matter?
this.#source.disconnect();
this.empty();

Expand All @@ -145,7 +154,11 @@ export class Sound extends EmittenCommon<SoundEventMap> {

readonly #handleEnded = () => {
// Intentionally not setting `stopping` state here,
// but we may want ot consider a "ending" state instead.
this.emit('ended', {id: this.id, source: this.#source});
// but we may want to consider a "ending" state instead.
this.emit('ended', {
id: this.id,
source: this.#source,
neverStarted: !this.#started,
});
};
}
19 changes: 19 additions & 0 deletions src/tests/Sound.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,25 @@ describe('Sound component', () => {
expect(spyEnded).toBeCalledWith({
id: testSound.id,
source: expect.any(AudioBufferSourceNode),
neverStarted: false,
});
});

it('emits `ended` event for a stopped sound that was never started', () => {
const testSound = new Sound(...mockConstructorArgs);
const spyEnded: SoundEventMap['ended'] = vi.fn((_event) => {});

testSound.on('ended', spyEnded);

expect(spyEnded).not.toBeCalled();
vi.advanceTimersToNextTimer();

testSound.stop();

expect(spyEnded).toBeCalledWith({
id: testSound.id,
source: expect.any(AudioBufferSourceNode),
neverStarted: true,
});
});
});
Expand Down

0 comments on commit 0925bf7

Please sign in to comment.