Page 1 of 1

Change audio_pipeline elements during runtime

Posted: Wed May 29, 2024 10:23 am
by divy98
I am developing a project based on the wifi_bt_ble_coex example using the LyraTD-MSC-v2.2 audio board. Our application requires the ESP32 device to switch between WiFi streaming and BT streaming. We removed the hfp stream part since we don't need it, and we replaced esp_audio APIs with audio_pipeline APIs and got BT streaming to work. Now we have to configure the pipeline to switch between http reader and bt reader stream when the "mode" button is pressed:

Code: Select all

pipeline: bt_stream_reader-->rsp_filter-->i2s_stream_write
[Mode button pressed]
pipeline: http_stream_reader-->mp3_decoder-->rsp_filter-->i2s_stream_writer
My assumption was that I will be able to stop the audio pipeline, unlink the elements, re-link the new elements (http reader in place of the bt_reader) and restart the pipeline.

The program is currently experiencing a crash after I try to re-link the elements. I am currently experimenting with these audio_pipeline functions to try to solve the issue.

Code: Select all

audio_pipeline_pause();
audio_pipeline_stop();
audio_pipeline_terminate();
audio_pipeline_link();
audio_pipeline_run();
Has anyone tried something like this? Any assistance is appreciated.

Re: Change audio_pipeline elements during runtime

Posted: Thu May 30, 2024 1:32 pm
by divy98
I solved the crash issue by using audio_pipeline_relink() instead of audio_pipelink_link().

Here is exact APIs call sequence I am using:

Code: Select all

...
else if (cx_handle->work_mode == BT_MODE) {
                    ESP_LOGI(TAG, "[ * ] Enter WIFI mode");
                    cx_handle->work_mode = WIFI_MODE;
...
                        periph_bt_pause(cx_handle->bt_periph);
                        audio_pipeline_pause(pipeline);
                        audio_pipeline_stop(pipeline);
                        audio_pipeline_wait_for_stop(pipeline);
                        vTaskDelay(300 / portTICK_RATE_MS);
                        audio_pipeline_unlink(pipeline);
                    }
                    if (g_wifi_connect_state == true) {
                        const char *link_tag[4] = {"http", "mp3", "filter", "i2s"};
                        audio_pipeline_relink(pipeline, &link_tag[0], 4);
                        audio_pipeline_run(pipeline);
                    }
                } else if (cx_handle->work_mode == WIFI_MODE) {
                    ESP_LOGI(TAG, "[ * ] Enter BT mode");
                    cx_handle->work_mode = BT_MODE;
                    audio_pipeline_pause(pipeline);
                    audio_pipeline_stop(pipeline);
                    audio_pipeline_wait_for_stop(pipeline);
                    if (g_a2dp_connect_state == true) {
                        audio_pipeline_unlink(pipeline);
                        const char *link_tag[3] = {"bt", "filter", "i2s"};
                        audio_pipeline_relink(pipeline, &link_tag[0], 3);
                        audio_pipeline_run(pipeline);
                        periph_bt_play(cx_handle->bt_periph);
                    }
This switches the pipeline successfully from BT to WiFi but I am experiencing another issue when switching back to BT from WiFi mode. I get this error continuously. There is no audio when it is printing this error.

Code: Select all

W (110849) A2DP_STREAM: discard a2dp(0x3ffe5ec4) sink pkt, A2DP_STREAM_QUEUE_SIZE value needs to be expanded
W (110869) A2DP_STREAM: discard a2dp(0x3ffe5ec4) sink pkt, A2DP_STREAM_QUEUE_SIZE value needs to be expanded
W (110889) A2DP_STREAM: discard a2dp(0x3ffe5ec4) sink pkt, A2DP_STREAM_QUEUE_SIZE value needs to be expanded
W (110919) A2DP_STREAM: discard a2dp(0x3ffe5ec4) sink pkt, A2DP_STREAM_QUEUE_SIZE value needs to be expanded
And when I switch back to WiFi mode, it shows

Code: Select all

W (31089) AUDIO_EVT: There is no space in external queue

***ERROR*** A stack overflow in task input_key_servi has been detected.
So now my approach is deinitialize and free the whole pipeline and its elements and reinitialise it upon Mode switch from BT to WiFi or vice versa

Re: Change audio_pipeline elements during runtime

Posted: Mon Jun 03, 2024 1:10 pm
by divy98
Fixed the issue without freeing and re-initialising the pipeline. Just had to set the event listener interface again, made it global so I could use it in the callback. Here is the code if anyone needs it in the future:

Code: Select all

...
                } else if (cx_handle->work_mode == BT_MODE) {
                    ESP_LOGI(TAG, "[ * ] Enter WIFI mode");
                    cx_handle->work_mode = WIFI_MODE;
                    if (g_a2dp_connect_state == true) {
                        periph_bt_pause(cx_handle->bt_periph);

                        audio_pipeline_pause(pipeline);
                        audio_pipeline_stop(pipeline);
                        audio_pipeline_wait_for_stop(pipeline);
                        audio_pipeline_unlink(pipeline);
                        vTaskDelay(300 / portTICK_RATE_MS);

                        const char *link_tag[4] = {"http", "mp3", "filter", "i2s"};
                        audio_pipeline_relink(pipeline, &link_tag[0], 4);
                        audio_pipeline_set_listener(g_coex_handle->pipeline, evt_if);
                        audio_pipeline_run(pipeline);
                    }
                } else if (cx_handle->work_mode == WIFI_MODE) {
                    ESP_LOGI(TAG, "[ * ] Enter BT mode");
                    cx_handle->work_mode = BT_MODE;
                    audio_pipeline_pause(pipeline);
                    audio_pipeline_stop(pipeline);
                    audio_pipeline_wait_for_stop(pipeline);
                    audio_pipeline_unlink(pipeline);
                    vTaskDelay(300 / portTICK_RATE_MS);

                    const char *link_tag[3] = {"bt", "filter", "i2s"};
                    audio_pipeline_relink(g_coex_handle->pipeline, &link_tag[0], 3);
                    audio_pipeline_set_listener(g_coex_handle->pipeline, evt_if);
                    audio_pipeline_run(pipeline);
                    if (g_a2dp_connect_state == true) {
                        periph_bt_play(cx_handle->bt_periph);
                    }
                }
                break;
...

Re: Change audio_pipeline elements during runtime

Posted: Tue Aug 06, 2024 1:11 pm
by divy98
There still existed an issue when switching pipelines between BT and WiFi. Due to periph_bt_pause() returning before the queue was emptied, and the audio pipeline pausing immediately which in-turn stops the queue from getting emptied. So inserting a small delay after periph_bt_pause() and before pausing the audio pipeline solved the issue.