System.Speech.Synthesis 是 Windows 桌面首选本地 TTS 方案,依赖 SAPI 引擎、无需联网;需确保交互式桌面会话、检查可用语音、合理设置 Rate,异步用 SpeakAsync,录音需 SetOutputToWaveFile 且避免混用输出方式。

用 System.Speech.Synthesis 实现基础 TTS(Windows 桌面首选)
这是 .NET Framework 3.0+ 自带的本地语音合成方案,无需联网、不依赖第三方服务,适合 WinForms/WPF 桌面应用。它调用的是 Windows 系统内置的 SAPI 引擎(如 Microsoft David/Zira),稳定且延迟低。
常见错误是直接 new SpeechSynthesizer() 后立刻调用 Speak(),结果无声或报错 InvalidOperationException: The operation is not supported on a non-interactive desktop——这通常发生在 Windows 服务或后台线程中(无用户会话)。必须确保代码运行在交互式桌面会话下。
- 初始化后建议先检查
synth.GetInstalledVoices().Count,确认至少有一个可用语音,否则Speak()会静默失败 - 设置语速用
Rate属性(范围 -10 到 10),别直接设 0 或负数过大,部分语音引擎不支持极端值 - 若需异步播放,用
SpeakAsync();若要暂停/继续,必须启用SetOutputToDefaultAudioDevice()且不能用Speak()同步阻塞 - 生成音频文件:调用
SetOutputToWaveFile("out.wav")后再Speak(),注意路径需有写权限,且不能同时对同一实例混用SetOutputToDefaultAudioDevice()和SetOutputToWaveFile()
var synth = new SpeechSynthesizer();
synth.SetOutputToDefaultAudioDevice();
synth.Speak("你好,这是本地 TTS");
用 Microsoft.CognitiveServices.Speech 调用 Azure TTS(跨平台 + 高质量)
这是微软官方推荐的现代方案,支持 Windows/macOS/Linux/.NET Core/.NET 5+,语音更自然(支持神经语音)、多语言、可细粒度控制音色/语调/停顿。但必须联网,且需要 Azure 订阅密钥和区域配置。
容易踩的坑是复制文档示例时漏掉 await 或忽略 DisposeAsync(),导致音频播放卡住或资源泄漏;另一个高频问题是 SpeechConfig.FromSubscription() 传入错误的 region(比如密钥在 eastus,却填成 chinaeast2),结果报错 Failed with status code Unauthorized。
- 语音名必须精确匹配 Azure 支持列表,例如中文用
zh-CN-XiaoxiaoNeural,写成zh-CN-xiaoxiao会静默回退到基础语音 - 合成到内存流用
SpeechSynthesizer(speechConfig, null)+SynthesizeTextAsync(),返回SpeechSynthesisResult,其AudioData是 WAV 格式原始字节 - 若在 ASP.NET Core 中使用,避免在静态单例里复用
SpeechSynthesizer实例(非线程安全),应按需创建或使用工厂模式
var config = SpeechConfig.FromSubscription("key", "eastus");
config.SpeechSynthesisVoiceName = "zh-CN-YunyangNeural";
using var synthesizer = new SpeechSynthesizer(config);
var result = await synthesizer.SynthesizeTextAsync("今天天气不错");
绕过权限/部署限制:用 Process.Start() 调起系统 TTS 工具
当目标机器无法安装 .NET Framework 或没权限引用 NuGet 包时,可借助 Windows 自带的 PowerShell 或 Windows.Media.SpeechSynthesis(UWP)间接实现。但注意:这不是纯 C# 实现,而是进程级调用,可控性弱、调试难。
典型失败场景是 PowerShell 脚本执行被组策略禁用(ExecutionPolicy 为 Restricted),或脚本中用了中文引号、全角空格导致解析失败;还有人误把 Out-Null 写成 Out-Nulll,结果进程卡死无响应。
- PowerShell 方案本质是调用
Add-Type -AssemblyName System.Speech; $s = New-Object System.Speech.Synthesis.SpeechSynthesizer; $s.Speak('text') - 必须用
UseShellExecute = false+CreateNoWindow = true,否则弹黑窗;重定向StandardError可捕获执行失败原因 - 不推荐用于高并发场景(每次启动新进程开销大),仅作临时补救或兼容老旧环境
为什么不用 Windows.Media.SpeechSynthesis(UWP)?
这个 API 在 UWP 应用中可用,但不能直接用于传统 .NET Framework/.NET Core 控制台或 WinForms 项目——引用 Windows.winmd 会触发“类型在多个程序集中定义”冲突,且打包部署复杂(需 AppContainer 权限、Store 签名等)。
即使强行通过 TargetPlatformVersion 和 WindowsSdkPackage 引入,在非 UWP 宿主中调用 SpeechSynthesizer 构造函数也会抛 COMException: Class not registered。简单说:它只属于 UWP 生态,硬塞进其他项目只会增加维护成本。
真正需要跨平台又不想碰云服务的,目前没有完美替代;要么接受 System.Speech 的 Windows 限定,要么用 Azure SDK 承担网络与配置负担。折中点在于:是否允许用户离线使用——如果必须离线,System.Speech 就是事实标准,别花时间折腾其他封装。











