algorithm example not working on lyrat mini v1.2 (AUD-6461)
Environment
- Audio development kit: [ESP32-LyraT-Mini|]
- Audio kit version (fESP32-LyraT-Mini]
- [Required] Module or chip used: [ESP32-WROVER-E]
- [Required] IDF version: v5.4
- [Required] ADF version: v2.7-105-g4200c64d
- Build system: [CMake]
- [Required] Running log:
`--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x13 (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:1 load:0x3fff0030,len:6592 load:0x40078000,len:16664 load:0x40080400,len:4 --- 0x40080400: _init at ??:?
ho 8 tail 4 room 4
load:0x40080404,len:4268
entry 0x40080658
I (31) boot: ESP-IDF v5.4-dirty 2nd stage bootloader
I (31) boot: compile time Jun 20 2025 08:12:10
I (31) boot: Multicore bootloader
I (33) boot: chip revision: v3.1
I (36) qio_mode: Enabling default flash chip QIO
I (40) boot.esp32: SPI Speed : 80MHz
I (44) boot.esp32: SPI Mode : QIO
I (47) boot.esp32: SPI Flash Size : 8MB
I (51) boot: Enabling RNG early entropy source...
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (64) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (71) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (77) boot: 2 factory factory app 00 00 00010000 00200000
I (84) boot: 3 model Unknown data 01 82 00210000 00200000
I (90) boot: End of partition table
I (94) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=1e314h (123668) map
I (133) esp_image: segment 1: paddr=0002e33c vaddr=3ff80000 size=0001ch ( 28) load
I (133) esp_image: segment 2: paddr=0002e360 vaddr=3ffb0000 size=01cb8h ( 7352) load
I (139) esp_image: segment 3: paddr=00030020 vaddr=400d0020 size=43e04h (278020) map
I (215) esp_image: segment 4: paddr=00073e2c vaddr=3ffb1cb8 size=020d0h ( 8400) load
I (218) esp_image: segment 5: paddr=00075f04 vaddr=40080000 size=13534h ( 79156) load
I (252) boot: Loaded app from partition at offset 0x10000
I (252) boot: Disabling RNG early entropy source...
I (262) quad_psram: This chip is ESP32-D0WD
I (263) esp_psram: Found 8MB PSRAM device
I (263) esp_psram: Speed: 80MHz
I (263) esp_psram: PSRAM initialized, cache is in low/high (2-core) mode.
W (270) esp_psram: Virtual address not enough for PSRAM, map as much as we can. 4MB is mapped
I (278) cpu_start: Multicore app
I (795) esp_psram: SPI SRAM memory test OK
I (803) cpu_start: Pro cpu start user code
I (803) cpu_start: cpu freq: 240000000 Hz
I (803) app_init: Application information:
I (803) app_init: Project name: algorithm_examples
I (808) app_init: App version: 1
I (811) app_init: Compile time: Jun 20 2025 08:15:10
I (816) app_init: ELF file SHA256: 5b7789baa...
I (820) app_init: ESP-IDF: v5.4-dirty
I (825) efuse_init: Min chip rev: v0.0
I (828) efuse_init: Max chip rev: v3.99
I (832) efuse_init: Chip rev: v3.1
I (836) heap_init: Initializing. RAM available for dynamic allocation:
I (843) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (848) heap_init: At 3FFB4A28 len 0002B5D8 (173 KiB): DRAM
I (853) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (858) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (864) heap_init: At 40093534 len 0000CACC (50 KiB): IRAM
I (869) esp_psram: Adding pool of 4096K of PSRAM memory to heap allocator
I (876) spi_flash: detected chip: gd
I (879) spi_flash: flash io: qio
W (882) ADC: legacy driver is deprecated, please migrate to esp_adc/adc_oneshot.h
I (890) main_task: Started on CPU0
I (893) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations
I (900) main_task: Calling app_main()
I (904) ALGORITHM_EXAMPLES: [2.0] Start codec chip
W (909) i2c_bus_v2: I2C master handle is NULL, will create new one
I (920) DRV8311: ES8311 in Slave mode
I (931) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (977) AUDIO_HAL: Codec mode is 3, Ctrl:1
I (984) ALGORITHM_EXAMPLES: [3.0] Create audio pipeline_rec for recording
I (984) ALGORITHM_EXAMPLES: [3.1] Create algorithm stream for aec
I (991) MODEL_LOADER: The storage free size is 3968 KB
I (991) MODEL_LOADER: The partition size is 2048 KB
I (1000) MODEL_LOADER: Successfully load srmodels
I (1000) ALGORITHM_EXAMPLES: [3.4] Register all elements to audio pipeline_rec
I (1006) ALGORITHM_EXAMPLES: [3.5] Link it together [codec_chip]-->aec-->wav_encoder-->fatfs_stream-->[sdcard]
I (1016) ALGORITHM_EXAMPLES: [5.0] Set up event listener
I (1021) ALGORITHM_EXAMPLES: [5.2] Listening event from peripherals
I (1027) ALGORITHM_EXAMPLES: [6.0] Start audio_pipeline
I (1032) AUDIO_THREAD: The aec task allocate stack on external memory
I (1039) AUDIO_ELEMENT: [aec-0x3f8018d0] Element task created
I (1043) AUDIO_PIPELINE: Func:audio_pipeline_run, Line:359, MEM Total:4425168 Bytes, Inter:332975 Bytes, Dram:281919 Bytes, Dram largest free:118784Bytes
I (1057) AUDIO_ELEMENT: [aec] AEL_MSG_CMD_RESUME,state:1 I (1123) AFE: AFE Version: (1MIC_V250121) I (1123) AFE: Input PCM Config: total 2 channels(1 microphone, 1 playback), sample rate:16000 I (1126) AFE: AFE Pipeline: [input] -> |AEC(VOIP_LOW_COST)| -> |NS(WebRTC)| -> [output] I (1135) AUDIO_THREAD: The algo_fetch task allocate stack on external memory I (1160) AUDIO_PIPELINE: Pipeline started I (1161) ALGORITHM_EXAMPLES: [7.0] Listen for all pipeline events`
- Operating system: [Windows]
- Using an IDE?: espressif ide
- Power supply: [USB]
Problem Description
I made loopback by connecting the algorithm input to the speaker output. I want to hear the echo cancellation performance live. There is noisy sound in the algorithm output. The microphone is not working properly. RECORD_HARDWARE_AEC variable is set to true.
Code to Reproduce This Issue
/* Algorithm Example
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 "driver/i2s.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "board.h"
#include "es8311.h"
#ifdef CONFIG_ESP32_S3_KORVO2_V3_BOARD
#include "es7210.h"
#endif /* CONFIG_ESP32_S3_KORVO2_V3_BOARD */
#include "fatfs_stream.h"
#include "i2s_stream.h"
#include "algorithm_stream.h"
#include "wav_encoder.h"
#include "mp3_decoder.h"
#include "filter_resample.h"
#include "audio_mem.h"
#include "audio_sys.h"
#include "audio_idf_version.h"
static const char *TAG = "ALGORITHM_EXAMPLES";
/* Debug original input data for AEC feature*/
// #define DEBUG_ALGO_INPUT
#define I2S_SAMPLE_RATE 16000
#if CONFIG_ESP_LYRAT_MINI_V1_1_BOARD || CONFIG_ESP32_S3_KORVO2L_V1_BOARD
#define I2S_CHANNELS I2S_CHANNEL_FMT_RIGHT_LEFT
#else
#define I2S_CHANNELS I2S_CHANNEL_FMT_ONLY_LEFT
#endif
#define I2S_BITS CODEC_ADC_BITS_PER_SAMPLE
/* The AEC internal buffering mechanism requires that the recording signal
is delayed by around 0 - 10 ms compared to the corresponding reference (playback) signal. */
#define DEFAULT_REF_DELAY_MS 0
#define ESP_RING_BUFFER_SIZE 256
extern const uint8_t adf_music_mp3_start[] asm("_binary_test_mp3_start");
extern const uint8_t adf_music_mp3_end[] asm("_binary_test_mp3_end");
#if !RECORD_HARDWARE_AEC
static ringbuf_handle_t ringbuf_ref;
#endif
static audio_element_handle_t i2s_stream_reader;
static audio_element_handle_t i2s_stream_writter;
static int i2s_read_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
size_t bytes_read = audio_element_input(i2s_stream_reader, buf, len);
if (bytes_read > 0) {
#if (CONFIG_IDF_TARGET_ESP32 && !RECORD_HARDWARE_AEC)
algorithm_mono_fix((uint8_t *)buf, bytes_read);
#endif
} else {
ESP_LOGE(TAG, "i2s read failed");
}
return bytes_read;
}
static int i2s_write_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
int bytes_write = 0;
#if !RECORD_HARDWARE_AEC
if (rb_write(ringbuf_ref, buf, len, wait_time) <= 0) {
ESP_LOGW(TAG, "ringbuf write timeout");
}
#endif
#if (CONFIG_IDF_TARGET_ESP32 && !RECORD_HARDWARE_AEC)
algorithm_mono_fix((uint8_t *)buf, len);
#endif
bytes_write = audio_element_output(i2s_stream_writter, buf, len);
if (bytes_write < 0) {
ESP_LOGE(TAG, "i2s write failed");
}
return bytes_write;
}
void app_main()
{
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_INFO);
// Initialize peripherals management
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
ESP_LOGI(TAG, "[2.0] Start codec chip");
i2s_stream_cfg_t i2s_w_cfg = I2S_STREAM_CFG_DEFAULT_WITH_PARA(I2S_NUM_0, I2S_SAMPLE_RATE, I2S_BITS, AUDIO_STREAM_WRITER);
i2s_w_cfg.task_stack = -1;
i2s_w_cfg.need_expand = (16 != I2S_BITS);
i2s_stream_set_channel_type(&i2s_w_cfg, I2S_CHANNELS);
i2s_stream_writter = i2s_stream_init(&i2s_w_cfg);
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);
audio_hal_set_volume(board_handle->audio_hal, 80);
i2s_stream_cfg_t i2s_r_cfg = I2S_STREAM_CFG_DEFAULT_WITH_PARA(CODEC_ADC_I2S_PORT, I2S_SAMPLE_RATE, I2S_BITS, AUDIO_STREAM_READER);
i2s_r_cfg.task_stack = -1;
i2s_stream_set_channel_type(&i2s_r_cfg, I2S_CHANNELS);
i2s_stream_reader = i2s_stream_init(&i2s_r_cfg);
ESP_LOGI(TAG, "[3.0] Create audio pipeline_rec for recording");
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
audio_pipeline_handle_t pipeline_rec = audio_pipeline_init(&pipeline_cfg);
mem_assert(pipeline_rec);
ESP_LOGI(TAG, "[3.1] Create algorithm stream for aec");
algorithm_stream_cfg_t algo_config = ALGORITHM_STREAM_CFG_DEFAULT();
algo_config.input_format = "RM";
#if !RECORD_HARDWARE_AEC
algo_config.input_type = ALGORITHM_STREAM_INPUT_TYPE2;
#endif
#if CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
algo_config.ref_linear_factor = 3;
#endif
#ifdef DEBUG_ALGO_INPUT
algo_config.debug_input = true;
#endif
algo_config.sample_rate = I2S_SAMPLE_RATE;
algo_config.out_rb_size = ESP_RING_BUFFER_SIZE;
audio_element_handle_t element_algo = algo_stream_init(&algo_config);
audio_element_set_music_info(element_algo, I2S_SAMPLE_RATE, 1, ALGORITHM_STREAM_DEFAULT_SAMPLE_BIT);
audio_element_set_read_cb(element_algo, i2s_read_cb, NULL);
audio_element_set_input_timeout(element_algo, portMAX_DELAY);
audio_element_set_write_cb(element_algo, i2s_write_cb, NULL);
audio_element_set_output_timeout(element_algo, portMAX_DELAY);
ESP_LOGI(TAG, "[3.4] Register all elements to audio pipeline_rec");
audio_pipeline_register(pipeline_rec, element_algo, "aec");
ESP_LOGI(TAG, "[3.5] Link it together [codec_chip]-->aec-->wav_encoder-->fatfs_stream-->[sdcard]");
const char *link_rec[1] = {"aec"};
audio_pipeline_link(pipeline_rec, &link_rec[0], 1);
#if !RECORD_HARDWARE_AEC
// Please reference the way of ALGORITHM_STREAM_INPUT_TYPE2 in "algorithm_stream.h"
ringbuf_ref = rb_create(ALGORITHM_STREAM_RINGBUFFER_SIZE, 1);
audio_element_set_multi_input_ringbuf(element_algo, ringbuf_ref, 0);
/* When the playback signal far ahead of the recording signal,
the playback signal needs to be delayed */
algo_stream_set_delay(element_algo, ringbuf_ref, DEFAULT_REF_DELAY_MS);
#endif
ESP_LOGI(TAG, "[5.0] 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);
ESP_LOGI(TAG, "[5.2] Listening event from peripherals");
audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);
ESP_LOGI(TAG, "[6.0] Start audio_pipeline");
audio_pipeline_run(pipeline_rec);
ESP_LOGI(TAG, "[7.0] Listen for all pipeline events");
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;
}
}
ESP_LOGI(TAG, "[8.0] Stop audio_pipeline");
audio_pipeline_stop(pipeline_rec);
audio_pipeline_wait_for_stop(pipeline_rec);
audio_pipeline_deinit(pipeline_rec);
audio_element_deinit(i2s_stream_reader);
audio_element_deinit(i2s_stream_writter);
/* Terminate the pipeline before removing the listener */
/* Stop all periph before removing the listener */
esp_periph_set_stop_all(set);
audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), evt);
/* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
audio_event_iface_destroy(evt);
esp_periph_set_destroy(set);
}
The speaker's output is the voice signal captured by the microphone. If used as a reference signal, it may have high correlation with the input signal, causing AEC errors. May I ask what specific requirement this test is trying to address? If the goal is to verify AEC performance, you can save the results to an SD card for analysis.
Hi all, Thank you for your answer.
The speaker's output is the voice signal output by the algorithm. I'm not using microphone or referance input directly. The algorithm is used as in the example, I don't understand the difference. The dac output reference signal comes from the i2s left channel and the right channel is the microphone. As in the example. Isn't the aec algorithm used this way? Please correct me if I'm wrong.
This is the point I particularly wanted to test in this example. I tried the same algorithm with the ring buffered version on my special development card other than Lyrat and I could see the difference of the algorithm on the echo. The problem is that my own development card does not have 2 ADC inputs, I applied this example with the reference buffer. I want to test the AEC performance with synchronous i2s data without using the ring buffer on Lyrat.
Technically, can I import the aec algorithm into pipeline_a2dp_sink_and_hfp application using esp32?
When I try to add it using the aec ring buffered version in the hf application, the aec algorithm has no effect. In the hf application, the microphone on the esp side only delays the sound by 4 seconds.
Thank you for your question. After testing, we found that you are using stereo format for playback, but the AEC algorithm outputs mono data. You may try modifying the buffer data in the i2s_write_cb callback function to convert it to stereo format before testing. The result should then produce normal human voice.
Regarding your testing method, the actual reason is due to the time difference : the current AEC reference signal comes from the previous output moment, which enables it to be properly canceled. Below is the reference code for your implementation:
static int i2s_write_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
int bytes_write = 0;
int16_t *mono_data = (int16_t *)buf;
#if !RECORD_HARDWARE_AEC
if (rb_write(ringbuf_ref, buf, len, wait_time) <= 0) {
ESP_LOGW(TAG, "ringbuf write timeout");
}
#endif
int16_t *stereo_data = malloc(len * 2);
if (!stereo_data) {
ESP_LOGE(TAG, "Failed to allocate stereo buffer");
return -1;
}
for (int i = 0; i < len/2; i++) {
stereo_data[2*i] = mono_data[i];
stereo_data[2*i+1] = mono_data[i];
}
#if (CONFIG_IDF_TARGET_ESP32 && !RECORD_HARDWARE_AEC)
algorithm_mono_fix((uint8_t *)buf, len);
#endif
bytes_write = audio_element_output(i2s_stream_writter,(char *)stereo_data, len*2);
free(stereo_data);
if (bytes_write < 0) {
ESP_LOGE(TAG, "i2s write failed");
}
return bytes_write/2;
}
Hi all,
It works. The AEC algorithm works successfully. Thank you for your answer.
After seeing the successful operation of AEC, I added the AEC algorithm to the pipe_a2dp_sink_and_hfp application in the code below.
I have only one problem. In the HF application, the sound from the other side comes instantly. But the voice data I receive from the algorithm output reaches the other side after 4 seconds. I don't see anything in the code below that would cause a 4 second delay.
Is this related to processor performance or algorithm performance? What could be the reason?
/* Play music from Bluetooth device
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 <inttypes.h>
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_peripherals.h"
#include "periph_touch.h"
#include "periph_adc_button.h"
#include "periph_button.h"
#include "esp_bt_defs.h"
#include "esp_gap_bt_api.h"
#include "esp_hf_client_api.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_mem.h"
#include "i2s_stream.h"
#include "board.h"
#include "bluetooth_service.h"
#include "filter_resample.h"
#include "raw_stream.h"
#if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD || CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
#include "filter_resample.h"
#endif
#include "bt_keycontrol.h"
#include "audio_idf_version.h"
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
#define HFP_RESAMPLE_RATE 16000
#else
#define HFP_RESAMPLE_RATE 8000
#endif
static const char *TAG = "BLUETOOTH_EXAMPLE";
static const char *BT_HF_TAG = "BT_HF";
static audio_element_handle_t bt_stream_reader, i2s_stream_writer, i2s_stream_reader;
static audio_pipeline_handle_t pipeline_d, pipeline_e;
static bool is_get_hfp = true;
ringbuf_handle_t ringbuf_algo_out;
#include "driver/i2s.h"
#include "audio_sys.h"
#include "algorithm_stream.h"
#define I2S_CHANNELS I2S_CHANNEL_FMT_RIGHT_LEFT
#define I2S_BITS CODEC_ADC_BITS_PER_SAMPLE
#define I2S_SAMPLE_RATE 16000
#define HFP_RESAMPLE_RATE 16000
volatile char hf_status = 0;
const char *c_hf_evt_str[] = {
"CONNECTION_STATE_EVT", /*!< connection state changed event */
"AUDIO_STATE_EVT", /*!< audio connection state change event */
"VR_STATE_CHANGE_EVT", /*!< voice recognition state changed */
"CALL_IND_EVT", /*!< call indication event */
"CALL_SETUP_IND_EVT", /*!< call setup indication event */
"CALL_HELD_IND_EVT", /*!< call held indicator event */
"NETWORK_STATE_EVT", /*!< network state change event */
"SIGNAL_STRENGTH_IND_EVT", /*!< signal strength indication event */
"ROAMING_STATUS_IND_EVT", /*!< roaming status indication event */
"BATTERY_LEVEL_IND_EVT", /*!< battery level indication event */
"CURRENT_OPERATOR_EVT", /*!< current operator name event */
"RESP_AND_HOLD_EVT", /*!< response and hold event */
"CLIP_EVT", /*!< Calling Line Identification notification event */
"CALL_WAITING_EVT", /*!< call waiting notification */
"CLCC_EVT", /*!< listing current calls event */
"VOLUME_CONTROL_EVT", /*!< audio volume control event */
"AT_RESPONSE", /*!< audio volume control event */
"SUBSCRIBER_INFO_EVT", /*!< subscriber information event */
"INBAND_RING_TONE_EVT", /*!< in-band ring tone settings */
"LAST_VOICE_TAG_NUMBER_EVT", /*!< requested number from AG event */
"RING_IND_EVT", /*!< ring indication event */
};
// esp_hf_client_connection_state_t
const char *c_connection_state_str[] = {
"disconnected",
"connecting",
"connected",
"slc_connected",
"disconnecting",
};
// esp_hf_client_audio_state_t
const char *c_audio_state_str[] = {
"disconnected",
"connecting",
"connected",
"connected_msbc",
};
/// esp_hf_vr_state_t
const char *c_vr_state_str[] = {
"disabled",
"enabled",
};
// esp_hf_service_availability_status_t
const char *c_service_availability_status_str[] = {
"unavailable",
"available",
};
// esp_hf_roaming_status_t
const char *c_roaming_status_str[] = {
"inactive",
"active",
};
// esp_hf_client_call_state_t
const char *c_call_str[] = {
"NO call in progress",
"call in progress",
};
// esp_hf_client_callsetup_t
const char *c_call_setup_str[] = {
"NONE",
"INCOMING",
"OUTGOING_DIALING",
"OUTGOING_ALERTING"
};
// esp_hf_client_callheld_t
const char *c_call_held_str[] = {
"NONE held",
"Held and Active",
"Held",
};
// esp_hf_response_and_hold_status_t
const char *c_resp_and_hold_str[] = {
"HELD",
"HELD ACCEPTED",
"HELD REJECTED",
};
// esp_hf_client_call_direction_t
const char *c_call_dir_str[] = {
"outgoing",
"incoming",
};
// esp_hf_client_call_state_t
const char *c_call_state_str[] = {
"active",
"held",
"dialing",
"alerting",
"incoming",
"waiting",
"held_by_resp_hold",
};
// esp_hf_current_call_mpty_type_t
const char *c_call_mpty_type_str[] = {
"single",
"multi",
};
// esp_hf_volume_control_target_t
const char *c_volume_control_target_str[] = {
"SPEAKER",
"MICROPHONE"
};
// esp_hf_at_response_code_t
const char *c_at_response_code_str[] = {
"OK",
"ERROR"
"ERR_NO_CARRIER",
"ERR_BUSY",
"ERR_NO_ANSWER",
"ERR_DELAYED",
"ERR_BLACKLILSTED",
"ERR_CME",
};
// esp_hf_subscriber_service_type_t
const char *c_subscriber_service_type_str[] = {
"unknown",
"voice",
"fax",
};
// esp_hf_client_in_band_ring_state_t
const char *c_inband_ring_state_str[] = {
"NOT provided",
"Provided",
};
static void bt_app_hf_client_audio_open(void)
{
ESP_LOGE(BT_HF_TAG, "bt_app_hf_client_audio_open");
int sample_rate = HFP_RESAMPLE_RATE;
audio_element_info_t bt_info = {0};
audio_element_getinfo(bt_stream_reader, &bt_info);
bt_info.sample_rates = sample_rate;
bt_info.channels = 1;
bt_info.bits = 16;
audio_element_setinfo(bt_stream_reader, &bt_info);
audio_element_report_info(bt_stream_reader);
}
static void bt_app_hf_client_audio_close(void)
{
ESP_LOGE(BT_HF_TAG, "bt_app_hf_client_audio_close");
int sample_rate = periph_bluetooth_get_a2dp_sample_rate();
audio_element_info_t bt_info = {0};
audio_element_getinfo(bt_stream_reader, &bt_info);
bt_info.sample_rates = sample_rate;
bt_info.channels = 2;
bt_info.bits = 16;
audio_element_setinfo(bt_stream_reader, &bt_info);
audio_element_report_info(bt_stream_reader);
}
static uint32_t bt_app_hf_client_outgoing_cb(uint8_t *p_buf, uint32_t sz)
{
int out_len_bytes = 0;
char *enc_buffer = (char *)audio_malloc(sz);
AUDIO_MEM_CHECK(BT_HF_TAG, enc_buffer, return 0);
if (is_get_hfp) {
out_len_bytes = rb_read(ringbuf_algo_out, (char*) enc_buffer, sz,0);
}
if (out_len_bytes == sz) {
is_get_hfp = false;
memcpy(p_buf, enc_buffer, out_len_bytes);
free(enc_buffer);
return sz;
} else {
is_get_hfp = true;
free(enc_buffer);
return 0;
}
}
static void bt_app_hf_client_incoming_cb(const uint8_t *buf, uint32_t sz)
{
if (bt_stream_reader) {
if (audio_element_get_state(bt_stream_reader) == AEL_STATE_RUNNING) {
audio_element_output(bt_stream_reader, (char *)buf, sz);
esp_hf_client_outgoing_data_ready();
}
}
}
/* callback for HF_CLIENT */
void bt_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param)
{
if (event <= ESP_HF_CLIENT_RING_IND_EVT) {
ESP_LOGE(BT_HF_TAG, "APP HFP event: %s", c_hf_evt_str[event]);
} else {
ESP_LOGE(BT_HF_TAG, "APP HFP invalid event %d", event);
}
switch (event) {
case ESP_HF_CLIENT_CONNECTION_STATE_EVT:
ESP_LOGE(BT_HF_TAG, "--connection state %s, peer feats 0x%" PRIx32 ", chld_feats 0x%" PRIx32,
c_connection_state_str[param->conn_stat.state],
param->conn_stat.peer_feat,
param->conn_stat.chld_feat);
break;
case ESP_HF_CLIENT_AUDIO_STATE_EVT:
ESP_LOGE(BT_HF_TAG, "--audio state %s",
c_audio_state_str[param->audio_stat.state]);
#if CONFIG_HFP_AUDIO_DATA_PATH_HCI
if ((param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED)
|| (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC)) {
bt_app_hf_client_audio_open();
esp_hf_client_register_data_callback(bt_app_hf_client_incoming_cb,
bt_app_hf_client_outgoing_cb);
} else if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED) {
bt_app_hf_client_audio_close();
}
#endif /* #if CONFIG_HFP_AUDIO_DATA_PATH_HCI */
break;
case ESP_HF_CLIENT_BVRA_EVT:
ESP_LOGE(BT_HF_TAG, "--VR state %s",
c_vr_state_str[param->bvra.value]);
break;
case ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT:
ESP_LOGE(BT_HF_TAG, "--NETWORK STATE %s",
c_service_availability_status_str[param->service_availability.status]);
break;
case ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT:
ESP_LOGE(BT_HF_TAG, "--ROAMING: %s",
c_roaming_status_str[param->roaming.status]);
break;
case ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT:
ESP_LOGE(BT_HF_TAG, "-- signal strength: %d",
param->signal_strength.value);
break;
case ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT:
ESP_LOGE(BT_HF_TAG, "--battery level %d",
param->battery_level.value);
break;
case ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT:
ESP_LOGE(BT_HF_TAG, "--operator name: %s",
param->cops.name);
break;
case ESP_HF_CLIENT_CIND_CALL_EVT:
ESP_LOGE(BT_HF_TAG, "--Call indicator %s",
c_call_str[param->call.status]);
break;
case ESP_HF_CLIENT_CIND_CALL_SETUP_EVT:
ESP_LOGE(BT_HF_TAG, "--Call setup indicator %s",
c_call_setup_str[param->call_setup.status]);
break;
case ESP_HF_CLIENT_CIND_CALL_HELD_EVT:
ESP_LOGE(BT_HF_TAG, "--Call held indicator %s",
c_call_held_str[param->call_held.status]);
break;
case ESP_HF_CLIENT_BTRH_EVT:
ESP_LOGE(BT_HF_TAG, "--response and hold %s",
c_resp_and_hold_str[param->btrh.status]);
break;
case ESP_HF_CLIENT_CLIP_EVT:
ESP_LOGE(BT_HF_TAG, "--clip number %s",
(param->clip.number == NULL) ? "NULL" : (param->clip.number));
break;
case ESP_HF_CLIENT_CCWA_EVT:
ESP_LOGE(BT_HF_TAG, "--call_waiting %s",
(param->ccwa.number == NULL) ? "NULL" : (param->ccwa.number));
break;
case ESP_HF_CLIENT_CLCC_EVT:
ESP_LOGE(BT_HF_TAG, "--Current call: idx %d, dir %s, state %s, mpty %s, number %s",
param->clcc.idx,
c_call_dir_str[param->clcc.dir],
c_call_state_str[param->clcc.status],
c_call_mpty_type_str[param->clcc.mpty],
(param->clcc.number == NULL) ? "NULL" : (param->clcc.number));
break;
case ESP_HF_CLIENT_VOLUME_CONTROL_EVT:
ESP_LOGE(BT_HF_TAG, "--volume_target: %s, volume %d",
c_volume_control_target_str[param->volume_control.type],
param->volume_control.volume);
break;
case ESP_HF_CLIENT_AT_RESPONSE_EVT:
ESP_LOGE(BT_HF_TAG, "--AT response event, code %d, cme %d",
param->at_response.code, param->at_response.cme);
break;
case ESP_HF_CLIENT_CNUM_EVT:
ESP_LOGE(BT_HF_TAG, "--subscriber type %s, number %s",
c_subscriber_service_type_str[param->cnum.type],
(param->cnum.number == NULL) ? "NULL" : param->cnum.number);
break;
case ESP_HF_CLIENT_BSIR_EVT:
ESP_LOGE(BT_HF_TAG, "--inband ring state %s",
c_inband_ring_state_str[param->bsir.state]);
break;
case ESP_HF_CLIENT_BINP_EVT:
ESP_LOGE(BT_HF_TAG, "--last voice tag number: %s",
(param->binp.number == NULL) ? "NULL" : param->binp.number);
break;
default:
ESP_LOGE(BT_HF_TAG, "HF_CLIENT EVT: %d", event);
break;
}
}
static int algo_i2s_read_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
//320byt 160 ornek per cb
return audio_element_input(i2s_stream_reader, buf, len);
}
static int algo_out_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
int bytes_write = 0;
//1024 algo output per cb
bytes_write = rb_write(ringbuf_algo_out, buf, len, wait_time);
if (bytes_write < 0)
{
ESP_LOGE(TAG, "ringbuf_algo_out w timeout");
bytes_write = len;
}
return bytes_write;
}
static int i2s_write_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
int bytes_write = 0;
bytes_write = audio_element_output(i2s_stream_writer, buf, len);
if (bytes_write < 0)
{
ESP_LOGE(TAG, "i2s write failed");
}
return bytes_write;
}
void app_main(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_DEBUG);
ESP_LOGI(TAG, "[ 1 ] Create Bluetooth service");
bluetooth_service_cfg_t bt_cfg = {
.device_name = "ESP-ADF-AUDIO",
.mode = BLUETOOTH_A2DP_SINK,
};
bluetooth_service_start(&bt_cfg);
esp_hf_client_register_callback(bt_hf_client_cb);
esp_hf_client_init();
ESP_LOGI(TAG, "[ 2 ] Start codec chip");
audio_board_handle_t board_handle = audio_board_init();
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START);
audio_hal_set_volume(board_handle->audio_hal, 100);
ESP_LOGI(TAG, "[ 3 ] Create audio pipeline for playback");
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
pipeline_d = audio_pipeline_init(&pipeline_cfg);
pipeline_e = audio_pipeline_init(&pipeline_cfg);
ESP_LOGI(TAG, "[3.1] Create i2s stream to write data to codec chip and read data from codec chip");
i2s_stream_cfg_t i2s_cfg1 = I2S_STREAM_CFG_DEFAULT_WITH_PARA(I2S_NUM_0, I2S_SAMPLE_RATE, I2S_BITS, AUDIO_STREAM_WRITER);
i2s_cfg1.task_stack = -1;
i2s_stream_set_channel_type(&i2s_cfg1, I2S_CHANNEL_FMT_RIGHT_LEFT);
i2s_cfg1.need_expand = (16 != I2S_BITS);
i2s_stream_writer = i2s_stream_init(&i2s_cfg1);
i2s_stream_cfg_t i2s_cfg2 = I2S_STREAM_CFG_DEFAULT_WITH_PARA(CODEC_ADC_I2S_PORT, I2S_SAMPLE_RATE, I2S_BITS, AUDIO_STREAM_READER);
i2s_cfg2.task_stack = -1;
i2s_stream_set_channel_type(&i2s_cfg2, I2S_CHANNEL_FMT_RIGHT_LEFT);
i2s_stream_reader = i2s_stream_init(&i2s_cfg2);
ESP_LOGI(TAG, "[3.2] Create Bluetooth stream");
bt_stream_reader = bluetooth_service_create_stream();
audio_element_set_write_cb(bt_stream_reader, i2s_write_cb, NULL);
audio_element_set_output_timeout(bt_stream_reader, portMAX_DELAY);
ESP_LOGI(TAG, "[ 3 ] Create audio pipeline for playback");
ringbuf_algo_out = rb_create(ALGORITHM_STREAM_RINGBUFFER_SIZE*4, 1);
if (ringbuf_algo_out == NULL)
{
ESP_LOGE(TAG, "ringbuf_algo_out mem error!!");
}
#define ESP_RING_BUFFER_SIZE 1024
ESP_LOGI(TAG, "[3.1] Create algorithm stream for aec");
algorithm_stream_cfg_t algo_config = ALGORITHM_STREAM_CFG_DEFAULT();
algo_config.input_format = "RM";
algo_config.sample_rate = I2S_SAMPLE_RATE;
algo_config.out_rb_size = ESP_RING_BUFFER_SIZE;
algo_config.task_core = 1;
audio_element_handle_t element_algo = algo_stream_init(&algo_config);
audio_element_set_music_info(element_algo, I2S_SAMPLE_RATE, 1, ALGORITHM_STREAM_DEFAULT_SAMPLE_BIT);
audio_element_set_read_cb(element_algo, algo_i2s_read_cb, NULL);
audio_element_set_input_timeout(element_algo, portMAX_DELAY);
audio_element_set_write_cb(element_algo, algo_out_cb, NULL);
audio_element_set_output_timeout(element_algo, portMAX_DELAY);
ESP_LOGI(TAG, "[3.4] Register all elements to audio pipeline_rec");
audio_pipeline_register(pipeline_e, element_algo, "aec");
ESP_LOGI(TAG, "[3.3] Register all elements to audio pipeline");
audio_pipeline_register(pipeline_d, bt_stream_reader, "bt");
ESP_LOGI(TAG, "[3.4] Link it together [Bluetooth]-->bt_stream_reader-->i2s_stream_writer-->[codec_chip]");
const char *link_d[1] = {"bt"};
audio_pipeline_link(pipeline_d, &link_d[0], 1);
const char *link_e[1] = {"aec"};
audio_pipeline_link(pipeline_e, &link_e[0], 1);
ESP_LOGI(TAG, "[ 4 ] Initialize peripherals");
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
ESP_LOGI(TAG, "[4.1] Initialize Touch peripheral");
audio_board_key_init(set);
ESP_LOGI(TAG, "[4.2] Create Bluetooth peripheral");
esp_periph_handle_t bt_periph = bluetooth_service_create_periph();
ESP_LOGI(TAG, "[4.2] Start all peripherals");
esp_periph_start(set, bt_periph);
ESP_LOGI(TAG, "[ 5 ] 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);
ESP_LOGI(TAG, "[5.1] Listening event from all elements of pipeline");
audio_pipeline_set_listener(pipeline_d, evt);
ESP_LOGI(TAG, "[5.2] Listening event from peripherals");
audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);
ESP_LOGI(TAG, "[ 6 ] Start audio_pipeline");
audio_pipeline_run(pipeline_d);
audio_pipeline_run(pipeline_e);
ESP_LOGI(TAG, "[ 7 ] Listen for all pipeline events");
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 *)bt_stream_reader
&& msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) {
audio_element_info_t music_info = {0};
audio_element_getinfo(bt_stream_reader, &music_info);
ESP_LOGI(TAG, "[ * ] Receive music info from Bluetooth, sample_rates=%d, bits=%d, ch=%d",
music_info.sample_rates, music_info.bits, music_info.channels);
i2s_stream_set_clk(i2s_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
continue;
}
if ((msg.source_type == PERIPH_ID_TOUCH || msg.source_type == PERIPH_ID_BUTTON || msg.source_type == PERIPH_ID_ADC_BTN)
&& (msg.cmd == PERIPH_TOUCH_TAP || msg.cmd == PERIPH_BUTTON_PRESSED || msg.cmd == PERIPH_ADC_BUTTON_PRESSED)) {
if ((int)msg.data == get_input_play_id()) {
ESP_LOGI(TAG, "[ * ] [Play] touch tap event");
periph_bluetooth_play(bt_periph);
} else if ((int)msg.data == get_input_set_id()) {
ESP_LOGI(TAG, "[ * ] [Set] touch tap event");
periph_bluetooth_pause(bt_periph);
} else if ((int)msg.data == get_input_volup_id()) {
ESP_LOGI(TAG, "[ * ] [Vol+] touch tap event");
periph_bluetooth_next(bt_periph);
} else if ((int)msg.data == get_input_voldown_id()) {
ESP_LOGI(TAG, "[ * ] [Vol-] touch tap event");
periph_bluetooth_prev(bt_periph);
}
}
/* Stop when the Bluetooth is disconnected or suspended */
if (msg.source_type == PERIPH_ID_BLUETOOTH
&& msg.source == (void *)bt_periph) {
if (msg.cmd == PERIPH_BLUETOOTH_DISCONNECTED) {
ESP_LOGW(TAG, "[ * ] Bluetooth disconnected");
break;
}
}
/* 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) {
ESP_LOGW(TAG, "[ * ] Stop event received");
break;
}
}
ESP_LOGI(TAG, "[ 8 ] Stop audio_pipeline");
audio_pipeline_stop(pipeline_d);
audio_pipeline_wait_for_stop(pipeline_d);
audio_pipeline_terminate(pipeline_d);
audio_pipeline_stop(pipeline_e);
audio_pipeline_wait_for_stop(pipeline_e);
audio_pipeline_terminate(pipeline_e);
audio_pipeline_unregister(pipeline_d, bt_stream_reader);
audio_pipeline_unregister(pipeline_d, i2s_stream_writer);
audio_pipeline_unregister(pipeline_e, i2s_stream_reader);
#if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD || CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
audio_pipeline_unregister(pipeline_d, filter_d);
audio_pipeline_unregister(pipeline_e, filter_e);
#endif
/* Terminate the pipeline before removing the listener */
audio_pipeline_remove_listener(pipeline_d);
/* Stop all peripherals before removing the listener */
esp_periph_set_stop_all(set);
audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), 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_d);
audio_element_deinit(bt_stream_reader);
audio_element_deinit(i2s_stream_writer);
audio_element_deinit(i2s_stream_reader);
#if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD || CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
audio_element_deinit(filter_d);
audio_element_deinit(filter_e);
#endif
esp_periph_set_destroy(set);
bluetooth_service_destroy();
}
Hello again,
I have a second question, independent of the above topic. We're in the design phase, and we need to make a quick decision on this issue. That's why I'm asking so we don't waste any time. I'd appreciate any help you can provide regarding these two issues.
We've verified that the aec algorithm works and has a 4-second delay. I want to do the same with the aec algorithm with a reference buffer (ALGORITHM_STREAM_INPUT_TYPE2).
When I add it to my own development board as in the code below, the algorithm has no effect. It echoes and the sound is delayed by 4 seconds.
Can you see an design problem in the code below when using aec input type 2?
Can we expect the aec input1 and input2 modes to work with the same performance?
/* Play music from Bluetooth device
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 <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_peripherals.h"
#include "periph_touch.h"
#include "periph_adc_button.h"
#include "periph_button.h"
#include "esp_bt_defs.h"
#include "esp_gap_bt_api.h"
#include "esp_hf_client_api.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_mem.h"
#include "i2s_stream.h"
#include "board.h"
#include "bluetooth_service.h"
#include "filter_resample.h"
#include "raw_stream.h"
//-----------
#include "algorithm_stream.h"
#include "tlv320aic31xx.h"
tlv320aic3100_config_t board_config = TLV320AIC3100_CONFIG_DEFAULT();
tlv320aic3100_handle_t board_handle;
ringbuf_handle_t ringbuf_ref;
ringbuf_handle_t ringbuf_algo_out;
volatile uint8_t hf_active = false;
#define I2S_SAMPLE_RATE 16000
#define HFP_RESAMPLE_RATE 16000
//--------------
#if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD || CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
#include "filter_resample.h"
#endif
#include "bt_keycontrol.h"
#include "audio_idf_version.h"
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
#define HFP_RESAMPLE_RATE 16000
#else
#define HFP_RESAMPLE_RATE 8000
#endif
static const char *TAG_MAIN = "BLUETOOTH";
static const char *TAG_BT_HF = "BT_HF";
static const char *TAG_ALG = "ALG";
static audio_element_handle_t raw_read, bt_stream_reader, i2s_stream_writer, i2s_stream_reader;
static audio_pipeline_handle_t pipeline_d, pipeline_e;
static bool is_get_hfp = true;
const char *c_hf_evt_str[] = {
"CONNECTION_STATE_EVT", /*!< connection state changed event */
"AUDIO_STATE_EVT", /*!< audio connection state change event */
"VR_STATE_CHANGE_EVT", /*!< voice recognition state changed */
"CALL_IND_EVT", /*!< call indication event */
"CALL_SETUP_IND_EVT", /*!< call setup indication event */
"CALL_HELD_IND_EVT", /*!< call held indicator event */
"NETWORK_STATE_EVT", /*!< network state change event */
"SIGNAL_STRENGTH_IND_EVT", /*!< signal strength indication event */
"ROAMING_STATUS_IND_EVT", /*!< roaming status indication event */
"BATTERY_LEVEL_IND_EVT", /*!< battery level indication event */
"CURRENT_OPERATOR_EVT", /*!< current operator name event */
"RESP_AND_HOLD_EVT", /*!< response and hold event */
"CLIP_EVT", /*!< Calling Line Identification notification event */
"CALL_WAITING_EVT", /*!< call waiting notification */
"CLCC_EVT", /*!< listing current calls event */
"VOLUME_CONTROL_EVT", /*!< audio volume control event */
"AT_RESPONSE", /*!< audio volume control event */
"SUBSCRIBER_INFO_EVT", /*!< subscriber information event */
"INBAND_RING_TONE_EVT", /*!< in-band ring tone settings */
"LAST_VOICE_TAG_NUMBER_EVT", /*!< requested number from AG event */
"RING_IND_EVT", /*!< ring indication event */
};
// esp_hf_client_connection_state_t
const char *c_connection_state_str[] = {
"disconnected",
"connecting",
"connected",
"slc_connected",
"disconnecting",
};
// esp_hf_client_audio_state_t
const char *c_audio_state_str[] = {
"disconnected",
"connecting",
"connected",
"connected_msbc",
};
/// esp_hf_vr_state_t
const char *c_vr_state_str[] = {
"disabled",
"enabled",
};
// esp_hf_service_availability_status_t
const char *c_service_availability_status_str[] = {
"unavailable",
"available",
};
// esp_hf_roaming_status_t
const char *c_roaming_status_str[] = {
"inactive",
"active",
};
// esp_hf_client_call_state_t
const char *c_call_str[] = {
"NO call in progress",
"call in progress",
};
// esp_hf_client_callsetup_t
const char *c_call_setup_str[] = {
"NONE",
"INCOMING",
"OUTGOING_DIALING",
"OUTGOING_ALERTING"
};
// esp_hf_client_callheld_t
const char *c_call_held_str[] = {
"NONE held",
"Held and Active",
"Held",
};
// esp_hf_response_and_hold_status_t
const char *c_resp_and_hold_str[] = {
"HELD",
"HELD ACCEPTED",
"HELD REJECTED",
};
// esp_hf_client_call_direction_t
const char *c_call_dir_str[] = {
"outgoing",
"incoming",
};
// esp_hf_client_call_state_t
const char *c_call_state_str[] = {
"active",
"held",
"dialing",
"alerting",
"incoming",
"waiting",
"held_by_resp_hold",
};
// esp_hf_current_call_mpty_type_t
const char *c_call_mpty_type_str[] = {
"single",
"multi",
};
// esp_hf_volume_control_target_t
const char *c_volume_control_target_str[] = {
"SPEAKER",
"MICROPHONE"
};
// esp_hf_at_response_code_t
const char *c_at_response_code_str[] = {
"OK",
"ERROR",
"ERR_NO_CARRIER",
"ERR_BUSY",
"ERR_NO_ANSWER",
"ERR_DELAYED",
"ERR_BLACKLILSTED",
"ERR_CME",
};
// esp_hf_subscriber_service_type_t
const char *c_subscriber_service_type_str[] = {
"unknown",
"voice",
"fax",
};
// esp_hf_client_in_band_ring_state_t
const char *c_inband_ring_state_str[] = {
"NOT provided",
"Provided",
};
static void bt_app_hf_client_audio_open(void)
{
ESP_LOGE(TAG_BT_HF, "bt_app_hf_client_audio_open");
int sample_rate = HFP_RESAMPLE_RATE;
audio_element_info_t bt_info = {0};
audio_element_getinfo(bt_stream_reader, &bt_info);
bt_info.sample_rates = sample_rate;
bt_info.channels = 1;
bt_info.bits = 16;
audio_element_setinfo(bt_stream_reader, &bt_info);
audio_element_report_info(bt_stream_reader);
}
static void bt_app_hf_client_audio_close(void)
{
ESP_LOGE(TAG_BT_HF, "bt_app_hf_client_audio_close");
int sample_rate = periph_bluetooth_get_a2dp_sample_rate();
audio_element_info_t bt_info = {0};
audio_element_getinfo(bt_stream_reader, &bt_info);
bt_info.sample_rates = sample_rate;
bt_info.channels = 2;
bt_info.bits = 16;
audio_element_setinfo(bt_stream_reader, &bt_info);
audio_element_report_info(bt_stream_reader);
}
static uint32_t bt_app_hf_client_outgoing_cb(uint8_t *p_buf, uint32_t sz)
{
//request 240 byt read per time from bt stack cb
int32_t out_len_bytes = 0;
if (rb_bytes_filled(ringbuf_algo_out) >= sz)
{
out_len_bytes = rb_read(ringbuf_algo_out, (char*) p_buf, sz,0);
return out_len_bytes;
}
else
{
return 0;
}
}
static void bt_app_hf_client_incoming_cb(const uint8_t *buf, uint32_t sz)
{
if (bt_stream_reader) {
if (audio_element_get_state(bt_stream_reader) == AEL_STATE_RUNNING) {
audio_element_output(bt_stream_reader, (char *)buf, sz);
esp_hf_client_outgoing_data_ready();
}
}
}
/* callback for HF_CLIENT */
void bt_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param)
{
if (event <= ESP_HF_CLIENT_RING_IND_EVT) {
ESP_LOGE(TAG_BT_HF, "APP HFP event: %s", c_hf_evt_str[event]);
} else {
ESP_LOGE(TAG_BT_HF, "APP HFP invalid event %d", event);
}
switch (event) {
case ESP_HF_CLIENT_CONNECTION_STATE_EVT:
ESP_LOGE(TAG_BT_HF, "--connection state %s, peer feats 0x%" PRIx32 ", chld_feats 0x%" PRIx32,
c_connection_state_str[param->conn_stat.state],
param->conn_stat.peer_feat,
param->conn_stat.chld_feat);
break;
case ESP_HF_CLIENT_AUDIO_STATE_EVT:
ESP_LOGE(TAG_BT_HF, "--audio state %s",
c_audio_state_str[param->audio_stat.state]);
#if CONFIG_HFP_AUDIO_DATA_PATH_HCI
if ((param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED)
|| (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC)) {
bt_app_hf_client_audio_open();
esp_hf_client_register_data_callback(bt_app_hf_client_incoming_cb,
bt_app_hf_client_outgoing_cb);
} else if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED) {
bt_app_hf_client_audio_close();
}
#endif /* #if CONFIG_HFP_AUDIO_DATA_PATH_HCI */
break;
case ESP_HF_CLIENT_BVRA_EVT:
ESP_LOGE(TAG_BT_HF, "--VR state %s",
c_vr_state_str[param->bvra.value]);
break;
case ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT:
ESP_LOGE(TAG_BT_HF, "--NETWORK STATE %s",
c_service_availability_status_str[param->service_availability.status]);
break;
case ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT:
ESP_LOGE(TAG_BT_HF, "--ROAMING: %s",
c_roaming_status_str[param->roaming.status]);
break;
case ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT:
ESP_LOGE(TAG_BT_HF, "-- signal strength: %d",
param->signal_strength.value);
break;
case ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT:
ESP_LOGE(TAG_BT_HF, "--battery level %d",
param->battery_level.value);
break;
case ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT:
ESP_LOGE(TAG_BT_HF, "--operator name: %s",
param->cops.name);
break;
case ESP_HF_CLIENT_CIND_CALL_EVT:
ESP_LOGE(TAG_BT_HF, "--Call indicator %s",
c_call_str[param->call.status]);
break;
case ESP_HF_CLIENT_CIND_CALL_SETUP_EVT:
ESP_LOGE(TAG_BT_HF, "--Call setup indicator %s",
c_call_setup_str[param->call_setup.status]);
break;
case ESP_HF_CLIENT_CIND_CALL_HELD_EVT:
ESP_LOGE(TAG_BT_HF, "--Call held indicator %s",
c_call_held_str[param->call_held.status]);
break;
case ESP_HF_CLIENT_BTRH_EVT:
ESP_LOGE(TAG_BT_HF, "--response and hold %s",
c_resp_and_hold_str[param->btrh.status]);
break;
case ESP_HF_CLIENT_CLIP_EVT:
ESP_LOGE(TAG_BT_HF, "--clip number %s",
(param->clip.number == NULL) ? "NULL" : (param->clip.number));
break;
case ESP_HF_CLIENT_CCWA_EVT:
ESP_LOGE(TAG_BT_HF, "--call_waiting %s",
(param->ccwa.number == NULL) ? "NULL" : (param->ccwa.number));
break;
case ESP_HF_CLIENT_CLCC_EVT:
ESP_LOGE(TAG_BT_HF, "--Current call: idx %d, dir %s, state %s, mpty %s, number %s",
param->clcc.idx,
c_call_dir_str[param->clcc.dir],
c_call_state_str[param->clcc.status],
c_call_mpty_type_str[param->clcc.mpty],
(param->clcc.number == NULL) ? "NULL" : (param->clcc.number));
break;
case ESP_HF_CLIENT_VOLUME_CONTROL_EVT:
ESP_LOGE(TAG_BT_HF, "--volume_target: %s, volume %d",
c_volume_control_target_str[param->volume_control.type],
param->volume_control.volume);
break;
case ESP_HF_CLIENT_AT_RESPONSE_EVT:
ESP_LOGE(TAG_BT_HF, "--AT response event, code %d, cme %d",
param->at_response.code, param->at_response.cme);
break;
case ESP_HF_CLIENT_CNUM_EVT:
ESP_LOGE(TAG_BT_HF, "--subscriber type %s, number %s",
c_subscriber_service_type_str[param->cnum.type],
(param->cnum.number == NULL) ? "NULL" : param->cnum.number);
break;
case ESP_HF_CLIENT_BSIR_EVT:
ESP_LOGE(TAG_BT_HF, "--inband ring state %s",
c_inband_ring_state_str[param->bsir.state]);
break;
case ESP_HF_CLIENT_BINP_EVT:
ESP_LOGE(TAG_BT_HF, "--last voice tag number: %s",
(param->binp.number == NULL) ? "NULL" : param->binp.number);
break;
default:
ESP_LOGE(TAG_BT_HF, "HF_CLIENT EVT: %d", event);
break;
}
}
static int algo_i2s_read_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
//320byt 160 sample per cb
return audio_element_input(i2s_stream_reader, buf, len);
}
static int i2s_write_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
// 240byt frame bt input handler * HF_IN_PCKT_COUNT = x per cb
int bytes_write = 0;
if ((bytes_write = rb_write(ringbuf_ref, buf, len, wait_time)) <= 0)
{
ESP_LOGW(TAG_MAIN, "ringbuf_ref w timeout");
}
bytes_write = audio_element_output(i2s_stream_writer, buf, len);
if (bytes_write < 0)
{
ESP_LOGE(TAG_MAIN, "i2s write failed");
}
return bytes_write;
}
static int algo_out_cb(audio_element_handle_t el, char *buf, int len, TickType_t wait_time, void *ctx)
{
//1024 algo output per cb
int bytes_write = 0;
bytes_write = rb_write(ringbuf_algo_out, buf, len, wait_time);
if (bytes_write < 0)
{
ESP_LOGE(TAG_MAIN, "ringbuf_algo_out w timeout");
bytes_write = len;
}
return bytes_write;
}
void app_main(void)
{
int value=0;
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES)
{
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
esp_log_level_set(TAG_MAIN, ESP_LOG_DEBUG);
esp_log_level_set(TAG_BT_HF, ESP_LOG_DEBUG);
ESP_LOGI(TAG_MAIN, "[ 1 ] Create Bluetooth service");
bluetooth_service_cfg_t bt_cfg =
{
.device_name = "ESP-ADF-AUDIO",
.mode = BLUETOOTH_A2DP_SINK,
};
bluetooth_service_start(&bt_cfg);
esp_hf_client_register_callback(bt_hf_client_cb);
esp_hf_client_init();
ESP_LOGI(TAG_MAIN, "[ 2 ] Start codec chip");
if(e_TLV320AIC3100_Init(&board_handle,&board_config) != kStatus_Success)
{
ESP_LOGE(TAG_MAIN, "TLV INIT ERROR!!");
}
e_TLV320AIC3100_SetModuleMute(&board_handle,kTLV320AIC3100_ModuleSpeakerDriver,false);
e_TLV320AIC3100_SetModuleMute(&board_handle,kTLV320AIC3100_ModuleDAC,false);
e_TLV320AIC3100_SetModuleMute(&board_handle,kTLV320AIC3100_ModuleADC,false);
e_TLV320AIC3100_SetModuleMute(&board_handle,kTLV320AIC3100_ModuleMIC,false);
e_TLV320AIC3100_SetModuleMute(&board_handle,kTLV320AIC3100_ModuleHeadphoneDriver,false);
e_TLV320AIC3100_SetModuleVolume(&board_handle, kTLV320AIC3100_ModuleMIC, 59); //(119-x)*0,5 dB mic gain analog +30 dB
e_TLV320AIC3100_SetModuleVolume(&board_handle, kTLV320AIC3100_ModuleADC, 30); //(x-24)*0,5 dB adc digital vol +3dB
e_TLV320AIC3100_SetModuleVolume(&board_handle, kTLV320AIC3100_ModuleDAC, 127); // (x-127)*0,5 dB dac r/l volume. 0dB
e_TLV320AIC3100_SetModuleVolume(&board_handle, kTLV320AIC3100_ModuleHeadphoneAnalog, 121); //-(127-x)*05 -dB hp out -3 dB
e_TLV320AIC3100_SetModuleVolume(&board_handle, kTLV320AIC3100_ModuleSpeakerAnalog, 121); //-(127-x)*0.5 -dB spk out -3 dB
value = l_TLV320AIC3100_GetModuleVolume(&board_handle,kTLV320AIC3100_ModuleADC);
ESP_LOGI(TAG_MAIN, "adc dB reg %d!!", value);
value = l_TLV320AIC3100_GetModuleVolume(&board_handle,kTLV320AIC3100_ModuleDAC);
ESP_LOGI(TAG_MAIN, "dac dB reg %d!!", value);
value = l_TLV320AIC3100_GetModuleVolume(&board_handle,kTLV320AIC3100_ModuleHeadphoneAnalog);
ESP_LOGI(TAG_MAIN, "hp dB reg %d!!", value);
value = l_TLV320AIC3100_GetModuleVolume(&board_handle,kTLV320AIC3100_ModuleSpeakerAnalog);
ESP_LOGI(TAG_MAIN, "spk dB reg %d!!", value);
ESP_LOGI(TAG_MAIN, "[ 3 ] Create audio pipeline for playback");
ringbuf_algo_out = rb_create(ALGORITHM_STREAM_RINGBUFFER_SIZE*32, 1);
if (ringbuf_algo_out == NULL)
{
ESP_LOGE(TAG_MAIN, "ringbuf_algo_out mem error!!");
}
ringbuf_ref = rb_create(ALGORITHM_STREAM_RINGBUFFER_SIZE*32, 1);
if (ringbuf_ref == NULL)
{
ESP_LOGE(TAG_MAIN, "ringbuf_ref mem error!!");
}
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
pipeline_d = audio_pipeline_init(&pipeline_cfg);
pipeline_e = audio_pipeline_init(&pipeline_cfg);
ESP_LOGI(TAG_MAIN, "[3.1] Create i2s stream to write data to codec chip and read data from codec chip");
i2s_stream_cfg_t i2s_write_cfg = I2S_STREAM_CFG_DEFAULT_WITH_PARA(I2S_NUM_0, I2S_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, AUDIO_STREAM_WRITER);
i2s_write_cfg.task_stack = -1;
i2s_stream_set_channel_type(&i2s_write_cfg, I2S_CHANNEL_TYPE_RIGHT_LEFT);
i2s_stream_writer = i2s_stream_init(&i2s_write_cfg);
i2s_stream_cfg_t i2s_read_cfg = I2S_STREAM_CFG_DEFAULT_WITH_PARA(I2S_NUM_0, I2S_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, AUDIO_STREAM_READER);
i2s_read_cfg.task_stack = -1;
i2s_stream_set_channel_type(&i2s_read_cfg, I2S_CHANNEL_TYPE_ONLY_LEFT);
i2s_stream_reader = i2s_stream_init(&i2s_read_cfg);
ESP_LOGI(TAG_MAIN, "[3.2] Create Bluetooth stream");
bt_stream_reader = bluetooth_service_create_stream();
audio_element_set_write_cb(bt_stream_reader, i2s_write_cb, NULL);
audio_element_set_output_timeout(bt_stream_reader, 0);
//------------------------------------------------ aec algorithm ---------------------------------------------//
// 1mS de 32 byt i2s datası aliniyor
ESP_LOGI(TAG_MAIN, "[3.1] Create algorithm stream for aec");
#define ESP_RING_BUFFER_SIZE 1024
#define DEFAULT_REF_DELAY_MS 10
algorithm_stream_cfg_t algo_config = ALGORITHM_STREAM_CFG_DEFAULT();
algo_config.input_format = "MR";
algo_config.task_core = 1;
algo_config.input_type = ALGORITHM_STREAM_INPUT_TYPE2;
algo_config.debug_input = false;
algo_config.multi_in_rb_num = true;
algo_config.sample_rate = I2S_SAMPLE_RATE;
algo_config.out_rb_size = ESP_RING_BUFFER_SIZE;
// algo_config.partition_label = NULL;
// algo_config.agc_mode = AFE_AGC_MODE_WEBRTC;
// algo_config.agc_compression_gain_db = 3;
// algo_config.ref_linear_factor = 3;
// algo_config.rec_linear_factor = 1;
// algo_config.agc_target_level_dbfs = -9;
// algo_config.enable_se = true;
// algo_config.afe_type = AFE_TYPE_VC;
// algo_config.mode = AFE_MODE_HIGH_PERF;
audio_element_handle_t element_algo = algo_stream_init(&algo_config);
audio_element_set_music_info(element_algo, I2S_SAMPLE_RATE, 1, ALGORITHM_STREAM_DEFAULT_SAMPLE_BIT);
audio_element_set_read_cb(element_algo, algo_i2s_read_cb, NULL);
audio_element_set_write_cb(element_algo, algo_out_cb, NULL);
audio_element_set_input_timeout(element_algo, portMAX_DELAY);
audio_element_set_output_timeout(element_algo, portMAX_DELAY);
//------------------------------------------------ aec algorithm ---------------------------------------------//
ESP_LOGI(TAG_MAIN, "[3.3] Register all elements to audio pipeline");
audio_pipeline_register(pipeline_d, bt_stream_reader, "bt");
audio_pipeline_register(pipeline_e, element_algo, "element_algo");
ESP_LOGI(TAG_MAIN, "[3.4] Link it together [Bluetooth]-->bt_stream_reader-->i2s_stream_writer-->[codec_chip]");
const char *link_d[1] = {"bt"};
audio_pipeline_link(pipeline_d, &link_d[0], 1);
const char *link_e[1] = {"element_algo"};
audio_pipeline_link(pipeline_e, &link_e[0], 1);
//----------------------------------
// set ref_input
audio_element_set_multi_input_ringbuf(element_algo, ringbuf_ref, 0);
// When the playback signal far ahead of the recording signal,
// the playback signal needs to be delayed
algo_stream_set_delay(element_algo, ringbuf_ref, DEFAULT_REF_DELAY_MS);
//-------------------------------------
ESP_LOGI(TAG_MAIN, "[ 4 ] Initialize peripherals");
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
ESP_LOGI(TAG_MAIN, "[4.2] Create Bluetooth peripheral");
esp_periph_handle_t bt_periph = bluetooth_service_create_periph();
ESP_LOGI(TAG_MAIN, "[4.2] Start all peripherals");
esp_periph_start(set, bt_periph);
ESP_LOGI(TAG_MAIN, "[ 5 ] 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);
ESP_LOGI(TAG_MAIN, "[5.1] Listening event from all elements of pipeline");
audio_pipeline_set_listener(pipeline_d, evt);
ESP_LOGI(TAG_MAIN, "[ 6 ] Start audio_pipeline");
audio_pipeline_run(pipeline_d);
audio_pipeline_run(pipeline_e);
ESP_LOGI(TAG_MAIN, "[ 7 ] Listen for all pipeline events");
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_MAIN, "[ * ] Event interface error : %d", ret);
continue;
}
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *)bt_stream_reader
&& msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) {
audio_element_info_t music_info = {0};
audio_element_getinfo(bt_stream_reader, &music_info);
ESP_LOGI(TAG_MAIN, "[ * ] Receive music info from Bluetooth, sample_rates=%d, bits=%d, ch=%d",
music_info.sample_rates, music_info.bits, music_info.channels);
i2s_stream_set_clk(i2s_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
continue;
}
if ((msg.source_type == PERIPH_ID_TOUCH || msg.source_type == PERIPH_ID_BUTTON || msg.source_type == PERIPH_ID_ADC_BTN)
&& (msg.cmd == PERIPH_TOUCH_TAP || msg.cmd == PERIPH_BUTTON_PRESSED || msg.cmd == PERIPH_ADC_BUTTON_PRESSED)) {
if ((int)msg.data == get_input_play_id()) {
ESP_LOGI(TAG_MAIN, "[ * ] [Play] touch tap event");
//periph_bluetooth_play(bt_periph);
} else if ((int)msg.data == get_input_set_id()) {
ESP_LOGI(TAG_MAIN, "[ * ] [Set] touch tap event");
//periph_bluetooth_pause(bt_periph);
} else if ((int)msg.data == get_input_volup_id()) {
ESP_LOGI(TAG_MAIN, "[ * ] [Vol+] touch tap event");
//periph_bluetooth_next(bt_periph);
} else if ((int)msg.data == get_input_voldown_id()) {
ESP_LOGI(TAG_MAIN, "[ * ] [Vol-] touch tap event");
//periph_bluetooth_prev(bt_periph);
}
}
/* Stop when the Bluetooth is disconnected or suspended */
if (msg.source_type == PERIPH_ID_BLUETOOTH
&& msg.source == (void *)bt_periph) {
if (msg.cmd == PERIPH_BLUETOOTH_DISCONNECTED) {
ESP_LOGW(TAG_MAIN, "[ * ] Bluetooth disconnected");
break;
}
}
/* 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) {
ESP_LOGW(TAG_MAIN, "[ * ] Stop event received");
break;
}
}
ESP_LOGI(TAG_MAIN, "[ 8 ] Stop audio_pipeline");
audio_pipeline_stop(pipeline_d);
audio_pipeline_wait_for_stop(pipeline_d);
audio_pipeline_terminate(pipeline_d);
audio_pipeline_stop(pipeline_e);
audio_pipeline_wait_for_stop(pipeline_e);
audio_pipeline_terminate(pipeline_e);
audio_pipeline_unregister(pipeline_d, bt_stream_reader);
audio_pipeline_unregister(pipeline_d, i2s_stream_writer);
audio_pipeline_unregister(pipeline_e, i2s_stream_reader);
audio_pipeline_unregister(pipeline_e, raw_read);
#if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD || CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
audio_pipeline_unregister(pipeline_d, filter_d);
audio_pipeline_unregister(pipeline_e, filter_e);
#endif
/* Terminate the pipeline before removing the listener */
audio_pipeline_remove_listener(pipeline_d);
/* Stop all peripherals before removing the listener */
esp_periph_set_stop_all(set);
audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), 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_d);
audio_element_deinit(bt_stream_reader);
audio_element_deinit(i2s_stream_writer);
audio_element_deinit(i2s_stream_reader);
audio_element_deinit(raw_read);
#if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD || CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
audio_element_deinit(filter_d);
audio_element_deinit(filter_e);
#endif
esp_periph_set_destroy(set);
bluetooth_service_destroy();
}
Hi,
Kindly reminder.