/*
* 语音听写(iFly Auto Transform)技术能够实时地将语音转换成对应的文字。
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "voice_control/qisr.h"
#include "voice_control/msp_cmn.h"
#include "voice_control/msp_errors.h"
#include "voice_control/speech_recognizer.h"

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

// 全局标志和结果变量
std::atomic<bool> resultFlag(false);
std::string g_result;


// 科大讯飞语音识别回调函数
void on_result(const char *result, char is_last)
{
    if (result != nullptr) {
        g_result += result;
        resultFlag = true;
		RCLCPP_INFO(rclcpp::get_logger("voice_recognition"), "识别结果:%s",result);
    }
}

void on_speech_begin()
{
    RCLCPP_INFO(rclcpp::get_logger("voice_recognition"), "开始说话...");
}

void on_speech_end(int reason)
{
    if (reason == END_REASON_VAD_DETECT) {
        RCLCPP_INFO(rclcpp::get_logger("voice_recognition"), "说话结束");
    } else {
        RCLCPP_WARN(rclcpp::get_logger("voice_recognition"), "说话结束，原因: %d", reason);
    }
}


/* demo recognize the audio from microphone */
static void demo_mic(const char* session_begin_params)
{
	int errcode;
	int i = 0;

	struct speech_rec iat;

	struct speech_rec_notifier recnotifier = {
		on_result,
		on_speech_begin,
		on_speech_end
	};

	errcode = sr_init(&iat, session_begin_params, SR_MIC, &recnotifier);
	if (errcode) {
		printf("speech recognizer init failed\n");
		return;
	}
	errcode = sr_start_listening(&iat);
	if (errcode) {
		printf("start listen failed %d\n", errcode);
	}
	/* demo 8 seconds recording */
	while(i++ < 3)
		sleep(1);
	errcode = sr_stop_listening(&iat);
	if (errcode) {
		printf("stop listening failed %d\n", errcode);
	}

	sr_uninit(&iat);
}

void WakeUp(const std_msgs::msg::String::ConstPtr& msg)
{
    printf("waking up\r\n");
    usleep(700*1000);
}

/* main thread: start/stop record ; query the result of recgonization.
 * record thread: record callback(data write)
 * helper thread: ui(keystroke detection)
 */
int main(int argc, char* argv[])
{
	// 初始化ROS 2
    rclcpp::init(argc, argv);
    auto node = rclcpp::Node::make_shared("voice_recognition");
    
    // 设置循环频率
    rclcpp::Rate loop_rate(10);

    // 发布语音识别结果
    auto voiceWordsPub = node->create_publisher<std_msgs::msg::String>("mic_msg", 1000);  

    RCLCPP_INFO(node->get_logger(), "Sleeping...");

	int ret = MSP_SUCCESS;
	/* login params, please do keep the appid correct */
	const char* login_params = "appid = 4d9c997f, work_dir = .";
	int aud_src = 0; /* from mic or file */

	/*
	* See "iFlytek MSC Reference Manual"
	*/
	const char* session_begin_params =
		"sub = iat, domain = iat, language = zh_cn, "
		"accent = mandarin, sample_rate = 16000, "
		"result_type = plain, result_encoding = utf8";

	/* Login first. the 1st arg is username, the 2nd arg is password
	 * just set them as NULL. the 3rd arg is login paramertes 
	 * */
	ret = MSPLogin(NULL, NULL, login_params);
	if (MSP_SUCCESS != ret)	{
		printf("MSPLogin failed , Error code %d.\n",ret);
		return -1; // 登录失败，退出程序
	}

	while (rclcpp::ok())
    {
        // 语音识别唤醒
		RCLCPP_INFO(node->get_logger(), "开始从麦克风识别语音");
		RCLCPP_INFO(node->get_logger(), "3秒内请说话...");

		demo_mic(session_begin_params);

		RCLCPP_INFO(node->get_logger(), "3秒已过");

        // 语音识别完成，发布结果
        if (resultFlag) {
            resultFlag = false;
            auto msg = std_msgs::msg::String();
            msg.data = g_result;
            voiceWordsPub->publish(msg);
            RCLCPP_INFO(node->get_logger(), "发布识别结果: %s", msg.data.c_str());
            g_result.clear(); // 清空结果，准备下一次识别
        }
        
        rclcpp::spin_some(node);
        loop_rate.sleep();
    }

	// 退出时清理
    MSPLogout();
    rclcpp::shutdown();
    return 0;
}
