#include #include #include #include #include #include "tvs_api/tvs_api.h" #include "tvs_alert_impl.h" #include "tvs_platform_impl.h" #include "tvs_mediaplayer_impl.h" #include "tvs_auth_manager.h" #include "tvs_api_config.h" #include "tvs_api_impl.h" #include "os_wrapper.h" #include "version.h" #include "server/ai_server.h" #include "os/os_api.h" #include "tvs_executor_service.h" #ifdef TVS_SDK_VERSION MODULE_VERSION_EXPORT(tvs_sdk, TVS_SDK_VERSION); #endif const struct ai_sdk_api tc_tvs_api; static void net_check(); static u8 ai_connected = 0; static int tc_tvs_pid = 0; static int net_check_pid = 0; static volatile u8 lock_inited = 0; u8 net_connected = 0; #if ARREARS_ENABLE int arrears_type; //欠费类型 u8 audio_play_disable; //tts音频播放禁用 int arrears_flag; //欠费标志位 #endif bool BTCombo_complete; //蓝牙配网完成标志位 void *BTCombo_mutex; extern int qcloud_tvs_task_start(void *priv); extern void qcloud_tvs_task_stop(void); extern void tvs_platform_adapter_on_network_state_changed(bool connect); extern bool tvs_ping_one(); extern bool sg_qcloud_tvs_task_running; __attribute__((weak)) int get_app_music_volume(void) { return 100; } const int tc_events[][2] = { { AI_EVENT_SPEAK_END, TC_SPEAK_END }, { AI_EVENT_MEDIA_END, TC_MEDIA_END }, { AI_EVENT_MEDIA_START, TC_MEDIA_START}, { AI_EVENT_MEDIA_STOP, TC_MEDIA_STOP}, { AI_EVENT_PREVIOUS_SONG, TC_PREVIOUS_SONG }, { AI_EVENT_NEXT_SONG, TC_NEXT_SONG }, { AI_EVENT_RECORD_START, TC_RECORD_START }, { AI_EVENT_RECORD_BREAK, TC_RECORD_BREAK }, { AI_EVENT_RECORD_STOP, TC_RECORD_STOP }, { AI_EVENT_COLLECT_RES, TC_COLLECT_RESOURCE }, { AI_EVENT_PLAY_PAUSE, TC_PLAY_PAUSE}, { AI_EVENT_VOLUME_CHANGE, TC_VOLUME_CHANGE}, { AI_EVENT_VOLUME_INCR, TC_VOLUME_INCR}, { AI_EVENT_VOLUME_DECR, TC_VOLUME_DECR}, { AI_EVENT_CUSTOM_FUN, TC_RECV_CHAT}, { AI_EVENT_QUIT, TC_QUIT }, }; static int event_to_tc(int event) { for (int i = 0; i < ARRAY_SIZE(tc_events); i++) { if (tc_events[i][0] == event) { return tc_events[i][1]; } } return -1; } static int tc_tvs_do_event(int event, int arg) { int err; int argc = 2; int argv[2]; int tc_event; printf("tc_tvs_do_event %d\n", event); tc_event = event_to_tc(event); if (tc_event == -1) { return 0; } argv[0] = tc_event; argv[1] = arg; err = os_taskq_post_type("tc_tvs_task", Q_USER, argc, argv); if (err != OS_NO_ERR) { printf("send msg to tc_tvs_task fail, event : %d\n", tc_event); } return 0; } /**********************************/ static bool g_tvs_status_idle = true; extern const char *tvs_get_states_name(tvs_recognize_state state); extern void init_authorize_on_boot(); static void on_tvs_sdk_enter_working_state() { // SDK进入工作状态,比如开始语音识别、开始播控等 } static void on_tvs_sdk_exit_working_state(void *state_param) { // SDK回到空闲状态 tvs_api_state_param *api_state_param = (tvs_api_state_param *)state_param; if (api_state_param == NULL) { return; } if (api_state_param->control_type == TVS_CONTROL_PLAY_FINISH) { switch (api_state_param->error) { case TVS_API_ERROR_NETWORK_ERROR: // 播放歌曲列表时,网络异常 break; case TVS_API_ERROR_NO_MORE_MEDIA: // 播放歌曲列表时,未下发媒体,一般是歌单播放结束,没有下一首了 break; } } } bool tvs_sdk_is_idle() { // SDK是否处于空闲状态 return g_tvs_status_idle; } static void callback_on_state_changed(tvs_recognize_state last_state, tvs_recognize_state new_state, void *param) { // TO-DO 监听SDK状态变换 g_tvs_status_idle = (new_state == TVS_STATE_IDLE); if (last_state == TVS_STATE_IDLE && new_state != TVS_STATE_IDLE) { on_tvs_sdk_enter_working_state(); } else if (last_state != TVS_STATE_IDLE && new_state == TVS_STATE_IDLE) { on_tvs_sdk_exit_working_state(param); } } static void callback_on_terminal_sync(const char *text, const char *token) { TVS_ADAPTER_PRINTF("api impl get terminal sync %s -- %s\n", text, token); // TO-DO 监听APP端推送 } static void callback_on_mode_changed(tvs_mode src_mode, tvs_mode dst_mode) { TVS_ADAPTER_PRINTF("api impl get mode changed %d -- %d\n", src_mode, dst_mode); // TO-DO 监听模式变换 } static void callback_on_expect_speech() { TVS_ADAPTER_PRINTF("api impl on expect speech\n"); //tvs_api_start_recognize(); // TO-DO 多轮会话,在此函数中拉起下一轮语音识别流程 tvs_taskq_post(TC_RECORD_START); } static void callback_on_tvs_control(const char *json) { TVS_ADAPTER_PRINTF("api impl get control %s\n", json); // TO-DO 处理自定义技能 } static void callback_on_speech_reader_stop(int session_id, int error) { if (tvs_api_get_current_session_id() == session_id) { TVS_ADAPTER_PRINTF("on speech reader stop, session id %d, error %d\n", session_id, error); // SDK发送数据结束,如果本地录音没有结束,需要通知其结束 switch (error) { case TVS_API_AUDIO_PROVIDER_ERROR_NONE: // 正常结束 break; case TVS_API_AUDIO_PROVIDER_ERROR_STOP_CAPTURE: // 收到云端VAD End标识 printf("-------%s---------%d", __func__, __LINE__); break; case TVS_API_AUDIO_PROVIDER_ERROR_TIME_OUT: // 收到SDK Timeout标识,一般是网络原因导致HTTP超时 printf("-------%s---------%d", __func__, __LINE__); break; case TVS_API_AUDIO_PROVIDER_ERROR_NETWORK: // 网络出错 printf("-------%s---------%d", __func__, __LINE__); break; default: // 其他原因 printf("-------%s---------%d", __func__, __LINE__); break; } } } void tvs_api_impl_speech_write_audio(const char *audio_data, int data_size) { tvs_api_audio_provider_write(audio_data, data_size); } void tvs_api_impl_speech_wakeup() { int session_id = tvs_api_new_session_id(); tvs_api_audio_provider_writer_begin(); //需要将“叮当叮当”替换为接入方自己的热词 int ret = tvs_api_on_voice_wakeup(session_id, "小智管家", 0, 0); if (ret != 0) { // SDK启动识别流程出错,此处需要通知录音模块结束 tvs_api_audio_provider_writer_end(); } } void tvs_api_impl_speech_write_end() { tvs_api_audio_provider_writer_end(); } void tvs_api_impl_speech_init() { tvs_api_audio_provider_listen(callback_on_speech_reader_stop); } static void callback_on_asr_result(const char *asr_text, bool is_end) { printf("callback_on_asr_result %s -- isEnd %d\n", asr_text, is_end); } static void callback_on_unbind(long long unbind_timeMs) { time_t seconds = unbind_timeMs / 1000; // printf("api impl get unbind:%s\n", asctime(localtime( &seconds))); } extern void tvs_config_enable_ip_provider(bool enable); extern char *mediaplayer_adapter_get_url_token(void); static void tvs_api_impl_init(void *priv) { g_tvs_status_idle = true; //开启打印功能 tvs_api_log_enable(true); //设置speech通知回调 tvs_api_impl_speech_init(); // 初始化API,设置回调监听 tvs_api_callback api_callback = {0}; api_callback.on_state_changed = callback_on_state_changed; api_callback.on_terminal_sync = callback_on_terminal_sync; api_callback.on_mode_changed = callback_on_mode_changed; api_callback.on_expect_speech = callback_on_expect_speech; api_callback.on_recv_tvs_control = callback_on_tvs_control; api_callback.on_unbind = callback_on_unbind; tvs_default_config config = {0}; // 默认环境,量产版本必须默认为正式环境 config.def_env = TVS_API_ENV_NORMAL; // 默认沙箱,量产版本必须默认为false config.def_sandbox_open = false; config.recorder_bitrate = 16000; config.recorder_channels = 1; // 设置云小微产品信息 tvs_product_qua qua = {0}; qua.version = "1.0.0.1000"; qua.package_name = "com.huwen.aiot.guomei.voicebox"; //true代表执行容灾机制 tvs_config_enable_ip_provider(true); //互斥锁初始化,回调注册,语音,设备信息配置写入 tvs_api_init(&api_callback, &config, &qua); lock_inited = 1; //关闭https功能 extern void tvs_config_enable_https(bool enable); //tvs_config_enable_https(true); tvs_config_enable_https(false); extern void tvs_config_print_asr_result(bool enable); // 允许输出ASR结果 tvs_config_print_asr_result(true); //设置asr回调函数 tvs_api_set_asr_callback(callback_on_asr_result); // 初始化platform adapter,赋予SDK操作终端的能力 tvs_platform_adaptor platform_adapter_impl = {0}; tvs_init_platform_adapter_impl(&platform_adapter_impl); tvs_platform_adapter_init(&platform_adapter_impl); // 初始化media player adapter,赋予SDK播放网络媒体的能力 tvs_mediaplayer_adapter media_adapter_impl = {0}; tvs_init_mediaplayer_adapter_impl(&media_adapter_impl); tvs_mediaplayer_adapter_init(&media_adapter_impl); // 初始化alert adapter,赋予SDK操作闹钟的能力 tvs_alert_adapter alert_adapter_impl = {0}; tvs_init_alert_adater_impl(&alert_adapter_impl); tvs_alert_adapter_init(&alert_adapter_impl); #if USE_MAC_DEVICE_NAME extern void get_mac_device_name(void); get_mac_device_name(); //获取mac地址作为腾讯云的设备名 extern u8 is_psk_available(void); //这里提示用户需要进行一次配网去获取psk if (!is_psk_available()) { printf("psk is not available, please auth again-------%s-------%d\r\n", __func__, __LINE__); } #endif #if ARREARS_ENABLE //从flash读取欠费标志位 extern void load_arrears_info(void); load_arrears_info(); #endif // 授权 init_authorize_on_boot(); // 启动SDK tvs_api_start(); tvs_executor_upload_volume(get_app_music_volume()); int msg[32]; int err; while (1) { err = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg)); if (err != OS_TASKQ || msg[0] != Q_USER) { continue; } switch (msg[1]) { case TC_MEDIA_END: tvs_mediaplayer_adapter_on_play_finished(mediaplayer_adapter_get_url_token()); break; case TC_MEDIA_START: tvs_mediaplayer_adapter_on_play_started(mediaplayer_adapter_get_url_token()); break; case TC_MEDIA_STOP: tvs_mediaplayer_adapter_on_play_stopped(0, mediaplayer_adapter_get_url_token()); break; case TC_PLAY_PAUSE: if (msg[2]) { tvs_mediaplayer_adapter_on_play_stopped(0, mediaplayer_adapter_get_url_token()); } else { tvs_mediaplayer_adapter_on_play_started(mediaplayer_adapter_get_url_token()); } break; case TC_PREVIOUS_SONG: tvs_api_playcontrol_previous(); break; case TC_NEXT_SONG: tvs_api_playcontrol_next(); break; case TC_VOLUME_CHANGE: tvs_platform_adapter_on_volume_changed(msg[2]); break; case TC_RECORD_START: extern void record_sem_post(void); extern void alarm_rings_stop(int tvs_alert_stop_reason); alarm_rings_stop(TVS_ALART_STOP_REASON_NEW_RECO); record_sem_post(); tvs_api_start_recognize(); break; case TC_RECORD_STOP: tvs_api_stop_recognize(); break; case TC_RECORD_BREAK: tvs_api_stop_all_activity(); break; case TC_QUIT: printf("tc_tvs_task exit.\n\r"); return; default: break; } } } void tvs_taskq_post(int msg) { os_taskq_post("tc_tvs_task", 1, msg); } static void net_check() { int cnt = 300; while (ai_connected) { if (tvs_ping_one()) { net_connected = 1; break; } else { net_connected = 0; } os_time_dly(cnt); cnt += 200; if (cnt >= 1000) { cnt = 300; } } } static void qcloud_tvs_task_disconnect() { tvs_platform_adapter_on_network_state_changed(false); qcloud_tvs_task_stop(); if (!net_check_pid) { thread_fork("net_check", 20, 1024, 0, &net_check_pid, net_check, NULL); } } static void qcloud_tvs_task_connect() { if (!sg_qcloud_tvs_task_running && read_BTCombo()) { //通知SDK联网 tvs_platform_adapter_on_network_state_changed(true); thread_fork("qcloud_tvs_task_start", 20, 2048, 20, NULL, qcloud_tvs_task_start, NULL); } } static int tc_tvs_check(void) { if (lock_inited) { if (net_connected) { qcloud_tvs_task_connect(); return AI_STAT_CONNECTED; } else { qcloud_tvs_task_disconnect(); return AI_STAT_DISCONNECTED; } } else { return AI_STAT_DISCONNECTED; } } static int tc_tvs_connect(void) { ai_connected = 1; //已经创建过不再创建 if (!tc_tvs_pid) { thread_fork("tc_tvs_task", 20, 1100, 64, &tc_tvs_pid, tvs_api_impl_init, NULL); } if (!net_check_pid) { thread_fork("net_check", 20, 1024, 0, &net_check_pid, net_check, NULL); } return 0; } static int tc_tvs_disconnect(void) { ai_connected = 0; qcloud_tvs_task_stop(); tvs_platform_adapter_on_network_state_changed(false); tvs_uninit_alert(); tvs_api_uninit(); lock_inited = 0; tvs_taskq_post(TC_QUIT); return 0; } REGISTER_AI_SDK(tc_tvs_api) = { .name = "tencent", .connect = tc_tvs_connect, .state_check = tc_tvs_check, .do_event = tc_tvs_do_event, .disconnect = tc_tvs_disconnect, };