diff --git a/examples/player/pipeline_sdcard_mp3_button_control/Makefile b/examples/player/pipeline_sdcard_mp3_button_control/Makefile new file mode 100644 index 00000000..e39b4813 --- /dev/null +++ b/examples/player/pipeline_sdcard_mp3_button_control/Makefile @@ -0,0 +1,2 @@ +PROJECT_NAME := play_sdcard_mp3_button_control +include $(ADF_PATH)/project.mk diff --git a/examples/player/pipeline_sdcard_mp3_button_control/README.md b/examples/player/pipeline_sdcard_mp3_button_control/README.md new file mode 100644 index 00000000..b26a6f47 --- /dev/null +++ b/examples/player/pipeline_sdcard_mp3_button_control/README.md @@ -0,0 +1,13 @@ +# Play MP3 files from microSD with butons control + +The demo plays MP3 files stored on the SD card using audio pipeline API. + +The playback control is done using buttons connected on GPIO32 and GPIO35. User can start, stop, pause, resume playback and advance to the next song. When playing, the application automatically advances to the next song once previous finishes. + +To run this example you need ESP32 LyraT or compatible board: + +- Connect speakers or headphones to the board. +- Insert a microSD card loaded with a MP3 files 'test.mp3', 'test1.mp3' and 'test2.mp3' into board's slot. +- Connect play button to GPIO35, next song button to GPIO32 + +Adding volume up/ down function just as same as examples/player/pipeline_sdcard_mp3_control diff --git a/examples/player/pipeline_sdcard_mp3_button_control/main/component.mk b/examples/player/pipeline_sdcard_mp3_button_control/main/component.mk new file mode 100644 index 00000000..44bd2b52 --- /dev/null +++ b/examples/player/pipeline_sdcard_mp3_button_control/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# diff --git a/examples/player/pipeline_sdcard_mp3_button_control/main/play_sdcard_mp3_button_control_example.c b/examples/player/pipeline_sdcard_mp3_button_control/main/play_sdcard_mp3_button_control_example.c new file mode 100644 index 00000000..e4bd1f6c --- /dev/null +++ b/examples/player/pipeline_sdcard_mp3_button_control/main/play_sdcard_mp3_button_control_example.c @@ -0,0 +1,281 @@ +/* Control with buttons playing MP3 files from SD Card + + Function ---- ESP32 Pin + BUTTON_NEXT 32 + BUTTON_PLAY 35 + + 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 +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "audio_element.h" +#include "audio_pipeline.h" +#include "audio_event_iface.h" +#include "audio_common.h" +#include "fatfs_stream.h" +#include "i2s_stream.h" +#include "mp3_decoder.h" + +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "periph_button.h" +#include "audio_hal.h" +#include "board.h" + +static const char *TAG = "SDCARD_MP3_CONTROL_EXAMPLE"; + +#define BUTTON_NEXT 32 +#define BUTTON_PLAY 35 +#define GPIO_INPUT_PIN_SEL ( (1ULL< MP3_FILE_COUNT - 1) { + file_index = 0; + } + if (file != NULL) { + fclose(file); + file = NULL; + } + } + // return a handle to the current file + if (file == NULL) { + file = fopen(mp3_file[file_index], "r"); + if (!file) { + ESP_LOGE(TAG, "Error opening file"); + return NULL; + } + } + return file; +} + +/* + * Callback function to feed audio data stream from sdcard to mp3 decoder element + */ +static int my_sdcard_read_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx) +{ + int read_len = fread(buf, 1, len, get_file(CURRENT)); + if (read_len == 0) { + read_len = AEL_IO_DONE; + } + return read_len; +} + + +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.0] Initialize peripherals management"); + esp_periph_config_t periph_cfg = { 0 }; + esp_periph_init(&periph_cfg); + + ESP_LOGI(TAG, "[1.1] Start SD card peripheral"); + periph_sdcard_cfg_t sdcard_cfg = { + .root = "/sdcard", + .card_detect_pin = SD_CARD_INTR_GPIO, //GPIO_NUM_34 + }; + esp_periph_handle_t sdcard_handle = periph_sdcard_init(&sdcard_cfg); + ESP_LOGI(TAG, "[1.2] Start SD card peripheral"); + esp_periph_start(sdcard_handle); + + // Wait until sdcard was mounted + while (!periph_sdcard_is_mounted(sdcard_handle)) { + vTaskDelay(100 / portTICK_PERIOD_MS); + } + + ESP_LOGI(TAG, "[1.3] Initialize Touch peripheral"); + periph_button_cfg_t button_cfg = { + .gpio_mask = GPIO_INPUT_PIN_SEL, + .long_press_time_ms = 1000, + }; + esp_periph_handle_t button_periph = periph_button_init(&button_cfg); + + ESP_LOGI(TAG, "[1.4] Start touch peripheral"); + esp_periph_start(button_periph); + + ESP_LOGI(TAG, "[ 2 ] Start codec chip"); + audio_hal_codec_config_t audio_hal_codec_cfg = AUDIO_HAL_ES8388_DEFAULT(); + audio_hal_codec_cfg.i2s_iface.samples = AUDIO_HAL_44K_SAMPLES; + 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); + int player_volume; + audio_hal_get_volume(hal, &player_volume); + + ESP_LOGI(TAG, "[3.0] Create audio pipeline for playback"); + audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG(); + pipeline = audio_pipeline_init(&pipeline_cfg); + mem_assert(pipeline); + + ESP_LOGI(TAG, "[3.1] 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, "[3.2] Create mp3 decoder to decode mp3 file"); + mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG(); + mp3_decoder = mp3_decoder_init(&mp3_cfg); + audio_element_set_read_cb(mp3_decoder, my_sdcard_read_cb, NULL); + + ESP_LOGI(TAG, "[3.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, "[3.4] Link it together [my_sdcard_read_cb]-->mp3_decoder-->i2s_stream-->[codec_chip]"); + audio_pipeline_link(pipeline, (const char *[]) {"mp3", "i2s"}, 2); + + ESP_LOGI(TAG, "[4.0] 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, "[4.1] Listen for all pipeline events"); + audio_pipeline_set_listener(pipeline, evt); + + ESP_LOGI(TAG, "[4.2] Listening event from peripherals"); + audio_event_iface_set_listener(esp_periph_get_event_iface(), evt); + + ESP_LOGW(TAG, "[ 5 ] Tap touch buttons to control music player:"); + ESP_LOGW(TAG, " [Play] to start, pause and resume, [Set] next song."); + //ESP_LOGW(TAG, " [Vol-] or [Vol+] to adjust volume."); + + while (1) { + /* Handle event interface messages from pipeline + to set music info and to advance to the next song + */ + 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){ + // Set music info for a new song to be played + if (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, "[ * ] Received music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d, volume=%d, codec_fmt=%d", + music_info.sample_rates, music_info.bits, music_info.channels, music_info.volume, music_info.codec_fmt); + 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; + } + // Advance to the next song when previous finishes + if (msg.source == (void *) i2s_stream_writer + && msg.cmd == AEL_MSG_CMD_REPORT_STATUS) { + audio_element_state_t el_state = audio_element_get_state(i2s_stream_writer); + if (el_state == AEL_STATE_FINISHED) { + ESP_LOGI(TAG, "[ * ] Finished, advancing to the next song"); + audio_pipeline_stop(pipeline); + get_file(NEXT); + audio_pipeline_resume(pipeline); + } + continue; + } + } + /* Handle touch pad events + to start, pause, resume, finish current song and adjust volume + */ + if (msg.source_type == PERIPH_ID_BUTTON + && msg.cmd == PERIPH_BUTTON_PRESSED + && msg.source == (void *)button_periph) { + if ((int) msg.data == BUTTON_PLAY) { + 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; + default : + ESP_LOGI(TAG, "[ * ] Not supported state %d", el_state); + } + } else if ((int) msg.data == BUTTON_NEXT) { + ESP_LOGI(TAG, "[ * ] [Set] touch tap event"); + ESP_LOGI(TAG, "[ * ] Finishing current song"); + // Stop the current song playing + audio_pipeline_stop(pipeline); + audio_pipeline_wait_for_stop(pipeline); + // Run the pipeline again so 'AEL_STATE_FINISHED' state is reported + audio_pipeline_run(pipeline); + // Application seeing 'AEL_STATE_FINISHED' should then advance to the next song + } + /* + else if ((int) msg.data == BUTTON_VOLUP) { + ESP_LOGI(TAG, "[ * ] [Vol+] touch tap event"); + player_volume += 10; + if (player_volume > 100) { + player_volume = 100; + } + audio_hal_set_volume(hal, player_volume); + ESP_LOGI(TAG, "[ * ] Volume set to %d %%", player_volume); + } else if ((int) msg.data == BUTTON_VOLDWN) { + ESP_LOGI(TAG, "[ * ] [Vol-] touch tap event"); + player_volume -= 10; + if (player_volume < 0) { + player_volume = 0; + } + audio_hal_set_volume(hal, player_volume); + ESP_LOGI(TAG, "[ * ] Volume set to %d %%", player_volume); + } + */ + } + } + + ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline"); + audio_pipeline_terminate(pipeline); + + /* Terminate the pipeline before removing the listener */ + audio_pipeline_remove_listener(pipeline); + + /* Stop all peripherals before removing the listener */ + esp_periph_stop_all(); + audio_event_iface_remove_listener(esp_periph_get_event_iface(), evt); + + /* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are 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); + esp_periph_destroy(); +} diff --git a/examples/useed/useed_toy_printer/.cproject b/examples/useed/useed_toy_printer/.cproject new file mode 100644 index 00000000..f26502db --- /dev/null +++ b/examples/useed/useed_toy_printer/.cproject @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + python + ${IDF_PATH}/tools/windows/eclipse_make.py + all -j9 + true + true + true + + + python + ${IDF_PATH}/tools/windows/eclipse_make.py + flash -j9 + true + true + true + + + + diff --git a/examples/useed/useed_toy_printer/.project b/examples/useed/useed_toy_printer/.project new file mode 100644 index 00000000..cedc6792 --- /dev/null +++ b/examples/useed/useed_toy_printer/.project @@ -0,0 +1,27 @@ + + + useed_toy_printer + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/examples/useed/useed_toy_printer/Makefile b/examples/useed/useed_toy_printer/Makefile new file mode 100644 index 00000000..8f8a1cb3 --- /dev/null +++ b/examples/useed/useed_toy_printer/Makefile @@ -0,0 +1,2 @@ +PROJECT_NAME := useed_toy_printer +include $(ADF_PATH)/project.mk diff --git a/examples/useed/useed_toy_printer/README.md b/examples/useed/useed_toy_printer/README.md new file mode 100644 index 00000000..ea7b971d --- /dev/null +++ b/examples/useed/useed_toy_printer/README.md @@ -0,0 +1,5 @@ +# Play mp3 file with a custom callback + +This example plays a sample 7 second mp3 file provided in 'main' folder. The file gets embedded in the application during compilation. After application upload the file is then played from ESP32's internal flash. + +To run this example you need ESP32 LyraT or compatible board with speakers or headphones connected. diff --git a/examples/useed/useed_toy_printer/main/Kconfig.projbuild b/examples/useed/useed_toy_printer/main/Kconfig.projbuild new file mode 100644 index 00000000..f39c8b86 --- /dev/null +++ b/examples/useed/useed_toy_printer/main/Kconfig.projbuild @@ -0,0 +1,21 @@ +menu "Useed Toy Printer Config" + +menu "Wifi Config" + +config WIFI_SSID + string "WiFi SSID" + default "useedtech" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "useedtech2555" + help + WiFi password (WPA or WPA2) for the example to use. + + Can be left blank if the network has no security set. + +endmenu + +endmenu \ No newline at end of file diff --git a/examples/useed/useed_toy_printer/main/adf_music.mp3 b/examples/useed/useed_toy_printer/main/adf_music.mp3 new file mode 100644 index 00000000..40147bc1 Binary files /dev/null and b/examples/useed/useed_toy_printer/main/adf_music.mp3 differ diff --git a/examples/useed/useed_toy_printer/main/component.mk b/examples/useed/useed_toy_printer/main/component.mk new file mode 100644 index 00000000..8a26779c --- /dev/null +++ b/examples/useed/useed_toy_printer/main/component.mk @@ -0,0 +1,5 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# + +COMPONENT_EMBED_TXTFILES := adf_music.mp3 diff --git a/examples/useed/useed_toy_printer/main/useed_toy_printer_main.c b/examples/useed/useed_toy_printer/main/useed_toy_printer_main.c new file mode 100644 index 00000000..88a1d183 --- /dev/null +++ b/examples/useed/useed_toy_printer/main/useed_toy_printer_main.c @@ -0,0 +1,344 @@ +/* Control with buttons playing MP3 files from SD Card + + Function ---- ESP32 Pin + BUTTON_NEXT 32 + BUTTON_PLAY 35 + + 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 +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "audio_element.h" +#include "audio_pipeline.h" +#include "audio_event_iface.h" +#include "audio_common.h" +#include "fatfs_stream.h" +#include "i2s_stream.h" +#include "mp3_decoder.h" + +#include "esp_peripherals.h" +#include "periph_sdcard.h" +#include "periph_console.h" +#include "periph_button.h" +#include "audio_hal.h" +#include "board.h" + +static const char *TAG = "SDCARD_MP3_CONTROL_EXAMPLE"; + +#define BUTTON_NEXT 32 +#define BUTTON_PLAY 35 +#define GPIO_INPUT_PIN_SEL ( (1ULL< MP3_FILE_COUNT - 1) { + file_index = 0; + } + if (file != NULL) { + fclose(file); + file = NULL; + } + } + // return a handle to the current file + if (file == NULL) { + file = fopen(mp3_file[file_index], "r"); + if (!file) { + ESP_LOGE(TAG, "Error opening file"); + return NULL; + } + } + return file; +} + +static esp_err_t cli_play(esp_periph_handle_t periph, int argc, char *argv[]) +{ + 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; + default : + ESP_LOGI(TAG, "[ * ] Not supported state %d", el_state); + break; + } + + return ESP_OK; +} + +static esp_err_t cli_next(esp_periph_handle_t periph, int argc, char *argv[]) +{ + ESP_LOGI(TAG, "[ * ] [Set] touch tap event"); + ESP_LOGI(TAG, "[ * ] Finishing current song"); + // Stop the current song playing + audio_pipeline_stop(pipeline); + audio_pipeline_wait_for_stop(pipeline); + // Run the pipeline again so 'AEL_STATE_FINISHED' state is reported + audio_pipeline_run(pipeline); + // Application seeing 'AEL_STATE_FINISHED' should then advance to the next song + + return ESP_OK; +} + +const periph_console_cmd_t cli_cmd[] = { + /* ======================== Esp_audio ======================== */ + { .cmd = "play", .id = 1, .help = "Play music", .func = cli_play }, + { .cmd = "next", .id = 2, .help = "Next song", .func = cli_next }, +}; + +static void cli_setup_console() +{ + periph_console_cfg_t console_cfg = { + .command_num = sizeof(cli_cmd) / sizeof(periph_console_cmd_t), + .commands = cli_cmd, + }; + esp_periph_handle_t console_handle = periph_console_init(&console_cfg); + esp_periph_start(console_handle); +} + +/* + * Callback function to feed audio data stream from sdcard to mp3 decoder element + */ +static int my_sdcard_read_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx) +{ + int read_len = fread(buf, 1, len, get_file(CURRENT)); + if (read_len == 0) { + read_len = AEL_IO_DONE; + } + return read_len; +} + + +void app_main(void) +{ + esp_log_level_set("*", ESP_LOG_WARN); + esp_log_level_set(TAG, ESP_LOG_INFO); + + ESP_LOGI(TAG, "[1.0] Initialize peripherals management"); + esp_periph_config_t periph_cfg = { 0 }; + esp_periph_init(&periph_cfg); + + cli_setup_console(); + + ESP_LOGI(TAG, "[1.1] Start SD card peripheral"); + periph_sdcard_cfg_t sdcard_cfg = { + .root = "/sdcard", + .card_detect_pin = SD_CARD_INTR_GPIO, //GPIO_NUM_34 + }; + esp_periph_handle_t sdcard_handle = periph_sdcard_init(&sdcard_cfg); + ESP_LOGI(TAG, "[1.2] Start SD card peripheral"); + esp_periph_start(sdcard_handle); + + // Wait until sdcard was mounted + while (!periph_sdcard_is_mounted(sdcard_handle)) { + vTaskDelay(100 / portTICK_PERIOD_MS); + } + + ESP_LOGI(TAG, "[1.3] Initialize Touch peripheral"); + periph_button_cfg_t button_cfg = { + .gpio_mask = GPIO_INPUT_PIN_SEL, + .long_press_time_ms = 1000, + }; + esp_periph_handle_t button_periph = periph_button_init(&button_cfg); + + ESP_LOGI(TAG, "[1.4] Start touch peripheral"); + esp_periph_start(button_periph); + + /* + ESP_LOGI(TAG, "[ 2 ] Start codec chip"); + audio_hal_codec_config_t audio_hal_codec_cfg = AUDIO_HAL_ES8388_DEFAULT(); + audio_hal_codec_cfg.i2s_iface.samples = AUDIO_HAL_44K_SAMPLES; + 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); + int player_volume; + audio_hal_get_volume(hal, &player_volume); + */ + + ESP_LOGI(TAG, "[3.0] Create audio pipeline for playback"); + audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG(); + pipeline = audio_pipeline_init(&pipeline_cfg); + mem_assert(pipeline); + + ESP_LOGI(TAG, "[3.1] 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, "[3.2] Create mp3 decoder to decode mp3 file"); + mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG(); + mp3_decoder = mp3_decoder_init(&mp3_cfg); + audio_element_set_read_cb(mp3_decoder, my_sdcard_read_cb, NULL); + + ESP_LOGI(TAG, "[3.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, "[3.4] Link it together [my_sdcard_read_cb]-->mp3_decoder-->i2s_stream-->[codec_chip]"); + audio_pipeline_link(pipeline, (const char *[]) {"mp3", "i2s"}, 2); + + ESP_LOGI(TAG, "[4.0] 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, "[4.1] Listen for all pipeline events"); + audio_pipeline_set_listener(pipeline, evt); + + ESP_LOGI(TAG, "[4.2] Listening event from peripherals"); + audio_event_iface_set_listener(esp_periph_get_event_iface(), evt); + + ESP_LOGW(TAG, "[ 5 ] Tap touch buttons to control music player:"); + ESP_LOGW(TAG, " [Play] to start, pause and resume, [Set] next song."); + //ESP_LOGW(TAG, " [Vol-] or [Vol+] to adjust volume."); + + while (1) { + /* Handle event interface messages from pipeline + to set music info and to advance to the next song + */ + 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){ + // Set music info for a new song to be played + if (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, "[ * ] Received music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d, volume=%d, codec_fmt=%d", + music_info.sample_rates, music_info.bits, music_info.channels, music_info.volume, music_info.codec_fmt); + 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; + } + // Advance to the next song when previous finishes + if (msg.source == (void *) i2s_stream_writer + && msg.cmd == AEL_MSG_CMD_REPORT_STATUS) { + audio_element_state_t el_state = audio_element_get_state(i2s_stream_writer); + if (el_state == AEL_STATE_FINISHED) { + ESP_LOGI(TAG, "[ * ] Finished, advancing to the next song"); + audio_pipeline_stop(pipeline); + get_file(NEXT); + audio_pipeline_resume(pipeline); + } + continue; + } + } + /* Handle touch pad events + to start, pause, resume, finish current song and adjust volume + */ + if (msg.source_type == PERIPH_ID_BUTTON + && msg.cmd == PERIPH_BUTTON_PRESSED + && msg.source == (void *)button_periph) { + if ((int) msg.data == BUTTON_PLAY) { + 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; + default : + ESP_LOGI(TAG, "[ * ] Not supported state %d", el_state); + break; + } + } else if ((int) msg.data == BUTTON_NEXT) { + ESP_LOGI(TAG, "[ * ] [Set] touch tap event"); + ESP_LOGI(TAG, "[ * ] Finishing current song"); + // Stop the current song playing + audio_pipeline_stop(pipeline); + audio_pipeline_wait_for_stop(pipeline); + // Run the pipeline again so 'AEL_STATE_FINISHED' state is reported + audio_pipeline_run(pipeline); + // Application seeing 'AEL_STATE_FINISHED' should then advance to the next song + } + /* + else if ((int) msg.data == BUTTON_VOLUP) { + ESP_LOGI(TAG, "[ * ] [Vol+] touch tap event"); + player_volume += 10; + if (player_volume > 100) { + player_volume = 100; + } + audio_hal_set_volume(hal, player_volume); + ESP_LOGI(TAG, "[ * ] Volume set to %d %%", player_volume); + } else if ((int) msg.data == BUTTON_VOLDWN) { + ESP_LOGI(TAG, "[ * ] [Vol-] touch tap event"); + player_volume -= 10; + if (player_volume < 0) { + player_volume = 0; + } + audio_hal_set_volume(hal, player_volume); + ESP_LOGI(TAG, "[ * ] Volume set to %d %%", player_volume); + } + */ + } + } + + ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline"); + audio_pipeline_terminate(pipeline); + + /* Terminate the pipeline before removing the listener */ + audio_pipeline_remove_listener(pipeline); + + /* Stop all peripherals before removing the listener */ + esp_periph_stop_all(); + audio_event_iface_remove_listener(esp_periph_get_event_iface(), evt); + + /* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are 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); + esp_periph_destroy(); +}