UWP DLL语音合成问题:移除Sleep后无声音,需无时限朗读文本
解决UWP SpeechSynthesis长文本朗读不完整/无声音的问题
我之前做UWP语音合成开发时也碰到过几乎一模一样的问题,你的核心痛点在于异步任务的生命周期管理错误和误用Sleep阻塞线程,咱们拆解问题并给出解决方案:
问题根源分析
- 保留Sleep(3000)时仅播3秒:Sleep会阻塞当前线程3秒,3秒后函数执行完毕,你定义的
player和speak都是局部变量,函数退出后这些对象会被CLR自动回收,自然就中断了长文本的播放。而且在UWP中随意阻塞线程(尤其是UI线程)是严重的反模式,会导致应用无响应。 - 移除Sleep后无声音:函数执行速度远快于语音合成和播放的启动速度,函数一结束,局部的
player、异步任务相关对象就被立即回收,媒体资源还没来得及加载播放就被销毁了。
解决方案
1. 调整对象生命周期,避免局部变量被回收
把SpeechSynthesizer和MediaPlayer改为类的成员变量,确保它们在播放过程中不会被回收:
// 在TextToSpeechUwpDll类中添加成员变量 private: SpeechSynthesizer^ m_speechSynth; MediaPlayer^ m_mediaPlayer;
在类的构造函数中初始化这些对象,并监听播放完成事件:
TextToSpeechUwpDll::TextToSpeechUwpDll() { m_speechSynth = ref new SpeechSynthesizer(); m_mediaPlayer = ref new MediaPlayer(); m_mediaPlayer->AutoPlay = true; // 监听播放完成事件,方便后续清理或状态更新 m_mediaPlayer->MediaEnded += ref new Windows::Foundation::TypedEventHandler<MediaPlayer^, Platform::Object^>(this, &TextToSpeechUwpDll::OnPlaybackCompleted); }
2. 重构ttsSpeak函数,修复内存泄漏+正确处理异步任务
int TextToSpeechUwpDll::ttsSpeak(const char* text) { // 处理字符串转换,用智能指针避免内存泄漏(你之前的new没有delete会导致泄漏) int wideCharCount = MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0); std::unique_ptr<wchar_t[]> wideText(new wchar_t[wideCharCount]); MultiByteToWideChar(CP_ACP, 0, text, -1, wideText.get(), wideCharCount); String^ sentence = ref new String(wideText.get()); // 先停止当前正在进行的播放(如果有的话) m_mediaPlayer->Pause(); m_mediaPlayer->Source = nullptr; // 异步执行语音合成并播放,添加异常处理避免崩溃 create_task(m_speechSynth->SynthesizeTextToStreamAsync(sentence)) .then([this](SpeechSynthesisStream^ speechStream) { m_mediaPlayer->Source = MediaSource::CreateFromStream(speechStream, speechStream->ContentType); m_mediaPlayer->Play(); }) .then([this](task<void> previousTask) { try { previousTask.get(); } catch (Platform::Exception^ ex) { // 这里可以添加自定义错误处理,比如返回错误码或日志 OutputDebugString(ex->Message->Data()); } }); return 0; // 根据你的需求返回成功/失败标识 }
3. 添加播放完成的回调处理
void TextToSpeechUwpDll::OnPlaybackCompleted(MediaPlayer^ sender, Platform::Object^ args) { // 播放完成后可以做一些清理工作,比如重置媒体源 sender->Source = nullptr; }
额外注意事项
- 内存泄漏问题:之前的代码中
new wchar_t[wchars_num]没有对应的delete[],会导致内存泄漏,用std::unique_ptr可以自动管理内存,避免这类问题。 - 异步异常处理:语音合成可能抛出异常(比如文本为空、语音引擎不可用等),一定要捕获这些异常,避免应用崩溃。
- 线程模型:如果你的DLL被非UWP进程调用,需要确保异步任务在正确的线程上下文执行,UWP的异步API默认会回到调用线程,但如果是跨进程场景可能需要额外处理。
内容的提问来源于stack exchange,提问作者georges619
相关产品推荐
相关产品推荐

