#include "protocol.h" #include #define TAG "Protocol" void Protocol::OnIncomingJson(std::function callback) { on_incoming_json_ = callback; } void Protocol::OnIncomingAudio(std::function&& data)> 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::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); } void Protocol::SendWakeWordDetected(const std::string& wake_word) { std::string json = "{\"session_id\":\"" + session_id_ + "\",\"type\":\"listen\",\"state\":\"detect\",\"text\":\"" + wake_word + "\"}"; SendText(json); } 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::SendIotDescriptors(const std::string& descriptors) { cJSON* root = cJSON_Parse(descriptors.c_str()); if (root == nullptr) { ESP_LOGE(TAG, "Failed to parse IoT descriptors: %s", descriptors.c_str()); return; } if (!cJSON_IsArray(root)) { ESP_LOGE(TAG, "IoT descriptors should be an array"); cJSON_Delete(root); return; } int arraySize = cJSON_GetArraySize(root); for (int i = 0; i < arraySize; ++i) { cJSON* descriptor = cJSON_GetArrayItem(root, i); if (descriptor == nullptr) { ESP_LOGE(TAG, "Failed to get IoT descriptor at index %d", i); continue; } cJSON* messageRoot = cJSON_CreateObject(); cJSON_AddStringToObject(messageRoot, "session_id", session_id_.c_str()); cJSON_AddStringToObject(messageRoot, "type", "iot"); cJSON_AddBoolToObject(messageRoot, "update", true); cJSON* descriptorArray = cJSON_CreateArray(); cJSON_AddItemToArray(descriptorArray, cJSON_Duplicate(descriptor, 1)); cJSON_AddItemToObject(messageRoot, "descriptors", descriptorArray); char* message = cJSON_PrintUnformatted(messageRoot); if (message == nullptr) { ESP_LOGE(TAG, "Failed to print JSON message for IoT descriptor at index %d", i); cJSON_Delete(messageRoot); continue; } SendText(std::string(message)); cJSON_free(message); cJSON_Delete(messageRoot); } cJSON_Delete(root); } void Protocol::SendIotStates(const std::string& states) { std::string message = "{\"session_id\":\"" + session_id_ + "\",\"type\":\"iot\",\"update\":true,\"states\":" + states + "}"; SendText(message); } 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_LOGE(TAG, "Channel timeout %lld seconds", duration.count()); } return timeout; } bool Protocol::IsAudioChannelBusy() const { return busy_sending_audio_; }