11
11
#include "freertos/FreeRTOSConfig.h"
12
12
#include "freertos/FreeRTOS.h"
13
13
#include "freertos/queue.h"
14
+ #include "freertos/semphr.h"
14
15
#include "freertos/task.h"
15
16
#include "esp_log.h"
16
17
#include "bt_app_core.h"
22
23
#endif
23
24
#include "freertos/ringbuf.h"
24
25
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
+
25
36
/*******************************
26
37
* STATIC FUNCTION DECLARATIONS
27
38
******************************/
@@ -43,6 +54,12 @@ static QueueHandle_t s_bt_app_task_queue = NULL; /* handle of work queue */
43
54
static TaskHandle_t s_bt_app_task_handle = NULL ; /* handle of application task */
44
55
static TaskHandle_t s_bt_i2s_task_handle = NULL ; /* handle of I2S task */
45
56
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
+ ********************************/
46
63
#ifndef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
47
64
extern i2s_chan_handle_t tx_chan ;
48
65
#endif
@@ -101,18 +118,33 @@ static void bt_i2s_task_handler(void *arg)
101
118
{
102
119
uint8_t * data = NULL ;
103
120
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 ;
104
127
size_t bytes_written = 0 ;
105
128
106
129
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
+ }
116
148
}
117
149
}
118
150
}
@@ -168,7 +200,14 @@ void bt_app_task_shut_down(void)
168
200
169
201
void bt_i2s_task_start_up (void )
170
202
{
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__ );
172
211
return ;
173
212
}
174
213
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)
184
223
vRingbufferDelete (s_ringbuf_i2s );
185
224
s_ringbuf_i2s = NULL ;
186
225
}
226
+ if (s_i2s_write_semaphore ) {
227
+ vSemaphoreDelete (s_i2s_write_semaphore );
228
+ s_i2s_write_semaphore = NULL ;
229
+ }
187
230
}
188
231
189
232
size_t write_ringbuf (const uint8_t * data , size_t size )
190
233
{
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
+ }
192
264
193
265
return done ? size : 0 ;
194
266
}
0 commit comments