Skip to content

Commit 55f92ec

Browse files
committed
Merge branch 'bt/opt_audio_datapath' into 'master'
bt/optimized a2dp_sink audio datapath Closes IDFGH-8124 and AUD-4106 See merge request espressif/esp-idf!20592
2 parents ab20e3e + 0459cf3 commit 55f92ec

File tree

2 files changed

+84
-15
lines changed

2 files changed

+84
-15
lines changed

components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ enum {
7777

7878
/* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */
7979
#define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (25)
80-
#define JITTER_BUFFER_WATER_LEVEL (5)
8180

8281
#define BTC_A2DP_SNK_DATA_QUEUE_IDX (1)
8382

@@ -688,9 +687,7 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
688687
p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
689688
APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
690689
fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
691-
if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= JITTER_BUFFER_WATER_LEVEL) {
692-
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
693-
}
690+
osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT);
694691
} else {
695692
/* let caller deal with a failed allocation */
696693
APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - ");

examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.c

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "freertos/FreeRTOSConfig.h"
1212
#include "freertos/FreeRTOS.h"
1313
#include "freertos/queue.h"
14+
#include "freertos/semphr.h"
1415
#include "freertos/task.h"
1516
#include "esp_log.h"
1617
#include "bt_app_core.h"
@@ -22,6 +23,16 @@
2223
#endif
2324
#include "freertos/ringbuf.h"
2425

26+
27+
#define RINGBUF_HIGHEST_WATER_LEVEL (32 * 1024)
28+
#define RINGBUF_PREFETCH_WATER_LEVEL (20 * 1024)
29+
30+
enum {
31+
RINGBUFFER_MODE_PROCESSING, /* ringbuffer is buffering incoming audio data, I2S is working */
32+
RINGBUFFER_MODE_PREFETCHING, /* ringbuffer is buffering incoming audio data, I2S is waiting */
33+
RINGBUFFER_MODE_DROPPING /* ringbuffer is not buffering (dropping) incoming audio data, I2S is working */
34+
};
35+
2536
/*******************************
2637
* STATIC FUNCTION DECLARATIONS
2738
******************************/
@@ -43,6 +54,12 @@ static QueueHandle_t s_bt_app_task_queue = NULL; /* handle of work queue */
4354
static TaskHandle_t s_bt_app_task_handle = NULL; /* handle of application task */
4455
static TaskHandle_t s_bt_i2s_task_handle = NULL; /* handle of I2S task */
4556
static RingbufHandle_t s_ringbuf_i2s = NULL; /* handle of ringbuffer for I2S */
57+
static SemaphoreHandle_t s_i2s_write_semaphore = NULL;
58+
static uint16_t ringbuffer_mode = RINGBUFFER_MODE_PROCESSING;
59+
60+
/*********************************
61+
* EXTERNAL FUNCTION DECLARATIONS
62+
********************************/
4663
#ifndef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
4764
extern i2s_chan_handle_t tx_chan;
4865
#endif
@@ -101,18 +118,33 @@ static void bt_i2s_task_handler(void *arg)
101118
{
102119
uint8_t *data = NULL;
103120
size_t item_size = 0;
121+
/**
122+
* The total length of DMA buffer of I2S is:
123+
* `dma_frame_num * dma_desc_num * i2s_channel_num * i2s_data_bit_width / 8`.
124+
* Transmit `dma_frame_num * dma_desc_num` bytes to DMA is trade-off.
125+
*/
126+
const size_t item_size_upto = 240 * 6;
104127
size_t bytes_written = 0;
105128

106129
for (;;) {
107-
/* receive data from ringbuffer and write it to I2S DMA transmit buffer */
108-
data = (uint8_t *)xRingbufferReceive(s_ringbuf_i2s, &item_size, (TickType_t)portMAX_DELAY);
109-
if (item_size != 0){
110-
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
111-
i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY);
112-
#else
113-
i2s_channel_write(tx_chan, data, item_size, &bytes_written, portMAX_DELAY);
114-
#endif
115-
vRingbufferReturnItem(s_ringbuf_i2s, (void *)data);
130+
if (pdTRUE == xSemaphoreTake(s_i2s_write_semaphore, portMAX_DELAY)) {
131+
for (;;) {
132+
item_size = 0;
133+
/* receive data from ringbuffer and write it to I2S DMA transmit buffer */
134+
data = (uint8_t *)xRingbufferReceiveUpTo(s_ringbuf_i2s, &item_size, (TickType_t)pdMS_TO_TICKS(20), item_size_upto);
135+
if (item_size == 0) {
136+
ESP_LOGI(BT_APP_CORE_TAG, "ringbuffer underflowed! mode changed: RINGBUFFER_MODE_PREFETCHING");
137+
ringbuffer_mode = RINGBUFFER_MODE_PREFETCHING;
138+
break;
139+
}
140+
141+
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
142+
i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY);
143+
#else
144+
i2s_channel_write(tx_chan, data, item_size, &bytes_written, portMAX_DELAY);
145+
#endif
146+
vRingbufferReturnItem(s_ringbuf_i2s, (void *)data);
147+
}
116148
}
117149
}
118150
}
@@ -168,7 +200,14 @@ void bt_app_task_shut_down(void)
168200

169201
void bt_i2s_task_start_up(void)
170202
{
171-
if ((s_ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF)) == NULL) {
203+
ESP_LOGI(BT_APP_CORE_TAG, "ringbuffer data empty! mode changed: RINGBUFFER_MODE_PREFETCHING");
204+
ringbuffer_mode = RINGBUFFER_MODE_PREFETCHING;
205+
if ((s_i2s_write_semaphore = xSemaphoreCreateBinary()) == NULL) {
206+
ESP_LOGE(BT_APP_CORE_TAG, "%s, Semaphore create failed", __func__);
207+
return;
208+
}
209+
if ((s_ringbuf_i2s = xRingbufferCreate(RINGBUF_HIGHEST_WATER_LEVEL, RINGBUF_TYPE_BYTEBUF)) == NULL) {
210+
ESP_LOGE(BT_APP_CORE_TAG, "%s, ringbuffer create failed", __func__);
172211
return;
173212
}
174213
xTaskCreate(bt_i2s_task_handler, "BtI2STask", 1024, NULL, configMAX_PRIORITIES - 3, &s_bt_i2s_task_handle);
@@ -184,11 +223,44 @@ void bt_i2s_task_shut_down(void)
184223
vRingbufferDelete(s_ringbuf_i2s);
185224
s_ringbuf_i2s = NULL;
186225
}
226+
if (s_i2s_write_semaphore) {
227+
vSemaphoreDelete(s_i2s_write_semaphore);
228+
s_i2s_write_semaphore = NULL;
229+
}
187230
}
188231

189232
size_t write_ringbuf(const uint8_t *data, size_t size)
190233
{
191-
BaseType_t done = xRingbufferSend(s_ringbuf_i2s, (void *)data, size, (TickType_t)portMAX_DELAY);
234+
size_t item_size = 0;
235+
BaseType_t done = pdFALSE;
236+
237+
if (ringbuffer_mode == RINGBUFFER_MODE_DROPPING) {
238+
ESP_LOGW(BT_APP_CORE_TAG, "ringbuffer is full, drop this packet!");
239+
vRingbufferGetInfo(s_ringbuf_i2s, NULL, NULL, NULL, NULL, &item_size);
240+
if (item_size <= RINGBUF_PREFETCH_WATER_LEVEL) {
241+
ESP_LOGI(BT_APP_CORE_TAG, "ringbuffer data decreased! mode changed: RINGBUFFER_MODE_PROCESSING");
242+
ringbuffer_mode = RINGBUFFER_MODE_PROCESSING;
243+
}
244+
return 0;
245+
}
246+
247+
done = xRingbufferSend(s_ringbuf_i2s, (void *)data, size, (TickType_t)0);
248+
249+
if (!done) {
250+
ESP_LOGW(BT_APP_CORE_TAG, "ringbuffer overflowed, ready to decrease data! mode changed: RINGBUFFER_MODE_DROPPING");
251+
ringbuffer_mode = RINGBUFFER_MODE_DROPPING;
252+
}
253+
254+
if (ringbuffer_mode == RINGBUFFER_MODE_PREFETCHING) {
255+
vRingbufferGetInfo(s_ringbuf_i2s, NULL, NULL, NULL, NULL, &item_size);
256+
if (item_size >= RINGBUF_PREFETCH_WATER_LEVEL) {
257+
ESP_LOGI(BT_APP_CORE_TAG, "ringbuffer data increased! mode changed: RINGBUFFER_MODE_PROCESSING");
258+
ringbuffer_mode = RINGBUFFER_MODE_PROCESSING;
259+
if (pdFALSE == xSemaphoreGive(s_i2s_write_semaphore)) {
260+
ESP_LOGE(BT_APP_CORE_TAG, "semphore give failed");
261+
}
262+
}
263+
}
192264

193265
return done ? size : 0;
194266
}

0 commit comments

Comments
 (0)