dsha-tts-bridge:把 DSH 的語音合成搬到宿主側

前言

DSH 在安卓上常跑在 proot 容器裏:容器內 /dev/snd 不可訪問,ffplay、aplay 這類播放命令全部失靈;而部分 ROM 的 Android WebView 又拿不到中文語音包,speechSynthesis.speak() 會直接靜默。兩條常見的朗讀路徑都不成立。

唯一穩定可用的方式,是在頁面裏用 <audio> 播放一個 MP3。下面介紹的這個插件就做了這件事:在 DSH 宿主進程裏把文字合成爲 MP3,通過 DSH 自帶的 webServer 暴露同源路由,頁面把 src 指過去即可。它由 flyinghouse-ma 維護。

這是什麼

dsha-tts-bridge 是宿主側的語音合成橋,只做一件事:文字 → MP3,然後由頁面負責播放。

它不依賴 API Key、不依賴賬號,走的是微軟 Edge 朗讀的 WebSocket 協議(api.msedgeservices.com,舊版端點是 speech.platform.bing.com),並非官方 Azure TTS SDK。插件自行實現了 WebSocket 客戶端(lib/websocket.js),因此零 npm 依賴。

核心功能

  1. 在宿主進程內合成語音,結果以 MP3 返回,頁面用 <audio> 就能播。
  2. 通過 DSH 自帶的 webServer 暴露同源路由,WebView 內可直接引用,不存在跨域問題。
  3. 內存中對最近 40 條合成結果做 LRU 緩存,同一句話反覆播報不會重複請求。
  4. 單次合成 15 秒超時,失敗即返回錯誤,不會卡住頁面。
  5. 成功返回 audio/mpeg;失敗返回 502 加純文本原因。

安裝與啓用

插件通過 DSH 的 profile 機制安裝:

dsh plugin --profile web add @flyinghouse-ma/dsha-tts-bridge

裝完需要重啓 dsh web,因爲它是宿主側模塊,熱加載不生效。

典型用法

裝好之後,任何頁面(含 WebView)都可以直接用 <audio> 播報:

<audio src="/dsh-tts/say.mp3?text=需要你確認一下" autoplay></audio>

需要控制音量或複用音頻時,可以用 fetch 取回 Blob 再播放:

const r = await fetch('/dsh-tts/say.mp3?text=' + encodeURIComponent('你好'));
const url = URL.createObjectURL(await r.blob());
new Audio(url).play();

服務端參數如下:

參數 說明
text 要念的文字,上限 200 字
voice 可選音色,默認 zh-CN-XiaoxiaoNeural(曉曉,中文女聲)

200 字上限是按“提醒播報”場景設定的,目的是防止該路由被當成通用 TTS 代理濫用。

適用場景與注意

適合以下情況:DSH 運行在安卓 proot 容器中、需要短語音播報(審批提醒、狀態播報)的開發者;或者 WebView 語音不可用、需要穩定朗讀路徑的場景。

幾點需要注意:

  1. 需要能訪問微軟的語音服務端點,網絡不通時會返回 502,這是已知限制。
  2. 插件只負責合成,播放控制(音量、打斷、隊列)由頁面自行決定。
  3. 插件以當前 dsh 進程的權限運行,安裝前應先閱讀源碼、確認許可證(MIT),再決定是否引入。
  4. 長文朗讀不適用於此插件(單條 200 字上限)。

結尾

dsha-tts-bridge 解決的是一個很窄但確實存在的問題:容器裏沒有音頻設備、WebView 又念不出中文時,用一個同源 MP3 路由把播報恢復可用。它不追求通用 TTS 能力,接口和限制都寫得很明確。

目錄頁:https://www.skillhub.cn/plugins/flyinghouse-ma/dsha-tts-bridge

源代碼:https://github.com/flyinghouse-ma/dsha-tts-bridge

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜