问题(上次提交 d5239cf 之后实测):
1. EnterIdleHibernate 触发的 LeaveRoom() 顺手关闭了 codec output:
LeaveRoom → on_audio_channel_closed_ → player_pipeline_close → EnableOutput(false)
导致后续 PlaySound(P3_KAKA_DAIMING) 入队后 AudioLoop 写不出声音,
WaitForAudioPlayback 3 秒超时退出, 用户听不到待命音。
2. LeaveRoom 调用 volc_rtc_destroy 后 rtc_handle_ = nullptr,
WakeFromHibernate → ToggleChatState → OpenAudioChannel 直接返回 false,
触发 2 秒重试循环, 同时每次失败回退 idle 都重新 PlaySound,
codec 状态震荡产生杂音, 服务端 AI 任务也无法重新加入房间。
方案 C+ 修复:
- Protocol::LeaveRoom() 新增 bool notify_closed=true 参数 (默认行为不变)。
- VolcRtcProtocol::LeaveRoom(notify_closed):
* 只 volc_rtc_stop, 不 volc_rtc_destroy, 保留 rtc_handle_ 供唤醒复用。
* notify_closed=false 时跳过 on_audio_channel_closed_, 不连带关 codec。
- EnterIdleHibernate:
* 调用 LeaveRoom(false) → codec output 保留。
* 手动 background_task_->WaitForCompletion + 清空队列 + 关麦克风。
* SetDeviceState(idle) 后 PlaySound 真正能播出来。
* WaitForAudioPlayback 完才 player_pipeline_close (这里再正常关 output)。
- WakeFromHibernate:
* 先放下 hibernating_ 让 AudioLoop guard 通过, 再 ToggleChatState。
* 因 rtc_handle_ 仍有效, OpenAudioChannel 走 volc_rtc_start 重启路径,
on_audio_channel_opened_ 回调重开 player_pipeline + 灌 200ms silence。
编译: kapi.bin 0x2e6330 (3.04MB), 分区 42% 空闲。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
2.9 KiB
C++
71 lines
2.9 KiB
C++
#ifndef _VOLC_RTC_PROTOCOL_H_
|
||
#define _VOLC_RTC_PROTOCOL_H_
|
||
|
||
#include "protocol.h"
|
||
#include "volc_rtc.h"
|
||
#include "base/volc_device_manager.h"
|
||
#include <freertos/FreeRTOS.h>
|
||
#include <freertos/event_groups.h>
|
||
#include <mutex>
|
||
#include <vector>
|
||
|
||
class VolcRtcProtocol : public Protocol {
|
||
public:
|
||
VolcRtcProtocol();
|
||
~VolcRtcProtocol();
|
||
|
||
void Start() override;
|
||
void SendAudio(const std::vector<uint8_t>& data) override;// 🔊 发送音频数据到RTC
|
||
void SendPcm(const std::vector<uint8_t>& data) override;// 🔊 发送PCM音频数据到RTC
|
||
void SendG711A(const std::vector<uint8_t>& data) override;// 🔊 发送G711A音频数据到RTC
|
||
bool OpenAudioChannel() override;// 🔊 打开音频通道
|
||
void CloseAudioChannel() override;// 🔊 关闭音频通道
|
||
void LeaveRoom(bool notify_closed = true) override;// Phase 6: 退出 RTC 房间(stop,保留 handle 供唤醒复用)
|
||
bool IsAudioChannelOpened() const override;// 🔊 检查音频通道是否已打开
|
||
void SendAbortSpeaking(AbortReason reason) override;// 🔊 发送中止通话请求
|
||
void SendStartListening(ListeningMode mode) override;// 🔊 发送开始监听请求
|
||
void SendTextMessage(const std::string& text) override;// 🔊 发送文本消息到RTC
|
||
void SendFunctionResult(const std::string& tool_call_id, const std::string& content) override;// 🔊 发送函数调用结果到RTC
|
||
|
||
/**
|
||
* @brief 设置Agent配置参数(如音色、提示词等)
|
||
* @param params JSON格式的配置参数字符串
|
||
*/
|
||
void SetAgentConfig(const std::string& params);
|
||
|
||
private:
|
||
EventGroupHandle_t event_group_handle_;
|
||
volc_rtc_t rtc_handle_ = nullptr;
|
||
std::mutex rtc_mutex_;
|
||
std::string extra_params_; // 存储额外的Agent配置参数
|
||
|
||
bool is_connected_ = false;
|
||
bool is_audio_channel_opened_ = false;
|
||
bool iot_ready_ = false;
|
||
volc_iot_info_t iot_info_ = {};
|
||
size_t opus_bytes_accum_ = 0;
|
||
size_t pcm_bytes_accum_ = 0;
|
||
size_t g711a_bytes_accum_ = 0;
|
||
size_t down_pcm_bytes_accum_ = 0;
|
||
size_t down_opus_bytes_accum_ = 0;
|
||
int opus_frames_accum_ = 0;
|
||
int pcm_frames_accum_ = 0;
|
||
int g711a_frames_accum_ = 0;
|
||
uint64_t uplink_last_log_us_ = 0;
|
||
std::vector<uint8_t> pcm_pending_;
|
||
std::vector<uint8_t> g711a_pending_;
|
||
bool first_downlink_logged_ = false;
|
||
|
||
static void MessageCallback(void* context, volc_msg_t* message);
|
||
static void DataCallback(void* context, const void* data, size_t len, volc_data_info_t* info);
|
||
|
||
void ParseServerMessage(const char* message);
|
||
void ProcessAudioData(const void* data, int size);
|
||
void SendText(const std::string& text) override;
|
||
void LogUplinkStatsMaybe();// 打印上传统计信息
|
||
void SendCtrl(const std::string& json);// 🔊 发送控制指令到RTC
|
||
void SendFunc(const std::string& json);// 🔊 发送函数调用指令到RTC
|
||
};
|
||
|
||
#endif
|