Skip to content

Commit

Permalink
Stop audio playback when anki dialog is closed
Browse files Browse the repository at this point in the history
  • Loading branch information
killergerbah committed Apr 15, 2024
1 parent 7053a0b commit 4ad4583
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 15 deletions.
71 changes: 57 additions & 14 deletions common/audio-clip/audio-clip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface AudioData {
start: number;
end: number;
play: () => Promise<void>;
stop: () => void;
blob: () => Promise<Blob>;
base64: () => Promise<string>;
slice: (start: number, end: number) => AudioData;
Expand Down Expand Up @@ -86,10 +87,7 @@ class Base64AudioData implements AudioData {

async play(): Promise<void> {
if (this.playingAudio) {
this.stopAudio(this.playingAudio);
clearTimeout(this.stopAudioTimeout!);
this.playingAudio = undefined;
this.stopAudioTimeout = undefined;
this.stop();
return;
}

Expand All @@ -108,6 +106,17 @@ class Base64AudioData implements AudioData {
}, (this._end - this._start) / this.playbackRate + 100);
}

stop() {
if (!this.playingAudio) {
return;
}

this.stopAudio(this.playingAudio);
clearTimeout(this.stopAudioTimeout!);
this.playingAudio = undefined;
this.stopAudioTimeout = undefined;
}

private stopAudio(audio: HTMLAudioElement) {
audio.pause();
const src = audio.src;
Expand Down Expand Up @@ -210,10 +219,7 @@ class FileAudioData implements AudioData {
}

if (this.playingAudio) {
this.stopAudio(this.playingAudio, true);
clearTimeout(this.stopAudioTimeout!);
this.playingAudio = undefined;
this.stopAudioTimeout = undefined;
this._stopPlayingAudio();
return;
}

Expand All @@ -228,6 +234,16 @@ class FileAudioData implements AudioData {
}, (this._end - this._start) / this.playbackRate + 100);
}

stop() {
if (this.playingAudio) {
this._stopPlayingAudio();
}

if (this.clippingAudio) {
this._stopClippingAudio();
}
}

async blob() {
if (!this._blob) {
this._blob = await this._clipAudio();
Expand All @@ -242,12 +258,7 @@ class FileAudioData implements AudioData {

async _clipAudio(): Promise<Blob | undefined> {
if (this.clippingAudio) {
this.stopAudio(this.clippingAudio, false);
clearTimeout(this.stopClippingTimeout!);
this.clippingAudioReject?.('Did not finish recording blob');
this.clippingAudio = undefined;
this.stopClippingTimeout = undefined;
this.clippingAudioReject = undefined;
this._stopClippingAudio();
return undefined;
}

Expand Down Expand Up @@ -295,6 +306,30 @@ class FileAudioData implements AudioData {
});
}

private _stopClippingAudio() {
if (!this.clippingAudio) {
return;
}

this.stopAudio(this.clippingAudio, false);
clearTimeout(this.stopClippingTimeout!);
this.clippingAudioReject?.('Did not finish recording blob');
this.clippingAudio = undefined;
this.stopClippingTimeout = undefined;
this.clippingAudioReject = undefined;
}

private _stopPlayingAudio() {
if (!this.playingAudio) {
return;
}

this.stopAudio(this.playingAudio, true);
clearTimeout(this.stopAudioTimeout!);
this.playingAudio = undefined;
this.stopAudioTimeout = undefined;
}

private _audioElement(blobUrl: string, selectTrack: boolean): Promise<ExperimentalAudioElement> {
const audio = new Audio() as ExperimentalAudioElement;
audio.preload = 'metadata';
Expand Down Expand Up @@ -424,6 +459,10 @@ class Mp3AudioData implements AudioData {
await this.data.play();
}

stop() {
this.data.stop();
}

async blob() {
if (!this._blob) {
this._blob = await Mp3Encoder.encode(await this.data.blob(), this.workerFactory);
Expand Down Expand Up @@ -524,6 +563,10 @@ export default class AudioClip {
await this.data.play();
}

stop() {
this.data.stop();
}

async base64() {
return await this.data.base64();
}
Expand Down
8 changes: 7 additions & 1 deletion common/components/AnkiDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ const AnkiDialog = ({

e.preventDefault();
e.stopPropagation();
audioClip!.play();
audioClip!.play().catch(console.info);
},
[audioClip]
);
Expand Down Expand Up @@ -660,6 +660,12 @@ const AnkiDialog = ({
const { audioHelperText, audioClipPlayable } = useAudioHelperText(audioClip, onRerecord);
const { imageHelperText, imageAvailable } = useImageHelperText(image);

useEffect(() => {
if (!open) {
audioClip?.stop();
}
}, [open, audioClip]);

return (
<Dialog open={open} disableEnforceFocus fullWidth maxWidth="sm" onClose={onCancel}>
<Toolbar>
Expand Down

0 comments on commit 4ad4583

Please sign in to comment.