【CI130x 离在线】语音芯片如何判断TTS音频播放完毕?

这个函数通过以下几个条件来综合判定TTS播放结束:

主要判定逻辑:

1. 缓冲区数据检查

c
#if NET_AUDIO_PLAY_BY_MP3
if (xStreamBufferBytesAvailable(mp3_player) == 0) // 播放完成
#elif NET_AUDIO_PLAY_BY_PCM || NET_AUDIO_PLAY_BY_OPUS
if (xStreamBufferBytesAvailable(gCiasAiotRunParam.pcm_play_data_stream_buffer) < 512)
#endif
  • MP3模式:缓冲区完全为空

  • PCM/OPUS模式:缓冲区数据少于512字节

2. 结束标志与重试次数组合判断

情况A - 有结束标志时:

c
if (gCiasAiotRunParam.play_cloud_end_flag)
{
    if (gCiasAiotRunParam.request_play_try_count >= 10)
    {
        ret = true;
    }
}

收到云端结束标志后,再重试10次(约1秒)确认真实结束

情况B - 无结束标志时:

c
else if (gCiasAiotRunParam.request_play_try_count >= 30)
{
    ret = true;
}

未收到结束标志时,重试30次(约3秒)后强制结束

3. 播放结束后的清理操作

当判定播放结束后,执行:

  • 设置播放状态为闲置(CI_SS_PLAY_STATE_IDLE)

  • 开启VOX语音检测

  • 重置所有相关标志位

  • 停止编解码器

  • 等待播放完全停止(最多300ms)

  • 发送PLAY_TTS_END命令

总结:

判定播放结束的核心是缓冲区数据基本耗尽 + 适当的重试等待,通过组合云端结束标志和本地缓冲区状态来确保播放真正完成,避免提前或延迟结束。

 

完整代码

#if NET_AUDIO_PLAY_BY_MP3
            if (xStreamBufferBytesAvailable(mp3_player) == 0) // 播放完成
#elif NET_AUDIO_PLAY_BY_PCM || NET_AUDIO_PLAY_BY_OPUS
    if (xStreamBufferBytesAvailable(gCiasAiotRunParam.pcm_play_data_stream_buffer) < 512)
#endif
            {
                if (gCiasAiotRunParam.play_cloud_end_flag)
                {
                    if (gCiasAiotRunParam.request_play_try_count >= 10)
                    {
                        ret = true;
                    }
                }
                else if (gCiasAiotRunParam.request_play_try_count >= 30)
                {
                    ret = true;
                }
                if (ret)
                {
                    mprintf("play stop sync state to wifi ....\r\n");
                    ret = false;
                    ciss_set(CI_SS_PLAY_STATE, CI_SS_PLAY_STATE_IDLE); // 设置播放结束
                    if (!gCiasAiotFuncParam.upload_play_full_duplex)
                    {
                        ciss_set(CI_SS_VOX_WORK_STATE, 1); // 开启vox vad计算
                    }
                    gCiasAiotRunParam.request_play_try_count = 0;
                    gCiasAiotRunParam.play_cloud_data_flag = false;
                    gCiasAiotRunParam.request_play_data_flag = false;
                    gCiasAiotRunParam.wait_play_end_flag = false;
                    gCiasAiotRunParam.rcv_cloud_play_data_flag = false;
                    gCiasAiotRunParam.stop_collect_pcm_flag = false;
#if NET_AUDIO_PLAY_BY_MP3
                    stop_play(NULL, NULL); // 必须保留,不然下一段播放音频会保留上一段音频数据
#elif NET_AUDIO_PLAY_BY_PCM || NET_AUDIO_PLAY_BY_OPUS
            cm_stop_codec(PLAY_CODEC_ID, CODEC_OUTPUT);
            cm_set_codec_mute(PLAY_CODEC_ID, CODEC_OUTPUT, 3, DISABLE);
#endif
                    int try_count = 30;
                    while(try_count--)   //等待播放状态同步完成
                    {
                        if(gCiasAiotRunParam.mp3_play_finish_flag)
                        {
                            break;
                        }
                        else
                        {
                            mprintf("===wait audio play over\r\n");
                            vTaskDelay(pdMS_TO_TICKS(10));
                        }
                    }
                    cias_send_cmd(PLAY_TTS_END, DEF_FILL);
                }
                gCiasAiotRunParam.request_play_try_count++;
            }

 

posted @ 2025-10-28 12:10  FBshark  阅读(17)  评论(0)    收藏  举报