#include "protocol.h" #include #define TAG "Protocol" void Protocol::OnIncomingJson(std::function callback) { on_incoming_json_ = callback; } void Protocol::OnIncomingAudio(std::function packet)> callback) { on_incoming_audio_ = callback; } void Protocol::OnAudioChannelOpened(std::function callback) { on_audio_channel_opened_ = callback; } void Protocol::OnAudioChannelClosed(std::function callback) { on_audio_channel_closed_ = callback; } void Protocol::OnNetworkError(std::function callback) { on_network_error_ = callback; } void Protocol::OnConnected(std::function callback) { on_connected_ = callback; } void Protocol::OnDisconnected(std::function callback) { on_disconnected_ = callback; } void Protocol::SetError(const std::string& message) { error_occurred_ = true; if (on_network_error_ != nullptr) { on_network_error_(message); } } void Protocol::SendAbortSpeaking(AbortReason reason) { std::string message = "{\"session_id\":\"" + session_id_ + "\",\"type\":\"abort\""; if (reason == kAbortReasonWakeWordDetected) { message += ",\"reason\":\"wake_word_detected\""; } message += "}"; SendText(message); } bool Protocol::SendWakeWordDetected(const std::string& wake_word) { cJSON* root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "session_id", session_id_.c_str()); cJSON_AddStringToObject(root, "type", "listen"); cJSON_AddStringToObject(root, "state", "detect"); cJSON_AddStringToObject(root, "text", wake_word.c_str()); char* json = cJSON_PrintUnformatted(root); cJSON_Delete(root); if (json == nullptr) { return false; } bool ok = SendText(json); cJSON_free(json); return ok; } void Protocol::SendStartListening(ListeningMode mode) { std::string message = "{\"session_id\":\"" + session_id_ + "\""; message += ",\"type\":\"listen\",\"state\":\"start\""; if (mode == kListeningModeRealtime) { message += ",\"mode\":\"realtime\""; } else if (mode == kListeningModeAutoStop) { message += ",\"mode\":\"auto\""; } else { message += ",\"mode\":\"manual\""; } message += "}"; SendText(message); } void Protocol::SendStopListening() { std::string message = "{\"session_id\":\"" + session_id_ + "\",\"type\":\"listen\",\"state\":\"stop\"}"; SendText(message); } void Protocol::SendMcpMessage(const std::string& payload) { std::string message = "{\"session_id\":\"" + session_id_ + "\",\"type\":\"mcp\",\"payload\":" + payload + "}"; SendText(message); } bool Protocol::IsAudioChannelConnected() const { return IsAudioChannelOpened(); } void Protocol::MarkIncomingActivity() { last_incoming_time_ = std::chrono::steady_clock::now(); } bool Protocol::IsTimeout() const { const int kTimeoutSeconds = 120; auto now = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast(now - last_incoming_time_); bool timeout = duration.count() > kTimeoutSeconds; if (timeout) { ESP_LOGW(TAG, "Channel idle %ld seconds (socket may still be up)", (long)duration.count()); } return timeout; }