From 463ea39467eeff5cc01d5b927639cfbb6e2bf018 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Sat, 11 Jan 2025 18:11:14 +0100 Subject: [PATCH] Fix occasionally current speak not stopped when changing voice or rate (#144) * Fix occasionally current speak not stopped when changing voice or rate * Inherit tts rate when changing tts engine --- .../app/reader/components/tts/TTSControl.tsx | 24 ++++++------- .../src/services/tts/EdgeTTSClient.ts | 10 +++--- .../src/services/tts/TTSController.ts | 34 +++++++++++-------- packages/foliate-js | 2 +- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx index a8b85da1..facc061c 100644 --- a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx +++ b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx @@ -97,16 +97,16 @@ const TTSControl = () => { if (!ttsController) return; if (isPlaying) { - ttsController.pause(); + await ttsController.pause(); setIsPlaying(false); setIsPaused(true); } else if (isPaused) { // start for forward/backward/setvoice-paused // set rate don't pause the tts if (ttsController.state === 'paused') { - ttsController.resume(); + await ttsController.resume(); } else { - ttsController.start(); + await ttsController.start(); } setIsPlaying(true); setIsPaused(false); @@ -130,7 +130,7 @@ const TTSControl = () => { const handleStop = async () => { const ttsController = ttsControllerRef.current; if (ttsController) { - ttsController.stop(); + await ttsController.stop(); ttsControllerRef.current = null; setIsPlaying(false); setShowPanel(false); @@ -143,11 +143,11 @@ const TTSControl = () => { const ttsController = ttsControllerRef.current; if (ttsController) { if (ttsController.state === 'playing') { - ttsController.pause(); - ttsController.setRate(rate); - ttsController.start(); + await ttsController.pause(); + await ttsController.setRate(rate); + await ttsController.start(); } else { - ttsController.setRate(rate); + await ttsController.setRate(rate); } } }; @@ -156,11 +156,11 @@ const TTSControl = () => { const ttsController = ttsControllerRef.current; if (ttsController) { if (ttsController.state === 'playing') { - ttsController.pause(); - ttsController.setVoice(voice); - ttsController.start(); + await ttsController.pause(); + await ttsController.setVoice(voice); + await ttsController.start(); } else { - ttsController.setVoice(voice); + await ttsController.setVoice(voice); } } }; diff --git a/apps/readest-app/src/services/tts/EdgeTTSClient.ts b/apps/readest-app/src/services/tts/EdgeTTSClient.ts index b429c9b1..08243d04 100644 --- a/apps/readest-app/src/services/tts/EdgeTTSClient.ts +++ b/apps/readest-app/src/services/tts/EdgeTTSClient.ts @@ -57,7 +57,7 @@ export class EdgeTTSClient implements TTSClient { voiceId = this.#voice.id; } - this.stopInternal(); + await this.stopInternal(); // Preloading for longer ssml if (marks.length > 1) { @@ -117,7 +117,7 @@ export class EdgeTTSClient implements TTSClient { break; } - this.stopInternal(); + await this.stopInternal(); } } @@ -136,10 +136,10 @@ export class EdgeTTSClient implements TTSClient { } async stop() { - this.stopInternal(); + await this.stopInternal(); } - private stopInternal() { + private async stopInternal() { this.#isPlaying = false; this.#pausedAt = 0; this.#startedAt = 0; @@ -153,7 +153,7 @@ export class EdgeTTSClient implements TTSClient { this.#sourceNode = null; } if (this.#audioContext) { - this.#audioContext.close(); + await this.#audioContext.close(); this.#audioContext = null; } this.#audioBuffer = null; diff --git a/apps/readest-app/src/services/tts/TTSController.ts b/apps/readest-app/src/services/tts/TTSController.ts index 30674c9f..eda6d438 100644 --- a/apps/readest-app/src/services/tts/TTSController.ts +++ b/apps/readest-app/src/services/tts/TTSController.ts @@ -16,6 +16,7 @@ export class TTSController extends EventTarget { view: FoliateView; #nossmlCnt: number = 0; + ttsRate: number = 1.0; ttsClient: TTSClient; ttsWebClient: TTSClient; ttsEdgeClient: TTSClient; @@ -61,7 +62,7 @@ export class TTSController extends EventTarget { // FIXME: in case we are at the end of the book, need a better way to handle this if (this.#nossmlCnt < 10 && this.state === 'playing') { await this.view.next(1); - this.forward(); + await this.forward(); } return; } else { @@ -78,7 +79,7 @@ export class TTSController extends EventTarget { } if (lastCode === 'end' && this.state === 'playing') { - this.forward(); + await this.forward(); } } @@ -103,26 +104,26 @@ export class TTSController extends EventTarget { return this.#speak(resumeOrStart); } - pause() { + async pause() { this.state = 'paused'; - this.ttsClient.pause().catch((e) => this.error(e)); + await this.ttsClient.pause().catch((e) => this.error(e)); } - resume() { + async resume() { this.state = 'playing'; - this.ttsClient.resume().catch((e) => this.error(e)); + await this.ttsClient.resume().catch((e) => this.error(e)); } - stop() { + async stop() { this.state = 'stopped'; - this.ttsClient.stop().catch((e) => this.error(e)); + await this.ttsClient.stop().catch((e) => this.error(e)); } // goto previous sentence async backward() { - this.initViewTTS(); + await this.initViewTTS(); if (this.state === 'playing') { - this.stop(); + await this.stop(); this.#speak(this.view.tts?.prev()); } else { this.state = 'backward-paused'; @@ -134,7 +135,7 @@ export class TTSController extends EventTarget { async forward() { await this.initViewTTS(); if (this.state === 'playing') { - this.stop(); + await this.stop(); this.#speak(this.view.tts?.next()); } else { this.state = 'forward-paused'; @@ -143,7 +144,8 @@ export class TTSController extends EventTarget { } async setRate(rate: number) { - this.ttsClient.setRate(rate); + this.ttsRate = rate; + await this.ttsClient.setRate(this.ttsRate); } async getVoices(lang: string) { @@ -154,14 +156,16 @@ export class TTSController extends EventTarget { async setVoice(voiceId: string) { this.state = 'setvoice-paused'; - this.ttsClient.stop(); + await this.ttsClient.stop(); const useEdgeTTS = !!this.ttsEdgeVoices.find( (voice) => (voiceId === '' || voice.id === voiceId) && !voice.disabled, ); if (useEdgeTTS) { this.ttsClient = this.ttsEdgeClient; + await this.ttsClient.setRate(this.ttsRate); } else { this.ttsClient = this.ttsWebClient; + await this.ttsClient.setRate(this.ttsRate); } await this.ttsClient.setVoice(voiceId); } @@ -175,8 +179,8 @@ export class TTSController extends EventTarget { this.state = 'stopped'; } - kill() { + async kill() { this.state = 'stopped'; - this.ttsClient.stop(); + await this.ttsClient.stop(); } } diff --git a/packages/foliate-js b/packages/foliate-js index 3bdbd3d0..b9347d80 160000 --- a/packages/foliate-js +++ b/packages/foliate-js @@ -1 +1 @@ -Subproject commit 3bdbd3d015145a1adc455caf3b8c0452eea90da2 +Subproject commit b9347d80e8df7ba91e599899289f55f1ec2f5cdc