ESP-ADF esp_dispatcher组件之audio_service子模块回调管理函数详解

ESP-ADF esp_dispatcher组件之audio_service子模块回调管理函数详解

版本信息: v2.7-65-gcf908721

本章节分析的源码位于 /components/esp_dispatcher/audio_service.c 文件

回调机制概述

audio_service子模块的回调管理函数负责设置和触发事件回调,是音频服务与应用程序之间通信的桥梁。回调机制允许音频服务将检测到的事件(如播放状态变化、连接状态变化等)通知给应用程序,应用程序则可以根据这些事件执行相应的逻辑。

回调机制的核心是以下事件结构和回调函数类型定义:

/**
 * @brief 音频服务事件信息
 */
typedef struct {
    int         type;       // 事件类型
    void       *source;     // 事件源
    void       *data;       // 事件数据
    int         len;        // 数据长度
} service_event_t;

/**
 * @brief 服务回调函数类型
 */
typedef esp_err_t (*service_callback)(audio_service_handle_t handle, service_event_t *evt, void *ctx);

通过这个回调机制,audio_service子模块实现了以下功能:

  1. 事件隔离:应用程序不需要直接处理底层音频事件
  2. 统一接口:不同类型的音频服务使用相同的回调机制
  3. 上下文传递:回调函数可以接收用户提供的上下文数据
  4. 灵活处理:应用程序可以根据事件类型和数据执行不同的逻辑

回调管理函数分析

audio_service_set_callback

audio_service_set_callback函数用于设置音频服务的事件回调函数。下面是其源码实现:

/**
 * @brief 设置音频服务的事件回调函数
 * 
 * 该函数为音频服务设置一个回调函数,用于接收服务产生的事件
 * 回调函数会在服务检测到事件时被调用,如播放状态变化、连接状态变化等
 * 
 * @param handle 音频服务实例句柄
 * @param cb 回调函数指针
 * @param ctx 传递给回调函数的上下文指针,可以是任意用户数据
 * @return esp_err_t 始终返回ESP_OK
 */
esp_err_t audio_service_set_callback(audio_service_handle_t handle, service_callback cb, void *ctx)
{
    // 获取服务实例
    audio_service_impl_t *impl = (audio_service_impl_t *) handle;
    
    // 设置回调函数和上下文
    impl->callback_func = cb;
    impl->user_cb_ctx = ctx;
    
    // 始终返回成功
    return ESP_OK;
}

下面的时序图展示了 audio_service_set_callback 函数的执行流程:

应用程序 audio_service_set_callback 服务实例(impl) 调用(handle, cb, ctx) 获取服务实例(impl) 设置callback_func = cb 设置user_cb_ctx = ctx 返回ESP_OK 应用程序 audio_service_set_callback 服务实例(impl)

audio_service_set_callback 函数的实现非常简单直接,它将应用程序提供的回调函数和上下文保存在服务实例中,供后续触发回调时使用。

audio_service_callback

audio_service_callback函数用于触发音频服务的事件回调。下面是其源码实现:

/**
 * @brief 触发音频服务的事件回调
 * 
 * 该函数由音频服务在检测到事件时调用,用于通知应用程序
 * 如果设置了回调函数,会调用该函数并传递事件数据
 * 
 * @param handle 音频服务实例句柄
 * @param evt 事件数据结构指针
 * @return esp_err_t 成功返回ESP_OK或回调函数的返回值,失败返回错误码
 */
esp_err_t audio_service_callback(audio_service_handle_t handle, service_event_t *evt)
{
    // 获取服务实例并进行参数检查
    audio_service_impl_t *impl = (audio_service_impl_t *) handle;
    AUDIO_NULL_CHECK(TAG, (handle && impl->callback_func), return ESP_ERR_INVALID_ARG);
    
    // 调用回调函数,传递服务句柄、事件数据和上下文
    return impl->callback_func(handle, evt, impl->user_cb_ctx);
}

下面的时序图展示了 audio_service_callback 函数的执行流程:

音频服务 audio_service_callback 服务实例(impl) 应用程序回调函数 调用(handle, evt) 获取服务实例(impl) 参数检查 调用回调函数(handle, evt, ctx) 处理事件 返回处理结果 返回处理结果 返回ESP_ERR_INVALID_ARG alt [参数有效] [参数无效] 音频服务 audio_service_callback 服务实例(impl) 应用程序回调函数

audio_service_callback 函数在检测到事件后,会调用应用程序提供的回调函数,并传递服务句柄、事件数据和上下文。这个函数通常由服务实现内部调用,而不是由应用程序直接调用。

回调机制的实际应用

典型音频事件类型

音频服务可能产生各种类型的事件,包括但不限于:

  1. 连接事件

    • 连接中(CONNECTING)
    • 已连接(CONNECTED)
    • 连接失败(CONNECTION_FAILED)
    • 断开连接(DISCONNECTED)
  2. 播放控制事件

    • 播放(PLAY)
    • 暂停(PAUSE)
    • 停止(STOP)
    • 下一曲(NEXT)
    • 上一曲(PREV)
  3. 状态变化事件

    • 缓冲中(BUFFERING)
    • 播放中(PLAYING)
    • 已暂停(PAUSED)
    • 已停止(STOPPED)
  4. 信息事件

    • 元数据更新(METADATA_UPDATED)
    • 音量变化(VOLUME_CHANGED)
    • 错误发生(ERROR_OCCURRED)

回调注册流程

应用程序通常在服务创建后,连接前注册回调函数,以确保可以接收到服务连接过程中产生的所有事件。下面是回调注册的典型流程:

服务运行阶段
服务处理事件
音频事件产生
audio_service_callback触发回调
应用程序回调函数执行
应用程序初始化
audio_service_create创建服务
audio_service_set_callback设置回调
audio_service_connect连接服务
服务运行阶段

回调处理示例

下面是一个蓝牙音频服务回调处理的示例:

// 应用程序回调函数
static esp_err_t bt_audio_service_cb(audio_service_handle_t handle, service_event_t *evt, void *ctx)
{
    // 获取用户上下文
    app_context_t *app_ctx = (app_context_t *)ctx;
    
    // 根据事件类型处理
    switch (evt->type) {
        case BT_A2D_CONNECTION_STATE_EVT:
            if (evt->data) {
                uint8_t state = *((uint8_t *)evt->data);
                if (state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
                    ESP_LOGI(TAG, "Bluetooth audio connected");
                    // 执行连接后逻辑
                    app_ctx->bt_connected = true;
                    // 可能需要启动音频服务
                    audio_service_start(handle);
                } else if (state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
                    ESP_LOGI(TAG, "Bluetooth audio disconnected");
                    // 执行断开后逻辑
                    app_ctx->bt_connected = false;
                    // 可能需要停止音频服务
                    audio_service_stop(handle);
                }
            }
            break;
            
        case BT_A2D_AUDIO_STATE_EVT:
            if (evt->data) {
                uint8_t state = *((uint8_t *)evt->data);
                if (state == ESP_A2D_AUDIO_STATE_STARTED) {
                    ESP_LOGI(TAG, "Bluetooth audio playing");
                    // 执行播放开始逻辑
                    app_ctx->bt_playing = true;
                } else if (state == ESP_A2D_AUDIO_STATE_STOPPED) {
                    ESP_LOGI(TAG, "Bluetooth audio stopped");
                    // 执行播放停止逻辑
                    app_ctx->bt_playing = false;
                }
            }
            break;
            
        case BT_A2D_AUDIO_CFG_EVT:
            if (evt->data && evt->len >= sizeof(esp_a2d_audio_cfg_t)) {
                esp_a2d_audio_cfg_t *cfg = (esp_a2d_audio_cfg_t *)evt->data;
                ESP_LOGI(TAG, "Audio configuration: %d Hz, %d bit, %d channel",
                          cfg->sample_rate, cfg->bits_per_sample, cfg->channel_count);
                // 更新音频配置
                app_ctx->audio_cfg = *cfg;
                // 可能需要重新配置音频输出
                reconfigure_audio_output(app_ctx);
            }
            break;
            
        default:
            ESP_LOGI(TAG, "Unknown bluetooth audio event: %d", evt->type);
            break;
    }
    
    return ESP_OK;
}

服务内部触发回调示例

下面是一个音频服务内部如何触发回调的示例:

// 蓝牙连接状态回调处理函数
static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
{
    bt_audio_impl_t *impl = bt_audio_instance;
    
    switch (event) {
        case ESP_A2D_CONNECTION_STATE_EVT:
            {
                // 创建事件数据
                service_event_t evt = {
                    .type = BT_A2D_CONNECTION_STATE_EVT,
                    .source = impl,
                    .data = &param->conn_stat.state,
                    .len = sizeof(uint8_t)
                };
                
                // 更新内部状态
                if (param->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
                    impl->connected = true;
                    impl->state = SERVICE_STATE_CONNECTED;
                } else if (param->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
                    impl->connected = false;
                    impl->state = SERVICE_STATE_IDLE;
                }
                
                // 触发回调
                audio_service_callback((audio_service_handle_t)impl, &evt);
            }
            break;
            
        case ESP_A2D_AUDIO_STATE_EVT:
            {
                // 创建事件数据
                service_event_t evt = {
                    .type = BT_A2D_AUDIO_STATE_EVT,
                    .source = impl,
                    .data = &param->audio_stat.state,
                    .len = sizeof(uint8_t)
                };
                
                // 更新内部状态
                if (param->audio_stat.state == ESP_A2D_AUDIO_STATE_STARTED) {
                    impl->playing = true;
                } else if (param->audio_stat.state == ESP_A2D_AUDIO_STATE_STOPPED) {
                    impl->playing = false;
                }
                
                // 触发回调
                audio_service_callback((audio_service_handle_t)impl, &evt);
            }
            break;
            
        default:
            break;
    }
}

回调管理的优势

audio_service子模块的回调管理机制具有以下优势:

  1. 解耦性:服务实现和应用程序逻辑完全分离,提高了代码的模块化程度
  2. 统一接口:不同类型的音频服务使用相同的回调接口,便于应用程序统一处理
  3. 上下文传递:可以传递任意用户数据作为上下文,使回调函数能够访问应用程序状态
  4. 事件驱动:采用事件驱动模型,提高了系统响应效率
  5. 简单易用:回调设置和触发接口简单清晰,易于使用

通过回调管理函数,audio_service子模块实现了高效的事件通知机制,使音频服务能够将事件及时传递给应用程序,应用程序也能根据事件执行相应的逻辑,提高了系统的灵活性和响应性。

回调管理与其他功能的集成

回调管理机制是audio_service子模块功能体系中的重要组成部分,它与其他功能(资源管理、连接管理、状态控制等)紧密集成,共同构成了完整的音频服务管理框架。

下面的图表展示了回调管理在audio_service功能体系中的位置:

应用程序
资源管理
create/destroy
回调管理
set_callback/callback
连接管理
connect/disconnect
状态控制
start/stop
数据管理
set_data/get_data
音频服务实例
底层音频处理
事件产生
服务检测事件
audio_service_callback
应用程序回调函数

通过这种集成,audio_service子模块为各种音频服务提供了统一的管理框架,简化了音频服务的开发和使用,使应用程序能够以一致的方式处理不同类型的音频服务和事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

omnibots

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值