学习ADF框架,不能错过音乐播放,本篇博客记录如何通过SD卡播放音乐:
上代码前先看这两张图:
这两图基本就是ADF框架播放mp3的流程:首先将MP3解码器和I2S流两个元素添加进管道,解码器的输入是MP3文件数据流,I2S流将解码后的音频数据输出到片外,各应用程序之间通过事件接口通信。
上代码:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "board.h"
#include "audio_pipeline.h"
#include "fatfs_stream.h"
#include "i2s_stream.h"
#include "raw_stream.h"
#include "esp_audio.h"
#include "mp3_decoder.h"
#include "filter_resample.h"
#include "rec_eng_helper.h"
static const char *TAG = "SDCARD_MP3_EXAMPLE";
static esp_audio_handle_t setup_player() //播放器
{
esp_audio_handle_t player = NULL;
esp_audio_cfg_t cfg = DEFAULT_ESP_AUDIO_CONFIG();
audio_board_handle_t board_handle = audio_board_init();
cfg.vol_handle = board_handle->audio_hal; //音量
cfg.prefer_type = ESP_AUDIO_PREFER_MEM;
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
cfg.resample_rate = 16000;//设置重采样率
#else
cfg.resample_rate = 48000;
#endif
player = esp_audio_create(&cfg);
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);//音量
fatfs_stream_cfg_t fs_reader = FATFS_STREAM_CFG_DEFAULT();
fs_reader.type = AUDIO_STREAM_READER;
raw_stream_cfg_t raw_reader = RAW_STREAM_CFG_DEFAULT();
raw_reader.type = AUDIO_STREAM_READER;
esp_audio_input_stream_add(player, raw_stream_init(&raw_reader));//
esp_audio_input_stream_add(player, fatfs_stream_init(&fs_reader));//
mp3_decoder_cfg_t mp3_dec_cfg = DEFAULT_MP3_DECODER_CONFIG();
esp_audio_codec_lib_add(player, AUDIO_CODEC_TYPE_DECODER, mp3_decoder_init(&mp3_dec_cfg));//初始化mp3 decoder
i2s_stream_cfg_t i2s_writer = I2S_STREAM_CFG_DEFAULT();
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
i2s_writer.i2s_config.sample_rate = 16000;
#else
i2s_writer.i2s_config.sample_rate = 48000;
#endif
i2s_writer.type = AUDIO_STREAM_WRITER;
audio_element_handle_t i2s_stream_writer = i2s_stream_init(&i2s_writer);//初始化i2s stream
esp_audio_output_stream_add(player, i2s_stream_writer);
esp_audio_vol_set(player, 100);//设置音量
ESP_LOGI(TAG, "esp_audio instance is:%p\r\n", player);
return player;
}
void app_main()
{
#if defined CONFIG_ESP_LYRAT_V4_3_BOARD
gpio_config_t gpio_conf = {
.pin_bit_mask = 1UL << get_green_led_gpio(),//LED灯设置
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = 0,
.pull_down_en = 0,
.intr_type = 0
};
gpio_config(&gpio_conf);
#endif
esp_log_level_set("*", ESP_LOG_WARN);
esp_log_level_set(TAG, ESP_LOG_INFO);
audio_pipeline_handle_t pipeline; //管道
audio_element_handle_t i2s_stream_reader, filter, raw_read; //音频元素
esp_audio_handle_t player;
ESP_LOGI(TAG, "[ 1 ] Start codec chip");//初始化codec 芯片
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
audio_board_sdcard_init(esp_periph_set_init(&periph_cfg));
ESP_LOGI(TAG, "[ 2.0 ] Create audio pipeline for recording");//创建音频管道给recording
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
pipeline = audio_pipeline_init(&pipeline_cfg);
mem_assert(pipeline);
ESP_LOGI(TAG, "[ 2.1 ] Create i2s stream to read audio data from codec chip");//为读音频数据创建i2s stream
i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
i2s_cfg.i2s_config.sample_rate = 48000;
i2s_cfg.type = AUDIO_STREAM_READER;
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
i2s_cfg.i2s_config.sample_rate = 16000;
i2s_cfg.i2s_port = 1;
i2s_cfg.i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
i2s_stream_reader = i2s_stream_init(&i2s_cfg);//初始化i2s
#else
i2s_stream_reader = i2s_stream_init(&i2s_cfg);
ESP_LOGI(TAG, "[ 2.2 ] Create filter to resample audio data");//为重采样音频数据创建filter
rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
rsp_cfg.src_rate = 48000;
rsp_cfg.src_ch = 2;
rsp_cfg.dest_rate = 16000;
rsp_cfg.dest_ch = 1;
filter = rsp_filter_init(&rsp_cfg);
#endif
ESP_LOGI(TAG, "[ 2.3 ] Create raw to receive data");//为接收数据创建raw
raw_stream_cfg_t raw_cfg = {
.out_rb_size = 8 * 1024,
.type = AUDIO_STREAM_READER,
};
raw_read = raw_stream_init(&raw_cfg);
ESP_LOGI(TAG, "[ 3 ] Register all elements to audio pipeline");//注册所有元素到管道
audio_pipeline_register(pipeline, i2s_stream_reader, "i2s");
audio_pipeline_register(pipeline, raw_read, "raw");
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
ESP_LOGI(TAG, "[ 4 ] Link elements together [codec_chip]-->i2s_stream-->raw-->[SR]");
audio_pipeline_link(pipeline, (const char *[]) {"i2s", "raw"}, 2);
#else
audio_pipeline_register(pipeline, filter, "filter");
ESP_LOGI(TAG, "[ 4 ] Link elements together [codec_chip]-->i2s_stream-->filter-->raw-->[SR]");
audio_pipeline_link(pipeline, (const char *[]) {"i2s", "filter", "raw"}, 3);
#endif
player = setup_player();
ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");//开始音频管道
audio_pipeline_run(pipeline);
esp_audio_sync_play(player, "file://sdcard/test.mp3", 0);//SD卡里文件名为test的mp3文件
ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");//停止音频管道
audio_pipeline_terminate(pipeline);
/* Terminate the pipeline before removing the listener */
audio_pipeline_remove_listener(pipeline);
audio_pipeline_unregister(pipeline, raw_read);
audio_pipeline_unregister(pipeline, i2s_stream_reader);
audio_pipeline_unregister(pipeline, filter);
/* Release all resources */
audio_pipeline_deinit(pipeline);
audio_element_deinit(raw_read);
audio_element_deinit(i2s_stream_reader);
audio_element_deinit(filter);
ESP_LOGI(TAG, "[ 7 ] Destroy model");
}
此程序是根据ADF例程中\examples\speech_recognition\asr例程修改而来,和player文件里的例程有所不同!这个修改后的例程将播放器模块化,方便后面的程序调用,一句:esp_audio_sync_play();即可调用播放!后面将根据这个模块,结合语音唤醒和命令词做进一步修改!用语言控制播放!