目录
ESP-ADF esp_dispatcher组件之audio_service子模块资源管理函数详解
版本信息: v2.7-65-gcf908721
本章节分析的源码位于
/components/esp_dispatcher/audio_service.c
文件
内部数据结构
audio_service子模块内部定义了关键的结构体,用于实现音频服务管理:
/**
* @brief 音频服务实现结构体
*/
typedef struct audio_service_impl {
service_ctrl service_start; // 服务启动函数
service_ctrl service_stop; // 服务停止函数
service_ctrl service_connect; // 服务连接函数
service_ctrl service_disconnect; // 服务断开连接函数
service_ctrl service_destroy; // 服务销毁函数
service_callback callback_func; // 回调函数
void *user_cb_ctx; // 用户回调上下文
char *service_name; // 服务名称
TaskHandle_t task_handle; // 任务句柄
void *user_data; // 用户数据
} audio_service_impl_t;
与此相关的公开结构体和类型定义包括:
// 音频服务状态
typedef enum {
SERVICE_STATE_UNKNOWN, // 未知状态
SERVICE_STATE_IDLE, // 空闲状态
SERVICE_STATE_CONNECTING, // 连接中状态
SERVICE_STATE_CONNECTED, // 已连接状态
SERVICE_STATE_RUNNING, // 运行状态
SERVICE_STATE_STOPPED, // 停止状态
} service_state_t;
// 音频服务事件信息
typedef struct {
int type; // 事件类型
void *source; // 事件源
void *data; // 事件数据
int len; // 数据长度
} service_event_t;
// 服务控制函数类型
typedef esp_err_t (*service_ctrl)(audio_service_handle_t handle);
// 服务回调函数类型
typedef esp_err_t (*service_callback)(audio_service_handle_t handle, service_event_t *evt, void *ctx);
// 音频服务配置
typedef struct {
int task_stack; // >0 服务任务栈大小; =0 不创建任务
int task_prio; // 服务任务优先级(基于FreeRTOS优先级)
int task_core; // 服务任务运行的核心(0或1)
TaskFunction_t task_func; // 服务任务函数
service_ctrl service_start; // 启动函数
service_ctrl service_stop; // 停止函数
service_ctrl service_connect; // 连接函数
service_ctrl service_disconnect; // 断开连接函数
service_ctrl service_destroy; // 销毁函数
const char *service_name; // 音频服务名称
void *user_data; // 用户数据
} audio_service_config_t;
结构体关系图
下面的图表展示了这些结构体之间的关系:
这个图表展示了音频服务的核心数据结构及其关系:
audio_service_config_t
是创建音频服务时的配置结构体,包含任务参数和各种回调函数audio_service_impl_t
是音频服务的内部实现结构体,由配置创建而来- 音频服务通过状态(
service_state_t
)和事件(service_event_t
)管理其生命周期和通知机制 - 各种回调函数类型(
service_ctrl
,service_callback
)定义了服务与应用程序的交互接口
资源管理函数分析
audio_service_create
audio_service_create
函数用于创建音频服务实例,分配必要的资源。下面是其源码实现:
/**
* @brief 创建音频服务实例
*
* 该函数完成以下主要操作:
* 1. 分配音频服务实例内存
* 2. 初始化服务结构体,复制配置参数
* 3. 复制服务名称(如果提供)
* 4. 创建服务任务(如果配置了任务栈)
*
* 资源创建失败时会进行适当的清理,避免资源泄漏
*
* @param config 配置参数,包含回调函数、任务参数等信息
* @return audio_service_handle_t 成功返回服务实例句柄,失败返回NULL
*/
audio_service_handle_t audio_service_create(audio_service_config_t *config)
{
// 检查配置参数是否为NULL
AUDIO_NULL_CHECK(TAG, config, return NULL);
// 分配服务实例内存
audio_service_handle_t impl = audio_calloc(1, sizeof(audio_service_impl_t));
AUDIO_MEM_CHECK(TAG, impl, return NULL);
// 初始化服务结构体
impl->service_start = config->service_start;
impl->service_stop = config->service_stop;
impl->service_connect = config->service_connect;
impl->service_disconnect = config->service_disconnect;
impl->service_destroy = config->service_destroy;
impl->user_data = config->user_data;
// 复制服务名称(如果提供)
if (config->service_name) {
impl->service_name = audio_strdup(config->service_name);
AUDIO_MEM_CHECK(TAG, impl, goto serv_failed);
}
// 创建服务任务(如果配置了任务栈)
if (config->task_stack > 0) {
if (pdPASS != xTaskCreatePinnedToCore(config->task_func,
config->service_name,
config->task_stack,
impl,
config->task_prio,
&impl->task_handle,
config->task_core)) {
ESP_LOGE(TAG, "Create task failed on %s", __func__);
goto serv_failed;
}
}
return impl;
// 失败处理部分
serv_failed:
// 释放已创建的资源
audio_free(impl->service_name);
impl->service_name = NULL;
audio_free(impl);
impl = NULL;
return impl;
}
下面的时序图展示了 audio_service_create
函数的执行流程:
这个时序图清晰地展示了 audio_service_create
函数的执行流程,包括资源分配、结构体初始化、任务创建以及错误处理的过程。通过这个图可以直观地理解函数内部的调用关系和数据流向。
audio_service_destroy
audio_service_destroy
函数用于销毁音频服务实例,释放所有资源。下面是其源码实现:
/**
* @brief 销毁音频服务实例并释放所有资源
*
* 该函数完成以下主要操作:
* 1. 调用服务的销毁函数(如果提供)
* 2. 释放服务名称内存
* 3. 清除任务句柄
* 4. 释放服务实例内存
*
* 函数确保所有在audio_service_create中分配的资源都被正确释放
*
* @param handle 服务实例句柄
* @return esp_err_t 成功返回ESP_OK,失败返回错误码
*/
esp_err_t audio_service_destroy(audio_service_handle_t handle)
{
// 检查句柄是否有效
AUDIO_NULL_CHECK(TAG, handle, return ESP_ERR_INVALID_ARG);
// 获取服务实例
audio_service_impl_t *impl = (audio_service_impl_t *) handle;
// 调用服务的销毁函数(如果提供)
if (impl->service_destroy) {
impl->service_destroy(handle);
}
// 释放服务名称内存
audio_free(impl->service_name);
impl->service_name = NULL;
// 清除任务句柄
impl->task_handle = NULL;
// 释放服务实例内存
audio_free(impl);
impl = NULL;
return ESP_OK;
}
下面的时序图展示了 audio_service_destroy
函数的执行流程:
这个时序图清晰地展示了 audio_service_destroy
函数的执行流程,包括调用服务销毁函数和释放资源的过程。通过这个图可以直观地理解函数内部的调用关系和资源释放顺序。