You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 11调用OneCore SAPI TTS时语音卡顿及语速无法修改问题

针对Delphi 11中OneCore SAPI TTS问题的解决方案

问题1:高负载下语音播放卡顿

核心原因

音乐播放器能流畅播放是因为它们会将音频会话标记为高优先级,避免系统在高负载时节流音频线程。你的TTS默认使用普通优先级线程,容易被其他进程抢占CPU时间。单纯将Speak()放入线程无法解决,因为线程优先级未针对性调整,且未配置音频会话优先级。

解决步骤

  1. 提升音频会话优先级
    Windows Audio Session API允许为音频流设置优先级,确保TTS音频不被系统节流。需导入IAudioSessionControl2接口并配置:

    type
      IAudioSessionControl2 = interface(IAudioSessionControl)
        ['{bfb7ff88-7239-4fc9-8fa2-07c950be9c6d}']
        function SetSessionPriority(priority: LPCWSTR): HRESULT; stdcall;
        // 其他接口方法需完整导入,此处省略
      end;
    
    procedure SetTTSSessionPriority;
    var
      pDeviceEnumerator: IMMDeviceEnumerator;
      pDefaultDevice: IMMDevice;
      pAudioSessionManager: IAudioSessionManager2;
      pSessionControl: IAudioSessionControl;
      pSessionControl2: IAudioSessionControl2;
    begin
      if CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, pDeviceEnumerator) = S_OK then
      begin
        if pDeviceEnumerator.GetDefaultAudioEndpoint(eRender, eMultimedia, pDefaultDevice) = S_OK then
        begin
          if pDefaultDevice.Activate(IID_IAudioSessionManager2, CLSCTX_ALL, nil, pAudioSessionManager) = S_OK then
          begin
            if pAudioSessionManager.GetAudioSessionControl(nil, 0, pSessionControl) = S_OK then
            begin
              if pSessionControl.QueryInterface(IID_IAudioSessionControl2, pSessionControl2) = S_OK then
              begin
                pSessionControl2.SetSessionPriority('Pro Audio');
                pSessionControl2.Release;
              end;
              pSessionControl.Release;
            end;
            pAudioSessionManager.Release;
          end;
          pDefaultDevice.Release;
        end;
        pDeviceEnumerator.Release;
      end;
    end;
    
  2. 调整TTS线程优先级
    处理TTS播放的线程需设置为高于普通优先级,避免被BLE数据处理等任务抢占:

    // 在TTS线程的Execute方法开头设置优先级
    SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_ABOVE_NORMAL);
    

    注意:仅在播放期间提升优先级,播放完成后恢复原优先级,避免影响系统整体性能。

  3. 使用异步播放并避免阻塞
    调用Speak时使用SPF_ASYNC参数,让SAPI在后台处理播放,不阻塞主线程或BLE处理线程:

    tts.Speak(s, SPF_ASYNC or SPF_PURGEBEFORESPEAK);
    

    同时实现ISpNotifySink接口监听播放完成事件,避免重复调用导致队列拥堵。

  4. 隔离BLE数据处理与TTS资源
    将BLE数据接收和处理放入低优先级线程,或使用线程安全队列缓冲数据,避免在接收回调中执行耗时操作,减少与TTS线程的CPU竞争。

问题2:SetRate无法修改语速

核心原因

OneCore SAPI的语速配置逻辑与传统SAPI略有差异,直接调用ISpVoice::SetRate可能未正确作用于当前使用的语音引擎,或参数范围与系统GUI的设置不匹配。

解决步骤

  1. 确认参数范围匹配
    OneCore语音引擎的语速范围可能与传统SAPI的-1010不同,部分中文引擎支持-50100的范围。先获取当前语速值,再调整:

    var
      CurrentRate: Integer;
    begin
      tts.GetRate(CurrentRate);
      // 测试不同范围的数值,比如设置为5(对应系统GUI的中等偏快)
      tts.SetRate(5);
    end;
    
  2. 通过语音Token配置语速
    直接修改语音引擎的属性,确保设置生效:

    var
      pVoiceToken: ISpObjectToken;
    begin
      if tts.GetVoice(pVoiceToken) = S_OK then
      begin
        pVoiceToken.SetStringValue('Attributes', 'Rate', '5');
        // 重新加载语音配置
        tts.SetVoice(pVoiceToken);
        pVoiceToken.Release;
      end;
    end;
    
  3. 确保设置时机正确
    必须在调用Speak之前调用SetRate,如果使用异步播放,需在上一次播放完成后再设置下一次的语速,避免被队列中的任务覆盖。

  4. 检查OneCore引擎兼容性
    部分OneCore中文语音引擎需要特定的初始化顺序,确保在创建ISpVoice实例后,先选择语音引擎再设置语速:

    var
      pVoiceToken: ISpObjectToken;
    begin
      // 查找OneCore中文语音引擎
      if SpFindBestToken(SPCAT_VOICES, 'Language=804;Vendor=Microsoft', nil, pVoiceToken) = S_OK then
      begin
        tts.SetVoice(pVoiceToken);
        tts.SetRate(3); // 设置语速
        pVoiceToken.Release;
      end;
    end;
    

内容的提问来源于stack exchange,提问作者Xiao Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 08:05:22