Skip to content

Commit a09208b

Browse files
committed
fix(media): cleanup audio resources on sound removal and replacement
- Cleanup old Sound before creating replacement when URL changes - Remove priority-stopped sounds from map (were leaked indefinitely) - Use cleanup() instead of stop() in stopSound/stopAllSounds/handleStop since these paths discard the Sound object entirely - Fix setTimeout end-timer closure: capture key at schedule time, only delete from map if the same sound instance is still at that key - Fix handleLoad variable shadowing bug (inner let shadowed outer)
1 parent 9b80f9c commit a09208b

1 file changed

Lines changed: 17 additions & 9 deletions

File tree

src/gmcp/Client/Media.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,8 @@ export class GMCPClientMedia extends GMCPPackage {
6767
async handleLoad(data: GMCPMessageClientMediaLoad) {
6868
const url = (data.url || this.defaultUrl) + data.name;
6969
const key = data.url + data.name;
70-
let sound = this.sounds[key] as ExtendedSound;
71-
if (!sound) {
72-
let sound: ExtendedSound = await this.client.cacophony.createSound(url);
70+
if (!this.sounds[key]) {
71+
const sound: ExtendedSound = await this.client.cacophony.createSound(url);
7372
sound.key = key;
7473
this.sounds[key] = sound;
7574
}
@@ -90,6 +89,10 @@ export class GMCPClientMedia extends GMCPPackage {
9089
const panType = data.is3d ? "HRTF" : "stereo";
9190
// Sound creation or updating
9291
if (!sound || sound.url !== mediaUrl) {
92+
// Cleanup old sound before replacing
93+
if (sound) {
94+
sound.cleanup();
95+
}
9396
// Create a new sound object
9497
if (data.type === "music") {
9598
sound = await this.client.cacophony.createSound(
@@ -128,9 +131,13 @@ export class GMCPClientMedia extends GMCPPackage {
128131
}
129132

130133
if (data.end) {
134+
const endKey = data.key!;
131135
setTimeout(() => {
132-
delete this.sounds[sound.key!];
133-
sound.stop();
136+
// Only remove if the same sound is still at this key
137+
if (this.sounds[endKey] === sound) {
138+
delete this.sounds[endKey];
139+
}
140+
sound.cleanup();
134141
}, data.end);
135142
}
136143

@@ -150,7 +157,8 @@ export class GMCPClientMedia extends GMCPPackage {
150157
for (let key in this.sounds) {
151158
const activeSound = this.sounds[key];
152159
if (activeSound.priority && activeSound.priority < data.priority) {
153-
activeSound.stop();
160+
activeSound.cleanup();
161+
delete this.sounds[key];
154162
}
155163
}
156164
sound.priority = data.priority;
@@ -213,14 +221,14 @@ export class GMCPClientMedia extends GMCPPackage {
213221
this.soundsByKey(data.key).forEach((sound) => this.stopSound(sound));
214222
}
215223
if (!data.name && !data.type && !data.tag && !data.key) {
216-
this.allSounds.forEach((sound) => sound.stop());
224+
this.allSounds.forEach((sound) => sound.cleanup());
217225
this.sounds = {};
218226
}
219227
}
220228

221229
private stopSound(sound: ExtendedSound) {
222230
delete this.sounds[sound.key!];
223-
sound.stop();
231+
sound.cleanup();
224232
}
225233

226234
handleListenerPosition(data: GMCPMessageClientMediaListenerPosition) {
@@ -265,7 +273,7 @@ export class GMCPClientMedia extends GMCPPackage {
265273
}
266274

267275
stopAllSounds() {
268-
this.allSounds.forEach((sound) => sound.stop());
276+
this.allSounds.forEach((sound) => sound.cleanup());
269277
this.sounds = {};
270278
}
271279
}

0 commit comments

Comments
 (0)