toy-Kapi_Rtc/components/common/src/volc_device_manager.c
Rdzleo aeae073e4f chore(git): 把 components/common/ 纳入 git 跟踪
components/common/ 是项目自己写的代码 (火山 RTC SDK 的 wrapper + HTTP 客户端 + JSON
工具 + 设备管理), 历史上被 .gitignore 的 components/ 规则误排除。共 15 个文件 2750
行项目代码长期未被 git 跟踪, 修改易丢失, 不利于多设备开发和回溯。

主要变动:

1. .gitignore
   - 改 components/ → /components/* (顶层 children 而非目录本身)
   - 加 !/components/common/ 例外, 让项目自己代码进入跟踪
   - 加 esp-spot/**/components/ 显式 ignore 子项目里的 components/ 保持原行为

2. components/common/ 首次入 git (~2750 行)
   - inc/volc_rtc.h, src/volc_rtc.c — 火山 RTC SDK 的封装层
   - inc/volc_http.h, src/volc_http.c — HTTP 客户端
   - inc/util/volc_json.h, src/volc_json.c — JSON 工具
   - inc/base/volc_device_manager.h, src/volc_device_manager.c — RTC 设备凭证管理
   - inc/util/volc_log.h — 日志宏
   - inc/util/volc_list.h — 链表工具
   - inc/volc_conv_ai.h — 会话 AI 接口定义
   - inc/volc_platform.h, src/volc_platform.c — 平台抽象
   - inc/base/volc_base.h — 基础类型

未跟踪的兄弟目录 (保持 ignore):
   - components/78__esp-opus-encoder/ (IDF managed component)
   - components/volc_engine_rtc_lite/ (火山 RTC SDK 二进制库)
   - components/zlib/ (第三方库)

后续 fix(rtc) NULL guard 等 components/common/ 的改动将作为独立 commit。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:50:52 +08:00

729 lines
25 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (2025) Beijing Volcano Engine Technology Ltd.
// SPDX-License-Identifier: Apache-2.0
#include "base/volc_device_manager.h"
#include "util/volc_log.h"
#include "volc_platform.h"
#include "volc_http.h"
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cJSON.h>
// For HMAC-SHA256 signature generation
#include <mbedtls/md.h>
#include <mbedtls/base64.h>
#include <mbedtls/aes.h>
// AES解密辅助函数
static char* volc_aes_decode_internal(const char* secret, const char* input, const bool partial_secret) {
size_t decoded_len = 0;
int key_bits = 0;
char* key = NULL;
unsigned char iv[16] = {0}; // 使用全零IV与官方项目保持一致
unsigned char* decoded_payload = NULL;
unsigned char* output = NULL;
if (input == NULL || strlen(input) == 0) {
LOGE("Input is NULL or empty");
return NULL;
}
// 计算Base64解码后的长度与官方项目保持一致
int padding = 0;
int input_len = strlen(input);
if (input_len >= 2 && input[input_len - 1] == '=' && input[input_len - 2] == '=') {
padding = 2;
} else if (input[input_len - 1] == '=') {
padding = 1;
}
decoded_len = (input_len * 3) / 4 - padding;
// 分配内存用于存储解码后的payload
decoded_payload = (unsigned char*)hal_calloc(decoded_len + 1, 1);
if (decoded_payload == NULL) {
LOGE("Failed to allocate memory for decoded payload");
return NULL;
}
// 执行Base64解码与官方项目保持一致的错误处理
size_t actual_len = 0;
int ret = mbedtls_base64_decode(decoded_payload, decoded_len + 1, &actual_len,
(const unsigned char*)input, input_len);
if (ret != 0) {
LOGW("Base64 decode failed with error: %d, but continuing", ret);
// 即使解码失败,也继续执行,与官方项目保持一致
} else {
decoded_len = actual_len;
}
// 准备AES密钥和IV与官方项目保持一致
if (partial_secret) {
// 使用128位密钥
key = (char*)hal_calloc(16, 1);
if (key == NULL) {
LOGE("Failed to allocate memory for key");
hal_free(decoded_payload);
return NULL;
}
memcpy(key, secret, 16);
key_bits = 128;
} else {
// 使用192位密钥
size_t secret_len = strlen(secret);
if (secret_len < 24) {
LOGE("Secret length is less than 24, secret: %s", secret);
hal_free(decoded_payload);
return NULL;
}
key = (char*)hal_calloc(24, 1);
if (key == NULL) {
LOGE("Failed to allocate memory for key");
hal_free(decoded_payload);
return NULL;
}
memcpy(key, secret, 24);
key_bits = 192;
}
// 分配内存用于存储解密后的结果(与官方项目保持一致的内存分配)
output = (unsigned char*)hal_calloc(decoded_len + 16, 1);
if (output == NULL) {
LOGE("Failed to allocate memory for output");
hal_free(key);
hal_free(decoded_payload);
return NULL;
}
// 使用密钥的前16字节作为IV与官方项目保持一致
memcpy(iv, secret, 16);
// 执行AES解密 - 使用CBC模式与官方项目保持一致
mbedtls_aes_context aes_ctx;
mbedtls_aes_init(&aes_ctx);
mbedtls_aes_setkey_dec(&aes_ctx, (const unsigned char*)key, key_bits);
// 使用CBC模式解密
ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, decoded_len, iv, decoded_payload, output);
mbedtls_aes_free(&aes_ctx);
// 清理临时变量
hal_free(key);
hal_free(decoded_payload);
if (ret != 0) {
LOGE("Failed to decrypt payload: %d", ret);
hal_free(output);
return NULL;
}
// 去除解密后可能存在的空白字符(与官方项目保持一致)
int len = strlen((const char*)output);
while (len > 0 && (output[len-1] < 32 || output[len-1] == 0x20)) {
--len;
}
output[len] = '\0';
return (char*)output;
}
// 定义常量
#define VOLC_IOT_HOST "https://iot-cn-shanghai.iot.volces.com"
#define VOLC_DYNAMIC_REGISTER_PATH "/2021-12-14/DynamicRegister"
#define VOLC_API_VERSION "2021-12-14"
#define VOLC_API_VERSION_QUERY_PARAM "Version=2021-12-14"
#define VOLC_API_ACTION_DYNAMIC_REGISTER "Action=DynamicRegister"
#define VOLC_GET_RTC_CONFIG_PATH "/2021-12-14/GetRTCConfig"
#define VOLC_API_ACTION_GET_RTC_CONFIG "Action=GetRTCConfig"
// 错误码映射函数(暂时简化实现)
int volc_inter_err_2_ext_err(int code) {
switch (code) {
case ERROR_LICENSE_EXHAUSTED:
return -1; // VOLC_ERR_LICENSE_EXHAUSTED
case ERROR_LICENSE_EXPIRED:
return -2; // VOLC_ERR_LICENSE_EXPIRED
default:
return -3; // VOLC_ERR_FAILED
}
}
// 生成签名函数 - 使用HMAC-SHA256算法
char* volc_generate_signature(const char* secret_key, const char* product_key, const char* device_name, int rnd, uint64_t timestamp, int auth_type) {
if (!secret_key || !product_key || !device_name) {
LOGE("Invalid parameters for signature generation");
return NULL;
}
// 构造待签名字符串(与官方项目格式一致,确保参数顺序正确)
char sign_str[512] = {0};
int sign_str_len = snprintf(sign_str, sizeof(sign_str),
"auth_type=%d&device_name=%s&random_num=%d&product_key=%s&timestamp=%" PRIu64,
auth_type, device_name, rnd, product_key, timestamp);
if (sign_str_len <= 0 || sign_str_len >= sizeof(sign_str)) {
LOGE("Failed to construct sign string");
return NULL;
}
// 计算HMAC-SHA256哈希值
unsigned char hmac_result[32] = {0};
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
int ret = mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
if (ret != 0) {
LOGE("Failed to setup MD context: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
ret = mbedtls_md_hmac_starts(&ctx, (const unsigned char*)secret_key, strlen(secret_key));
if (ret != 0) {
LOGE("Failed to start HMAC: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
ret = mbedtls_md_hmac_update(&ctx, (const unsigned char*)sign_str, sign_str_len);
if (ret != 0) {
LOGE("Failed to update HMAC: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
ret = mbedtls_md_hmac_finish(&ctx, hmac_result);
if (ret != 0) {
LOGE("Failed to finish HMAC: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
mbedtls_md_free(&ctx);
// 将HMAC结果进行Base64编码
// 使用更可靠的Base64长度计算方式
size_t src_len = sizeof(hmac_result);
size_t base64_len = ((src_len + 2) / 3) * 4 + 1; // +1 for null terminator
char* signature = (char*)hal_malloc(base64_len);
if (!signature) {
LOGE("Failed to allocate signature buffer");
return NULL;
}
size_t olen = 0;
int ret_b64 = mbedtls_base64_encode((unsigned char*)signature, base64_len, &olen, hmac_result, src_len);
if (ret_b64 != 0) {
LOGE("Failed to encode Base64: %d", ret_b64);
hal_free(signature);
return NULL;
}
signature[olen] = '\0';
return signature;
}
// 生成WebSocket签名函数与官方项目实现一致
char* volc_generate_signature_ws(const char* secret_key, const char* product_key, const char* device_name, const char* instance_id, int rnd, uint64_t timestamp, int auth_type) {
if (!secret_key || !product_key || !device_name || !instance_id) {
LOGE("Invalid parameters for WebSocket signature generation");
return NULL;
}
// 构造待签名字符串(与官方项目格式一致)
char sign_str[512] = {0};
int sign_str_len = snprintf(sign_str, sizeof(sign_str),
"auth_type=%d&device_name=%s&random_num=%d&product_key=%s&timestamp=%" PRIu64 "&instance_id=%s",
auth_type, device_name, rnd, product_key, timestamp, instance_id);
if (sign_str_len <= 0 || sign_str_len >= sizeof(sign_str)) {
LOGE("Failed to construct WebSocket sign string");
return NULL;
}
// 计算HMAC-SHA256哈希值
unsigned char hmac_result[32] = {0};
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
int ret = mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
if (ret != 0) {
LOGE("Failed to setup MD context for WebSocket signature: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
ret = mbedtls_md_hmac_starts(&ctx, (const unsigned char*)secret_key, strlen(secret_key));
if (ret != 0) {
LOGE("Failed to start HMAC for WebSocket signature: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
ret = mbedtls_md_hmac_update(&ctx, (const unsigned char*)sign_str, sign_str_len);
if (ret != 0) {
LOGE("Failed to update HMAC for WebSocket signature: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
ret = mbedtls_md_hmac_finish(&ctx, hmac_result);
if (ret != 0) {
LOGE("Failed to finish HMAC for WebSocket signature: %d", ret);
mbedtls_md_free(&ctx);
return NULL;
}
mbedtls_md_free(&ctx);
// 将HMAC结果进行Base64编码
size_t src_len = sizeof(hmac_result);
size_t base64_len = ((src_len + 2) / 3) * 4 + 1; // +1 for null terminator
char* signature = (char*)hal_malloc(base64_len);
if (!signature) {
LOGE("Failed to allocate WebSocket signature buffer");
return NULL;
}
size_t olen = 0;
int ret_b64 = mbedtls_base64_encode((unsigned char*)signature, base64_len, &olen, hmac_result, src_len);
if (ret_b64 != 0) {
LOGE("Failed to encode WebSocket signature Base64: %d", ret_b64);
hal_free(signature);
return NULL;
}
signature[olen] = '\0';
return signature;
}
// 实现设备注册函数
int volc_device_register(volc_iot_info_t* info, char** output) {
if (!info || !output || !info->product_key || !info->device_name || !info->product_secret) {
LOGE("Invalid input parameters: info=%p, output=%p, product_key=%p, device_name=%p, product_secret=%p",
info, output, info->product_key, info->device_name, info->product_secret);
return -1;
}
int ret = 0;
uint64_t current_time = hal_get_time_ms();
int32_t random_num = (int32_t)current_time;
char url[256] = {0};
char* signature = NULL;
char* response = NULL;
cJSON* root = NULL;
cJSON* rtc_app_id = NULL;
char* device_secret_str = NULL; // 使用正确的变量名,与解密后的变量保持一致
char* json_str = NULL; // 初始化json_str变量避免未初始化警告
cJSON* request_root = NULL;
// 生成签名使用正确的auth_type值1与官方项目保持一致
signature = volc_generate_signature(info->product_secret, info->product_key, info->device_name, random_num, current_time, 1);
if (!signature) {
LOGE("Failed to generate signature");
return -1;
}
// 构造URL
snprintf(url, sizeof(url), "%s%s?%s&%s", VOLC_IOT_HOST, VOLC_DYNAMIC_REGISTER_PATH,
VOLC_API_ACTION_DYNAMIC_REGISTER, VOLC_API_VERSION_QUERY_PARAM);
LOGI("Device register URL: %s", url);
// 使用cJSON构造请求体与官方实现保持一致避免字符串长度限制问题
request_root = cJSON_CreateObject();
if (!request_root) {
LOGE("Failed to create JSON root object for request");
ret = -1;
goto err_out_label;
}
// 总是添加InstanceID字段
cJSON_AddStringToObject(request_root, "InstanceID", info->instance_id);// 必须添加 实例ID字段
cJSON_AddStringToObject(request_root, "product_key", info->product_key);// 必须添加 产品密钥字段
cJSON_AddStringToObject(request_root, "device_name", info->device_name);// 必须添加 设备名称字段
// cJSON_AddStringToObject(request_root, "bot_id", info->bot_id);
cJSON_AddNumberToObject(request_root, "random_num", random_num);// 必须添加 随机数字段
cJSON_AddNumberToObject(request_root, "timestamp", (double)current_time); // 与官方实现保持一致使用double类型
cJSON_AddNumberToObject(request_root, "auth_type", 1);// 必须添加 认证类型字段
cJSON_AddStringToObject(request_root, "signature", signature);// 必须添加 签名字段
json_str = cJSON_PrintUnformatted(request_root);// 必须添加 JSON字符串字段
if (!json_str) {
LOGE("Failed to print JSON request body");
cJSON_Delete(request_root);
ret = -1;
goto err_out_label;
}
// 调用HTTP POST请求
response = volc_http_post(url, json_str, strlen(json_str));
if (!response) {
LOGE("Failed to send HTTP POST request for device registration");
cJSON_Delete(request_root);
hal_free(json_str);
ret = -1;
goto err_out_label;
}
LOGI("Device register response received: %s", response);
// 解析JSON响应
root = cJSON_Parse(response);
if (!root) {
LOGE("Failed to parse device registration response");
ret = -1;
goto err_out_label;
}
// 检查是否有错误信息(参考官方实现的检查方式)
cJSON* response_metadata = cJSON_GetObjectItem(root, "ResponseMetadata");
if (response_metadata && response_metadata->type == cJSON_Object) {
cJSON* error = cJSON_GetObjectItem(response_metadata, "Error");
if (error && error->type == cJSON_Object) {
cJSON* code_n = cJSON_GetObjectItem(error, "CodeN");
if (code_n && code_n->type == cJSON_Number) {
// 检查是否是RTC许可证绑定失败错误
int error_code = (int)code_n->valuedouble;
cJSON* message = cJSON_GetObjectItem(error, "Message");
LOGE("Device registration failed, error code: %d", error_code);
if (message && message->type == cJSON_String && message->valuestring) {
LOGE("Error message: %s", message->valuestring);
}
// 如果是RTC许可证绑定失败记录更详细的信息
if (error_code == 12000130) {
LOGE("Device bind RTC license failed, please check device configuration");
}
ret = -1;
goto err_out_label;
}
}
}
// 检查响应格式兼容官方项目的ResponseMetadata/Result格式
cJSON* result = cJSON_GetObjectItem(root, "Result");
if (!result || result->type != cJSON_Object) {
LOGE("Device registration response missing or invalid 'Result' field");
ret = -1;
goto err_out_label;
}
// 提取rtc_app_id安全检查
rtc_app_id = cJSON_GetObjectItem(result, "RTCAppID");
if (!rtc_app_id || rtc_app_id->type != cJSON_String || !rtc_app_id->valuestring || strlen(rtc_app_id->valuestring) == 0) {
LOGE("Device registration response missing or invalid 'RTCAppID' field");
ret = -1;
goto err_out_label;
}
// 从payload中解析device_secret安全检查
cJSON* payload = cJSON_GetObjectItem(result, "payload");
if (!payload || payload->type != cJSON_String || !payload->valuestring || strlen(payload->valuestring) == 0) {
LOGE("Device registration response missing or invalid 'payload' field");
ret = -1;
goto err_out_label;
}
// 使用AES解密payload获取device_secret
device_secret_str = volc_aes_decode_internal(info->product_secret, payload->valuestring, true);
if (!device_secret_str) {
LOGE("Failed to decode device secret from payload");
ret = -1;
goto err_out_label;
}
// 验证解密结果是否有效
if (strlen(device_secret_str) == 0) {
LOGE("Decrypted device secret is empty");
hal_free(device_secret_str);
device_secret_str = NULL;
ret = -1;
goto err_out_label;
}
LOGI("Decoded device secret: %s", device_secret_str);
// 存储device_secret到iot_info结构体中
info->device_secret = strdup(device_secret_str);
if (!info->device_secret) {
LOGE("Failed to allocate memory for device secret");
hal_free(device_secret_str);
ret = -1;
goto err_out_label;
}
// 返回device_secret
if (*output) {
hal_free(*output);
*output = NULL;
}
// 使用解密后的device_secret_str赋值给output
*output = strdup(device_secret_str);
if (!*output) {
LOGE("Failed to allocate memory for device secret");
hal_free(device_secret_str);
ret = -1;
goto err_out_label;
}
// 释放临时内存
hal_free(device_secret_str);
device_secret_str = NULL;
// 保存rtc_app_id
if (info->rtc_app_id) {
hal_free(info->rtc_app_id);
info->rtc_app_id = NULL;
}
info->rtc_app_id = strdup(rtc_app_id->valuestring);
if (!info->rtc_app_id) {
LOGE("Failed to allocate memory for rtc_app_id");
ret = -1;
goto err_out_label;
}
LOGI("Device registration successful: rtc_app_id=%s", info->rtc_app_id);
err_out_label:
// 清理资源
if (root) {
cJSON_Delete(root);
}
if (request_root) {
cJSON_Delete(request_root);
}
if (json_str) {
hal_free(json_str);
}
if (response) {
hal_free(response);
}
if (signature) {
hal_free(signature);
}
if (device_secret_str) {
hal_free(device_secret_str);
}
return ret;
}
// 实现RTC配置获取函数 extra_params 用于传递额外的AgentConfig配置参数
int volc_get_rtc_config(volc_iot_info_t* info, int audio_codec, const char* bot_id, const char* task_id, const char* extra_params, volc_room_info_t* room_info) {
if (!info || !room_info || !bot_id || !task_id || !info->product_key || !info->device_name || !info->device_secret) {
LOGE("Invalid input parameters: info=%p, room_info=%p, bot_id=%p, task_id=%p, product_key=%p, device_name=%p, device_secret=%p",
info, room_info, bot_id, task_id, info->product_key, info->device_name, info->device_secret);
return -1;
}
int ret = 0;
uint64_t current_time = hal_get_time_ms();
int32_t random_num = (int32_t)current_time;
char url[256] = {0};
char* signature = NULL;
char* response = NULL;
cJSON* root = NULL;
cJSON* channel_name = NULL;
cJSON* uid = NULL;
cJSON* token = NULL;
cJSON* request_root = NULL;
char* json_str = NULL;
// 生成签名使用auth_type=0与官方代码一致
signature = volc_generate_signature(info->device_secret, info->product_key, info->device_name, random_num, current_time, 0);
if (!signature) {
LOGE("Failed to generate signature");
return -1;
}
// 构造URL
snprintf(url, sizeof(url), "%s%s?%s&%s", VOLC_IOT_HOST, VOLC_GET_RTC_CONFIG_PATH,
VOLC_API_ACTION_GET_RTC_CONFIG, VOLC_API_VERSION_QUERY_PARAM);
// 使用cJSON构造JSON请求体与官方代码保持一致
request_root = cJSON_CreateObject();
cJSON_AddStringToObject(request_root, "InstanceID", info->instance_id);
cJSON_AddStringToObject(request_root, "product_key", info->product_key);
cJSON_AddStringToObject(request_root, "device_name", info->device_name);
cJSON_AddNumberToObject(request_root, "random_num", random_num);
cJSON_AddNumberToObject(request_root, "timestamp", (double)current_time);
cJSON_AddStringToObject(request_root, "signature", signature);
cJSON_AddStringToObject(request_root, "bot_id", bot_id);
cJSON_AddNumberToObject(request_root, "audio_codec", audio_codec);
cJSON_AddStringToObject(request_root, "task_id", task_id);
// 如果有额外参数如AgentConfig解析并合并到请求体中
if (extra_params && strlen(extra_params) > 0) {
cJSON* params_json = cJSON_Parse(extra_params);
if (params_json) {
// 如果是对象遍历所有字段并添加到request_root
if (cJSON_IsObject(params_json)) {
cJSON* child = params_json->child;
while (child) {
cJSON_AddItemToObject(request_root, child->string, cJSON_Duplicate(child, 1));
child = child->next;
}
} else {
// 如果不是对象不太可能尝试直接添加为AgentConfig备选方案
LOGW("extra_params is not a JSON object, ignoring");
}
cJSON_Delete(params_json);
} else {
LOGW("Failed to parse extra_params JSON");
}
}
json_str = cJSON_PrintUnformatted(request_root);
LOGI("Get RTC config URL: %s", url);
LOGI("RTC config request body: %s", json_str);
// 调用HTTP POST请求
response = volc_http_post(url, json_str, strlen(json_str));
if (!response) {
LOGE("Failed to send HTTP POST request for RTC config");
ret = -1;
goto err_out_label;
}
LOGI("Get RTC config response received");
LOGI("RTC config response content: %s", response);
// 解析JSON响应
root = cJSON_Parse(response);
if (!root) {
LOGE("Failed to parse RTC config response: %s", response);
ret = -1;
goto err_out_label;
}
// 检查响应格式兼容官方项目的ResponseMetadata/Result格式
cJSON* result = cJSON_GetObjectItem(root, "Result");
if (!result || result->type != cJSON_Object) {
LOGE("RTC config response missing or invalid 'Result' field");
ret = -1;
goto err_out_label;
}
// 提取RTC配置信息与官方代码保持一致的字段名
channel_name = cJSON_GetObjectItem(result, "RoomID");
if (!channel_name || channel_name->type != cJSON_String || !channel_name->valuestring) {
LOGE("RTC config response missing or invalid 'RoomID' field");
ret = -1;
goto err_out_label;
}
uid = cJSON_GetObjectItem(result, "UserID");
if (!uid || uid->type != cJSON_String || !uid->valuestring) {
LOGE("RTC config response missing or invalid 'UserID' field");
ret = -1;
goto err_out_label;
}
token = cJSON_GetObjectItem(result, "Token");
if (!token || token->type != cJSON_String || !token->valuestring) {
LOGE("RTC config response missing or invalid 'Token' field");
ret = -1;
goto err_out_label;
}
// 提取TaskID与官方代码保持一致
cJSON* task_id_json = cJSON_GetObjectItem(result, "TaskID");
if (!task_id_json || task_id_json->type != cJSON_String || !task_id_json->valuestring) {
LOGE("RTC config response missing or invalid 'TaskID' field");
ret = -1;
goto err_out_label;
}
// 保存RTC配置先释放旧的内存
char* new_channel_name = strdup(channel_name->valuestring);
char* new_uid = strdup(uid->valuestring);
char* new_token = strdup(token->valuestring);
char* new_task_id = strdup(task_id_json->valuestring);
// 检查内存分配是否成功
if (!new_channel_name || !new_uid || !new_token || !new_task_id) {
LOGE("Failed to allocate memory for RTC config");
ret = -1;
// 清理已分配的内存
if (new_channel_name) hal_free(new_channel_name);
if (new_uid) hal_free(new_uid);
if (new_token) hal_free(new_token);
if (new_task_id) hal_free(new_task_id);
goto err_out_label;
}
// 释放旧的内存并设置新的指针
if (room_info->rtc_opt.p_channel_name) {
hal_free(room_info->rtc_opt.p_channel_name);
}
if (room_info->rtc_opt.p_uid) {
hal_free(room_info->rtc_opt.p_uid);
}
if (room_info->rtc_opt.p_token) {
hal_free(room_info->rtc_opt.p_token);
}
if (room_info->task_id) {
hal_free(room_info->task_id);
}
// 保存RTC配置
room_info->rtc_opt.p_channel_name = new_channel_name;
room_info->rtc_opt.p_uid = new_uid;
room_info->rtc_opt.p_token = new_token;
room_info->task_id = new_task_id;
// 检查是否所有分配都成功
if (!room_info->rtc_opt.p_channel_name || !room_info->rtc_opt.p_uid ||
!room_info->rtc_opt.p_token || !room_info->task_id) {
LOGE("Failed to allocate memory for RTC config");
ret = -1;
goto err_out_label;
}
LOGI("Retrieved RTC config: channel_name=%s, uid=%s, task_id=%s",
room_info->rtc_opt.p_channel_name, room_info->rtc_opt.p_uid, room_info->task_id);
err_out_label:
// 清理资源
if (root) {
cJSON_Delete(root);
}
if (request_root) {
cJSON_Delete(request_root);
}
if (json_str) {
hal_free(json_str);
}
if (response) {
hal_free(response);
}
if (signature) {
hal_free(signature);
}
return ret;
}