From 2a365f4e08a9a04610780bfc8baaa47aff2e7fe9 Mon Sep 17 00:00:00 2001 From: cheng Date: Tue, 16 Sep 2025 15:12:00 +0800 Subject: [PATCH] =?utf8?q?=E9=9B=B7=E9=B8=9F=EF=BC=9A=E8=B0=83=E6=95=B4ln?= =?utf8?q?=5Fapi.c=E6=96=87=E4=BB=B6=E4=B8=AD=E4=BB=A3=E7=A0=81=E4=BD=8D?= =?utf8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- code/sdk/zhihui/leiniao/imsl_ln/ln_api.c | 1252 +++++++++++----------- code/sdk/zhihui/leiniao/imsl_ln/ln_api.h | 10 +- 2 files changed, 637 insertions(+), 625 deletions(-) diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c index 5c8c94151..20ffbf7e0 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c @@ -453,753 +453,761 @@ void ln_ws_process_message(int cmd, const char *json_str) } cJSON_Delete(root); } +/* ============================ WebSocket 业务消息 上层处理 End============================ */ -// 发送队列 -static void ln_http_server_send_task(void const *arg) + + + +/* ============================ mp3下载功能 ============================ */ + +/** + * 高级MP3下载函数,支持自定义保存目录和文件名 + * @param audio_url 音频文件URL + * @param save_dir 保存目录 + * @param filename 文件名(不包含路径) + * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败 + */ +static uint32_t ln_download_mp3_file_advanced(const char *audio_url, const char *save_dir, const char *filename) { - errcode_t ret; + if (!audio_url || !save_dir || !filename) + { + printf("[SSE] download_mp3_advanced: invalid parameters\n"); + return ERRCODE_FAIL; + } - ln_http_data_mail_t mail = {0}; - uint32_t msgsize = sizeof(ln_http_data_mail_t); + // 构建完整保存路径 + char save_path[512]; + snprintf(save_path, sizeof(save_path), "%s/%s", save_dir, filename); - while (1) + // 确保目录存在 + if (access(save_dir, F_OK) == -1) { - ret = osal_msg_queue_read_copy(g_ln_send_queue, (void *)&mail, &msgsize, - OSAL_MSGQ_WAIT_FOREVER); - if (ret != OSAL_SUCCESS) - { - continue; - } - if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN) - { - if (mail.data != NULL && mail.len == sizeof(ln_device_token_req_t)) - { - printf("LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN:获取雷鸟设备Token\n"); - ln_device_token_req_t req; - memcpy(&req, mail.data, sizeof(req)); - ln_get_device_token_http(req.device_id, req.device_iccid, req.device_model, req.device_version); - } - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_SPEECH_CHAT_STREAM) - { - if (mail.data != NULL && mail.len == sizeof(ln_speech_chat_req_t)) - { - printf("LN_HTTP_SERVICE_CMD_SPEECH_CHAT_STREAM\n"); - ln_speech_chat_req_t req; - memcpy(&req, mail.data, sizeof(req)); - ln_speech_chat_stream_http(req.device_id, req.device_token, req.audio_path); - } - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_CHOOSE) - { - if (mail.data && mail.len == sizeof(ln_story_choose_req_t)) { - printf("LN_HTTP_SERVICE_CMD_STORY_CHOOSE:选择故事\n"); - ln_story_choose_req_t req; memcpy(&req, mail.data, sizeof(req)); - ln_story_choose_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), req.audio_path); - } - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_RANDOM) - { - if (mail.data && mail.len == sizeof(ln_story_random_req_t)) { - printf("LN_HTTP_SERVICE_CMD_STORY_RANDOM:随机故事\n"); - ln_story_random_req_t req; memcpy(&req, mail.data, sizeof(req)); - ln_story_random_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), req.story_theme[0] ? req.story_theme : NULL); - } - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_EXIT_INQUIRY) - { - printf("LN_HTTP_SERVICE_CMD_STORY_EXIT_INQUIRY:获取退出哄睡询问\n"); - ln_story_exit_inquiry_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_FINISH) - { - printf("LN_HTTP_SERVICE_CMD_STORY_FINISH:确认结束哄睡\n"); - ln_story_finish_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_CHARACTER) - { - printf("LN_HTTP_SERVICE_CMD_GET_CHARACTER:获取设备角色信息\n"); - ln_device_get_character_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_USER_ID) - { - printf("LN_HTTP_SERVICE_CMD_GET_USER_ID:获取设备绑定用户ID\n"); - ln_device_get_user_id_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_GET_TASK) - { - printf("LN_HTTP_SERVICE_CMD_OTA_GET_TASK:获取OTA升级任务\n"); - ln_ota_get_task_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), uapi_ln_get_device_version()); - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD) - { - printf("LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD:下载OTA升级包\n"); - ln_ota_download_flow_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), uapi_ln_get_device_version()); - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY) - { - printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY:播放音频\n"); - #ifdef BOARD_N9 - if (ln_story_player_simple_start("/user/leiniao/story/choose")) - { - printf("播放开始成功\n"); - } - #endif - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_STOP) - { - printf("LN_HTTP_SERVICE_CMD_AUDIO_STOP:停止播放音频\n"); - #ifdef BOARD_N9 - ln_story_player_simple_stop(); - #endif - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT) - { - printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT:播放下一首\n"); - #ifdef BOARD_N9 - ln_story_player_simple_handle_message(LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT, NULL, 0); - #endif - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_FILE) + uapi_create_folder(save_dir); + } + + printf("[SSE] downloading MP3: %s -> %s\n", audio_url, save_path); + + #ifdef SUPPORT_CAT1_SERVICE + /* CAT1 网络保活处理 */ + cat1_api_add_cat1_vote(); + cat1_api_wakeup_cat1(1); + cat1_api_keep_wakeup(1); + cat1_api_disable_cat1_cmd(0); + LOS_Msleep(300); + #endif + + HttpClient client = {0}; + HttpClientData client_data = {0}; + int ret = -1; + size_t total_written = 0; + + // 打开文件准备写入 + FILE *fd = fopen(save_path, "wb"); + if (!fd) + { + printf("[SSE] fopen failed for %s\n", save_path); + return ERRCODE_FAIL; + } + + HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 2); + if (prep != HTTP_SUCCESS) + { + printf("[SSE] prepare failed: %d\n", prep); + fclose(fd); + return ERRCODE_FAIL; + } + + // 建立连接 + ret = HttpClientConn(&client, audio_url); + if (ret != 0) + { + printf("[SSE] connection failed, ret=0x%x\n", ret); + fclose(fd); + HttpClientUnprepare(&client_data); + return ERRCODE_FAIL; + } + + // 发送GET请求 + ret = HttpClientSend(&client, audio_url, HTTP_GET, &client_data); + if (ret != 0) + { + printf("[SSE] send request failed, ret=0x%x\n", ret); + fclose(fd); + HttpClientClse(&client); + HttpClientUnprepare(&client_data); + return ERRCODE_FAIL; + } + + // 接收响应数据 + do + { + HTTPC_RESULT recv_res = HttpClientRecvResponse(&client, &client_data); + if (recv_res == HTTP_SUCCESS || recv_res == HTTP_EAGAIN) { - printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY_FILE:播放指定文件\n"); - #ifdef BOARD_N9 - if (mail.data != NULL) + if (client_data.contentBlockLen > 0) { - char *file_path = (char*)mail.data; - printf("Playing file: %s\n", file_path); - if (ln_story_player_simple_play_file(file_path)) - { - printf("File playback started successfully\n"); - } - else + /* 一边下载到文件,一边推送到播放器队列,尝试边下边播 */ + size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd); + if (written != client_data.contentBlockLen) { - printf("Failed to start file playback\n"); + printf("[SSE] write failed, written=%zu, expected=%d\n", + written, client_data.contentBlockLen); + fclose(fd); + HttpClientClse(&client); + HttpClientUnprepare(&client_data); + return ERRCODE_FAIL; } + + /* 非阻塞入队,队列满则忽略该块 */ + (void)ln_audio_player_write((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen); + + total_written += written; } - else - { - printf("Error: No file path provided\n"); - } - #endif - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PAUSE) - { - printf("LN_HTTP_SERVICE_CMD_AUDIO_PAUSE:暂停播放\n"); - #ifdef BOARD_N9 - if (ln_story_player_simple_pause()) - { - printf("Playback paused successfully\n"); - } - else - { - printf("Failed to pause playback\n"); - } - #endif - } - else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_RESUME) - { - printf("LN_HTTP_SERVICE_CMD_AUDIO_RESUME:恢复播放\n"); - #ifdef BOARD_N9 - if (ln_story_player_simple_resume()) - { - printf("Playback resumed successfully\n"); - } - else - { - printf("Failed to resume playback\n"); - } - #endif } - if (mail.data != NULL) + else { - printf("free(mail.data)\n"); - free(mail.data); + printf("[SSE] receive ended (code: %d)\n", recv_res); + break; } - } + } while (client_data.isMore); + + fclose(fd); + HttpClientUnprepare(&client_data); + HttpClientClse(&client); + + printf("[SSE] download completed, total bytes: %zu\n", total_written); + return ERRCODE_SUCC; } -// 接收队列 -static void ln_http_server_recv_task(void const *arg) +/** + * 解析JSON数据,下载MP3并推送消息 + * @param json_data JSON数据字符串 + * @param interface_type 接口类型 + * @param segment_index 片段索引 + * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败 + */ +static uint32_t ln_parse_and_process_json_data(const char *json_data, int interface_type, int segment_index) { - errcode_t ret; + if (!json_data) + { + printf("[JSON_PARSE] invalid json_data\n"); + return ERRCODE_FAIL; + } - ln_http_data_mail_t mail = {0}; - uint32_t msgsize = sizeof(ln_http_data_mail_t); + printf("[JSON_PARSE] parsing JSON data (interface_type=%d, segment=%d): %s\n", + interface_type, segment_index, json_data); - while (1) + // 解析JSON数据 + cJSON *root = cJSON_Parse(json_data); + if (!root) { - ret = osal_msg_queue_read_copy(g_ln_recv_queue, (void *)&mail, &msgsize, - OSAL_MSGQ_WAIT_FOREVER); - if (ret != OSAL_SUCCESS) - { - continue; - } + printf("[JSON_PARSE] JSON parse failed: %s\n", json_data); + return ERRCODE_FAIL; + } - // 消息有效性检查 - if (!mail.data || mail.len <= 0) - { - continue; - } + // 检查是否有错误 + cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode"); + if (errorCode && !cJSON_IsNull(errorCode)) + { + printf("[JSON_PARSE] server error: %s\n", + cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown"); + cJSON_Delete(root); + return ERRCODE_FAIL; + } - // 分类处理消息 - const char *tag = "UNKNOWN"; - if (mail.cmd == LN_HTTP_SERVICE_CMD_SSE_RECV) { - tag = "SPEECH_CHAT"; - } else if (mail.cmd == LN_HTTP_RECV_STORY_CHOOSE) { - tag = "STORY_CHOOSE"; - } else if (mail.cmd == LN_HTTP_RECV_STORY_RANDOM) { - tag = "STORY_RANDOM"; - } else if (mail.cmd == LN_HTTP_RECV_STORY_EXIT) { - tag = "STORY_EXIT"; - } else if (mail.cmd == LN_HTTP_RECV_STORY_FINISH) { - tag = "STORY_FINISH"; - } else if (mail.cmd == LN_HTTP_RECV_DEVICE_CHARACTER) { - tag = "DEVICE_CHARACTER"; - } else if (mail.cmd == LN_HTTP_RECV_DEVICE_USER_ID) { - tag = "DEVICE_USER_ID"; - } else if (mail.cmd == LN_HTTP_RECV_OTA_TASK) { - tag = "OTA_TASK"; - } else if (mail.cmd == LN_HTTP_RECV_OTA_DOWNLOAD_MSG) { - tag = "OTA_DOWNLOAD_MSG"; - } + // 获取data字段 + cJSON *data = cJSON_GetObjectItem(root, "data"); + if (!data || !cJSON_IsObject(data)) + { + printf("[JSON_PARSE] no data field found\n"); + cJSON_Delete(root); + return ERRCODE_FAIL; + } - printf("[%s] 数据长度: %u\n", tag, mail.len); - /* 确保可打印:追加\0 */ - char *buf = (char *)malloc(mail.len + 1); - if (buf) { - memcpy(buf, mail.data, mail.len); - buf[mail.len] = '\0'; - printf("[%s] 原始数据:%s\n", tag, buf); - /* 在收到 OTA_TASK 后,根据升级策略决定是否触发下载 */ - if (mail.cmd == LN_HTTP_RECV_OTA_TASK) { - ln_handle_ota_task_response(buf, (int)mail.len); - } - /* 在收到 OTA_DOWNLOAD_MSG 后,解析状态并回调处理(进度/完成/失败) */ - if (mail.cmd == LN_HTTP_RECV_OTA_DOWNLOAD_MSG) { - OtaDownloadMsg m = {0}; - if (parse_ota_download_msg(buf, &m) == 0) { - handle_ota_download_msg(&m); - } - } - free(buf); + // 根据接口类型获取音频URL + char *audio_url = NULL; + if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV) + { + // 语音对话接口:使用 audioUrl 字段 + cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl"); + if (audioUrl && cJSON_IsString(audioUrl)) + { + audio_url = audioUrl->valuestring; } } -} - -static void create_ln_http_send_queue(void) -{ - if (osal_msg_queue_create("ln_http_send_queue", 24, &g_ln_send_queue, - 0, sizeof(ln_http_data_mail_t)) != ERRCODE_SUCC) + else if (interface_type == LN_HTTP_RECV_STORY_CHOOSE || interface_type == LN_HTTP_RECV_STORY_RANDOM) { - printf("[ln][service] app create mail fail\n"); + // 故事接口:使用 storyAudioUrl 字段 + cJSON *storyAudioUrl = cJSON_GetObjectItem(data, "storyAudioUrl"); + if (storyAudioUrl && cJSON_IsString(storyAudioUrl)) + { + audio_url = storyAudioUrl->valuestring; + } } -} - -static void create_ln_http_recv_queue(void) -{ - if (osal_msg_queue_create("ln_http_recv_queue", 24, &g_ln_recv_queue, - 0, sizeof(ln_http_data_mail_t)) != ERRCODE_SUCC) + else { - printf("[ln][service] app create mail fail\n"); + // 默认尝试 audioUrl 字段 + cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl"); + if (audioUrl && cJSON_IsString(audioUrl)) + { + audio_url = audioUrl->valuestring; + } } -} -// 雷鸟http服务初始化 -errcode_t uapi_ln_http_server_init(void) -{ - printf("uapi_ln_http_server_init !\r\n"); - - ln_send_taskcfg.create_queue_handle = create_ln_http_send_queue; - ln_send_taskcfg.attr.name = "ln_http_server_send_task"; - ln_send_taskcfg.attr.priority = osPriorityNormal; - ln_send_taskcfg.attr.stack_size = LN_HTTP_BOARD_TASK_SIZE; - ln_send_taskcfg.func = ln_http_server_send_task; - ln_send_taskcfg.use_mem = USE_EXTEND_MEM; - - errcode_t ret = uapi_create_osThread_custom(&ln_send_taskcfg); - if (ret != ERRCODE_SUCC) + // 获取textContent + cJSON *textContent = cJSON_GetObjectItem(data, "textContent"); + char *text_content = NULL; + if (textContent && cJSON_IsString(textContent)) { - printf("create ln_send_service failed %d!\r\n", ret); - return ERRCODE_FAIL; + text_content = textContent->valuestring; } - ln_recv_taskcfg.create_queue_handle = create_ln_http_recv_queue; - ln_recv_taskcfg.attr.name = "ln_http_server_recv_task"; - ln_recv_taskcfg.attr.priority = osPriorityNormal; - ln_recv_taskcfg.attr.stack_size = LN_HTTP_BOARD_TASK_SIZE; - ln_recv_taskcfg.func = ln_http_server_recv_task; - ln_recv_taskcfg.use_mem = USE_EXTEND_MEM; - - ret = uapi_create_osThread_custom(&ln_recv_taskcfg); - if (ret != ERRCODE_SUCC) + // 获取intention + cJSON *intention = cJSON_GetObjectItem(data, "intention"); + char *intention_str = NULL; + if (intention && cJSON_IsString(intention)) { - printf("create gnss_recv_service failed %d!\r\n", ret); - return ERRCODE_FAIL; + intention_str = intention->valuestring; } - /* 初始化音频播放器(流式输出) */ - if (ln_audio_player_init() != ERRCODE_SUCC) + // 获取storyTheme(故事接口特有) + cJSON *storyTheme = cJSON_GetObjectItem(data, "storyTheme"); + char *story_theme = NULL; + if (storyTheme && cJSON_IsString(storyTheme)) { - printf("[LN_AUDIO] init failed in http server init\n"); - /* 不中断HTTP服务,按需可返回失败 */ + story_theme = storyTheme->valuestring; } - return ERRCODE_SUCC; -} + // 获取storyContent(故事接口特有) + cJSON *storyContent = cJSON_GetObjectItem(data, "storyContent"); + char *story_content = NULL; + if (storyContent && cJSON_IsString(storyContent)) + { + story_content = storyContent->valuestring; + } -/* 通用发送接口:向 LN HTTP 发送队列投递消息 */ -void do_ln_http_server_send_data(int cmd, char *data, uint32_t len) -{ - errcode_t ret; - ln_http_data_mail_t send_data = {0}; - send_data.cmd = cmd; - if (len && data) + // 创建推送数据 + cJSON *push_data = cJSON_CreateObject(); + + // 根据接口类型添加相应字段 + if (text_content && strlen(text_content) > 0) { - send_data.len = len; - send_data.data = (char *)malloc(len); - if (send_data.data == NULL) - { - printf("malloc failed\n"); - return; - } - memcpy(send_data.data, data, len); + cJSON_AddStringToObject(push_data, "textContent", text_content); + } + + if (story_content && strlen(story_content) > 0) + { + cJSON_AddStringToObject(push_data, "storyContent", story_content); + } + + if (intention_str && strlen(intention_str) > 0) + { + cJSON_AddStringToObject(push_data, "intention", intention_str); + } + + if (story_theme && strlen(story_theme) > 0) + { + cJSON_AddStringToObject(push_data, "storyTheme", story_theme); } - uint32_t send_len = sizeof(send_data); - - ret = osal_msg_queue_write_copy(g_ln_send_queue, (void *)&send_data, - send_len, 0); - if (ret != OSAL_SUCCESS) + // 推送到相应的接收线程 + char *json_string = cJSON_Print(push_data); + if (json_string) { - printf("Error ln http send failed! err=0x%x! \r\n", ret); + printf("[JSON_PARSE] pushing data to interface_type=%d: %s\n", interface_type, json_string); + do_ln_http_server_recv_data(interface_type, json_string, strlen(json_string)); + free(json_string); } -} + cJSON_Delete(push_data); -/* 通用接收接口:向 LN HTTP 接收队列投递消息 */ -void do_ln_http_server_recv_data(int cmd, char *data, uint32_t len) -{ - errcode_t ret; - ln_http_data_mail_t recv_data = {0}; - recv_data.cmd = cmd; - if (len && data) + // 下载音频文件 + if (audio_url && strlen(audio_url) > 0) { - recv_data.len = len; - recv_data.data = (char *)malloc(len); - if (recv_data.data == NULL) + char save_dir[256]; + char filename[128]; + + // 根据接口类型确定保存目录和文件名 + switch (interface_type) { - printf("malloc failed\n"); - return; + case LN_HTTP_SERVICE_CMD_SSE_RECV: + snprintf(save_dir, sizeof(save_dir), "%s/speech", LN_DATA_PATH); + snprintf(filename, sizeof(filename), "%d.mp3", segment_index); + break; + case LN_HTTP_RECV_STORY_CHOOSE: + snprintf(save_dir, sizeof(save_dir), "%s/story/choose", LN_DATA_PATH); + snprintf(filename, sizeof(filename), "%d.mp3", segment_index); + break; + case LN_HTTP_RECV_STORY_RANDOM: + snprintf(save_dir, sizeof(save_dir), "%s/story/random", LN_DATA_PATH); + snprintf(filename, sizeof(filename), "%d.mp3", segment_index); + break; + default: + snprintf(save_dir, sizeof(save_dir), "%s", LN_DATA_PATH); + snprintf(filename, sizeof(filename), "%d.mp3", segment_index); + break; } - memcpy(recv_data.data, data, len); - } - - uint32_t send_len = sizeof(recv_data); - ret = osal_msg_queue_write_copy(g_ln_recv_queue, (void *)&recv_data, - send_len, 0); - if (ret != OSAL_SUCCESS) + printf("[JSON_PARSE] found audio URL (interface_type=%d): %s\n", interface_type, audio_url); + printf("[JSON_PARSE] downloading audio to: %s/%s\n", save_dir, filename); + + uint32_t download_result = ln_download_mp3_file_advanced(audio_url, save_dir, filename); + if (download_result == ERRCODE_SUCC) + { + printf("[JSON_PARSE] audio downloaded successfully: %s/%s\n", save_dir, filename); + } + else + { + printf("[JSON_PARSE] audio download failed\n"); + } + } + else { - printf("Error ln http recv send failed! err=0x%x! \r\n", ret); - if (recv_data.data) free(recv_data.data); + printf("[JSON_PARSE] no audio URL found for interface_type=%d, skipping download\n", interface_type); } -} + cJSON_Delete(root); + return ERRCODE_SUCC; +} /** - * 高级MP3下载函数,支持自定义保存目录和文件名 - * @param audio_url 音频文件URL - * @param save_dir 保存目录 - * @param filename 文件名(不包含路径) + * 从文件中解析data数据,下载MP3并推送消息 + * @param file_path 文件路径 + * @param interface_type 接口类型 * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败 */ -static uint32_t ln_download_mp3_file_advanced(const char *audio_url, const char *save_dir, const char *filename) +uint32_t ln_parse_file_and_process_data(const char *file_path, int interface_type) { - if (!audio_url || !save_dir || !filename) + if (!file_path) { - printf("[SSE] download_mp3_advanced: invalid parameters\n"); + printf("[FILE_PARSE] invalid file path\n"); return ERRCODE_FAIL; } - // 构建完整保存路径 - char save_path[512]; - snprintf(save_path, sizeof(save_path), "%s/%s", save_dir, filename); + printf("[FILE_PARSE] processing file: %s (interface_type=%d)\n", file_path, interface_type); - // 确保目录存在 - if (access(save_dir, F_OK) == -1) + FILE *fp = fopen(file_path, "r"); + if (!fp) { - uapi_create_folder(save_dir); + printf("[FILE_PARSE] failed to open file: %s\n", file_path); + return ERRCODE_FAIL; } - printf("[SSE] downloading MP3: %s -> %s\n", audio_url, save_path); + char line[2048]; + int line_count = 0; + int success_count = 0; + int error_count = 0; - #ifdef SUPPORT_CAT1_SERVICE - /* CAT1 网络保活处理 */ - cat1_api_add_cat1_vote(); - cat1_api_wakeup_cat1(1); - cat1_api_keep_wakeup(1); - cat1_api_disable_cat1_cmd(0); - LOS_Msleep(300); - #endif + while (fgets(line, sizeof(line), fp)) + { + line_count++; + + // 去除行尾的换行符 + size_t len = strlen(line); + if (len > 0 && line[len - 1] == '\n') + { + line[len - 1] = '\0'; + len--; + } + if (len > 0 && line[len - 1] == '\r') + { + line[len - 1] = '\0'; + len--; + } - HttpClient client = {0}; - HttpClientData client_data = {0}; - int ret = -1; - size_t total_written = 0; + // 跳过空行 + if (len == 0) + { + continue; + } - // 打开文件准备写入 - FILE *fd = fopen(save_path, "wb"); - if (!fd) - { - printf("[SSE] fopen failed for %s\n", save_path); - return ERRCODE_FAIL; - } + // 检查是否是SSE数据格式 (data: {...}) + if (strncmp(line, "data:", 5) == 0) + { + char *json_start = line + 5; + // 跳过可能的空格 + while (*json_start == ' ' || *json_start == '\t') + { + json_start++; + } - HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 2); - if (prep != HTTP_SUCCESS) - { - printf("[SSE] prepare failed: %d\n", prep); - fclose(fd); - return ERRCODE_FAIL; + printf("[FILE_PARSE] line %d: processing JSON: %s\n", line_count, json_start); + + uint32_t result = ln_parse_and_process_json_data(json_start, interface_type, line_count); + if (result == ERRCODE_SUCC) + { + success_count++; + } + else + { + error_count++; + } + } + else + { + printf("[FILE_PARSE] line %d: invalid format (not SSE data): %s\n", line_count, line); + error_count++; + } } - // 建立连接 - ret = HttpClientConn(&client, audio_url); - if (ret != 0) - { - printf("[SSE] connection failed, ret=0x%x\n", ret); - fclose(fd); - HttpClientUnprepare(&client_data); - return ERRCODE_FAIL; - } + fclose(fp); - // 发送GET请求 - ret = HttpClientSend(&client, audio_url, HTTP_GET, &client_data); - if (ret != 0) - { - printf("[SSE] send request failed, ret=0x%x\n", ret); - fclose(fd); - HttpClientClse(&client); - HttpClientUnprepare(&client_data); - return ERRCODE_FAIL; - } + printf("[FILE_PARSE] processing completed: total lines=%d, success=%d, errors=%d\n", + line_count, success_count, error_count); - // 接收响应数据 - do + return (error_count == 0) ? ERRCODE_SUCC : ERRCODE_FAIL; +} +/* ============================ mp3下载功能 End ============================ */ + +/* ============================ 队列相关代码 ============================ */ +// 发送队列 +static void ln_http_server_send_task(void const *arg) +{ + errcode_t ret; + + ln_http_data_mail_t mail = {0}; + uint32_t msgsize = sizeof(ln_http_data_mail_t); + + while (1) { - HTTPC_RESULT recv_res = HttpClientRecvResponse(&client, &client_data); - if (recv_res == HTTP_SUCCESS || recv_res == HTTP_EAGAIN) + ret = osal_msg_queue_read_copy(g_ln_send_queue, (void *)&mail, &msgsize, + OSAL_MSGQ_WAIT_FOREVER); + if (ret != OSAL_SUCCESS) + { + continue; + } + if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN) + { + if (mail.data != NULL && mail.len == sizeof(ln_device_token_req_t)) + { + printf("LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN:获取雷鸟设备Token\n"); + ln_device_token_req_t req; + memcpy(&req, mail.data, sizeof(req)); + ln_get_device_token_http(req.device_id, req.device_iccid, req.device_model, req.device_version); + } + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_SPEECH_CHAT_STREAM) + { + if (mail.data != NULL && mail.len == sizeof(ln_speech_chat_req_t)) + { + printf("LN_HTTP_SERVICE_CMD_SPEECH_CHAT_STREAM\n"); + ln_speech_chat_req_t req; + memcpy(&req, mail.data, sizeof(req)); + ln_speech_chat_stream_http(req.device_id, req.device_token, req.audio_path); + } + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_CHOOSE) + { + if (mail.data && mail.len == sizeof(ln_story_choose_req_t)) { + printf("LN_HTTP_SERVICE_CMD_STORY_CHOOSE:选择故事\n"); + ln_story_choose_req_t req; memcpy(&req, mail.data, sizeof(req)); + ln_story_choose_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), req.audio_path); + } + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_RANDOM) { - if (client_data.contentBlockLen > 0) + if (mail.data && mail.len == sizeof(ln_story_random_req_t)) { + printf("LN_HTTP_SERVICE_CMD_STORY_RANDOM:随机故事\n"); + ln_story_random_req_t req; memcpy(&req, mail.data, sizeof(req)); + ln_story_random_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), req.story_theme[0] ? req.story_theme : NULL); + } + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_EXIT_INQUIRY) + { + printf("LN_HTTP_SERVICE_CMD_STORY_EXIT_INQUIRY:获取退出哄睡询问\n"); + ln_story_exit_inquiry_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_FINISH) + { + printf("LN_HTTP_SERVICE_CMD_STORY_FINISH:确认结束哄睡\n"); + ln_story_finish_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_CHARACTER) + { + printf("LN_HTTP_SERVICE_CMD_GET_CHARACTER:获取设备角色信息\n"); + ln_device_get_character_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_USER_ID) + { + printf("LN_HTTP_SERVICE_CMD_GET_USER_ID:获取设备绑定用户ID\n"); + ln_device_get_user_id_http(uapi_ln_get_device_id(), uapi_ln_get_device_token()); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_GET_TASK) + { + printf("LN_HTTP_SERVICE_CMD_OTA_GET_TASK:获取OTA升级任务\n"); + ln_ota_get_task_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), uapi_ln_get_device_version()); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD) + { + printf("LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD:下载OTA升级包\n"); + ln_ota_download_flow_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), uapi_ln_get_device_version()); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY) + { + printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY:播放音频\n"); + #ifdef BOARD_N9 + if (ln_story_player_simple_start("/user/leiniao/story/choose")) { - /* 一边下载到文件,一边推送到播放器队列,尝试边下边播 */ - size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd); - if (written != client_data.contentBlockLen) + printf("播放开始成功\n"); + } + #endif + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_STOP) + { + printf("LN_HTTP_SERVICE_CMD_AUDIO_STOP:停止播放音频\n"); + #ifdef BOARD_N9 + ln_story_player_simple_stop(); + #endif + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT) + { + printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT:播放下一首\n"); + #ifdef BOARD_N9 + ln_story_player_simple_handle_message(LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT, NULL, 0); + #endif + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_FILE) + { + printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY_FILE:播放指定文件\n"); + #ifdef BOARD_N9 + if (mail.data != NULL) + { + char *file_path = (char*)mail.data; + printf("Playing file: %s\n", file_path); + if (ln_story_player_simple_play_file(file_path)) { - printf("[SSE] write failed, written=%zu, expected=%d\n", - written, client_data.contentBlockLen); - fclose(fd); - HttpClientClse(&client); - HttpClientUnprepare(&client_data); - return ERRCODE_FAIL; + printf("File playback started successfully\n"); } - - /* 非阻塞入队,队列满则忽略该块 */ - (void)ln_audio_player_write((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen); - - total_written += written; + else + { + printf("Failed to start file playback\n"); + } + } + else + { + printf("Error: No file path provided\n"); } + #endif } - else + else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PAUSE) { - printf("[SSE] receive ended (code: %d)\n", recv_res); - break; + printf("LN_HTTP_SERVICE_CMD_AUDIO_PAUSE:暂停播放\n"); + #ifdef BOARD_N9 + if (ln_story_player_simple_pause()) + { + printf("Playback paused successfully\n"); + } + else + { + printf("Failed to pause playback\n"); + } + #endif } - } while (client_data.isMore); - - fclose(fd); - HttpClientUnprepare(&client_data); - HttpClientClse(&client); - - printf("[SSE] download completed, total bytes: %zu\n", total_written); - return ERRCODE_SUCC; + else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_RESUME) + { + printf("LN_HTTP_SERVICE_CMD_AUDIO_RESUME:恢复播放\n"); + #ifdef BOARD_N9 + if (ln_story_player_simple_resume()) + { + printf("Playback resumed successfully\n"); + } + else + { + printf("Failed to resume playback\n"); + } + #endif + } + if (mail.data != NULL) + { + printf("free(mail.data)\n"); + free(mail.data); + } + } } -/** - * 解析JSON数据,下载MP3并推送消息 - * @param json_data JSON数据字符串 - * @param interface_type 接口类型 - * @param segment_index 片段索引 - * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败 - */ -uint32_t ln_parse_and_process_json_data(const char *json_data, int interface_type, int segment_index) +// 接收队列 +static void ln_http_server_recv_task(void const *arg) { - if (!json_data) - { - printf("[JSON_PARSE] invalid json_data\n"); - return ERRCODE_FAIL; - } - - printf("[JSON_PARSE] parsing JSON data (interface_type=%d, segment=%d): %s\n", - interface_type, segment_index, json_data); - - // 解析JSON数据 - cJSON *root = cJSON_Parse(json_data); - if (!root) - { - printf("[JSON_PARSE] JSON parse failed: %s\n", json_data); - return ERRCODE_FAIL; - } - - // 检查是否有错误 - cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode"); - if (errorCode && !cJSON_IsNull(errorCode)) - { - printf("[JSON_PARSE] server error: %s\n", - cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown"); - cJSON_Delete(root); - return ERRCODE_FAIL; - } + errcode_t ret; - // 获取data字段 - cJSON *data = cJSON_GetObjectItem(root, "data"); - if (!data || !cJSON_IsObject(data)) - { - printf("[JSON_PARSE] no data field found\n"); - cJSON_Delete(root); - return ERRCODE_FAIL; - } + ln_http_data_mail_t mail = {0}; + uint32_t msgsize = sizeof(ln_http_data_mail_t); - // 根据接口类型获取音频URL - char *audio_url = NULL; - if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV) + while (1) { - // 语音对话接口:使用 audioUrl 字段 - cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl"); - if (audioUrl && cJSON_IsString(audioUrl)) + ret = osal_msg_queue_read_copy(g_ln_recv_queue, (void *)&mail, &msgsize, + OSAL_MSGQ_WAIT_FOREVER); + if (ret != OSAL_SUCCESS) { - audio_url = audioUrl->valuestring; + continue; } - } - else if (interface_type == LN_HTTP_RECV_STORY_CHOOSE || interface_type == LN_HTTP_RECV_STORY_RANDOM) - { - // 故事接口:使用 storyAudioUrl 字段 - cJSON *storyAudioUrl = cJSON_GetObjectItem(data, "storyAudioUrl"); - if (storyAudioUrl && cJSON_IsString(storyAudioUrl)) - { - audio_url = storyAudioUrl->valuestring; + + // 消息有效性检查 + if (!mail.data || mail.len <= 0) + { + continue; } - } - else - { - // 默认尝试 audioUrl 字段 - cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl"); - if (audioUrl && cJSON_IsString(audioUrl)) - { - audio_url = audioUrl->valuestring; + + // 分类处理消息 + const char *tag = "UNKNOWN"; + if (mail.cmd == LN_HTTP_SERVICE_CMD_SSE_RECV) { + tag = "SPEECH_CHAT"; + } else if (mail.cmd == LN_HTTP_RECV_STORY_CHOOSE) { + tag = "STORY_CHOOSE"; + } else if (mail.cmd == LN_HTTP_RECV_STORY_RANDOM) { + tag = "STORY_RANDOM"; + } else if (mail.cmd == LN_HTTP_RECV_STORY_EXIT) { + tag = "STORY_EXIT"; + } else if (mail.cmd == LN_HTTP_RECV_STORY_FINISH) { + tag = "STORY_FINISH"; + } else if (mail.cmd == LN_HTTP_RECV_DEVICE_CHARACTER) { + tag = "DEVICE_CHARACTER"; + } else if (mail.cmd == LN_HTTP_RECV_DEVICE_USER_ID) { + tag = "DEVICE_USER_ID"; + } else if (mail.cmd == LN_HTTP_RECV_OTA_TASK) { + tag = "OTA_TASK"; + } else if (mail.cmd == LN_HTTP_RECV_OTA_DOWNLOAD_MSG) { + tag = "OTA_DOWNLOAD_MSG"; + } + + printf("[%s] 数据长度: %u\n", tag, mail.len); + /* 确保可打印:追加\0 */ + char *buf = (char *)malloc(mail.len + 1); + if (buf) { + memcpy(buf, mail.data, mail.len); + buf[mail.len] = '\0'; + printf("[%s] 原始数据:%s\n", tag, buf); + /* 在收到 OTA_TASK 后,根据升级策略决定是否触发下载 */ + if (mail.cmd == LN_HTTP_RECV_OTA_TASK) { + ln_handle_ota_task_response(buf, (int)mail.len); + } + /* 在收到 OTA_DOWNLOAD_MSG 后,解析状态并回调处理(进度/完成/失败) */ + if (mail.cmd == LN_HTTP_RECV_OTA_DOWNLOAD_MSG) { + OtaDownloadMsg m = {0}; + if (parse_ota_download_msg(buf, &m) == 0) { + handle_ota_download_msg(&m); + } + } + free(buf); } } +} - // 获取textContent - cJSON *textContent = cJSON_GetObjectItem(data, "textContent"); - char *text_content = NULL; - if (textContent && cJSON_IsString(textContent)) - { - text_content = textContent->valuestring; - } - - // 获取intention - cJSON *intention = cJSON_GetObjectItem(data, "intention"); - char *intention_str = NULL; - if (intention && cJSON_IsString(intention)) +/* 创建雷鸟http发送队列 */ +static void create_ln_http_send_queue(void) +{ + if (osal_msg_queue_create("ln_http_send_queue", 24, &g_ln_send_queue, + 0, sizeof(ln_http_data_mail_t)) != ERRCODE_SUCC) { - intention_str = intention->valuestring; + printf("[ln][service] app create mail fail\n"); } +} - // 获取storyTheme(故事接口特有) - cJSON *storyTheme = cJSON_GetObjectItem(data, "storyTheme"); - char *story_theme = NULL; - if (storyTheme && cJSON_IsString(storyTheme)) +/* 创建雷鸟http接收队列 */ +static void create_ln_http_recv_queue(void) +{ + if (osal_msg_queue_create("ln_http_recv_queue", 24, &g_ln_recv_queue, + 0, sizeof(ln_http_data_mail_t)) != ERRCODE_SUCC) { - story_theme = storyTheme->valuestring; + printf("[ln][service] app create mail fail\n"); } +} - // 获取storyContent(故事接口特有) - cJSON *storyContent = cJSON_GetObjectItem(data, "storyContent"); - char *story_content = NULL; - if (storyContent && cJSON_IsString(storyContent)) +/* 通用发送接口:向 LN HTTP 发送队列投递消息 */ +void do_ln_http_server_send_data(int cmd, char *data, uint32_t len) +{ + errcode_t ret; + ln_http_data_mail_t send_data = {0}; + send_data.cmd = cmd; + if (len && data) { - story_content = storyContent->valuestring; + send_data.len = len; + send_data.data = (char *)malloc(len); + if (send_data.data == NULL) + { + printf("malloc failed\n"); + return; + } + memcpy(send_data.data, data, len); } - // 创建推送数据 - cJSON *push_data = cJSON_CreateObject(); - - // 根据接口类型添加相应字段 - if (text_content && strlen(text_content) > 0) - { - cJSON_AddStringToObject(push_data, "textContent", text_content); - } - - if (story_content && strlen(story_content) > 0) - { - cJSON_AddStringToObject(push_data, "storyContent", story_content); - } - - if (intention_str && strlen(intention_str) > 0) - { - cJSON_AddStringToObject(push_data, "intention", intention_str); - } - - if (story_theme && strlen(story_theme) > 0) - { - cJSON_AddStringToObject(push_data, "storyTheme", story_theme); - } + uint32_t send_len = sizeof(send_data); - // 推送到相应的接收线程 - char *json_string = cJSON_Print(push_data); - if (json_string) + ret = osal_msg_queue_write_copy(g_ln_send_queue, (void *)&send_data, + send_len, 0); + if (ret != OSAL_SUCCESS) { - printf("[JSON_PARSE] pushing data to interface_type=%d: %s\n", interface_type, json_string); - do_ln_http_server_recv_data(interface_type, json_string, strlen(json_string)); - free(json_string); + printf("Error ln http send failed! err=0x%x! \r\n", ret); } - cJSON_Delete(push_data); +} - // 下载音频文件 - if (audio_url && strlen(audio_url) > 0) +/* 通用接收接口:向 LN HTTP 接收队列投递消息 */ +void do_ln_http_server_recv_data(int cmd, char *data, uint32_t len) +{ + errcode_t ret; + ln_http_data_mail_t recv_data = {0}; + recv_data.cmd = cmd; + if (len && data) { - char save_dir[256]; - char filename[128]; - - // 根据接口类型确定保存目录和文件名 - switch (interface_type) - { - case LN_HTTP_SERVICE_CMD_SSE_RECV: - snprintf(save_dir, sizeof(save_dir), "%s/speech", LN_DATA_PATH); - snprintf(filename, sizeof(filename), "%d.mp3", segment_index); - break; - case LN_HTTP_RECV_STORY_CHOOSE: - snprintf(save_dir, sizeof(save_dir), "%s/story/choose", LN_DATA_PATH); - snprintf(filename, sizeof(filename), "%d.mp3", segment_index); - break; - case LN_HTTP_RECV_STORY_RANDOM: - snprintf(save_dir, sizeof(save_dir), "%s/story/random", LN_DATA_PATH); - snprintf(filename, sizeof(filename), "%d.mp3", segment_index); - break; - default: - snprintf(save_dir, sizeof(save_dir), "%s", LN_DATA_PATH); - snprintf(filename, sizeof(filename), "%d.mp3", segment_index); - break; - } - - printf("[JSON_PARSE] found audio URL (interface_type=%d): %s\n", interface_type, audio_url); - printf("[JSON_PARSE] downloading audio to: %s/%s\n", save_dir, filename); - - uint32_t download_result = ln_download_mp3_file_advanced(audio_url, save_dir, filename); - if (download_result == ERRCODE_SUCC) - { - printf("[JSON_PARSE] audio downloaded successfully: %s/%s\n", save_dir, filename); - } - else + recv_data.len = len; + recv_data.data = (char *)malloc(len); + if (recv_data.data == NULL) { - printf("[JSON_PARSE] audio download failed\n"); + printf("malloc failed\n"); + return; } + memcpy(recv_data.data, data, len); } - else + + uint32_t send_len = sizeof(recv_data); + + ret = osal_msg_queue_write_copy(g_ln_recv_queue, (void *)&recv_data, + send_len, 0); + if (ret != OSAL_SUCCESS) { - printf("[JSON_PARSE] no audio URL found for interface_type=%d, skipping download\n", interface_type); + printf("Error ln http recv send failed! err=0x%x! \r\n", ret); + if (recv_data.data) free(recv_data.data); } - - cJSON_Delete(root); - return ERRCODE_SUCC; } - -/** - * 从文件中解析data数据,下载MP3并推送消息 - * @param file_path 文件路径 - * @param interface_type 接口类型 - * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败 - */ -uint32_t ln_parse_file_and_process_data(const char *file_path, int interface_type) +// 雷鸟http服务初始化 +errcode_t uapi_ln_http_server_init(void) { - if (!file_path) + printf("uapi_ln_http_server_init !\r\n"); + + ln_send_taskcfg.create_queue_handle = create_ln_http_send_queue; + ln_send_taskcfg.attr.name = "ln_http_server_send_task"; + ln_send_taskcfg.attr.priority = osPriorityNormal; + ln_send_taskcfg.attr.stack_size = LN_HTTP_BOARD_TASK_SIZE; + ln_send_taskcfg.func = ln_http_server_send_task; + ln_send_taskcfg.use_mem = USE_EXTEND_MEM; + + errcode_t ret = uapi_create_osThread_custom(&ln_send_taskcfg); + if (ret != ERRCODE_SUCC) { - printf("[FILE_PARSE] invalid file path\n"); + printf("create ln_send_service failed %d!\r\n", ret); return ERRCODE_FAIL; } - printf("[FILE_PARSE] processing file: %s (interface_type=%d)\n", file_path, interface_type); + ln_recv_taskcfg.create_queue_handle = create_ln_http_recv_queue; + ln_recv_taskcfg.attr.name = "ln_http_server_recv_task"; + ln_recv_taskcfg.attr.priority = osPriorityNormal; + ln_recv_taskcfg.attr.stack_size = LN_HTTP_BOARD_TASK_SIZE; + ln_recv_taskcfg.func = ln_http_server_recv_task; + ln_recv_taskcfg.use_mem = USE_EXTEND_MEM; - FILE *fp = fopen(file_path, "r"); - if (!fp) + ret = uapi_create_osThread_custom(&ln_recv_taskcfg); + if (ret != ERRCODE_SUCC) { - printf("[FILE_PARSE] failed to open file: %s\n", file_path); + printf("create gnss_recv_service failed %d!\r\n", ret); return ERRCODE_FAIL; } - char line[2048]; - int line_count = 0; - int success_count = 0; - int error_count = 0; - - while (fgets(line, sizeof(line), fp)) + /* 初始化音频播放器(流式输出) */ + if (ln_audio_player_init() != ERRCODE_SUCC) { - line_count++; - - // 去除行尾的换行符 - size_t len = strlen(line); - if (len > 0 && line[len - 1] == '\n') - { - line[len - 1] = '\0'; - len--; - } - if (len > 0 && line[len - 1] == '\r') - { - line[len - 1] = '\0'; - len--; - } - - // 跳过空行 - if (len == 0) - { - continue; - } - - // 检查是否是SSE数据格式 (data: {...}) - if (strncmp(line, "data:", 5) == 0) - { - char *json_start = line + 5; - // 跳过可能的空格 - while (*json_start == ' ' || *json_start == '\t') - { - json_start++; - } - - printf("[FILE_PARSE] line %d: processing JSON: %s\n", line_count, json_start); - - uint32_t result = ln_parse_and_process_json_data(json_start, interface_type, line_count); - if (result == ERRCODE_SUCC) - { - success_count++; - } - else - { - error_count++; - } - } - else - { - printf("[FILE_PARSE] line %d: invalid format (not SSE data): %s\n", line_count, line); - error_count++; - } + printf("[LN_AUDIO] init failed in http server init\n"); + /* 不中断HTTP服务,按需可返回失败 */ } - fclose(fp); - - printf("[FILE_PARSE] processing completed: total lines=%d, success=%d, errors=%d\n", - line_count, success_count, error_count); - - return (error_count == 0) ? ERRCODE_SUCC : ERRCODE_FAIL; + return ERRCODE_SUCC; } - +/* ============================ 队列相关代码 End ============================ */ \ No newline at end of file diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h index 29fe6072a..0c1db7c68 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h @@ -13,6 +13,9 @@ extern "C" #include #include "wearable_log.h" +// 产品名称:Amby Box +// 产品型号:AB101 +// 认证主体:深圳文阅数字科技有限公司 typedef struct { int cmd; @@ -175,7 +178,10 @@ extern char g_ln_last_package_md5[65]; extern int g_ln_last_package_size; /* ============================== 公共工具函数(供拆分后的模块复用) ============================== */ + HTTPC_RESULT ln_http_prepare_auto(HttpClientData *clientData, int header_size, int resp_size); +uint32_t ln_parse_file_and_process_data(const char *file_path, int interface_type); + /* ============================== 各接口函数声明 ============================== */ uint32_t ln_get_device_token_http(const char *device_id, const char *device_iccid, @@ -219,9 +225,7 @@ int ln_ws_start(void); int ln_ws_send_text(const char *text); int ln_ws_stop(void); - /* 文件解析和数据处理函数 */ -uint32_t ln_parse_file_and_process_data(const char *file_path, int interface_type); -uint32_t ln_parse_and_process_json_data(const char *json_data, int interface_type, int segment_index); + #ifdef __cplusplus } #endif -- 2.17.1