system.speech.synthesis仅支持windows交互式桌面会话,不适用于服务或.net core跨平台环境;需确认已安装neural语音引擎,rate控制在-5~5,录音需先setoutputtowavefile,异步操作注意线程上下文与资源释放。

System.Speech.Synthesis 在 Windows 桌面程序里直接用,但别在服务或 .NET Core 跨平台项目里硬套
它只支持 Windows 交互式桌面会话,Linux/macOS 或 Windows 服务中运行会直接抛 PlatformNotSupportedException 或 InvalidOperationException: The operation is not supported on a non-interactive desktop。不是代码写错了,是环境不支持。
- 必须先确认语音引擎已安装:打开「设置 → 时间和语言 → 语音」,中文需看到“晓晓”“云健”等 Neural 语音;否则
synth.GetInstalledVoices()返回空列表,SelectVoice()失败后Speak()静音无报错 -
Rate值范围是 -10 到 10,设成 -12 或 15 会被静默截断,部分语音引擎对负值支持差,建议控制在 -5~5 - 要录音到文件,必须调用
SetOutputToWaveFile("out.wav")后再Speak();不能和SetOutputToDefaultAudioDevice()混用同一个SpeechSynthesizer实例,否则抛InvalidOperationException - 异步播放用
SpeakAsync(),但暂停/继续(Pause()/Resume())仅适用于当前正在播放的音频流,无法中断已排队的后续文本
Azure Speech SDK 的语音名必须全匹配,不能靠区域自动推导
填 zh-CN 不等于能用 zh-CN-XiaoxiaoNeural,SDK 不做模糊匹配。写错名称(比如大小写、拼写、少“Neural”)会导致静默回退到基础语音,甚至合成失败却不报明显错误。
- 语音名必须从 Azure 官方文档查最新列表,例如当前有效的是
zh-CN-XiaoxiaoNeural、zh-CN-YunxiNeural,写成zh-CN-xiaoxiao或zh-CN-XiaoXiao都不行 - 初始化
SpeechConfig时传的是 region 字符串(如"eastasia"),不是 endpoint URL;填错 region 会返回Unauthorized或InvalidRegion - 免费层每月限 0.5 百万字符,超量后请求返回
403 Forbidden或429 Too Many Requests,错误信息里不带配额提示,得自己记用量 - 合成结果
AudioData默认是 WAV 格式二进制,要 MP3 得用AudioConfig.FromStreamOutput()+ 手动编码,SDK 不内置 MP3 封装
WebView2 调用 Web Speech API 是唯一免装引擎、不依赖系统 TTS 的轻量方案
它绕过了 Windows SAPI 和 Azure 订阅,直接走 Edge 内核的 speechSynthesis,适合 WinForms/WPF 中嵌入简单播报,但受限于 Edge 版本和系统麦克风/语音权限策略。
- 必须确保目标机器已安装 WebView2 Runtime(或打包随应用分发),且 Edge 版本 ≥ 90;旧版可能不支持中文 Neural 语音
- 首次调用前需检查
window.speechSynthesis.getVoices()是否有中文语音,没有就说明系统没授权或 Edge 未加载语音引擎 - 不能控制采样率、位深等底层参数,输出格式固定为系统默认(通常是 WAV),也不支持 SSML
- 调用
speechSynthesis.speak()后无法精确暂停,只能cancel()全部队列,不适合需要毫秒级控制的场景
三个方案混用时最容易忽略的资源释放和线程上下文
System.Speech 实例不显式 Dispose() 可能卡住音频设备;Azure SDK 的 SpeechSynthesizer 必须 await DisposeAsync(),否则后续合成可能卡在 pending 状态。更隐蔽的是:WinForms 中若在非 UI 线程调用 SpeakAsync(),事件回调(如 SpeakCompleted)可能跑在后台线程,更新 UI 时直接崩。
- 所有
SpeechSynthesizer(System.Speech)实例建议用using包裹,尤其生成文件场景,避免句柄泄漏 - Azure SDK 的
SpeechSynthesizer创建开销大,不要每次合成都 new 一个,应复用并注意并发安全 - WebView2 中 JS 调用
speechSynthesis是异步的,C# 层通过ExecuteScriptAsync()触发后,没法同步等待完成,得靠 JS 回调通知 C# - 跨线程触发语音时,System.Speech 的
SpeakCompleted事件默认不在 UI 线程触发,WinForms 中需手动BeginInvoke更新控件











