esp-adf框架笔记 1 概述
这个笔记的只是用于个人对于学习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 概述相关推荐
- System Verilog自学笔记专栏概述博文目录
本文用于梳理学习笔记目录下的博文笔记,概述会有笔者的System Verilog的学习反思以及相关随笔,望有同学发现问题及时提出~感谢 概述随笔 了解基本的概念,框架后,开始使用例子进行学习语言.需要 ...
- Java基础知识强化之集合框架笔记76:ConcurrentHashMap之 ConcurrentHashMap简介
1. ConcurrentHashMap简介: ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和Hashtable功能相同但是线程安全的方法.Conc ...
- ET框架笔记 (笑览世界写)(转)
客户端 1.使用unity2017.2.0版本及以上2018版以下,编译原始版ET客户端报没有引用错误时,删除hoxfit下引用的UnityEngine.dll和UnityEngine.UI.dll, ...
- msm8996平台的 camera 框架笔记
msm8996平台的 camera 框架笔记 标签(空格分隔): camera 文章目录 msm8996平台的 camera 框架笔记 @[toc] 0 前言 1 kernel中的camera结构 1 ...
- 解读基金—读书框架笔记①
解读基金-读书框架笔记① 基础概念 投资目标的确定 基金风险 投资金额比例 & 投资时间 复利计算"72"法则 & 基金选择的关键点 基金基础知识 & 品种 ...
- 计算机网络笔记Part1 概述
本人计算机网络笔记总目录 计算机网络笔记Part1 概述 计算机网络笔记Part2 物理层(Physical Layer) 计算机网络笔记Part3 数据链路层(Data Link Layer) 计算 ...
- frame框架说明(概述)
frame框架说明(概述) 1. 这个框架是为了解决什么问题? 减少服务的重复代码 多个服务使用框架提供的API,框架能够集中管理服务的资源分配(使用与实现的分离有利于服务的升级) 多个服务复用一个框 ...
- Oracle学习笔记 字符集概述
Oracle 学习笔记 字符集概述 这节课开始讲oracle里面的字符集 偏重于原理和简单的一些判断以及实现 字符集它涉及到很多的东西 比如建库和操作系统环境 这节课把字符集的原理性的东西以及常见的操 ...
- Android O Treble框架笔记(基于高通845平台)
Android O Treble框架笔记(基于高通845平台) tags: android 文章目录 Android O Treble框架笔记(基于高通845平台) @[toc] **0 前言** * ...
最新文章
- CPU0 处理器的架构及应用
- 中国程序员人数将增长50%,过半500强都要卖软件,边缘应用程序增长8倍丨IDC预测下一个五年...
- 全球及中国家用空气净化器市场销售需求及营销策略模式分析报告2022-2027年
- 多态部分作业 3..创建Rodent(啮齿动物):Mnouse(老鼠),Gerbil(鼹鼠),Hamster(大颊鼠)
- 计划的执行与回顾的重要性与必要性
- 关于使用cadence建pad
- 函数的参数个数是不固定_EXCEL这些序号技巧,你还真不一定都知道
- 7.企业安全建设入门(基于开源软件打造企业网络安全) --- 蜜罐与攻击欺骗
- 【C++】 ArcFace Demo2.0版
- ContextCaptureMaster/Smart3D 集群简单配置
- XX数据中心技术方案
- 阿里云loT物联网学习
- Java获取时间戳,System.currentTimeMillis() 和 System.nanoTime() 哪个更快?
- python鼠标画点连线_浅谈画点连线的步骤以及注意事项
- java网络爬虫电影数据,Java豆瓣电影爬虫——减少与数据库交互实现批量插入
- 分词统计(四)唐宋元诗人吟诗作词的时候,最偏爱哪些词语呢?(附上AI写的1000句诗!)
- jpg照片如何压缩变小?三步轻松搞定
- dataset中shuffle()、repeat()、batch()用法
- PHP 中的 cURL 爬虫实战基础
- SolidWorks渲染图
热门文章
- 星号塔php,PHP实现星号金字塔代码分享
- html avatar属性,CSS自定义属性在组件开发中的使用
- Yii2.0 后台UI框架以及权限管理扩展实现权限菜单管理
- 西门子标准报文111解析
- UiBot 填写日期 设置元素文本
- 二十四节气——正解反解
- 【CC3200AI 实验教程12】疯壳·AI语音人脸识别(会议记录仪/人脸打卡机)-语音采集
- android 怎么取id3信息,一个可以读取ID3信息的类[可以很方便添加MP3了]
- 李宏毅2021机器学习笔记——GAN
- Ant Design table实现表头列宽拖拉 官方 vue-draggable-resizable的魔改版