当前位置: 首页 > news >正文

ESP-ADF esp_dispatcher组件之audio_service子模块状态控制函数详解

目录

  • ESP-ADF esp_dispatcher组件之audio_service子模块状态控制函数详解
    • 状态控制概述
    • 状态控制函数分析
      • audio_service_start
      • audio_service_stop
    • 状态控制与服务实现
    • 状态控制在服务生命周期中的作用
    • 最佳实践
    • 状态控制与连接管理的协同工作

ESP-ADF esp_dispatcher组件之audio_service子模块状态控制函数详解

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

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

状态控制概述

audio_service子模块的状态控制函数负责管理音频服务的运行状态,包括启动和停止服务。这些函数是音频服务生命周期管理的关键部分,用于控制服务的活动状态。音频服务通常有以下几种状态:

// 音频服务状态
typedef enum {SERVICE_STATE_UNKNOWN,       // 未知状态SERVICE_STATE_IDLE,          // 空闲状态SERVICE_STATE_CONNECTING,    // 连接中状态SERVICE_STATE_CONNECTED,     // 已连接状态SERVICE_STATE_RUNNING,       // 运行状态SERVICE_STATE_STOPPED,       // 停止状态
} service_state_t;

音频服务的状态转换通常遵循以下流程:

  1. 创建后处于IDLE状态
  2. 连接后进入CONNECTED状态
  3. 调用start函数后转为RUNNING状态
  4. 调用stop函数后转为STOPPED状态
  5. 断开连接后返回IDLE状态
  6. 调用destroy函数销毁服务

这种状态管理使得音频服务能够清晰地控制其生命周期中的不同阶段。

状态控制函数分析

audio_service_start

audio_service_start函数用于启动音频服务,使服务开始处理音频事件。下面是其源码实现:

/*** @brief 启动特定的音频服务* * 该函数调用服务实现提供的启动函数,使服务进入运行状态* 启动后,服务通常会开始处理音频事件并通过回调函数通知应用程序* 在调用此函数前,应确保已成功连接到音频服务* * @param handle 音频服务实例句柄* @return esp_err_t 成功返回ESP_OK,失败返回错误码*/
esp_err_t audio_service_start(audio_service_handle_t handle)
{// 获取服务实例并进行参数检查audio_service_impl_t *impl = (audio_service_impl_t *) handle;AUDIO_NULL_CHECK(TAG, (handle && impl->service_start), return ESP_ERR_INVALID_ARG);// 调用服务实现提供的启动函数return impl->service_start(handle);
}

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

应用程序 audio_service_start 服务实例(impl) 服务启动函数(service_start) 调用(handle) 获取服务实例(impl) 参数检查 调用服务启动函数 执行特定服务的启动逻辑 更新服务状态为RUNNING 返回结果 返回结果 返回ESP_ERR_INVALID_ARG alt [参数有效] [参数无效] 应用程序 audio_service_start 服务实例(impl) 服务启动函数(service_start)

这个时序图展示了 audio_service_start 函数的执行流程,它主要是检查参数有效性,然后调用服务实现提供的启动函数。具体的启动逻辑由服务实现负责,这种设计使得不同类型的音频服务可以有不同的启动行为。

audio_service_stop

audio_service_stop函数用于停止音频服务,使服务不再处理音频事件。下面是其源码实现:

/*** @brief 停止特定的音频服务* * 该函数调用服务实现提供的停止函数,使服务进入停止状态* 停止后,服务通常会停止处理音频事件* 停止服务并不会断开与音频服务的连接,如果需要断开连接,应调用audio_service_disconnect* * @param handle 音频服务实例句柄* @return esp_err_t 成功返回ESP_OK,失败返回错误码*/
esp_err_t audio_service_stop(audio_service_handle_t handle)
{// 获取服务实例并进行参数检查audio_service_impl_t *impl = (audio_service_impl_t *) handle;AUDIO_NULL_CHECK(TAG, (handle && impl->service_stop), return ESP_ERR_INVALID_ARG);// 调用服务实现提供的停止函数return impl->service_stop(handle);
}

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

应用程序 audio_service_stop 服务实例(impl) 服务停止函数(service_stop) 调用(handle) 获取服务实例(impl) 参数检查 调用服务停止函数 执行特定服务的停止逻辑 更新服务状态为STOPPED 返回结果 返回结果 返回ESP_ERR_INVALID_ARG alt [参数有效] [参数无效] 应用程序 audio_service_stop 服务实例(impl) 服务停止函数(service_stop)

这个时序图展示了 audio_service_stop 函数的执行流程,它主要是检查参数有效性,然后调用服务实现提供的停止函数。具体的停止逻辑由服务实现负责,这种设计使得不同类型的音频服务可以有不同的停止行为。

状态控制与服务实现

audio_service子模块的状态控制函数只是提供了统一的接口,实际的启动和停止逻辑由具体的服务实现提供。这种设计有以下优点:

  1. 统一接口:应用程序可以使用相同的接口控制不同类型的音频服务
  2. 灵活实现:不同类型的音频服务可以有不同的启动和停止逻辑
  3. 状态管理:服务可以在启动和停止函数中管理自己的状态

下面是服务实现可能提供的启动和停止函数的示例:

/*** @brief 蓝牙音频服务启动函数示例*/
static esp_err_t bt_audio_start(audio_service_handle_t handle)
{bt_audio_impl_t *impl = (bt_audio_impl_t *)handle;// 检查是否已连接if (impl->state != SERVICE_STATE_CONNECTED) {ESP_LOGE(TAG, "BT audio service not connected");return ESP_ERR_INVALID_STATE;}// 启动音频流处理esp_a2d_sink_register_data_callback(bt_a2d_data_callback);esp_a2d_sink_init();// 设置音频参数i2s_config_t i2s_cfg = {.mode = I2S_MODE_MASTER | I2S_MODE_TX,.sample_rate = 44100,.bits_per_sample = 16,.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,.communication_format = I2S_COMM_FORMAT_STAND_I2S,.tx_desc_auto_clear = true,.dma_buf_count = 8,.dma_buf_len = 64};i2s_driver_install(0, &i2s_cfg, 0, NULL);i2s_set_pin(0, &pin_config);i2s_start(0);// 更新服务状态impl->state = SERVICE_STATE_RUNNING;// 通知应用程序服务已启动service_event_t evt = {.type = BT_AUDIO_SERVICE_STARTED,.source = impl,.data = NULL,.len = 0};audio_service_callback(handle, &evt);return ESP_OK;
}/*** @brief 蓝牙音频服务停止函数示例*/
static esp_err_t bt_audio_stop(audio_service_handle_t handle)
{bt_audio_impl_t *impl = (bt_audio_impl_t *)handle;// 检查是否正在运行if (impl->state != SERVICE_STATE_RUNNING) {ESP_LOGE(TAG, "BT audio service not running");return ESP_ERR_INVALID_STATE;}// 停止音频流处理i2s_stop(0);i2s_driver_uninstall(0);// 停止A2DP接收器esp_a2d_sink_deinit();// 更新服务状态impl->state = SERVICE_STATE_STOPPED;// 通知应用程序服务已停止service_event_t evt = {.type = BT_AUDIO_SERVICE_STOPPED,.source = impl,.data = NULL,.len = 0};audio_service_callback(handle, &evt);return ESP_OK;
}

状态控制在服务生命周期中的作用

状态控制函数是音频服务生命周期管理的关键部分,它们位于连接管理(audio_service_connectaudio_service_disconnect)和资源管理(audio_service_createaudio_service_destroy)之间,控制着服务的运行状态。

下面的图表展示了音频服务的完整生命周期,突出显示了状态控制函数的位置:

状态控制
连接管理
资源管理
audio_service_start启动服务
audio_service_stop停止服务
audio_service_connect连接服务
audio_service_disconnect断开服务
audio_service_create创建服务
audio_service_destroy销毁服务
应用程序初始化
准备服务配置
audio_service_set_callback设置回调
服务运行阶段
应用程序结束

通过这种设计,应用程序可以灵活地控制音频服务的运行状态,在需要时启动服务处理音频事件,在不需要时停止服务节省系统资源,实现了高效的音频服务管理。

最佳实践

使用audio_service子模块的状态控制函数时,可以遵循以下最佳实践:

  1. 按顺序操作:先连接,再启动;先停止,再断开连接
  2. 检查返回值:始终检查状态控制函数的返回值,确保操作成功
  3. 错误处理:如果状态控制函数返回错误,应该进行适当的错误处理
  4. 状态监控:在复杂的应用中,可能需要跟踪服务的状态,以避免在错误的状态下执行操作
  5. 优雅关闭:在应用程序关闭前,确保所有服务都被正确停止和断开连接

下面是一个使用状态控制函数的示例:

// 启动服务
esp_err_t ret = audio_service_start(service_handle);
if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to start audio service: %s", esp_err_to_name(ret));// 进行错误处理audio_service_disconnect(service_handle);return ret;
}// 服务运行阶段
// ...// 停止服务
ret = audio_service_stop(service_handle);
if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to stop audio service: %s", esp_err_to_name(ret));// 进行错误处理,尝试强制断开连接audio_service_disconnect(service_handle);
} else {// 正常断开连接audio_service_disconnect(service_handle);
}

状态控制与连接管理的协同工作

在audio_service子模块中,状态控制函数通常与连接管理函数协同工作,形成完整的服务生命周期。下面是一个典型的工作流程:

// 1. 创建服务
audio_service_handle_t service = audio_service_create(&service_config);// 2. 设置回调
audio_service_set_callback(service, service_callback, user_context);// 3. 连接服务
audio_service_connect(service);// 4. 等待连接完成
// 通常通过回调函数异步通知// 5. 启动服务
audio_service_start(service);// 6. 服务运行阶段
// 处理音频数据和事件// 7. 停止服务
audio_service_stop(service);// 8. 断开连接
audio_service_disconnect(service);// 9. 销毁服务
audio_service_destroy(service);

这种完整的生命周期管理确保了音频服务能够正确地创建、连接、启动、停止、断开连接和销毁,防止资源泄漏和状态错误。

通过正确使用状态控制函数,可以实现音频服务的可靠启动和停止,提高应用程序的稳定性和用户体验。

相关文章:

  • pytest——参数化
  • 【dify—10】工作流实战——文生图工具
  • 精益数据分析(37/126):深度剖析SaaS模式下的参与度与流失率指标
  • 游戏引擎学习第254天:重新启用性能分析
  • C++析构函数详解
  • Synthesis的分类
  • cat file.tar.gz | tar -xzf - -C /target/dir两个减号之间为什么有个空格?是写错了吗?(管道命令后续)
  • JavaScript基础-赋值运算符
  • Windows 使用set和setx设置环境变量(skywalk3)
  • 区块链+IoT:创新场景落地背后的技术攻坚战
  • 驱动开发系列56 - Linux Graphics QXL显卡驱动代码分析(三)显示模式设置
  • Java 实现socket VAD通讯客户端
  • (35)VTK C++开发示例 ---将图片映射到平面2
  • 目标检测中的损失函数(三) | SIoU WIoUv1 WIoUv2 WIoUv3
  • 硬件性能与能效比竞赛:解码 PC 硬件的 “速度与激情”
  • 云计算-容器云-服务网格Bookinfo
  • 云计算-容器云-部署jumpserver 版本2
  • 推荐免费的RVC模型下载网站
  • 开源无人机地面站QGroundControl安卓界面美化与逻辑优化实战
  • 如何在NGINX中实现基于IP的访问控制(IP黑白名单)?
  • 我的诗歌阅读史
  • 5月1日全国铁路发送旅客2311.9万人次,创历史新高
  • 保险经纪公司元保在纳斯达克挂牌上市,去年净赚4.36亿元
  • 三家“券商系”公募同日变更掌门人,新董事长均为公司股东方老将
  • 市场监管总局出手整治涉企乱收费,聚焦政府部门及下属单位等领域
  • 奔驰一季度利润降四成,受美国加征关税影响放弃全年盈利展望