From d760650ccaac75cb17acab1ea5a701a804f1327e Mon Sep 17 00:00:00 2001 From: xue <2144439972@qq.com> Date: Fri, 6 Mar 2026 14:36:59 +0800 Subject: [PATCH] =?utf8?q?=E4=BF=AE=E5=A4=8D=E6=AF=8F=E6=AC=A1=E5=BC=80?= =?utf8?q?=E6=9C=BA=E5=B1=8F=E4=BF=9D=E9=9C=80=E8=A6=81=E9=87=8D=E6=96=B0?= =?utf8?q?=E8=8E=B7=E5=8F=96=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../thunderbird/include/ThunderBirdModel.h | 5 + .../thunderbird/src/ThunderBirdModel.cpp | 98 ++++++++++++++++--- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h index afc36ee66..10f3c5b7d 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h @@ -305,6 +305,11 @@ namespace OHOS // 退出哄睡模式时恢复表情 void OnExitLullabyMode(); + + /** 对话模式播放语音界面:启动 BGM 混播(仅从聆听进入说话时调用) */ + void StartDialogueBgm(); + /** 对话模式离开播放语音界面:停止 BGM */ + void StopDialogueBgm(); // 音频文本队列操作函数 void EnqueueAudioText(const std::string& text); diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp index 763a5c1eb..845ccac14 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp @@ -1495,7 +1495,16 @@ extern "C" { json_buf[n] = '\0'; ParseCharacterConfigData(json_buf); fclose(file); - printf("[DEVICE_CHARACTER] read character config success\n"); + // hasScreenImage_ 非服务端字段,由角色配置变更时写入 KV,此处从 KV 恢复 + // UtilsGetValue 成功时:从文件返回 value 长度(如 "1" 返回 1),从缓存返回 0;失败返回负数 + char temp[16] = {0}; + int kvRet = UtilsGetValue("character_has_screen_image", temp, sizeof(temp)); + if (kvRet >= 0 && temp[0] == '1') { + hasScreenImage_ = 1; + } else { + hasScreenImage_ = 0; + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] read character config success (hasScreenImage_=%d from KV, kvRet=%d)", hasScreenImage_, kvRet); } // 解析JSON中的data数据 @@ -2714,6 +2723,7 @@ extern "C" { last_hairColor_ = hairColor_; last_eyesColor_ = eyesColor_; last_hairStyle_ = hairStyle_; + last_hasScreenImage_ = hasScreenImage_; last_screenImageAsEmoji_ = screenImageAsEmoji_; return; } @@ -2776,7 +2786,11 @@ extern "C" { last_screenImageAsEmoji_ = screenImageAsEmoji; last_hasScreenImage_ = hasScreenImage; WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleCharacterConfigChange: 角色配置已更新"); - + // hasScreenImage 非服务端字段,仅本地使用;写入 KV 以便重启后恢复 + (void)UtilsSetValue("character_has_screen_image", hasScreenImage ? "1" : "0"); + // printf("character_has_screen_image: %s\n", hasScreenImage ? "1" : "0"); + // printf("hasScreenImage_: %d\n", hasScreenImage_); + // 角色切换完成后,上报蓝牙连接状态 ln_bt_report_earphone_connection_status(false); // 不需要弹窗 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleCharacterConfigChange: 角色切换完成,已上报蓝牙连接状态"); @@ -3370,6 +3384,24 @@ extern "C" { m_alwaysOnRefreshActive = false; m_alwaysOnRefreshTime = 0; } + + //测试BGM开始函数 + void ThunderBirdModel::StartDialogueBgm() + { + static const char *kDialogueBgmPath = "/user/res/music/BGM.mp3"; + int ret = ln_audio_simple_play_loop(kDialogueBgmPath, true); + if (ret != 0) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "StartDialogueBgm: play_loop %s failed, ret=%d", kDialogueBgmPath, ret); + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "StartDialogueBgm: BGM mix started: %s", kDialogueBgmPath); + } + } + //测试BGM停止函数 + void ThunderBirdModel::StopDialogueBgm() + { + ln_audio_simple_stop(); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "StopDialogueBgm: BGM stopped"); + } void ThunderBirdModel::HandleBluetoothConnect(const char *bluetoothAddress) { @@ -3455,6 +3487,20 @@ extern "C" { if(ThunderBirdMainView::GetInstance()){ uapi_set_screen_on_api(); // 亮屏 int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView(); //获取当前视图 + int currentSubView = ThunderBirdMainView::GetInstance()->GetCurrentSubView(); + // 如果是从对话模式(说话/聆听)跳转到绑定成功界面,则先退出对话模式再跳转 + if (currentView == THUNDERBIRD_DIALOGUEVIEW && + (currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING || + currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleBindAndUnbind: 从对话模式跳转绑定成功,先退出对话模式"); + StopCountUpTimer(); + ThunderBirdPresenter::GetInstance()->SetDialogueing(false); + ln_ws_end_audio_chat();//结束对话 + AI_ForceInterrupt(); + ln_ws_send_voice_chat_interrupt("退出对话"); + OnExitDialogueMode(); + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_AUDIO_DEINIT, NULL, 0); + } ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_ADJUSTVIEW, ThunderBirdAdjustView::THUNDERBIRD_ADJUSTVIEW_BIND_SUCCESS); } int volume = AudioManager::GetInstance().SetVolume(AUDIO_STREAM_VOICE_ASSISTANT, 50); @@ -3469,6 +3515,7 @@ extern "C" { { //增加设备解绑提示 int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView(); //获取当前视图 + int currentSubView = ThunderBirdMainView::GetInstance()->GetCurrentSubView(); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleBindAndUnbind: 设备已解绑,显示解绑警告"); uapi_set_screen_on_api(); bind_status = false;//解绑标志值位,用于界面跳转真正解绑放到出厂设置里面 @@ -3477,6 +3524,20 @@ extern "C" { m_pending_factory_reset = true; ThunderBirdModel::GetInstance()->StartFactoryResetTimer(1); // 2秒后恢复出厂设置 + // 如果是从对话模式(说话/聆听)跳转到解绑警告/绑定成功界面,则先退出对话模式 + if (currentView == THUNDERBIRD_DIALOGUEVIEW && + (currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING || + currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleBindAndUnbind: 从对话模式跳转解绑警告/绑定成功,先退出对话模式"); + StopCountUpTimer(); + ThunderBirdPresenter::GetInstance()->SetDialogueing(false); + ln_ws_end_audio_chat();//结束对话 + AI_ForceInterrupt(); + ln_ws_send_voice_chat_interrupt("退出对话"); + OnExitDialogueMode(); + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_AUDIO_DEINIT, NULL, 0); + } + ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_ADJUSTVIEW, ThunderBirdAdjustView::THUNDERBIRD_ADJUSTVIEW_BIND_SUCCESS); if(ThunderBirdAdjustView::GetInstance()) { @@ -3619,6 +3680,8 @@ extern "C" { if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::GetInstance()->listenIcon) { ThunderBirdMainView::GetInstance()->listenIcon->SetVisible(true); } + // 播放结束进入聆听前状态,打开 VAD 识别 + ln_ws_set_vad_recognition_enabled(true); // 启动20秒定时器,时间到就退出对话 StartCountUpTimer(20); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioPlaybackEnd: 启动20秒定时器,时间到就退出对话"); @@ -3708,16 +3771,26 @@ extern "C" { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioRecordingStart: 在哄睡界面(故事模式),忽略录音开始事件"); return; } - if ((currentView == THUNDERBIRD_DIALOGUEVIEW && - currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING) ) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "录音开始,跳转到聆听状态"); - view->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING); - // ThunderBirdDialogueView::GetInstance()->IsNormalEnd = false; - } - // 如果当前在哄睡界面,且不在故事选择状态,则跳转到故事选择状态 - else { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioRecordingStart: 不满足推送条件"); + if (currentView == THUNDERBIRD_DIALOGUEVIEW) { + if (currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "ThunderBirdModel::HandleAudioRecordingStart: speaking 中收到录音开始,交由 VAD 流程处理,只切换到聆听界面"); + auto* mainView = ThunderBirdMainView::GetInstance(); + if (mainView && mainView->listenIcon) { + mainView->listenIcon->SetVisible(true); + } + view->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, + ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING); + return; + } else if (currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "ThunderBirdModel::HandleAudioRecordingStart: 已在聆听界面,忽略重复的录音开始事件"); + return; + } } + + // 其它界面当前不处理录音开始 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioRecordingStart: 不满足推送条件"); } } @@ -4015,12 +4088,15 @@ extern "C" { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 眨眼表情文件不存在: %s", winkingExpressionPath.c_str()); } } + // 进入对话且为聆听界面时打开 VAD 识别(仅在此处与播放结束、按键进入聆听时打开) + ln_ws_set_vad_recognition_enabled(true); } // 退出对话模式时恢复表情 void ThunderBirdModel::OnExitDialogueMode() { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 开始退出对话模式"); + ln_ws_set_vad_recognition_enabled(false); #ifdef SUPPORT_CAT1_SERVICE // 退出对话模式时恢复AT+CESQ命令,恢复获取4G信号 -- 2.17.1