ESP-ADF ⼊门——从play_mp3_control ⼊门adf
什么是ESP-ADF ?
是乐鑫基于⾃家的——开发的⾳频开发框架
创建第⼀个esp-adf ⼯程
本⽂主要为了⽅便⼤家对esp-adf的了解,抛弃了官⽅的流程。将esp-adf作为idf⼯程的组件创建esp-adf的最简⼯程,并从中分析adf的使⽤⽅法。本章默认⼤家已经装好了esp-idf,如果有不会安装的可以看。如有不合理之处欢迎⼤家雅正。
如何优雅的下载github 上的仓库并且下载⼦模块
我⾃⼰在gitee上上传了⼀个⾃⼰常⽤的脚本,原理是递归换源。把github换成国内源,这样⽅便我们去下载仓库及其⼦模块。话不多说,来看看如何下载esp-adf。
这样⼀来我们的esp-adf下载好了,esp-adf实际上⾃带⼀个esp-idf,这个是它推荐的版本,如果你⽬前的idf能够编译,那就不需要这个idf。
创建第⼀个adf ⼯程
然后我们打开play_mp3_control ⼯程下⾯的删掉include($ENV{ADF_PATH}/)这⼀⾏,就完成了我们的⼯程创建,通过export.sh激活idf环境,然后idf.py build就编译完成我们的⼯程了。
分析play_mp3_control ⼯程
抛开components不看先看看主代码# 下载我的换源脚本git clone gitee/geekheart/github_download_tools.git # 使⽤脚本下载esp-adf 及其⼦模块git clone github/espressif/esp-adf.git -s
1
2
3
4# 复制出最基础的例程cp -r esp-adf/examples/get-started/play_mp3_control ./# 进⼊例程⽂件夹中cd play_mp3_control # 复制⼯程所需的全部组件cp -r ../esp-adf/components/* ./components
1
2
3
4
5
6/* Play mp3 file by audio pipeline with possibility to start, stop, pause and resume playback as well as adjust volume This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*/#include <string.h>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "esp_log.h"#include "audio_element.h"#include "audio_pipeline.h"#include "audio_event_iface.h"#include "audio_mem.h"#include "audio_common.h"#include "i2s_stream.h"#include "mp3_decoder.h"
1
2
3decoder
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "esp_peripherals.h"#include "periph_touch.h"#include "periph_adc_button.h"#include "periph_button.h"#include "board.h"static const char *TAG = "PLAY_FLASH_MP3_CONTROL";static struct marker { int pos ; // 已读长度 const uint
8_t *start ; // 开始指针 const uint8_t *end ; // 结束指针} file_marker ;// low rate mp3 audio extern const uint8_t lr_mp3_start [] asm ("_binary_music_16b_2c_8000hz_mp3_start");extern const uint8_t lr_mp3_end [] asm ("_binary_music_16b_2c_8000hz_mp3_end");// medium rate mp3 audio extern const uint8_t mr_mp3_start [] asm ("_binary_music_16b_2c_22050hz_mp3_start");extern const uint8_t mr_mp3_end [] asm ("_binary_music_16b_2c_22050hz_mp3_end");// high rate mp3 audio extern const uint8_t hr_mp3_start [] asm ("_binary_music_16b_2c_44100hz_mp3_start");extern const uint8_t hr_mp3_end [] asm ("_binary_music_16b_2c_44100hz_mp3_end");/** * @brief 轮询三个⾳频⽂件 * */static void set_next_file_marker (){ static int idx = 0; switch (idx ) { case 0: file_marker .start = lr_mp3_start ; file_marker .end = lr_mp3_end ; break ; case 1: file_marker .start = mr_mp3_start ; file_marker .end = mr_mp3_end ; break ; case 2: file_marker .start = hr_mp3_start ; file_marker .end = hr_mp3_end ; break ; default : ESP_LOGE (TAG , "[ * ] Not supported index = %d", idx ); } if (++idx > 2) { idx = 0; } file_marker .pos = 0;}/** * @brief ⾳频回调函数 * * @param el ⾳频对象 * @param buf 读取⾳频指针 * @param len 读取⾳频长度 * @param wait_time 等待时间 * @param ctx ⽤户传递数据
* @return int 下⼀步读取长度
222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
* @return int 下⼀步读取长度 */int mp3_music_read_cb (audio_element_handle_t el , char *buf , int len , TickType_t wait_time , void *ctx ){ int read_size = file_marker .end - file_marker .start - file_marker .pos ; // 剩余未读长度 if (read_size == 0) // 如果剩余长度为0,则返回读取完毕 { return AEL_IO_DONE ; } else if (len < read_size ) // 如果剩余长度还⾜够则还读len 长度,如果不够则读剩余长度 { read_size = len ; } memcpy (buf , file_marker .start + file_marker .pos , read_size ); // 更新下⼀段读取的部分 file_marker .pos += read_size ; // 跟新接下来要读取的位置 return read_size ; // 返回下⼀段读取的长度}void app_main (void ){ audio_pipeline_handle_t pipeline ; // 设置管道对象 audio_element_handle_t i2s_stream_writer , mp3_decoder ; // 设置管道数据,i2s 流,mp3流 // 设置level 等级 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 (); // codec 等模块初始化 audio_hal_ctrl_codec (board_handle ->audio_hal , AUDIO_HAL_CODEC_MODE_BOTH , AUDIO_HAL_CTRL_START ); // 初始化 int player_volume ; audio_hal_get_volume (board_handle ->audio_hal , &player_volume ); // 获取播放器⾳量 ESP_LOGI (TAG , "[ 2 ] Create a
udio pipeline, add all elements to pipeline, and subscribe pipeline event"); audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG (); // 设置默认的管道参数 pipeline = audio_pipeline_init (&pipeline_cfg ); // 创建管道 ESP_LOGI (TAG , "[2.1] Create mp3 decoder to decode mp3 file and set custom read callback"); mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG (); // 设置默认的mp3解析流 mp3_decoder = mp3_decoder_init (&mp3_cfg ); // 初始化MP3解析流 audio_element_set_read_cb (mp3_decoder , mp3_music_read_cb , NULL ); // 此 API 允许应⽤程序为管道中的第⼀个 audio_element 设置读取回调,以允许 ESP_LOGI (TAG , "[2.2] Create i2s stream to write data to codec chip"); i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT (); // 设置默认的i2s 流参数 // pe = AUDIO_STREAM_WRITER; // 设置i2s 类型 i2s_stream_writer = i2s_stream_init (&i2s_cfg ); // 初始化i2s 流 ESP_LOGI (TAG , "[2.3] Register all elements to audio pipeline"); audio_pipeline_register (pipeline , mp3_decoder , "mp3"); // 管道中注册mp3流 audio_pipeline_register (pipeline , i2s_stream_writer , "i2s"); // 管道中注册i2s 流 ESP_LOGI (TAG , "[2.4] Link it together [mp3_music_read_cb]-->mp3_decoder-->i2s_stream-->[codec_chip]"); const char *link_tag [2] = {"mp3", "i2s"}; audio_pipeline_link (pipeline , link_tag , 2); // 按照link_tag 的顺序链接数据流 ESP_LOGI (TAG , "[ 3 ] Initialize peripherals"); esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG (); // 设置默认外设参数 esp_periph_set_handle_t set = e
sp_periph_set_init (&periph_cfg ); // 初始化外设参数 ESP_LOGI (TAG , "[3.1] Initialize keys on board"); audio_board_key_init (set ); // 初始化adc 按钮 ESP_LOGI (TAG , "[ 4 ] Set up event listener"); audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG (); // 设置默认事件监听参数
audio_event_iface_handle_t evt = audio_event_iface_init (&evt_cfg ); // 初始化事件
87888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
audio_event_iface_handle_t evt = audio_event_iface_init (&evt_cfg ); // 初始化事件 ESP_LOGI (TAG , "[4.1] Listening event from all elements of pipeline"); audio_pipeline_set_listener (pipeline , evt ); // 监听管道的事件 ESP_LOGI (TAG , "[4.2] Listening event from peripherals"); audio_event_iface_set_listener (esp_periph_set_get_event_iface (set ), evt ); // 监听外设事件 ESP_LOGW (TAG , "[ 5 ] Tap touch buttons to control music player:"); ESP_LOGW (TAG , " [Play] to start, pause and resume, [Set] to stop."); ESP_LOGW (TAG , " [Vol-] or [Vol+] to adjust volume."); ESP_LOGI (TAG , "[ 5.1 ] Start audio_pipeline"); set_next_file_marker (); // 切换第⼀个⾳频 audio_pipeline_run (pipeline ); // 运⾏管道 while (1) { audio_event_iface_msg_t msg ; // 事件句柄 esp_err_t ret = audio_event_iface_listen (evt , &msg ,
portMAX_DELAY ); // 监听⾳频事件 if (ret != ESP_OK ) { continue ; } // 监听⾳频事件 if (msg .source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg .source == (void *)mp3_decoder && msg .cmd == AEL_MSG_CMD_REPORT_MU
{ audio_element_info_t music_info = {0}; audio_element_getinfo (mp3_decoder , &music_info ); // 获取⾳频信息 ESP_LOGI (TAG , "[ * ] Receive music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d", music_info .sample_rates , music_info .bits , music_info .channels ); // audio_element_setinfo(i2s_stream_writer, &music_info); // 设置⾳频信息 i2s_stream_set_clk (i2s_stream_writer , music_info .sample_rates , music_info .bits , music_info .channels ); // 通过music 信息初始化i2s 参数 continue ; } // 监听外设事件 if ((msg .source_type == PERIPH_ID_TOUCH || msg .source_type == PERIPH_ID_BUTTON || msg .source_type == PERIPH_ID_ADC_BTN ) && { // adc 按钮对应功能 if ((int )msg .data == get_input_play_id ()) { ESP_LOGI (TAG , "[ * ] [Play] touch tap event"); audio_element_state_t el_state = audio_element_get_state (i2s_stream_writer ); // 获取⾳频状态 switch (el_state ) { case AEL_STATE_INIT : ESP_LOGI (TAG , "[ * ] Starting audio pipeline"); audio_pipeline_run (pipeline ); // 运⾏管道 break ; case AEL_STATE_RUNNING : ESP_LOGI (TAG , "[ * ]
Pausing audio pipeline"); audio_pipeline_pause (pipeline ); // 暂停管道 break ; case AEL_STATE_PAUSED : ESP_LOGI (TAG , "[ * ] Resuming audio pipeline"); audio_pipeline_resume (pipeline ); // 恢复管道 break ; case AEL_STATE_FINISHED : ESP_LOGI (TAG , "[ * ] Rewinding audio pipeline"); audio_pipeline_reset_ringbuffer (pipeline ); // 重置环形缓冲区 audio_pipeline_reset_elements (pipeline ); // 重置管道链接元素 audio_pipeline_change_state (pipeline , AEL_STATE_INIT ); // 改变管道状态 set_next_file_marker (); // 切换⾳频
audio_pipeline_run (pipeline ); // 运⾏管道152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
audio_pipeline_run (pipeline ); // 运⾏管道 break ; default : ESP_LOGI (TAG , "[ * ] Not supported state %d", el_state ); } } else if ((int )msg .data == get_input_set_id ()) { ESP_LOGI (TAG , "[ * ] [Set] touch tap event"); ESP_LOGI (TAG , "[ * ] Stopping audio pipeline"); break ; } else if ((int )msg .data == get_input_mode_id ()) { ESP_LOGI (TAG , "[ * ] [mode] tap event"); audio_pipeline_stop (pipeline ); // 停⽌管道 audio_pipeline_wai
t_for_stop (pipeline ); // 等待管道停⽌ audio_pipeline_terminate (pipeline ); // 终⽌管道 audio_pipeline_reset_ringbuffer (pipeline ); // 重置环形缓冲区 audio_pipeline_reset_elements (pipeline ); // 重置管道链接元素 set_next_file_marker (); // 切换⾳频 audio_pipeline_run (pipeline ); // 运⾏管道 } else if ((int )msg .data == get_input_volup_id ()) { ESP_LOGI (TAG , "[ * ] [Vol+] touch tap event"); player_volume += 10; if (player_volume > 100) { player_volume = 100; } audio_hal_set_volume (board_handle ->audio_hal , player_volume ); // 设置⾳量 ESP_LOGI (TAG , "[ * ] Volume set to %d %%", player_volume ); } else if ((int )msg .data == get_input_voldown_id ()) { ESP_LOGI (TAG , "[ * ] [Vol-] touch tap event"); player_volume -= 10; if (player_volume < 0) { player_volume = 0; } audio_hal_set_volume (board_handle ->audio_hal , player_volume ); // 设置⾳量 ESP_LOGI (TAG , "[ * ] Volume set to %d %%", player_volume ); } } } ESP_LOGI (TAG , "[ 6 ] Stop audio_pipeline"); audio_pipeline_stop (pipeline ); // 停⽌管道 audio_pipeline_wait_for_stop (pipeline ); // 等待管道停⽌完毕 audio_pipeline_terminate (pipeline ); // 结束管道 audio_pipeline_unregister (pipeline , mp3_decoder ); // 卸载mp3流 audio_pipeline_unregister (pipeline , i2s_stream_writer ); // 卸载i2s 流 /* Terminate the pip
eline before removing the listener */ audio_pipeline_remove_listener (pipeline ); // 移除管道事件监听 /* Make sure audio_pipeline_remove_listener is called before destroying event_iface */ audio_event_iface_destroy (evt ); // 销毁事件监听 /* Release all resources */ audio_pipeline_deinit (pipeline ); // 注销管道 audio_element_deinit (i2s_stream_writer ); // 注销i2s 流 audio_element_deinit (mp3_decoder ); // 注销mp3流
}217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论