For others that may have a similar issue and want to output audio to multiple elements, I found a solution that works. You cannot use the ESP-ADF pipeline. You need to go to the layer below the pipeline function and connect the elements with ringbuffers. This allows one of the elements to use "audio_element_set_multi_output_ringbuf(audio_element_handle_t el, ringbuf_handle_t rb, int index)" which will use the input ringbuffer for multiple other elements.
Code: Select all
audio_element_handle_t fatfs_stream_writer, i2s_stream_reader, wav_encoder, bt_stream_writer;
ringbuf_handle_t ringbuf01, ringbuf02, ringbuf11;
esp_log_level_set("*", ESP_LOG_WARN);
esp_log_level_set(TAG, ESP_LOG_INFO);
ESP_LOGI(TAG, "[ 1 ] Mount sdcard");
// 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);
// Initialize SD Card peripheral
audio_board_sdcard_init(set);
ESP_LOGI(TAG, "[ 2 ] Start codec chip");
audio_board_handle_t board_handle = audio_board_init();
codec_begin(); //This will start up the codec
int player_volume;
audio_hal_get_volume(board_handle->audio_hal, &player_volume);
ESP_LOGI(TAG, "[3.0] Create audio pipeline for recording");
ESP_LOGI(TAG, "[3.2] Create i2s stream to read audio data from codec chip");
i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
i2s_cfg.type = AUDIO_STREAM_READER;
i2s_cfg.multi_out_num = 1;
i2s_cfg.task_core = 1;
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
i2s_cfg.i2s_port = (i2s_port_t)1;
#endif
i2s_stream_reader = i2s_stream_init(&i2s_cfg);
ESP_LOGI(TAG, "[3.3] Create wav encoder to encode wav format");
wav_encoder_cfg_t wav_cfg = DEFAULT_WAV_ENCODER_CONFIG();
wav_encoder = wav_encoder_init(&wav_cfg);
ESP_LOGI(TAG, "[3.1] Create fatfs stream to write data to sdcard");
fatfs_stream_cfg_t fatfs_cfg = FATFS_STREAM_CFG_DEFAULT();
fatfs_cfg.type = AUDIO_STREAM_WRITER;
fatfs_stream_writer = fatfs_stream_init(&fatfs_cfg);
audio_element_info_t info = AUDIO_ELEMENT_INFO_DEFAULT();
audio_element_getinfo(i2s_stream_reader, &info);
audio_element_setinfo(fatfs_stream_writer, &info);
ESP_LOGI(TAG, "[3.3] Create a ringbuffer and insert it between i2s_stream_reader and wav_encoder");
ringbuf01 = rb_create(RING_BUFFER_SIZE, 1);
audio_element_set_output_ringbuf(i2s_stream_reader, ringbuf01);
audio_element_set_input_ringbuf(wav_encoder, ringbuf01);
ESP_LOGI(TAG, "[3.4] Create a ringbuffer and insert it between wav_encoder and wav_fatfs_stream_writer");
ringbuf02 = rb_create(RING_BUFFER_SIZE, 1);
audio_element_set_output_ringbuf(wav_encoder, ringbuf02);
audio_element_set_input_ringbuf(fatfs_stream_writer, ringbuf02);
ESP_LOGI(TAG, "[3.4.1] Set up uri (file as fatfs_stream, wav as wav encoder)");
audio_element_set_uri(fatfs_stream_writer, "/sdcard/rec1.wav");
ESP_LOGI(TAG, "[3.5] Create Bluetooth with i2s element input ");
a2dp_stream_config_t a2dp_config = {
.type = AUDIO_STREAM_WRITER,
.user_callback = {0},
};
bt_stream_writer = a2dp_stream_init(&a2dp_config);
// bt_stream_writer = bluetooth_service_create_stream();
ringbuf11 = rb_create(RING_BUFFER_SIZE, 1);
audio_element_set_multi_output_ringbuf(i2s_stream_reader,ringbuf11,0);
audio_element_set_input_ringbuf(bt_stream_writer,ringbuf11);
ESP_LOGI(TAG, "[5.0] Set callback function for audio_elements");
/**
* Event handler used here is quite generic and simple one.
* It just reports state changes of different audio_elements
* Note that, it is not mandatory to set event callbacks.
* One may remove entire step [5.0]. This example could still run.
*/
audio_element_set_event_callback(wav_encoder, audio_element_event_handler, NULL);
audio_element_set_event_callback(i2s_stream_reader, audio_element_event_handler, NULL);
audio_element_set_event_callback(fatfs_stream_writer, audio_element_event_handler, NULL);
audio_element_set_event_callback(bt_stream_writer, audio_element_event_handler, NULL);
ESP_LOGI(TAG, "[ 6.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_periph_handle_t bt_periph;
ESP_LOGI(TAG, "[6.1] Create bt peripheral");
bt_periph = bt_create_periph();
ESP_LOGI(TAG, "[6.2] Start bt peripheral");
esp_periph_start(set, bt_periph);
ESP_LOGI(TAG, "[7.0] Listening event from peripherals");
audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);
ESP_LOGI(TAG, "[8.0] Start audio elements");
audio_element_run(i2s_stream_reader);
audio_element_run(wav_encoder);
audio_element_run(fatfs_stream_writer);
audio_element_run(bt_stream_writer);
//RUN starts in a paused state. RESUME starts the element going
audio_element_resume(i2s_stream_reader, 0, 0);
audio_element_resume(wav_encoder, 0, 0);
audio_element_resume(fatfs_stream_writer, 0, 0);
audio_element_resume(bt_stream_writer, 0, 0);
ESP_LOGI(TAG, "[ 6 ] Listen for all pipeline events, record for %d Seconds", RECORD_TIME_SECONDS);
int second_recorded = 0;
while (1) {
audio_event_iface_msg_t msg;
int button_debounce = 3; //Seconds before the button can be pressed again to stop the recording
int button_time = 0;
if (audio_event_iface_listen(evt, &msg, 1000 / portTICK_RATE_MS) != ESP_OK) {
second_recorded ++;
ESP_LOGI(TAG, "[ * ] Recording ... %d", second_recorded);
/*Button pressed again to stop recording*/
// if ((get_button(8) || get_button(9)) && button_time >= button_debounce){
// ESP_LOGI(TAG, "Button Pressed to Stop");
// break;
// }
//button_time++;
if (second_recorded >= RECORD_TIME_SECONDS) {
break;
}
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 (msg.source_type == PERIPH_ID_BLUETOOTH && msg.source == (void *)bt_periph) {
if ((msg.cmd == PERIPH_BLUETOOTH_DISCONNECTED) || (msg.cmd == PERIPH_BLUETOOTH_AUDIO_SUSPENDED)) {
ESP_LOGW(TAG, "[ * ] Bluetooth disconnected or suspended");
// periph_bt_stop(bt_periph);
break;
}
}
/* Stop when the last pipeline element (i2s_stream_reader in this case) receives stop event */
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_reader
&& msg.cmd == AEL_MSG_CMD_REPORT_STATUS
&& (((int)msg.data == AEL_STATUS_STATE_STOPPED) || ((int)msg.data == AEL_STATUS_STATE_FINISHED))) {
ESP_LOGW(TAG, "[ * ] Stop event received");
break;
}
}
ESP_LOGI(TAG, "[ 7 ] Stop audio_pipeline");
/* Stop all periph before removing the listener */
esp_periph_set_stop_all(set);
/* Release all resources */
audio_element_deinit(i2s_stream_reader);
audio_element_deinit(wav_encoder);
audio_element_deinit(fatfs_stream_writer);
audio_element_deinit(bt_stream_writer);
esp_periph_set_destroy(set);
rb_destroy(ringbuf01);
rb_destroy(ringbuf02);
rb_destroy(ringbuf11);
}