在C#/WPF文本转语音应用中如何获取语音播报时长?
C#/WPF 文本转语音播报时长获取实现方案
以下是两种经过验证的可行实现方案:
方案1:基于WAV内存流解析提前获取精准时长(推荐)
该方案不依赖播报事件,可在播报前就计算出和实际播报完全一致的时长,稳定性和准确率最高。
using System.Speech.Synthesis; using System.IO; // 传入待播报文本、和播报参数一致的语音配置,返回精准播报时长 public TimeSpan CalculateSpeechDuration(string speakText, VoiceInfo targetVoice = null, int speakRate = 0, int speakVolume = 100) { using var synth = new SpeechSynthesizer(); // 保持计算参数和实际播报参数完全一致,避免时长偏差 if (targetVoice != null) synth.SelectVoice(targetVoice.Name); synth.Rate = speakRate; synth.Volume = speakVolume; using var memoryStream = new MemoryStream(); // 输出语音到内存流,不实际播报也不生成本地文件 synth.SetOutputToWaveStream(memoryStream); synth.Speak(speakText); synth.SetOutputToDefaultAudioDevice(); // 解析WAV头参数计算时长 int sampleRate = BitConverter.ToInt32(memoryStream.GetBuffer(), 24); short bitsPerSample = BitConverter.ToInt16(memoryStream.GetBuffer(), 34); short channels = BitConverter.ToInt16(memoryStream.GetBuffer(), 22); long audioDataLength = memoryStream.Length - 44; // WAV头固定占44字节 double totalSeconds = audioDataLength / (sampleRate * (bitsPerSample / 8.0) * channels); return TimeSpan.FromSeconds(totalSeconds); }
- 优点:时长完全精准,不受播报过程中暂停、中断、跳转的影响,适合需要提前展示时长的场景
- 注意:如果播报时会动态调整语速、音量、切换语音,需要同步调整计算时的对应参数
方案2:基于播报事件实时统计实际播报时长
如果不需要提前展示时长,只需要在播报完成后展示用户实际听到的时长(包含暂停、手动调整进度的时间),可以用这个轻量方案:
private readonly SpeechSynthesizer _synth = new SpeechSynthesizer(); private DateTime _speakStartTime; public void InitSpeechEventHandler() { // 异步播报开始时记录启动时间 _synth.SpeakStarted += (sender, args) => { _speakStartTime = DateTime.Now; }; // 播报完成后计算时长,更新WPF界面 _synth.SpeakCompleted += (sender, args) => { var actualDuration = DateTime.Now - _speakStartTime; // WPF跨线程更新UI需要调度到UI线程 Application.Current.Dispatcher.Invoke(() => { // 此处替换为你自己的UI更新逻辑 SpeechDurationTextBlock.Text = actualDuration.ToString(@"mm\:ss"); }); }; } // 调用播报时必须用异步方法,否则事件不会正常触发 public void StartSpeak(string text) { _synth.SpeakAsync(text); }
- 优点:实现简单无额外性能开销,统计的是用户实际感知的播报时长
- 注意:不要使用同步
Speak()方法播报,会阻塞UI线程同时导致事件触发异常
常见失效原因排查
如果你之前使用事件方案没有生效,大概率是以下问题:
- 调用了同步
Speak()方法而非异步SpeakAsync(),事件触发逻辑异常 - 没有将UI更新逻辑调度到WPF的UI线程,导致属性修改后界面没有刷新
- 多段语音同时播报时没有区分不同
Prompt实例,计时逻辑冲突
内容的提问来源于stack exchange,提问作者Jose Afonso Braga
相关产品推荐
相关产品推荐

