From 70481429367ca00144b24f118cbfdfb28b02967d Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期三, 26 八月 2026 15:54:31 +0800
Subject: [PATCH] add sening functions

---
 xiaozhi-esp32-2.2.6/main/protocols/mqtt_protocol.cc |   98 +++++++++++++++++++++++++++++++++++++------------
 1 files changed, 74 insertions(+), 24 deletions(-)

diff --git a/xiaozhi-esp32-2.2.6/main/protocols/mqtt_protocol.cc b/xiaozhi-esp32-2.2.6/main/protocols/mqtt_protocol.cc
index 94d9d12..5e9341b 100644
--- a/xiaozhi-esp32-2.2.6/main/protocols/mqtt_protocol.cc
+++ b/xiaozhi-esp32-2.2.6/main/protocols/mqtt_protocol.cc
@@ -18,11 +18,11 @@
         .callback = [](void* arg) {
             MqttProtocol* protocol = (MqttProtocol*)arg;
             auto& app = Application::GetInstance();
-            if (app.GetDeviceState() == kDeviceStateIdle) {
+            if (app.GetDeviceState() == kDeviceStateIdle && Board::GetInstance().IsNetworkReady()) {
                 ESP_LOGI(TAG, "Reconnecting to MQTT server");
                 auto alive = protocol->alive_;  // Capture alive flag
                 app.Schedule([protocol, alive]() {
-                    if (*alive) {
+                    if (*alive && Board::GetInstance().IsNetworkReady()) {
                         protocol->StartMqttClient(false);
                     }
                 });
@@ -56,9 +56,25 @@
     return StartMqttClient(false);
 }
 
+void MqttProtocol::PrepareForNetworkStandby() {
+    network_standby_preparing_ = true;
+    if (reconnect_timer_ != nullptr) {
+        esp_timer_stop(reconnect_timer_);
+    }
+    audio_channel_opened_ = false;
+    udp_.reset();
+    if (mqtt_ != nullptr) {
+        mqtt_->Disconnect();
+        mqtt_.reset();
+    }
+    network_standby_preparing_ = false;
+}
+
 bool MqttProtocol::StartMqttClient(bool report_error) {
     if (mqtt_ != nullptr) {
         ESP_LOGW(TAG, "Mqtt client already started");
+        audio_channel_opened_ = false;
+        udp_.reset();
         mqtt_.reset();
     }
 
@@ -83,6 +99,9 @@
     mqtt_->SetKeepAlive(keepalive_interval);
 
     mqtt_->OnDisconnected([this]() {
+        if (network_standby_preparing_ || !Board::GetInstance().IsNetworkReady()) {
+            return;
+        }
         if (on_disconnected_ != nullptr) {
             on_disconnected_();
         }
@@ -143,7 +162,9 @@
     }
     if (!mqtt_->Connect(broker_address, broker_port, client_id, username, password)) {
         ESP_LOGE(TAG, "Failed to connect to endpoint, code=%d", mqtt_->GetLastError());
-        SetError(Lang::Strings::SERVER_NOT_CONNECTED);
+        if (report_error) {
+            SetError(Lang::Strings::SERVER_NOT_CONNECTED);
+        }
         return false;
     }
 
@@ -164,32 +185,60 @@
 }
 
 bool MqttProtocol::SendAudio(std::unique_ptr<AudioStreamPacket> packet) {
-    std::lock_guard<std::mutex> lock(channel_mutex_);
-    if (udp_ == nullptr) {
-        return false;
+    bool notify_channel_closed = false;
+
+    {
+        std::lock_guard<std::mutex> lock(channel_mutex_);
+        if (udp_ == nullptr || !audio_channel_opened_) {
+            return false;
+        }
+        if (!Board::GetInstance().IsNetworkReady()) {
+            ESP_LOGW(TAG, "Network is not ready, drop UDP audio and close channel");
+            audio_channel_opened_ = false;
+            udp_.reset();
+            notify_channel_closed = true;
+        } else {
+            std::string nonce(aes_nonce_);
+            *(uint16_t*)&nonce[2] = htons(packet->payload.size());
+            *(uint32_t*)&nonce[8] = htonl(packet->timestamp);
+            *(uint32_t*)&nonce[12] = htonl(++local_sequence_);
+
+            std::string encrypted;
+            encrypted.resize(aes_nonce_.size() + packet->payload.size());
+            memcpy(encrypted.data(), nonce.data(), nonce.size());
+
+            size_t nc_off = 0;
+            uint8_t stream_block[16] = {0};
+            if (mbedtls_aes_crypt_ctr(&aes_ctx_, packet->payload.size(), &nc_off, (uint8_t*)nonce.c_str(), stream_block,
+                (uint8_t*)packet->payload.data(), (uint8_t*)&encrypted[nonce.size()]) != 0) {
+                ESP_LOGE(TAG, "Failed to encrypt audio data");
+                return false;
+            }
+
+            int ret = udp_->Send(encrypted);
+            if (ret <= 0) {
+                ESP_LOGW(TAG, "UDP audio send failed, close audio channel");
+                audio_channel_opened_ = false;
+                udp_.reset();
+                notify_channel_closed = true;
+            } else {
+                return true;
+            }
+        }
     }
 
-    std::string nonce(aes_nonce_);
-    *(uint16_t*)&nonce[2] = htons(packet->payload.size());
-    *(uint32_t*)&nonce[8] = htonl(packet->timestamp);
-    *(uint32_t*)&nonce[12] = htonl(++local_sequence_);
-
-    std::string encrypted;
-    encrypted.resize(aes_nonce_.size() + packet->payload.size());
-    memcpy(encrypted.data(), nonce.data(), nonce.size());
-
-    size_t nc_off = 0;
-    uint8_t stream_block[16] = {0};
-    if (mbedtls_aes_crypt_ctr(&aes_ctx_, packet->payload.size(), &nc_off, (uint8_t*)nonce.c_str(), stream_block,
-        (uint8_t*)packet->payload.data(), (uint8_t*)&encrypted[nonce.size()]) != 0) {
-        ESP_LOGE(TAG, "Failed to encrypt audio data");
-        return false;
+    if (notify_channel_closed && on_audio_channel_closed_ != nullptr) {
+        on_audio_channel_closed_();
     }
-
-    return udp_->Send(encrypted) > 0;
+    return false;
 }
 
 void MqttProtocol::CloseAudioChannel(bool send_goodbye) {
+    if (!audio_channel_opened_) {
+        return;
+    }
+    audio_channel_opened_ = false;
+
     {
         std::lock_guard<std::mutex> lock(channel_mutex_);
         udp_.reset();
@@ -287,6 +336,7 @@
     });
 
     udp_->Connect(udp_server_, udp_port_);
+    audio_channel_opened_ = true;
 
     if (on_audio_channel_opened_ != nullptr) {
         on_audio_channel_opened_();
@@ -385,5 +435,5 @@
 }
 
 bool MqttProtocol::IsAudioChannelOpened() const {
-    return udp_ != nullptr && !error_occurred_ && !IsTimeout();
+    return audio_channel_opened_ && udp_ != nullptr && !error_occurred_ && !IsTimeout();
 }

--
Gitblit v1.9.1