我是卓波,很高興你來看我的博客。
系列文章:
本文延續上一篇博客
將D:\msys32\home\user\esp\esp-adf\examples\get-started目錄下的play_mp3工程直接拷貝到esp目錄下
看一下代碼,代碼量也不多,核心是創建一個mp3元素和一個i2s元素,然后將兩個元素鏈接到管道中。
形成了mp3元素拿數據給i2s元素播放的關系。
/* Play mp3 file by audio pipeline 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" #include "audio_hal.h" static const char *TAG = "PLAY_MP3_FLASH"; /* To embed it in the app binary, the mp3 file is named in the component.mk COMPONENT_EMBED_TXTFILES variable. */ extern const uint8_t adf_music_mp3_start[] asm("_binary_adf_music_mp3_start"); extern const uint8_t adf_music_mp3_end[] asm("_binary_adf_music_mp3_end"); int mp3_music_read_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx) { static int mp3_pos; int read_size = adf_music_mp3_end - adf_music_mp3_start - mp3_pos; if (read_size == 0) { return AEL_IO_DONE; } else if (len < read_size) { read_size = len; } memcpy(buf, adf_music_mp3_start + mp3_pos, read_size); mp3_pos += read_size; return read_size; } void app_main(void) { audio_pipeline_handle_t pipeline; 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_hal_codec_config_t audio_hal_codec_cfg = AUDIO_HAL_ES8388_DEFAULT(); audio_hal_handle_t hal = audio_hal_init(&audio_hal_codec_cfg, 0); audio_hal_ctrl_codec(hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START); ESP_LOGI(TAG, "[ 2 ] Create audio 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); mem_assert(pipeline); 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_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_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT(); i2s_cfg.type = AUDIO_STREAM_WRITER; i2s_stream_writer = i2s_stream_init(&i2s_cfg); ESP_LOGI(TAG, "[2.3] Register all elements to audio pipeline"); audio_pipeline_register(pipeline, mp3_decoder, "mp3"); 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]"); audio_pipeline_link(pipeline, (const char *[]) {"mp3", "i2s"}, 2); ESP_LOGI(TAG, "[ 3 ] Setup 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); 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"); 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) { ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret); continue; } if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) mp3_decoder && msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) { 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); continue; } /* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */ if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_writer && msg.cmd == AEL_MSG_CMD_REPORT_STATUS && (int) msg.data == AEL_STATUS_STATE_STOPPED) { break; } } ESP_LOGI(TAG, "[ 5 ] Stop audio_pipeline"); audio_pipeline_terminate(pipeline); /* Terminate the pipeline 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); audio_element_deinit(mp3_decoder); }
然后根據上一篇介紹的方法編譯和下載
運行后在串口調試助手輸出
ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x3f (SPI_FAST_FLASH_BOOT) flash read err, 1000 ets_main.c 371 ets Jun 8 2016 00:22:57 rst:0x10 (RTCWDT_RTC_RESET),boot:0x3f (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3fff0018,len:4 load:0x3fff001c,len:5576 load:0x40078000,len:0 ho 12 tail 0 room 4 load:0x40078000,len:13756 entry 0x40078fb4 [0;32mI (31) boot: ESP-IDF v3.0.1 2nd stage bootloader[0m [0;32mI (31) boot: compile time 11:50:00[0m [0;32mI (33) boot: Enabling RNG early entropy source...[0m [0;32mI (35) boot: SPI Speed : 40MHz[0m [0;32mI (39) boot: SPI Mode : DIO[0m [0;32mI (43) boot: SPI Flash Size : 4MB[0m [0;32mI (47) boot: Partition Table:[0m [0;32mI (51) boot: ## Label Usage Type ST Offset Length[0m [0;32mI (58) boot: 0 nvs WiFi data 01 02 00009000 00006000[0m [0;32mI (66) boot: 1 phy_init RF data 01 01 0000f000 00001000[0m [0;32mI (73) boot: 2 factory factory app 00 00 00010000 00100000[0m [0;32mI (81) boot: End of partition table[0m [0;32mI (85) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x1f468 (128104) map[0m [0;32mI (139) esp_image: segment 1: paddr=0x0002f490 vaddr=0x3ffb0000 size=0x00b80 ( 2944) load[0m [0;32mI (140) esp_image: segment 2: paddr=0x00030018 vaddr=0x400d0018 size=0x21604 (136708) map[0m [0;32mI (193) esp_image: segment 3: paddr=0x00051624 vaddr=0x3ffb0b80 size=0x0169c ( 5788) load[0m [0;32mI (196) esp_image: segment 4: paddr=0x00052cc8 vaddr=0x40080000 size=0x00400 ( 1024) load[0m [0;32mI (200) esp_image: segment 5: paddr=0x000530d0 vaddr=0x40080400 size=0x09e80 ( 40576) load[0m [0;32mI (226) esp_image: segment 6: paddr=0x0005cf58 vaddr=0x400c0000 size=0x00000 ( 0) load[0m [0;32mI (232) boot: Loaded app from partition at offset 0x10000[0m [0;32mI (232) boot: Disabling RNG early entropy source...[0m [0;32mI (235) cpu_start: Pro cpu up.[0m [0;32mI (239) cpu_start: Starting app cpu, entry point is 0x40080ee4[0m [0;32mI (0) cpu_start: App cpu up.[0m [0;32mI (249) heap_init: Initializing. RAM available for dynamic allocation:[0m [0;32mI (256) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM[0m [0;32mI (262) heap_init: At 3FFB2A48 len 0002D5B8 (181 KiB): DRAM[0m [0;32mI (268) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM[0m [0;32mI (275) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM[0m [0;32mI (281) heap_init: At 4008A280 len 00015D80 (87 KiB): IRAM[0m [0;32mI (287) cpu_start: Pro cpu start user code[0m [0;32mI (305) cpu_start: Starting scheduler on PRO CPU.[0m [0;32mI (0) cpu_start: Starting scheduler on APP CPU.[0m [0;32mI (307) PLAY_MP3_FLASH: [ 1 ] Start audio codec chip[0m [0;32mI (327) PLAY_MP3_FLASH: [ 2 ] Create audio pipeline, add all elements to pipeline, and subscribe pipeline event[0m [0;32mI (327) PLAY_MP3_FLASH: [2.1] Create mp3 decoder to decode mp3 file and set custom read callback[0m [0;32mI (337) PLAY_MP3_FLASH: [2.2] Create i2s stream to write data to codec chip[0m [0;32mI (347) PLAY_MP3_FLASH: [2.3] Register all elements to audio pipeline[0m [0;32mI (357) PLAY_MP3_FLASH: [2.4] Link it together [mp3_music_read_cb]-->mp3_decoder-->i2s_stream-->[codec_chip][0m [0;32mI (367) PLAY_MP3_FLASH: [ 3 ] Setup event listener[0m [0;32mI (367) PLAY_MP3_FLASH: [3.1] Listening event from all elements of pipeline[0m [0;32mI (377) PLAY_MP3_FLASH: [ 4 ] Start audio_pipeline[0m [0;32mI (397) PLAY_MP3_FLASH: [ * ] Receive music info from mp3 decoder, sample_rates=44100, bits=16, ch=2[0m [0;32mI (7177) PLAY_MP3_FLASH: [ 5 ] Stop audio_pipeline[0m [0;33mW (7177) AUDIO_PIPELINE: There are no listener registered[0m
接上喇叭,就可以聽到音樂
關於idf和adf的api用法,官方有相關教程鏈接:
IDF: https://docs.espressif.com/projects/esp-idf/en/latest/
ADF: https://docs.espressif.com/projects/esp-adf/en/latest/
最后
本文主要介紹了運行adf的mp3播放例子的方法,在adf的examples文件夾下還有很多例子,親們可以去研究研究。
版權所有,轉載請打賞喲
如果你喜歡我的文章,可以通過微信掃一掃給我打賞喲