#endif
/* 非阻塞入队,队列满则忽略该块 */
+ //播放下载的音频
(void)ln_audio_player_write((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen);
}
* @param segment_index 片段索引
* @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
*/
+/* 辅助函数:根据接口类型生成保存目录与文件名 */
+static void ln_build_audio_save_path(int interface_type, int segment_index, int is_error,
+ char *save_dir, size_t save_dir_len,
+ char *filename, size_t filename_len)
+{
+ if (!save_dir || !filename) return;
+ if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
+ {
+ (void)snprintf(save_dir, save_dir_len, "%s/speech", LN_DATA_PATH);
+ }
+ else if (interface_type == LN_HTTP_RECV_STORY_CHOOSE)
+ {
+ (void)snprintf(save_dir, save_dir_len, "%s/story/choose", LN_DATA_PATH);
+ }
+ else if (interface_type == LN_HTTP_RECV_STORY_RANDOM)
+ {
+ (void)snprintf(save_dir, save_dir_len, "%s/story/random", LN_DATA_PATH);
+ }
+ else
+ {
+ (void)snprintf(save_dir, save_dir_len, "%s", LN_DATA_PATH);
+ }
+
+ if (is_error)
+ {
+ (void)snprintf(filename, filename_len, "%d_err.mp3", segment_index);
+ }
+ else
+ {
+ (void)snprintf(filename, filename_len, "%d.mp3", segment_index);
+ }
+}
+
+/* 辅助函数:提取音频URL */
+static const char *ln_get_audio_url_for_interface(cJSON *data, int interface_type)
+{
+ if (!data) return NULL;
+ if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
+ {
+ cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl");
+ if (audioUrl && cJSON_IsString(audioUrl)) return audioUrl->valuestring;
+ return NULL;
+ }
+ if (interface_type == LN_HTTP_RECV_STORY_CHOOSE || interface_type == LN_HTTP_RECV_STORY_RANDOM)
+ {
+ cJSON *storyAudioUrl = cJSON_GetObjectItem(data, "storyAudioUrl");
+ if (storyAudioUrl && cJSON_IsString(storyAudioUrl)) return storyAudioUrl->valuestring;
+ return NULL;
+ }
+ cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl");
+ if (audioUrl && cJSON_IsString(audioUrl)) return audioUrl->valuestring;
+ return NULL;
+}
+
+/* 辅助函数:若存在音频URL则执行下载 */
+static void ln_download_audio_if_present(const char *audio_url, int interface_type, int segment_index, int is_error)
+{
+ if (!audio_url || strlen(audio_url) == 0) return;
+ char save_dir[256];
+ char filename[128];
+ ln_build_audio_save_path(interface_type, segment_index, is_error, save_dir, sizeof(save_dir), filename, sizeof(filename));
+ printf("[JSON_PARSE] downloading audio to: %s/%s\n", save_dir, filename);
+ (void)ln_download_mp3_file_advanced(audio_url, save_dir, filename);
+}
+
+// 解析JSON数据并处理
static uint32_t ln_parse_and_process_json_data(const char *json_data, int interface_type, int segment_index)
{
if (!json_data)
{
- printf("[JSON_PARSE] invalid json_data\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] invalid json_data\n");
return ERRCODE_FAIL;
}
- printf("[JSON_PARSE] parsing JSON data (interface_type=%d, segment=%d): %s\n",
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[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);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[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;
- }
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] 失败响应,开始处理数据\n");
+ const char *err = cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown";
+ cJSON *message = cJSON_GetObjectItem(root, "message");
+ const char *msg_str = (message && cJSON_IsString(message)) ? message->valuestring : "";
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] server error: %s, message=%s\n", err, msg_str);
- // 获取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;
- }
-
- // 根据接口类型获取音频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))
+ const char *audio_url_err = NULL;
+ const char *text_content_err = NULL;
+ cJSON *data_err = cJSON_GetObjectItem(root, "data");
+ if (data_err && cJSON_IsObject(data_err))
{
- audio_url = audioUrl->valuestring;
+ cJSON *audioUrl = cJSON_GetObjectItem(data_err, "audioUrl");
+ if (audioUrl && cJSON_IsString(audioUrl)) audio_url_err = audioUrl->valuestring;
+ cJSON *textContent = cJSON_GetObjectItem(data_err, "textContent");
+ if (textContent && cJSON_IsString(textContent)) text_content_err = textContent->valuestring;
}
- }
- 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))
+
+ if (text_content_err && strlen(text_content_err) > 0)
{
- audio_url = storyAudioUrl->valuestring;
+ // 推送文本到UI
+ do_ln_http_server_recv_data(interface_type, (char *)text_content_err, (uint32_t)strlen(text_content_err));
}
- }
- else
- {
- // 默认尝试 audioUrl 字段
- cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl");
- if (audioUrl && cJSON_IsString(audioUrl))
+
+ // 下载音频,并播放
+ ln_download_audio_if_present(audio_url_err, interface_type, segment_index, 1);
+
+ if (err)
{
- audio_url = audioUrl->valuestring;
+ if (strcmp(err, "AUTH_FAILURE") == 0 || strcmp(err, "DEVICE_NOT_FOUND") == 0)
+ {
+ // 获取设备Token
+ do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN, NULL, 0);
+ }
+ else if (strcmp(err, "MODEL_NOT_FOUND") == 0 || strcmp(err, "VOICE_NOT_FOUND") == 0)
+ {
+ // 获取角色配置
+ do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_CHARACTER, NULL, 0);
+ }
}
- }
- // 获取textContent
- cJSON *textContent = cJSON_GetObjectItem(data, "textContent");
- char *text_content = NULL;
- if (textContent && cJSON_IsString(textContent))
- {
- text_content = textContent->valuestring;
+ cJSON_Delete(root);
+ return ERRCODE_FAIL;
}
- // 获取intention
- cJSON *intention = cJSON_GetObjectItem(data, "intention");
- char *intention_str = NULL;
- if (intention && cJSON_IsString(intention))
- {
- intention_str = intention->valuestring;
- }
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] 成功响应,开始处理数据\n");
- // 获取storyTheme(故事接口特有)
- cJSON *storyTheme = cJSON_GetObjectItem(data, "storyTheme");
- char *story_theme = NULL;
- if (storyTheme && cJSON_IsString(storyTheme))
+ /* -------------------------------- 获取data字段 -------------------------------- */
+ cJSON *data = cJSON_GetObjectItem(root, "data");
+ if (!data || !cJSON_IsObject(data))
{
- story_theme = storyTheme->valuestring;
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] no data field found\n");
+ cJSON_Delete(root);
+ return ERRCODE_FAIL;
}
- // 获取storyContent(故事接口特有)
- cJSON *storyContent = cJSON_GetObjectItem(data, "storyContent");
- char *story_content = NULL;
- if (storyContent && cJSON_IsString(storyContent))
- {
- story_content = storyContent->valuestring;
- }
+ // 获取音频URL
+ const char *audio_url = ln_get_audio_url_for_interface(data, interface_type);
- // 创建推送数据
- 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 *textContent = cJSON_GetObjectItem(data, "textContent");
+ if (textContent && cJSON_IsString(textContent) && strlen(textContent->valuestring) > 0)
{
- cJSON_AddStringToObject(push_data, "intention", intention_str);
+ // 推送文本到UI
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] textContent: %s\n", textContent->valuestring);
+ do_ln_http_server_recv_data(interface_type, textContent->valuestring, (uint32_t)strlen(textContent->valuestring));
}
-
- if (story_theme && strlen(story_theme) > 0)
+ else
{
- cJSON_AddStringToObject(push_data, "storyTheme", story_theme);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] no textContent found\n");
}
- // 推送到相应的接收线程
- char *json_string = cJSON_Print(push_data);
- if (json_string)
+ // 识别意图并触发相应业务
+ cJSON *intention = cJSON_GetObjectItem(data, "intention");
+ if (intention && cJSON_IsString(intention) && intention->valuestring && intention->valuestring[0])
{
- // printf("[JSON_PARSE] pushing data to interface_type=%d: %s\n", interface_type, json_string);
- // [JSON_PARSE] pushing data to interface_type=3: {
- // "textContent": "在剧中,她曾利用香料和药材来达到自己的目的,比如制作迷香等。"
- // }
- // 解析textContent中字符串发送给ui
- cJSON *textContent = cJSON_GetObjectItem(push_data, "textContent");
- if (textContent && cJSON_IsString(textContent))
- {
- // 发送开始对话标志
- set_start_conversation_flag(1);
- printf("[JSON_PARSE] textContent: %s\n", textContent->valuestring);
- do_ln_http_server_recv_data(interface_type, textContent->valuestring, strlen(textContent->valuestring));
- }
- else
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] intention: %s\n", intention->valuestring);
+ if (strcmp(intention->valuestring, "StartSleepMode") == 0)
{
- printf("[JSON_PARSE] no textContent found\n");
+ // 触发故事接口(默认随机故事,无主题)
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] intention: StartSleepMode\n");
+ ln_story_random_req_t req;
+ memset(&req, 0, sizeof(req));
+ do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_STORY_RANDOM, (char *)&req, sizeof(req));
}
- free(json_string);
}
- cJSON_Delete(push_data);
- // 下载音频文件
+ // 下载音频,并播放
if (audio_url && strlen(audio_url) > 0)
{
- 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
- {
- printf("[JSON_PARSE] audio download failed\n");
- }
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] found audio URL (interface_type=%d): %s\n", interface_type, audio_url);
+ ln_download_audio_if_present(audio_url, interface_type, segment_index, 0);
}
else
{
- printf("[JSON_PARSE] no audio URL found for interface_type=%d, skipping download\n", interface_type);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] no audio URL found for interface_type=%d, skipping download\n", interface_type);
}
cJSON_Delete(root);
{
if (!file_path)
{
- printf("[FILE_PARSE] invalid file path\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] invalid file path\n");
return ERRCODE_FAIL;
}
- printf("[FILE_PARSE] processing file: %s (interface_type=%d)\n", file_path, interface_type);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] processing file: %s (interface_type=%d)\n", file_path, interface_type);
FILE *fp = fopen(file_path, "r");
if (!fp)
{
- printf("[FILE_PARSE] failed to open file: %s\n", file_path);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] failed to open file: %s\n", file_path);
return ERRCODE_FAIL;
}
int success_count = 0;
int error_count = 0;
+ /* 向UI上报开始状态 */
+ if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
+ {
+ set_start_conversation_flag(START_CONVERSATION_FLAG_START);
+ }
+ else if (interface_type == LN_HTTP_RECV_STORY_CHOOSE || interface_type == LN_HTTP_RECV_STORY_RANDOM)
+ {
+ set_start_conversation_flag(START_CONVERSATION_FLAG_STORY_START);
+ }
+
if(g_ln_audio_download_cancel)//如果之前中断了播放,新的对话就恢复播放
{
uapi_ln_audio_download_is_cancel(0);
while (fgets(line, sizeof(line), fp))
{
if (g_ln_audio_download_cancel) {
- printf("[SSE] download canceled by user\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[SSE] download canceled by user\n");
break;
}
{
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)
}
else
{
- printf("[FILE_PARSE] line %d: invalid format (not SSE data): %s\n", line_count, line);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] line %d: invalid format (not SSE data): %s\n", line_count, line);
error_count++;
}
}
fclose(fp);
- printf("[FILE_PARSE] processing completed: total lines=%d, success=%d, errors=%d\n",
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] processing completed: total lines=%d, success=%d, errors=%d\n",
line_count, success_count, error_count);
- //语音对话结束
- set_start_conversation_flag(0);
+ /* 向UI上报结束状态 */
+ if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
+ {
+ set_start_conversation_flag(START_CONVERSATION_FLAG_END);
+ }
+ else if (interface_type == LN_HTTP_RECV_STORY_CHOOSE || interface_type == LN_HTTP_RECV_STORY_RANDOM)
+ {
+ set_start_conversation_flag(START_CONVERSATION_FLAG_STORY_END);
+ }
+
return (error_count == 0) ? ERRCODE_SUCC : ERRCODE_FAIL;
}
/* ============================ mp3下载功能 End ============================ */