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

如何检测espeak语音合成结束?实现程序等待语音完成

解决espeak播放完成检测与程序等待的问题

针对你遇到的espeak播放未完成就执行后续代码的问题,有两种常用的解决方案,结合你用到pocketsphinx的场景,我给你详细说明:


1. 最简单的方式:使用同步播放模式

espeak默认可能采用异步播放(后台输出音频),但你可以通过espeak_Synth函数的参数让它同步执行——也就是函数会阻塞直到语音完全播放完毕才返回,这样后续的Line 2代码就会自然等待播放结束后再执行。

示例代码(C语言,espeak的C API):

#include <espeak/speak_lib.h>
#include <string.h>

int main() {
    // 初始化espeak,使用同步音频输出模式
    espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, NULL, 0);
    
    // Line 1: 同步播放,函数会一直阻塞到语音结束
    const char* text = "hello, this is espeak";
    espeak_Synth(text, strlen(text) + 1, 0, POS_CHARACTER, 0, espeakCHARS_AUTO, NULL, NULL);
    
    // Line 2: 现在这段代码会在语音播放完成后才执行
    // 你的pocketsphinx识别逻辑,比如启动识别、读取麦克风输入等
    // ...
    
    espeak_Terminate();
    return 0;
}

这种方式的优点是代码简洁,不需要额外的标志位或回调,适合不需要在播放时并行处理其他任务的场景。


2. 灵活的方式:通过回调函数监听播放结束事件

如果你的程序需要在espeak播放时做一些其他后台任务,不想完全阻塞主线程,可以通过注册合成回调函数来监听espeak的播放事件,当检测到播放完成的信号时,设置一个标志位,让主线程等待该标志位触发后再执行后续代码。

步骤1:定义回调函数,监听播放完成事件

#include <espeak/speak_lib.h>
#include <unistd.h>

// 全局标志位,标记语音是否播放完成
int g_speech_finished = 0;

// espeak的合成回调函数
void SynthCallback(short *wav, int numsamples, espeak_EVENT *events) {
    // 遍历所有事件
    while (events->type != EE_LIST_TERMINATED) {
        // 检测到句子播放完成的事件
        if (events->type == EE_SENTENCE) {
            g_speech_finished = 1;
        }
        events++;
    }
}

步骤2:初始化espeak并设置回调,异步播放+等待标志位

int main() {
    // 初始化espeak,使用异步播放模式(AUDIO_OUTPUT_PLAYBACK)
    espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, NULL, 0);
    // 设置合成回调函数
    espeak_SetSynthCallback(&SynthCallback);
    
    // 重置标志位
    g_speech_finished = 0;
    
    // Line 1: 异步播放语音(不会阻塞主线程)
    const char* text = "hello, this is espeak";
    espeak_Synth(text, strlen(text) + 1, 0, POS_CHARACTER, 0, espeakCHARS_AUTO, NULL, NULL);
    
    // 等待语音播放完成:循环检查标志位,加小延迟避免CPU占用过高
    while (!g_speech_finished) {
        usleep(10000); // 暂停10毫秒
    }
    
    // Line 2: 语音完成后执行pocketsphinx识别逻辑
    // 注意:这里最好先暂停pocketsphinx的识别,避免拾取到espeak的声音
    // 比如:ps_end_utt(ps); // 结束当前识别会话
    // 执行识别...
    // ps_start_utt(ps); // 重新开始识别
    
    espeak_Terminate();
    return 0;
}

结合pocketsphinx的额外注意事项

因为你同时在用pocketsphinx做语音识别,一定要注意:espeak播放时,麦克风可能会拾取到播放的语音,导致pocketsphinx识别错误。所以建议你:

  • 在espeak开始播放前,先调用ps_end_utt(ps)结束pocketsphinx的当前识别会话;
  • 等espeak播放完成后,再调用ps_start_utt(ps)重新启动识别,这样就能避免干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:07:01