- void Message_handle(const uint8_t *data, uint16_t len)
- {
- char * str1;
- char * str2 = "串口发送数据。";
- char * str3 = "485发送数据。";
- char * str4 = "CAN发送数据。";
- char * str5 = "IO发送数据。";
- cJSON *root = cJSON_Parse((const char *)data);
- if (!root)
- {
- LOG_E("Error before: [%s]\n", cJSON_GetErrorPtr());
- return;
- }
- char *type = my_json_string(root, "type");
- if (strcmp(type, "hello") == 0)
- {
- char *session_id = cJSON_GetObjectItem(root, "session_id")->valuestring;
- cJSON *audio_param = cJSON_GetObjectItem(root, "audio_params");
- g_app.ws.sample_rate = cJSON_GetObjectItem(audio_param, "sample_rate")->valueint;
- g_app.ws.frame_duration = cJSON_GetObjectItem(audio_param, "frame_duration")->valueint;
- strncpy(g_app.ws.session_id, session_id, 9);
- rt_bool_t in_listening = (g_app.state == kDeviceStateListening) || xz_mic_is_enabled();
- if (!in_listening && g_app.state != kDeviceStateSpeaking)
- {
- g_app.state = kDeviceStateIdle;
- }
- xz_ws_audio_init();
- /* Initialize only on first connection */
- if (!g_app.iot_initialized)
- {
- LOG_I("Initializing IoT devices for first time\n");
- extern void iot_initialize(void);
- iot_initialize();
- g_app.iot_initialized = 1;
- }
- else
- {
- LOG_D("IoT already initialized, skipping repeated initialization\n");
- }
- /* Resend device info after each reconnect */
- send_iot_descriptors();
- send_iot_states();
- rt_bool_t pending_listen = g_app.pending_listen_start;
- if (!pending_listen && !in_listening)
- {
- xiaozhi_ui_chat_status(" 待命中");
- xiaozhi_ui_chat_output(" ");
- xiaozhi_ui_update_emoji("neutral");
- LOG_I("Waiting...\n");
- }
- else
- {
- LOG_I("Pending wake-up detected on hello, preparing to listen\n");
- }
- /* Initialize wake word detection once */
- if (!g_app.wakeword_initialized_session)
- {
- LOG_I("Initializing wake word detection...");
- if (xz_wakeword_init() == 0)
- {
- g_app.wakeword_initialized_session = 1;
- /* Start detection only if no pending listen */
- if (!pending_listen && !in_listening)
- {
- if (xz_wakeword_start() == 0)
- {
- LOG_D("Wake word detection started successfully");
- }
- else
- {
- LOG_E("Failed to start wake word detection");
- }
- }
- }
- else
- {
- LOG_E("Failed to initialize wake word detection");
- }
- }
- else
- {
- if (pending_listen)
- {
- if (xz_wakeword_is_enabled())
- {
- LOG_D("Stopping wake word detection before pending listen start");
- xz_wakeword_stop();
- }
- }
- else
- {
- /* Just ensure wake word is running */
- if (!xz_wakeword_is_enabled() && !in_listening)
- {
- LOG_D("Restarting wake word detection");
- xz_wakeword_start();
- }
- }
- }
- if (pending_listen)
- {
- if (g_app.state == kDeviceStateListening || g_app.state == kDeviceStateSpeaking)
- {
- g_app.pending_listen_start = RT_FALSE;
- g_app.pending_play_wake_sound = RT_FALSE;
- return;
- }
- g_app.pending_listen_start = RT_FALSE;
- if (g_app.pending_play_wake_sound)
- {
- xz_play_wake_sound();
- }
- g_app.pending_play_wake_sound = RT_FALSE;
- if (xz_wakeword_is_enabled())
- {
- xz_wakeword_stop();
- }
- g_app.state = kDeviceStateListening;
- xz_mic(1);
- if (ws_send_listen_start(&g_app.ws.clnt, g_app.ws.session_id, kListeningModeAutoStop))
- {
- xiaozhi_ui_chat_status(" 聆听中");
- xiaozhi_ui_chat_output("聆听中...");
- }
- else
- {
- LOG_W("Listen start failed after hello, falling back to idle");
- g_app.state = kDeviceStateIdle;
- xz_mic(0);
- xiaozhi_ui_chat_status(" 就绪");
- xiaozhi_ui_chat_output("就绪");
- if (!xz_wakeword_is_enabled())
- {
- xz_wakeword_start();
- }
- }
- }
- }
- else if (strcmp(type, "goodbye") == 0)
- {
- /* Ensure mic is closed when entering sleep */
- xz_mic(0);
- xiaozhi_ui_chat_status(" 休眠中");
- xiaozhi_ui_chat_output("等待唤醒");
- xiaozhi_ui_update_emoji("sleepy");
- g_app.state = kDeviceStateUnknown;
- LOG_I("session ended\n");
- /* Reset the initialization flag for next session */
- g_app.wakeword_initialized_session = 0;
- /* Keep wake word detection running in sleep mode for wake-up */
- if (!xz_wakeword_is_enabled())
- {
- LOG_I("Starting wake word detection for sleep mode");
- xz_wakeword_start();
- }
- }
- else if (strcmp(type, "tts") == 0)
- {
- char *state = my_json_string(root, "state");
- if (strcmp(state, "start") == 0)
- {
- if (g_app.state == kDeviceStateIdle || g_app.state == kDeviceStateListening)
- {
- /* Ensure mic off before TTS starts */
- if (g_app.state == kDeviceStateListening)
- {
- xz_mic(0);
- }
- g_app.state = kDeviceStateSpeaking;
- xiaozhi_ui_chat_status(" 说话中");
- xz_speaker(1);
- LOG_D("State transitioned to Speaking, microphone stopped\n");
- /* Start fallback timeout in case sentence_end never arrives */
- if (g_app.multi_turn_conversation_enabled && g_app.tts_sentence_end_timer)
- {
- rt_timer_stop(g_app.tts_sentence_end_timer);
- rt_err_t start_ret = rt_timer_start(g_app.tts_sentence_end_timer);
- if (start_ret == RT_EOK)
- {
- LOG_D("Started TTS sentence end timer on TTS start (%d ms)", TTS_SENTENCE_TIMEOUT_MS);
- }
- else
- {
- LOG_W("Failed to start TTS sentence end timer on TTS start, start_ret=%d", start_ret);
- }
- }
- }
- else
- {
- LOG_D("Already in Speaking state, ignoring duplicate start\n");
- }
- }
- else if (strcmp(state, "stop") == 0)
- {
- /* Stop the sentence end timer if it's running */
- if (g_app.tts_sentence_end_timer)
- {
- rt_timer_stop(g_app.tts_sentence_end_timer);
- LOG_D("Stopped TTS sentence end timer on TTS stop");
- }
- g_app.state = kDeviceStateIdle;
- xz_speaker(0);
- /* Ensure microphone is closed when conversation ends */
- if (xz_mic_is_enabled())
- {
- xz_mic(0);
- }
- /* Microphone recording should have been stopped already */
- LOG_D("TTS stopped: mic enabled=%d, wakeword enabled=%d",
- xz_mic_is_enabled(), xz_wakeword_is_enabled());
- xiaozhi_ui_chat_status(" 就绪");
- xiaozhi_ui_chat_output("就绪");
- LOG_D("TTS stopped, state reset to Idle\n");
- #ifdef LX_LITEGFX_VGLITE_ENABLE
- qday_show_emoji_by_rtt_info(12);
- #endif
- /* Check if multi-turn conversation is enabled */
- if (g_app.multi_turn_conversation_enabled)
- {
- /* Multi-turn conversation: start delay timer to restart listening after audio finishes */
- if (tts_stop_delay_timer)
- {
- LOG_D("Starting TTS stop delay timer (%d ms)", TTS_STOP_DELAY_MS);
- rt_timer_start(tts_stop_delay_timer);
- }
- else
- {
- LOG_W("Delay timer not available, restarting listening immediately");
- /* Fallback: restart immediately */
- g_app.state = kDeviceStateListening;
- xz_mic(1);
- if (ws_send_listen_start(&g_app.ws.clnt, g_app.ws.session_id, kListeningModeAutoStop))
- {
- xiaozhi_ui_chat_status(" 聆听中");
- xiaozhi_ui_chat_output("聆听中...");
- }
- else
- {
- LOG_W("Listen start failed in TTS stop handler");
- g_app.state = kDeviceStateIdle;
- xz_mic(0);
- xiaozhi_ui_chat_status(" 就绪");
- xiaozhi_ui_chat_output("就绪");
- }
- }
- }
- else
- {
- /* Single-turn conversation: restart wake word detection after conversation ends */
- if (!xz_wakeword_is_enabled())
- {
- LOG_I("Restarting wake word detection after conversation ends");
- if (xz_wakeword_start() == 0)
- {
- LOG_I("Wake word detection re-enabled successfully after conversation");
- }
- else
- {
- LOG_E("Failed to re-enable wake word detection after conversation");
- }
- }
- }
- }
- else if (strcmp(state, "sentence_start") == 0)
- {
- // LOG_I("tts:%s", my_json_string(root, "text"));
- // xiaozhi_ui_chat_output(my_json_string(root, "text"));
- }
- else if (strcmp(state, "sentence_end") == 0)
- {
- /* sentence_end indicates the end of a sentence */
- LOG_D("TTS sentence ended");
- /* For multi-turn conversation, start a timeout timer to restart listening after sentence end */
- if (g_app.multi_turn_conversation_enabled && g_app.state == kDeviceStateSpeaking)
- {
- /* Use the pre-created timer: stop then start to reset timeout */
- if (g_app.tts_sentence_end_timer)
- {
- rt_err_t stop_ret = rt_timer_stop(g_app.tts_sentence_end_timer);
- if (stop_ret != RT_EOK)
- {
- LOG_W("rt_timer_stop returned %d when resetting TTS timer", stop_ret);
- }
- rt_err_t start_ret = rt_timer_start(g_app.tts_sentence_end_timer);
- if (start_ret == RT_EOK)
- {
- LOG_D("Started TTS sentence end timer (%d ms), stop_ret=%d start_ret=%d", TTS_SENTENCE_TIMEOUT_MS, stop_ret, start_ret);
- }
- else
- {
- LOG_E("Failed to start existing TTS sentence end timer, start_ret=%d", start_ret);
- }
- }
- else
- {
- /* Fallback: try to create and start the timer if it wasn't created earlier */
- g_app.tts_sentence_end_timer = rt_timer_create("tts_end_timer",
- tts_sentence_end_timeout,
- RT_NULL,
- rt_tick_from_millisecond(TTS_SENTENCE_TIMEOUT_MS),
- RT_TIMER_FLAG_ONE_SHOT);
- if (g_app.tts_sentence_end_timer && rt_timer_start(g_app.tts_sentence_end_timer) == RT_EOK)
- {
- LOG_D("Created and started fallback TTS sentence end timer (%d ms)", TTS_SENTENCE_TIMEOUT_MS);
- }
- else
- {
- LOG_E("Failed to create/start fallback TTS sentence end timer");
- }
- }
- }
- }
- else
- {
- LOG_E("Unknown tts state: %s\n", state);
- }
- }
- else if (strcmp(type, "llm") == 0)
- {
- LOG_I("llm emotion: %s", cJSON_GetObjectItem(root, "emotion")->valuestring);
- xiaozhi_ui_update_emoji(
- cJSON_GetObjectItem(root, "emotion")->valuestring);
- }
- else if (strcmp(type, "stt") == 0)
- {
- LOG_I("stt:%s", cJSON_GetObjectItem(root, "text")->valuestring);
- str1 = cJSON_GetObjectItem(root, "text")->valuestring;
- if (strcasecmp(str1, str2) == 0) {
- LOG_I("串口发送数据成功");
- }
- if (strcasecmp(str1, str3) == 0) {
- LOG_I("485发送数据成功");
- }
- if (strcasecmp(str1, str4) == 0) {
- LOG_I("CAN发送数据成功");
- }
- if (strcasecmp(str1, str5) == 0) {
- LOG_I("IO发送数据成功");
- }
- }
- else if (strcmp(type, "iot") == 0)
- {
- LOG_D("iot command");
- cJSON *commands = cJSON_GetObjectItem(root, "commands");
- for (int i = 0; i < cJSON_GetArraySize(commands); i++)
- {
- cJSON *cmd = cJSON_GetArrayItem(commands, i);
- char *cmd_str = cJSON_PrintUnformatted(cmd);
- if (cmd_str)
- {
- iot_invoke((uint8_t *)cmd_str, strlen(cmd_str));
- send_iot_states();
- cJSON_free(cmd_str);
- }
- }
- }
- else if (strcmp(type, "mcp") == 0)
- {
- LOG_D("mcp command");
- cJSON *payload = cJSON_GetObjectItem(root, "payload");
- if (payload && cJSON_IsObject(payload))
- {
- // extern void McpServer_ParseMessage(const char *message);
- char *payload_str = cJSON_PrintUnformatted(payload);
- if (payload_str)
- {
- McpServer_ParseMessage(payload_str);
- cJSON_free(payload_str);
- }
- }
- }
- else if (strcmp(type, "error") == 0)
- {
- cJSON *message = cJSON_GetObjectItem(root, "message");
- if (message && cJSON_IsString(message))
- {
- LOG_E("Server error: %s\n", message->valuestring);
- }
- else
- {
- LOG_E("Server returned error\n");
- }
- }
- else
- {
- LOG_E("Unknown type: %s\n", type);
- }
- cJSON_Delete(root);
- }