增加回答响应12S超时 3366/1 3366/head 3368/target/1
authorxue <2144439972@qq.com>
Fri, 24 Apr 2026 10:57:13 +0000 (18:57 +0800)
committerxue <2144439972@qq.com>
Fri, 24 Apr 2026 10:57:13 +0000 (18:57 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdPresenter.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdMainView.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp

index 87c37bf..d1c526b 100644 (file)
@@ -42,6 +42,11 @@ namespace OHOS
         /** 仅当当前在提醒界面时启动 3 秒退出定时器(供 LN_HTTP_SERVICE_CMD_AUDIO_STOP 使用,避免哄睡结束误触) */
         void StartCountUpTimerForDialogueExitIfInSpeaking(void);
         void StopCountUpTimer(void);
+        /** 进入对话「说话」界面后:8s 内须收到服务端文本(SetTextStr),否则定时器触发模拟语音键回「聆听」 */
+        void StartSpeakingTtsWaitTimer(void);
+        void StopSpeakingTtsWaitTimer(void);
+        /** 由 one-shot 定时器经 PostGraphicEvent 调用 */
+        void HandleSpeakingTtsWaitExpired(void);
         void StartFactoryResetTimer(uint32_t delaySeconds);
         void StopFactoryResetTimer(void);
         void HandleFactoryReset(void);
@@ -485,6 +490,7 @@ namespace OHOS
         void* m_storyAudioPlaybackTimeoutTimer;  // 故事模式音频播放超时定时器(5秒内无音频播放则退出)
         void* m_factoryResetTimer;              // 恢复出厂设置定时器
         void* m_stressAudioLoopTimer;            // 压测音频循环定时器(每1.5秒播放一次)
+        void* m_speakingTtsWaitTimer;            // 说话界面等待收到文本 8s 超时
 
         // 对话模式相关标志
         bool m_dialogueModeFinished = false; // 对话模式是否已finished(收到finished=true)
index 234616c..3048c38 100644 (file)
@@ -45,6 +45,9 @@ namespace OHOS
 
         void SetDialogueing(bool dialogueing);//设置对话模式标志位
 
+        /** 与在「说话」界面按语音键一致:打断并回到「聆听」(供「说话」界面收文本超时等调用) */
+        void SimulateVoiceKeySpeakingToListening(void);
+
          // FUNC键长按功能
          void RegisterFuncKeyLongPressEvent(void);
          void HandleFuncKeyLongPress(void);
index 7fed399..ecf9c24 100644 (file)
@@ -1233,6 +1233,7 @@ namespace OHOS
                     WaitForVideoSwitchComplete(2000);
                 }
                 ThunderBirdModel::GetInstance()->StopCountUpTimer();
+                ThunderBirdModel::GetInstance()->StopSpeakingTtsWaitTimer();
                 ThunderBirdPresenter::GetInstance()->SetDialogueing(false);
                 ln_ws_end_audio_chat();//结束对话
                 AI_ForceInterrupt();
index 0dbef42..0261aa8 100644 (file)
@@ -196,9 +196,10 @@ extern "C" {
                                           m_bootTime(0),
                                           m_lastCat1RestartTime(0),
                                           m_storyModeTimeoutTimer(nullptr),
-                                          m_storyAudioPlaybackTimeoutTimer(nullptr),
-                                          m_stressAudioLoopTimer(nullptr),
-                                          m_networkConnectingReason(NetworkConnectingReason::NONE),
+                                           m_storyAudioPlaybackTimeoutTimer(nullptr),
+                                           m_stressAudioLoopTimer(nullptr),
+                                           m_speakingTtsWaitTimer(nullptr),
+                                           m_networkConnectingReason(NetworkConnectingReason::NONE),
                                           m_networkConnectingTimeoutCount(0)
      {
         // 初始化时加载提醒数据
@@ -246,6 +247,7 @@ extern "C" {
      
      ThunderBirdModel::~ThunderBirdModel() 
      {
+         StopSpeakingTtsWaitTimer();
          // 停止所有定时器
          StopTimeDisplayTimer();
          StopOtaCountdown();
@@ -422,6 +424,71 @@ extern "C" {
          
          WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Count up timer stopped");
      }
+
+     static void SpeakingTtsWaitTimerCallback(uint8_t data)
+     {
+         (void)data;
+         GraphicService::GetInstance()->PostGraphicEvent(
+             std::bind([]() {
+                 ThunderBirdModel::GetInstance()->HandleSpeakingTtsWaitExpired();
+             }));
+     }
+
+     void ThunderBirdModel::StartSpeakingTtsWaitTimer(void)
+     {
+         if (m_stressTestDialogueActive) {
+             return;
+         }
+         ThunderBirdPresenter *pre = ThunderBirdPresenter::GetInstance();
+         if (pre == nullptr || !pre->isDialogueing) {
+             return;
+         }
+         StopSpeakingTtsWaitTimer();
+         m_speakingTtsWaitTimer =
+             osTimerNew((osTimerFunc_t)SpeakingTtsWaitTimerCallback, osTimerOnce, nullptr, nullptr);
+         if (m_speakingTtsWaitTimer == nullptr) {
+             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "StartSpeakingTtsWaitTimer: osTimerNew failed");
+             return;
+         }
+         static constexpr uint32_t kSpeakingTtsWaitMs = 12000;
+         osStatus_t ret = osTimerStart(m_speakingTtsWaitTimer, kSpeakingTtsWaitMs);
+         if (ret != osOK) {
+             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "StartSpeakingTtsWaitTimer: osTimerStart failed ret=%d", (int)ret);
+             (void)osTimerDelete(m_speakingTtsWaitTimer);
+             m_speakingTtsWaitTimer = nullptr;
+             return;
+         }
+         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "StartSpeakingTtsWaitTimer: %ums 内须收到服务端文本", (unsigned)kSpeakingTtsWaitMs);
+     }
+
+     void ThunderBirdModel::StopSpeakingTtsWaitTimer(void)
+     {
+         if (m_speakingTtsWaitTimer != nullptr) {
+             (void)osTimerStop(m_speakingTtsWaitTimer);
+             (void)osTimerDelete(m_speakingTtsWaitTimer);
+             m_speakingTtsWaitTimer = nullptr;
+         }
+     }
+
+     void ThunderBirdModel::HandleSpeakingTtsWaitExpired(void)
+     {
+         StopSpeakingTtsWaitTimer();
+         ThunderBirdMainView *view = ThunderBirdMainView::GetInstance();
+         if (view == nullptr) {
+             return;
+         }
+         if (view->GetCurrentView() != THUNDERBIRD_DIALOGUEVIEW ||
+             view->GetCurrentSubView() != ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING) {
+             return;
+         }
+         ThunderBirdPresenter *pre = ThunderBirdPresenter::GetInstance();
+         if (pre == nullptr || !pre->isDialogueing) {
+             return;
+         }
+         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+             "HandleSpeakingTtsWaitExpired: 8s 内未收到文本,模拟语音键进入聆听");
+         pre->SimulateVoiceKeySpeakingToListening();
+     }
      
      // ---------------------- 仅当当前在提醒界面时启动 3 秒退出定时器(供 LN_HTTP_SERVICE_CMD_AUDIO_STOP 使用,避免哄睡结束误触) ----------------------
      void ThunderBirdModel::StartCountUpTimerForDialogueExitIfInSpeaking(void)
@@ -1377,6 +1444,9 @@ extern "C" {
             // 直接推送到对话界面
             if(ThunderBirdDialogueView::GetInstance() && currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING)
             {
+                if (!m_stressTestDialogueActive) {
+                    StopSpeakingTtsWaitTimer();
+                }
                 ThunderBirdDialogueView::GetInstance()->UpdateDialogueText(textId);
                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "第一个文本直接显示在对话界面: %s", textId);
             }
@@ -3741,6 +3811,7 @@ extern "C" {
                          currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING)) {
                         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleBindAndUnbind: 从对话模式跳转绑定成功,先退出对话模式");
                         StopCountUpTimer();
+                        StopSpeakingTtsWaitTimer();
                         ThunderBirdPresenter::GetInstance()->SetDialogueing(false);
                         ln_ws_end_audio_chat();//结束对话
                         AI_ForceInterrupt();
@@ -3777,6 +3848,7 @@ extern "C" {
                      currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING)) {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleBindAndUnbind: 从对话模式跳转解绑警告/绑定成功,先退出对话模式");
                     StopCountUpTimer();
+                    StopSpeakingTtsWaitTimer();
                     ThunderBirdPresenter::GetInstance()->SetDialogueing(false);
                     ln_ws_end_audio_chat();//结束对话
                     AI_ForceInterrupt();
@@ -4025,6 +4097,7 @@ extern "C" {
                 if (currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING) {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
                         "ThunderBirdModel::HandleAudioRecordingStart: speaking 中收到录音开始,交由 VAD 流程处理,只切换到聆听界面");
+                    StopSpeakingTtsWaitTimer();
                     auto* mainView = ThunderBirdMainView::GetInstance();
                     if (mainView && mainView->listenIcon) {
                         mainView->listenIcon->SetVisible(true);
@@ -4074,6 +4147,7 @@ extern "C" {
                 if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::GetInstance()->listenIcon) {
                     ThunderBirdMainView::GetInstance()->listenIcon->SetVisible(false);
                 }
+                StartSpeakingTtsWaitTimer();
             }
             else if (currentView == THUNDERBIRD_LULLABYVIEW && 
                 currentSubView == ThunderBirdLullabyView::THUNDERBIRD_LULLABYVIEW_3 ) {
index 376c64c..1b4d34a 100644 (file)
@@ -75,6 +75,7 @@ namespace OHOS
         ThunderBirdModel::GetInstance()->StopTimeDisplayTimer();
         ThunderBirdModel::GetInstance()->StopOtaCountdown();
         ThunderBirdModel::GetInstance()->StopCountUpTimer();
+        ThunderBirdModel::GetInstance()->StopSpeakingTtsWaitTimer();
         //ThunderBirdModel::GetInstance()->StopReminderHideTimer();
         
         // 停止录音
@@ -424,6 +425,34 @@ namespace OHOS
 
     // ==================== 辅助函数 ====================
 
+    void ThunderBirdPresenter::SimulateVoiceKeySpeakingToListening(void)
+    {
+        if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::IsSwitchingVideo()) {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SimulateVoiceKeySpeakingToListening: 等待视频切换完成");
+            ThunderBirdMainView::WaitForVideoSwitchComplete(2000);
+        }
+        ThunderBirdModel::GetInstance()->StopCountUpTimer();
+        ThunderBirdModel::GetInstance()->StopSpeakingTtsWaitTimer();
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SimulateVoiceKeySpeakingToListening: 与语音键一致,SPEAKING→LISTENING");
+        AI_ForceInterrupt();
+        ln_ws_end_audio_chat();
+        ln_ws_send_voice_chat_interrupt("新对话开始");
+        auto *dialogueView = ThunderBirdDialogueView::GetInstance();
+        if (dialogueView) {
+            dialogueView->IsReconnect = true;
+        }
+        auto *mainView = ThunderBirdMainView::GetInstance();
+        if (mainView && mainView->listenIcon) {
+            mainView->listenIcon->SetVisible(true);
+        }
+        ln_ws_set_vad_recognition_enabled(true);
+        if (mainView) {
+            const int16_t cv = mainView->GetCurrentView();
+            mainView->ChangeView(cv, THUNDERBIRD_DIALOGUEVIEW,
+                ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING);
+        }
+    }
+
     /**
      * @brief 处理对话功能
      */
@@ -431,6 +460,7 @@ namespace OHOS
     {
         // 在对话界面进行按键操作时,取消退出对话的定时器(用户有操作,说明要继续对话)
         ThunderBirdModel::GetInstance()->StopCountUpTimer();
+        ThunderBirdModel::GetInstance()->StopSpeakingTtsWaitTimer();
         WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HandleDialogueViewNavigation: 取消退出对话定时器");
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "HandleDialogueFunction: currentView=%d, currentSubView=%d", currentView, currentSubView);
         
@@ -455,6 +485,7 @@ namespace OHOS
                 mainView->listenIcon->SetVisible(false);
             }
             ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING);
+            ThunderBirdModel::GetInstance()->StartSpeakingTtsWaitTimer();
         } else if(currentView == THUNDERBIRD_DIALOGUEVIEW && currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING) {
             // 检查 WebSocket 连接状态,如果正在重连,等待重连完成
             // int wsState = ln_ws_get_connection_state();
@@ -1286,6 +1317,7 @@ namespace OHOS
                 
                 // 先停止定时器,避免在退出过程中继续触发
                 ThunderBirdModel::GetInstance()->StopCountUpTimer();
+                ThunderBirdModel::GetInstance()->StopSpeakingTtsWaitTimer();
                 
                 ln_ws_end_audio_chat();//结束对话