#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <ctype.h>
#include "cJSON.h" // Added for JSON parsing
#include "custom_utils.h"
#include "soc_osal.h"
static ws_command_t ln_ws_parse_command_string(const char *command_str);
static int ln_ws_parse_data_message(const char *json_str, ws_data_msg_t *data_msg);
static void ln_ws_free_data_message(ws_data_msg_t *data_msg);
+static int ln_ws_save_tts_audio_setting_to_file(void);
+static int ln_ws_load_tts_audio_setting_from_file(void);
+static uint32_t ln_ws_convert_audio_format_string_to_enum(const char *format_str);
static void ln_ws_default_message_handler(const ws_data_msg_t *data_msg, ws_command_t type);
static void ln_ws_process_message_with_callback(const ws_data_msg_t *data_msg);
static int ln_ws_close_with_status(int client_fd);
// 全局音频聊天上下文
static audio_chat_context_t g_audio_chat_ctx = {0};
+// TTS音频设置结构体
+typedef struct {
+ uint32_t audio_bit_rate; // 音频比特率
+ uint32_t audio_sample_rate; // 音频采样率
+ uint32_t audio_channel; // 音频声道数
+ char audio_format[16]; // 音频格式(如 "mp3", "pcm")
+ bool valid; // 数据是否有效
+} tts_audio_setting_t;
+
+// 全局TTS音频设置
+static tts_audio_setting_t g_tts_audio_setting = {0};
+
// 音频聊天结束标志
static bool g_audio_chat_ending = false;
.sampleRate = 16000
};
+ // 从文件加载TTS音频设置
+ ln_ws_load_tts_audio_setting_from_file();
+
+ // 初始化audioParams_out,使用默认值
AIVoiceAudioParams audioParams_out = {
.audioFormat = MP3,
.channelCount = 1,
.sampleRate = 16000
};
+
+ // 如果从文件加载了有效配置,则应用配置
+ if (g_tts_audio_setting.valid) {
+ // 转换音频格式字符串为枚举值
+ audioParams_out.audioFormat = ln_ws_convert_audio_format_string_to_enum(g_tts_audio_setting.audio_format);
+
+ // 应用采样率(如果有效)
+ if (g_tts_audio_setting.audio_sample_rate > 0) {
+ audioParams_out.sampleRate = g_tts_audio_setting.audio_sample_rate;
+ }
+
+ // 应用声道数(如果有效)
+ if (g_tts_audio_setting.audio_channel > 0) {
+ audioParams_out.channelCount = g_tts_audio_setting.audio_channel;
+ }
+
+ AI_SetTTSAudioBitRate(g_tts_audio_setting.audio_bit_rate);
+
+ LN_WS_INFO("Applied TTS audio settings: format=%u, sampleRate=%u, channelCount=%u\n",
+ audioParams_out.audioFormat, audioParams_out.sampleRate, audioParams_out.channelCount);
+ } else {
+ LN_WS_DEBUG("Using default audio parameters for audioParams_out\n");
+ }
+
+
#ifdef SUPPORT_CAT1_SERVICE
cat1_api_keep_wakeup(1);
return WS_CMD_CANCEL_DOWNLOAD_EMOJI;
} else if (strcmp(command_str, "CancelDownloadEmojiAck") == 0) {
return WS_CMD_CANCEL_DOWNLOAD_EMOJI_ACK;
+ } else if (strcmp(command_str, "TTSAudioSetting") == 0) {
+ return WS_CMD_TTS_AUDIO_SETTING;
} else {
return WS_CMD_UNKNOWN;
}
data_msg->finished ? "true" : "false", data_msg->chat_id, data_msg->audio_url, data_msg->text_content, data_msg->audio_duration);
}
+ // 解析TTSAudioSetting特定字段
+ if (data_msg->command == WS_CMD_TTS_AUDIO_SETTING) {
+ cJSON *data_obj = cJSON_GetObjectItem(root, "data");
+ if (data_obj && cJSON_IsObject(data_obj)) {
+ // 清空之前的设置
+ memset(&g_tts_audio_setting, 0, sizeof(tts_audio_setting_t));
+
+ // 解析audioBitRate字段
+ cJSON *audio_bit_rate = cJSON_GetObjectItem(data_obj, "audioBitRate");
+ if (audio_bit_rate && cJSON_IsNumber(audio_bit_rate)) {
+ g_tts_audio_setting.audio_bit_rate = (uint32_t)audio_bit_rate->valuedouble;
+ } else {
+ LN_WS_WARN("Missing or invalid audioBitRate in TTSAudioSetting\n");
+ }
+
+ // 解析audioSampleRate字段
+ cJSON *audio_sample_rate = cJSON_GetObjectItem(data_obj, "audioSampleRate");
+ if (audio_sample_rate && cJSON_IsNumber(audio_sample_rate)) {
+ g_tts_audio_setting.audio_sample_rate = (uint32_t)audio_sample_rate->valuedouble;
+ } else {
+ LN_WS_WARN("Missing or invalid audioSampleRate in TTSAudioSetting\n");
+ }
+
+ // 解析audioChannel字段
+ cJSON *audio_channel = cJSON_GetObjectItem(data_obj, "audioChannel");
+ if (audio_channel && cJSON_IsNumber(audio_channel)) {
+ g_tts_audio_setting.audio_channel = (uint32_t)audio_channel->valuedouble;
+ } else {
+ LN_WS_WARN("Missing or invalid audioChannel in TTSAudioSetting\n");
+ }
+
+ // 解析audioFormat字段
+ cJSON *audio_format = cJSON_GetObjectItem(data_obj, "audioFormat");
+ if (audio_format && cJSON_IsString(audio_format) && audio_format->valuestring) {
+ strncpy(g_tts_audio_setting.audio_format, audio_format->valuestring, sizeof(g_tts_audio_setting.audio_format) - 1);
+ g_tts_audio_setting.audio_format[sizeof(g_tts_audio_setting.audio_format) - 1] = '\0';
+ } else {
+ LN_WS_WARN("Missing or invalid audioFormat in TTSAudioSetting\n");
+ }
+
+ // 标记数据有效
+ g_tts_audio_setting.valid = true;
+
+ // 保存配置到文件
+ if (ln_ws_save_tts_audio_setting_to_file() == 0) {
+ LN_WS_DEBUG("TTSAudioSetting saved to file successfully\n");
+ } else {
+ LN_WS_WARN("Failed to save TTSAudioSetting to file\n");
+ }
+ } else {
+ LN_WS_WARN("Missing or invalid data object in TTSAudioSetting\n");
+ }
+
+ LN_WS_DEBUG("TTSAudioSetting parsed: bitRate=%u, sampleRate=%u, channel=%u, format=%s\n",
+ g_tts_audio_setting.audio_bit_rate, g_tts_audio_setting.audio_sample_rate,
+ g_tts_audio_setting.audio_channel, g_tts_audio_setting.audio_format);
+ }
+
// 解析ChooseStoryResponse特定字段
if (data_msg->command == WS_CMD_CHOOSE_STORY_RESPONSE) {
cJSON *data_obj = cJSON_GetObjectItem(root, "data");
LN_WS_DEBUG("Story Audio URL: %s\n", data_msg->audio_url);
}
break;
+ case WS_CMD_TTS_AUDIO_SETTING:
+ if (data_msg) {
+ LN_WS_DEBUG("Default: Processing TTSAudioSetting message\n");
+ if (g_tts_audio_setting.valid) {
+ LN_WS_DEBUG("TTSAudioSetting details: bitRate=%u, sampleRate=%u, channel=%u, format=%s\n",
+ g_tts_audio_setting.audio_bit_rate, g_tts_audio_setting.audio_sample_rate,
+ g_tts_audio_setting.audio_channel, g_tts_audio_setting.audio_format);
+ } else {
+ LN_WS_WARN("TTSAudioSetting data is invalid\n");
+ }
+ }
+ break;
case WS_CMD_UNKNOWN:
if (data_msg) {
LN_WS_DEBUG("Default: Processing unknown command message\n");
}
return ret;
+}
+
+/**
+ * @brief 保存TTS音频设置到文件
+ * @return 0 成功,-1 失败
+ */
+static int ln_ws_save_tts_audio_setting_to_file(void)
+{
+ if (!g_tts_audio_setting.valid) {
+ LN_WS_WARN("TTS audio setting is invalid, cannot save to file\n");
+ return -1;
+ }
+
+ const char *file_path = "/user/tts_audio_setting.json";
+
+ // 创建JSON对象
+ cJSON *root = cJSON_CreateObject();
+ if (!root) {
+ LN_WS_ERROR("Failed to create JSON object for TTS audio setting\n");
+ return -1;
+ }
+
+ cJSON_AddNumberToObject(root, "audioBitRate", g_tts_audio_setting.audio_bit_rate);
+ cJSON_AddNumberToObject(root, "audioSampleRate", g_tts_audio_setting.audio_sample_rate);
+ cJSON_AddNumberToObject(root, "audioChannel", g_tts_audio_setting.audio_channel);
+ cJSON_AddStringToObject(root, "audioFormat", g_tts_audio_setting.audio_format);
+
+ // 转换为JSON字符串
+ char *json_str = cJSON_Print(root);
+ if (!json_str) {
+ LN_WS_ERROR("Failed to create JSON string for TTS audio setting\n");
+ cJSON_Delete(root);
+ return -1;
+ }
+
+ // 写入文件
+ FILE *fp = fopen(file_path, "w");
+ if (fp == NULL) {
+ LN_WS_ERROR("Failed to open file for writing: %s\n", file_path);
+ cJSON_free(json_str);
+ cJSON_Delete(root);
+ return -1;
+ }
+
+ size_t len = strlen(json_str);
+ size_t written = fwrite(json_str, 1, len, fp);
+ fclose(fp);
+
+ cJSON_free(json_str);
+ cJSON_Delete(root);
+
+ if (written != len) {
+ LN_WS_ERROR("Failed to write all data to file: %s, written: %zu, expected: %zu\n",
+ file_path, written, len);
+ return -1;
+ }
+
+ LN_WS_DEBUG("TTS audio setting saved to file: %s\n", file_path);
+ return 0;
+}
+
+/**
+ * @brief 从文件加载TTS音频设置
+ * @return 0 成功,-1 失败
+ */
+static int ln_ws_load_tts_audio_setting_from_file(void)
+{
+ const char *file_path = "/user/tts_audio_setting.json";
+
+ // 打开文件
+ FILE *fp = fopen(file_path, "r");
+ if (fp == NULL) {
+ LN_WS_DEBUG("TTS audio setting file not found: %s, using default values\n", file_path);
+ return -1;
+ }
+
+ // 获取文件大小
+ fseek(fp, 0, SEEK_END);
+ long file_size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ if (file_size <= 0 || file_size > 1024) { // 限制文件大小
+ LN_WS_WARN("Invalid file size: %ld\n", file_size);
+ fclose(fp);
+ return -1;
+ }
+
+ // 读取文件内容
+ char *buffer = (char *)malloc(file_size + 1);
+ if (!buffer) {
+ LN_WS_ERROR("Failed to allocate memory for file content\n");
+ fclose(fp);
+ return -1;
+ }
+
+ size_t read_size = fread(buffer, 1, file_size, fp);
+ fclose(fp);
+
+ if (read_size != (size_t)file_size) {
+ LN_WS_WARN("Failed to read all data from file: %s\n", file_path);
+ free(buffer);
+ return -1;
+ }
+
+ buffer[file_size] = '\0';
+
+ // 解析JSON
+ cJSON *root = cJSON_Parse(buffer);
+ free(buffer);
+
+ if (!root) {
+ const char *error_ptr = cJSON_GetErrorPtr();
+ if (error_ptr != NULL) {
+ LN_WS_ERROR("JSON parse error: %s\n", error_ptr);
+ }
+ return -1;
+ }
+
+ // 清空之前的设置
+ memset(&g_tts_audio_setting, 0, sizeof(tts_audio_setting_t));
+
+ // 解析字段
+ cJSON *audio_bit_rate = cJSON_GetObjectItem(root, "audioBitRate");
+ if (audio_bit_rate && cJSON_IsNumber(audio_bit_rate)) {
+ g_tts_audio_setting.audio_bit_rate = (uint32_t)audio_bit_rate->valuedouble;
+ }
+
+ cJSON *audio_sample_rate = cJSON_GetObjectItem(root, "audioSampleRate");
+ if (audio_sample_rate && cJSON_IsNumber(audio_sample_rate)) {
+ g_tts_audio_setting.audio_sample_rate = (uint32_t)audio_sample_rate->valuedouble;
+ }
+
+ cJSON *audio_channel = cJSON_GetObjectItem(root, "audioChannel");
+ if (audio_channel && cJSON_IsNumber(audio_channel)) {
+ g_tts_audio_setting.audio_channel = (uint32_t)audio_channel->valuedouble;
+ }
+
+ cJSON *audio_format = cJSON_GetObjectItem(root, "audioFormat");
+ if (audio_format && cJSON_IsString(audio_format) && audio_format->valuestring) {
+ strncpy(g_tts_audio_setting.audio_format, audio_format->valuestring,
+ sizeof(g_tts_audio_setting.audio_format) - 1);
+ g_tts_audio_setting.audio_format[sizeof(g_tts_audio_setting.audio_format) - 1] = '\0';
+ }
+
+ // 标记数据有效
+ g_tts_audio_setting.valid = true;
+
+ cJSON_Delete(root);
+
+ LN_WS_DEBUG("TTS audio setting loaded from file: %s\n", file_path);
+ LN_WS_DEBUG("Loaded settings: bitRate=%u, sampleRate=%u, channel=%u, format=%s\n",
+ g_tts_audio_setting.audio_bit_rate, g_tts_audio_setting.audio_sample_rate,
+ g_tts_audio_setting.audio_channel, g_tts_audio_setting.audio_format);
+
+ return 0;
+}
+
+/**
+ * @brief 将音频格式字符串转换为枚举值
+ * @param format_str 格式字符串(如 "mp3", "pcm")
+ * @return AudioCodecFormat 枚举值,如果无效则返回 MP3(默认值)
+ */
+static uint32_t ln_ws_convert_audio_format_string_to_enum(const char *format_str)
+{
+ if (!format_str) {
+ return MP3; // 默认值
+ }
+
+ // 转换为小写进行比较
+ char lower_str[16] = {0};
+ for (int i = 0; i < (int)sizeof(lower_str) - 1 && format_str[i] != '\0'; i++) {
+ lower_str[i] = (char)tolower((unsigned char)format_str[i]);
+ }
+
+ if (strcmp(lower_str, "mp3") == 0) {
+ return MP3;
+ } else if (strcmp(lower_str, "pcm") == 0) {
+ return PCM;
+ } else if (strcmp(lower_str, "aac") == 0 || strcmp(lower_str, "aac_lc") == 0) {
+ return AAC_LC;
+ } else if (strcmp(lower_str, "opus") == 0) {
+ return OPUS;
+ } else if (strcmp(lower_str, "flac") == 0) {
+ return FLAC;
+ } else {
+ LN_WS_WARN("Unknown audio format: %s, using default MP3\n", format_str);
+ return MP3; // 默认值
+ }
}
\ No newline at end of file