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

DialogFlow Android SDK:实现监听等待TTS语音播放完成后恢复

解决DialogFlow监听与TTS播放冲突的问题

嘿,这个问题我之前做语音机器人时也碰到过!核心问题就是你现在的代码不管TTS有没有说完,直接就恢复监听了,导致机器人自己说话的时候监听已经在等输入,没几秒就超时失效。咱们可以通过监听TTS的播放完成事件,精准控制DialogFlow监听恢复的时机,让对话变得更自然流畅。

具体实现步骤

核心思路是用两个标志位跟踪状态,再配合TTS的播放完成监听器,确保只有机器人说完话后才恢复监听:

  • isTtsPlaying:标记当前TTS是否正在播放语音
  • shouldResumeListening:标记当TTS结束后是否需要恢复DialogFlow的监听

1. 初始化TTS并设置播放完成监听

private TextToSpeech tts;
private boolean isTtsPlaying = false;
private boolean shouldResumeListening = false;

// 在初始化方法(比如Activity的onCreate)里配置TTS
tts = new TextToSpeech(this, status -> {
    if (status == TextToSpeech.SUCCESS) {
        // 设置TTS语言(根据你的需求调整)
        int langResult = tts.setLanguage(Locale.CHINESE);
        if (langResult == TextToSpeech.LANG_MISSING_DATA || langResult == TextToSpeech.LANG_NOT_SUPPORTED) {
            Log.e("TTS", "当前设备不支持该语言");
        } else {
            // 设置播放完成监听(Android 21及以上版本可用)
            tts.setOnPlaybackCompletedListener(utteranceId -> {
                isTtsPlaying = false;
                // 如果TTS播放前已经标记需要恢复监听,现在执行
                if (shouldResumeListening) {
                    aiService.resume();
                    shouldResumeListening = false;
                }
            });
        }
    } else {
        Log.e("TTS", "TTS初始化失败");
    }
});

2. 修改DialogFlow的回调方法,统一处理监听恢复

把原来直接调用aiService.resume()的地方,改成调用自定义方法,先判断TTS状态再决定是否恢复:

@Override 
public void onListeningCanceled() {
    resumeListeningAfterTts();
} 

@Override 
public void onListeningFinished() {
    resumeListeningAfterTts();
} 

@Override 
public void onError(AIError error) {
    resumeListeningAfterTts();
}

// 自定义方法:根据TTS状态决定是否立即恢复监听
private void resumeListeningAfterTts() {
    if (isTtsPlaying) {
        // TTS还在说话,先标记需要在结束后恢复监听
        shouldResumeListening = true;
    } else {
        // 没有播放,直接恢复监听
        aiService.resume();
    }
}

3. 播放TTS响应时更新状态

当你拿到DialogFlow的文本响应,准备用TTS播放时,记得把isTtsPlaying设为true:

// 播放机器人的响应语音
public void playBotResponse(String responseText) {
    isTtsPlaying = true;
    shouldResumeListening = false; // 重置标记,避免旧状态干扰
    
    // 设置utterance ID,方便监听识别(可选但推荐)
    HashMap<String, String> ttsParams = new HashMap<>();
    ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "bot_response");
    
    // 播放语音,QUEUE_FLUSH表示立即停止当前播放,开始新的响应
    tts.speak(responseText, TextToSpeech.QUEUE_FLUSH, ttsParams, "bot_response");
}

逻辑说明

  • 当TTS开始播放时,isTtsPlaying变为true,此时如果DialogFlow的监听回调触发(比如onListeningFinished),会先把shouldResumeListening设为true,而不是直接恢复监听。
  • 当TTS播放完成后,监听器会把isTtsPlaying设为false,同时检查shouldResumeListening,如果为true就立即恢复DialogFlow的监听。
  • 这样就保证了机器人说完话之后,才会再次开始监听用户的输入,完全符合自然对话的逻辑。

额外注意事项

  • 记得在页面销毁时释放TTS资源,避免内存泄漏:tts.shutdown();
  • 如果你的App需要支持Android 21以下版本,可以用OnUtteranceCompletedListener替代OnPlaybackCompletedListener,用法基本一致。
  • 如果有多个TTS请求排队,可以根据需求调整QUEUE_FLUSH或QUEUE_ADD,前者会覆盖当前播放,后者会追加到播放队列。

内容的提问来源于stack exchange,提问作者Ganesh K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:25:32