Skip to content

[Bug] TTS 朗读中切换语音引擎,旧引擎不会停止、仍在后台继续朗读 / Switching TTS engine mid-playback doesn't stop the previous engine #349

@chy5301

Description

@chy5301

Type

Bug

Description

中文

现象

桌面端 TTS 朗读时,点击「开始」播放后,中途切换到另一个语音引擎(音源),会出现:

  1. 之前已经开始朗读的旧引擎不会暂停,仍在后台继续朗读
  2. 此时的「开始/暂停」按钮只能控制切换后的当前引擎,对仍在后台播放的旧引擎完全无效
  3. 想真正让旧引擎停下,必须:先暂停当前引擎 → 切回原引擎 → 再「开始/暂停」各按一次,旧引擎才会真正停止。

复现步骤

  1. 打开一本书,进入 TTS,选引擎 A(如 Edge TTS),点「开始」,正常朗读;
  2. 朗读过程中,在引擎选择里切到引擎 B(如系统 TTS / DashScope);
  3. 观察:A 仍在后台出声,B 并未真正接管;此时按「开始/暂停」只影响 B,A 关不掉;
  4. 只有切回 A 并再「开始/暂停」各一次,A 才停。

可核实的代码事实(仅供定位,未下结论)

源码 packages/core/src/stores/tts-store.ts 中,system / edge / dashscope 三个引擎各持有独立的 player 单例:

  • 切换引擎的 UI(packages/app/src/components/reader/TTSPage.tsx:405)调用 onUpdateConfig({ engine }),最终落到 store 的 updateConfigtts-store.ts:313-316),它只是 { ...config, ...updates } 合并配置,没有停止当前正在播放的 player
  • play / pause / resumetts-store.ts:149-270)都只对当前 config.engine 对应的那一个 player 操作,因此切换引擎后这些操作落在「新引擎」上,碰不到仍在后台播放的旧引擎单例;
  • 对比同文件中已经写对的两处:stoptts-store.ts:272-282)与 jumpToChunktts-store.ts:332-334)都会 getSystemTTS().stop(); getEdgeTTS().stop(); getDashScopeTTS().stop(); 把三个引擎全部停掉。play / updateConfig 缺少这一步。

可能的修复方向(仅建议):在切换引擎、或 play() 启动前,参照 stop/jumpToChunk 先停掉全部三个引擎,再启动目标引擎,避免旧实例残留后台播放。

English

Symptom

On desktop, while TTS is reading, if you switch to another TTS engine mid-playback:

  1. The previously-playing engine does not pause and keeps reading in the background;
  2. The Play/Pause button now only controls the newly-selected engine and has no effect on the still-playing old engine;
  3. To actually stop the old engine you must: pause the current engine → switch back to the original engine → press Play/Pause once each, and only then does the old engine truly stop.

Steps to reproduce

  1. Open a book, start TTS with engine A (e.g. Edge TTS), playback works;
  2. While it's reading, switch to engine B (e.g. System / DashScope) in the engine selector;
  3. Observe: A is still audible in the background, B hasn't really taken over; Play/Pause only affects B, A can't be stopped;
  4. Only after switching back to A and pressing Play/Pause again does A stop.

Verifiable code facts (for triage; not conclusions)

In packages/core/src/stores/tts-store.ts, the three engines (system / edge / dashscope) each hold their own player singleton:

  • The engine-switch UI (packages/app/src/components/reader/TTSPage.tsx:405) calls onUpdateConfig({ engine }), which reaches the store's updateConfig (tts-store.ts:313-316). That only merges { ...config, ...updates } and never stops the currently-playing player;
  • play / pause / resume (tts-store.ts:149-270) each act only on the player matching the current config.engine, so after switching they target the new engine and never touch the old engine's still-playing singleton;
  • For comparison, two places in the same file get this right: stop (tts-store.ts:272-282) and jumpToChunk (tts-store.ts:332-334) both call getSystemTTS().stop(); getEdgeTTS().stop(); getDashScopeTTS().stop(); to stop all three. play / updateConfig omit this step.

Possible fix direction (suggestion only): before switching engines, or at the start of play(), stop all three engines first (as stop/jumpToChunk already do) and then start the target engine, to avoid a leftover old instance playing in the background.

Device

  • Platform: Desktop (Windows), Tauri
  • OS: Windows 11 (Build 26200)
  • App: v1.3.2
  • Locale: zh-CN

Logs

会话诊断日志(去重 + 脱敏)/ De-duplicated & sanitized session log

说明:本应用的 TTS 引擎切换路径(tts-store.tsplay/pause/resume/updateConfig)没有任何 console 日志埋点,因此该 bug 不会在 App 自带的诊断日志中留痕——上面这份日志仅作环境/会话佐证(Tauri + Windows、EPUB 已打开、TTS 会话已激活),不包含切换动作本身。
Note: the engine-switch code path emits no console logs, so this bug leaves no trace in the app's diagnostic logs. The linked log is environment/session context only and does not contain the switch action itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions