这个笔记的只是用于个人对于学习esp-adf的记录,如有错误纯属正常

esp-adf 介绍

ESP-ADF 在 ESP-IDF(乐鑫物联网开发框架,广泛运用于 ESP32 的 SDK)的基础上开发而成,具有高度的灵活性,既可作为一整套应用方案,面向配网、OTA (Over The Air) 等各类应用场景,亦可作为开发平台,供开发人员搭建各类定制化应用场景。

ESP-ADF 具有一系列丰富的功能特色,涵盖编解码器、发送端和接收端音频流、管线化支持、唤醒词引擎,以及其他各类服务和控制等。

乐鑫音频开发框架:

  • 支持音频格式:MP3、AAC、WAV、OGG、AMR、TS、OPUS、SPEEX 等

  • 支持 EQ、Mixer、Resample 等音效处理功能

  • 多音频播放来源:HTTP、HLS (HTTP Live)、SD 卡、Bluetooth A2DP/HFP

  • 支持多媒体交互:DLNA、Airplay、微信和 Internet radio 等

  • 云端语音接入:Alexa、DuerOS、Turing、IFLYTEK、TmallGenie、RooBo 等

  • ESP-ADF 应用场景包括:智能音箱、语音对讲机、语音播报机,以及其他音频类解决方案,如语音故事机和点读机。

esp-adf API介绍

此文来自对

https://docs.espressif.com/projects/esp-adf/zh_CN/latest/api-reference/index.html

乐鑫关于esp-adf的说明文档整理而来,由于本人英文水平有限特此将文档整理出来为了以后学习使用。在这其中也添加了我个人学习esp-adf的心得。

1. 整体框架介绍

根据上面图可以看出,esp-adf 底层是调用esp-idf框架,esp-idf是乐鑫最早推出的基于esp32的物联网软件框架。

esp-adf是面向对象的思想实现的,整个框架分层处理,保证每层都有相对的独立性。每个具体功能都定义成一个模块,最后为上层应用提供统一的接口。

在esp-adf中最低层应该是硬件的驱动和功能的实现,包括:音频3款音频编解码器芯片驱动(ESP8388,ES8374,ZL38063)然后就是诸如SD卡,LED,wifi等软件的基于esp-idf的重新封装。 在这之上则是软件个功能的实现(软件编解码MP3,wav,amr等,DLNA的协议,REcorder,Player )等。在这之上就是element(元素),stream(数据流),pipeline(管道),然后在这上面就是软件层具体的协议实现了包括baidu DueroOS,amazon Alexa等。

2. esp-adf运行机制

esp-adf运行主要是基于pipeline运行,每个pipeline中最基本的运行单元就是element,每个element之间靠stream传送音频数据。 这个是esp-adf提供的例程play_mp3的运行示意图。

其中MP3 decoder 就是一个element,而I2S stream就是一个stream。

我查看源码其中pipeline是通过链表方式实现的,他没有具体的功能操作,只是将pipeline中的内容链接在一起。 而element 和 streamm 是基于freeRTOS的task实现的,也就是说当你开始运行一个pipeline时,他是同时启动了几个 freeRTOS任务函数,每个任务通过freertos自带的队列、信号量,互斥体等机制实现数据的传输和消息的传递。

3. esp-adf 支持的elements和stream

​从图中可以看到esp-adf 现在支持的音频数据流有i2s,http,fatfs,raw,spifss。

* i2s是通过操作i2s接口控制硬件编解码器的。
* http是通过http协议将音频数据发送到远程服务器中。
* fatfs则是实现了fatfs文件系统,一般是用于操作SD卡读写音频文件。
* raw则是一种数据传输流,本身没有功能,只是负责将音频传送到下一个element。
* spifss是一种基于flash的文件系统,可以通过它对flash以为文件系统方式操对音频文件进行读写。

实际在源码中还有另外两种数据流algorithm stream和tone stream。algorithm stream是回声处理,唤醒词处理加入到里面数据流,tone stream则是另外一种flash操作方法。

4. 例程分析

先通过一个最简单的例程,来说明一下esp-adf的工作机制,以esp-adf/exampele/get-started/play_mp3 为例,他实现的功能就是播放一段flash中mp3格式的音频文件。

/*定义一个pipeline管道*/audio_pipeline_handle_t pipeline;/*定义两个音频元素,一个用于mp3解码,一个用于将音频数据通过i2s传送硬件播放*/audio_element_handle_t i2s_stream_writer, mp3_decoder;esp_log_level_set("*", ESP_LOG_WARN);esp_log_level_set(TAG, ESP_LOG_INFO);ESP_LOGI(TAG, "[ 1 ] Start audio codec chip");/*初始化开发板硬件*/audio_board_handle_t board_handle = audio_board_init();/*使能编解码器*/audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);ESP_LOGI(TAG, "[ 2 ] Create audio pipeline, add all elements to pipeline, and subscribe pipeline event");/*将pipeline设置成默认配置*/audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();/*初始化pipeline*/pipeline = audio_pipeline_init(&pipeline_cfg);mem_assert(pipeline);ESP_LOGI(TAG, "[2.1] Create mp3 decoder to decode mp3 file and set custom read callback");/*将mp3_decoder 配置成默认配置*/mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();/*初始化 mp3 解码器*/mp3_decoder = mp3_decoder_init(&mp3_cfg);audio_element_set_read_cb(mp3_decoder, mp3_music_read_cb, NULL);ESP_LOGI(TAG, "[2.2] Create i2s stream to write data to codec chip");/*配置i2s_stream */i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();i2s_cfg.type = AUDIO_STREAM_WRITER;i2s_cfg.i2s_config.sample_rate = 48000;/*初始化 i2s_stream*/i2s_stream_writer = i2s_stream_init(&i2s_cfg);ESP_LOGI(TAG, "[2.3] Register all elements to audio pipeline");/*将mp3_decoder 添加到pipeline 中*/audio_pipeline_register(pipeline, mp3_decoder, "mp3");/*将i2s_stream 添加到pipeline 中*/audio_pipeline_register(pipeline, i2s_stream_writer, "i2s");ESP_LOGI(TAG, "[2.4] Link it together [mp3_music_read_cb]-->mp3_decoder-->i2s_stream-->[codec_chip]");/*将两个elements链接在一起*/audio_pipeline_link(pipeline, (const char *[]) {"mp3", "i2s"}, 2);ESP_LOGI(TAG, "[ 3 ] Set up  event listener");/*创建监听事件,用于监听pipeline中的标志变化*/audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);ESP_LOGI(TAG, "[3.1] Listening event from all elements of pipeline");audio_pipeline_set_listener(pipeline, evt);ESP_LOGI(TAG, "[ 4 ] Start audio_pipeline");/*运行pipeline*/audio_pipeline_run(pipeline);/*audio_pipeline_run执行之后,同时开始运行两个audio_element 任务,mp3_decode将读取到mp3音频传输给i2s_steam ,i2s_stream 通过控制编辑码芯片将音频播放出来*/

5. ringbuf 和event interface

  • event interface

在上一个例程中出现了新的类型 audio_event_iface_handle_t 音频事件接口

audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);
audio_pipeline_set_listener(pipeline, evt);

这个数据类型的作用是监听pipeline运行的的发生事件。消息事件是通过消息队列实现的,使用audio_event_iface_init(&evt_cfg);

完成创建队列,然后通过audio_pipeline_set_listener(pipeline, evt); 将队列指针与pipeline中的队列指针关联,以达到通过获取这个消息队列内容就可以获取整个pipeline的目的。在实际使用过程中,在主循环中循环调用 audio_event_iface_listen获取当前pipeline的消息。

while(1){...      audio_event_iface_msg_t msg;     esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);      ... } 
  • ringbuffer

ringbuffer是一种环形缓冲区,这种缓冲区不仅用作数据缓冲同样也用于连接 audio element ,没element 向ringbuffer请求数据时都会导致ringbuffer任务阻塞,直到ringbufer中的数据可以使用这个任务才可以继续执行。

6. 结束

之前的esp-idf教程是想到那写到那根本没有学习路径可言(之后还是会这样),因此决定写esp-adf笔记之前立下flag,以防写着写着忘记了(也是提醒自己不要放弃)。

  • esp-adf概述介绍

  • 根据官方提供的文档撰写api 参考手册

  • 找出几个比较有代表性的例程分析相关代码

  • 自己实现一个esp-adf 项目(具体还没想好) 在这个计划之外还会时不时的上传当前使用esp-adf的一些心得体会。

欢迎关注我的个人网站:zwww.zcxbb.com

知乎专栏:物联网开发入门 - 知乎 (zhihu.com)

esp-adf框架笔记 1 概述相关推荐

  1. System Verilog自学笔记专栏概述博文目录

    本文用于梳理学习笔记目录下的博文笔记,概述会有笔者的System Verilog的学习反思以及相关随笔,望有同学发现问题及时提出~感谢 概述随笔 了解基本的概念,框架后,开始使用例子进行学习语言.需要 ...

  2. Java基础知识强化之集合框架笔记76:ConcurrentHashMap之 ConcurrentHashMap简介

    1. ConcurrentHashMap简介: ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和Hashtable功能相同但是线程安全的方法.Conc ...

  3. ET框架笔记 (笑览世界写)(转)

    客户端 1.使用unity2017.2.0版本及以上2018版以下,编译原始版ET客户端报没有引用错误时,删除hoxfit下引用的UnityEngine.dll和UnityEngine.UI.dll, ...

  4. msm8996平台的 camera 框架笔记

    msm8996平台的 camera 框架笔记 标签(空格分隔): camera 文章目录 msm8996平台的 camera 框架笔记 @[toc] 0 前言 1 kernel中的camera结构 1 ...

  5. 解读基金—读书框架笔记①

    解读基金-读书框架笔记① 基础概念 投资目标的确定 基金风险 投资金额比例 & 投资时间 复利计算"72"法则 & 基金选择的关键点 基金基础知识 & 品种 ...

  6. 计算机网络笔记Part1 概述

    本人计算机网络笔记总目录 计算机网络笔记Part1 概述 计算机网络笔记Part2 物理层(Physical Layer) 计算机网络笔记Part3 数据链路层(Data Link Layer) 计算 ...

  7. frame框架说明(概述)

    frame框架说明(概述) 1. 这个框架是为了解决什么问题? 减少服务的重复代码 多个服务使用框架提供的API,框架能够集中管理服务的资源分配(使用与实现的分离有利于服务的升级) 多个服务复用一个框 ...

  8. Oracle学习笔记 字符集概述

    Oracle 学习笔记 字符集概述 这节课开始讲oracle里面的字符集 偏重于原理和简单的一些判断以及实现 字符集它涉及到很多的东西 比如建库和操作系统环境 这节课把字符集的原理性的东西以及常见的操 ...

  9. Android O Treble框架笔记(基于高通845平台)

    Android O Treble框架笔记(基于高通845平台) tags: android 文章目录 Android O Treble框架笔记(基于高通845平台) @[toc] **0 前言** * ...

最新文章

  1. CPU0 处理器的架构及应用
  2. 中国程序员人数将增长50%,过半500强都要卖软件,边缘应用程序增长8倍丨IDC预测下一个五年...
  3. 全球及中国家用空气净化器市场销售需求及营销策略模式分析报告2022-2027年
  4. 多态部分作业 3..创建Rodent(啮齿动物):Mnouse(老鼠),Gerbil(鼹鼠),Hamster(大颊鼠)
  5. 计划的执行与回顾的重要性与必要性
  6. 关于使用cadence建pad
  7. 函数的参数个数是不固定_EXCEL这些序号技巧,你还真不一定都知道
  8. 7.企业安全建设入门(基于开源软件打造企业网络安全) --- 蜜罐与攻击欺骗
  9. 【C++】 ArcFace Demo2.0版
  10. ContextCaptureMaster/Smart3D 集群简单配置
  11. XX数据中心技术方案
  12. 阿里云loT物联网学习
  13. Java获取时间戳,System.currentTimeMillis() 和 System.nanoTime() 哪个更快?
  14. python鼠标画点连线_浅谈画点连线的步骤以及注意事项
  15. java网络爬虫电影数据,Java豆瓣电影爬虫——减少与数据库交互实现批量插入
  16. 分词统计(四)唐宋元诗人吟诗作词的时候,最偏爱哪些词语呢?(附上AI写的1000句诗!)
  17. jpg照片如何压缩变小?三步轻松搞定
  18. dataset中shuffle()、repeat()、batch()用法
  19. PHP 中的 cURL 爬虫实战基础
  20. SolidWorks渲染图

热门文章

  1. 星号塔php,PHP实现星号金字塔代码分享
  2. html avatar属性,CSS自定义属性在组件开发中的使用
  3. Yii2.0 后台UI框架以及权限管理扩展实现权限菜单管理
  4. 西门子标准报文111解析
  5. UiBot 填写日期 设置元素文本
  6. 二十四节气——正解反解
  7. 【CC3200AI 实验教程12】疯壳·AI语音人脸识别(会议记录仪/人脸打卡机)-语音采集
  8. android 怎么取id3信息,一个可以读取ID3信息的类[可以很方便添加MP3了]
  9. 李宏毅2021机器学习笔记——GAN
  10. Ant Design table实现表头列宽拖拉 官方 vue-draggable-resizable的魔改版