1 /*
2 * Copyright (C) 2018 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "btstack_audio_esp32.c"
39
40 /*
41 * btstack_audio_esp32.c
42 *
43 * Implementation of btstack_audio.h using polling ESP32 I2S driver
44 *
45 */
46
47 #include "btstack_config.h"
48 #include "btstack_debug.h"
49 #include "btstack_audio.h"
50 #include "btstack_run_loop.h"
51
52 #include "freertos/FreeRTOS.h"
53 #include "freertos/queue.h"
54
55 #include "driver/gpio.h"
56 #include "driver/i2s.h"
57 #include "esp_log.h"
58
59 #include <inttypes.h>
60 #include <string.h>
61
62 #define LOG_TAG "AUDIO"
63
64 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
65 #include "driver/i2c.h"
66 #include "es8388.h"
67 #define IIC_DATA (GPIO_NUM_18)
68 #define IIC_CLK (GPIO_NUM_23)
69 #endif
70
71 #if CONFIG_IDF_TARGET_ESP32C3
72 // Arbitrary choice - Strapping Pins 2,8,9 are used as outputs
73 #define BTSTACK_AUDIO_I2S_BCK GPIO_NUM_2
74 #define BTSTACK_AUDIO_I2S_WS GPIO_NUM_8
75 #define BTSTACK_AUDIO_I2S_OUT GPIO_NUM_9
76 #define BTSTACK_AUDIO_I2S_IN GPIO_NUM_10
77 #elif CONFIG_IDF_TARGET_ESP32S3
78 // ESP32-S3-Korvo-2 V3.0
79 #define BTSTACK_AUDIO_I2S_BCK GPIO_NUM_9
80 #define BTSTACK_AUDIO_I2S_WS GPIO_NUM_45
81 #define BTSTACK_AUDIO_I2S_OUT GPIO_NUM_8
82 #define BTSTACK_AUDIO_I2S_IN GPIO_NUM_10
83 #else
84 // ESP32-LyraT V4
85 #define BTSTACK_AUDIO_I2S_BCK GPIO_NUM_5
86 #define BTSTACK_AUDIO_I2S_WS GPIO_NUM_25
87 #define BTSTACK_AUDIO_I2S_OUT GPIO_NUM_26
88 #define BTSTACK_AUDIO_I2S_IN GPIO_NUM_35
89 #endif
90
91 // prototypes
92 static void btstack_audio_esp32_sink_fill_buffer(void);
93 static void btstack_audio_esp32_source_process_buffer(void);
94
95 #define BTSTACK_AUDIO_I2S_NUM (I2S_NUM_0)
96
97 #define DRIVER_POLL_INTERVAL_MS 5
98 #define DMA_BUFFER_COUNT 2
99 #define BYTES_PER_SAMPLE_STEREO 4
100
101 // one DMA buffer for max sample rate
102 #define MAX_DMA_BUFFER_SAMPLES (48000 * 2 * DRIVER_POLL_INTERVAL_MS/ 1000)
103
104 typedef enum {
105 BTSTACK_AUDIO_ESP32_OFF = 0,
106 BTSTACK_AUDIO_ESP32_INITIALIZED,
107 BTSTACK_AUDIO_ESP32_STREAMING
108 } btstack_audio_esp32_state_t;
109
110 static bool btstack_audio_esp32_i2s_installed;
111 static bool btstack_audio_esp32_i2s_streaming;
112 static uint32_t btstack_audio_esp32_i2s_samplerate;
113 static uint16_t btstack_audio_esp32_samples_per_dma_buffer;
114
115 // timer to fill output ring buffer
116 static btstack_timer_source_t btstack_audio_esp32_driver_timer;
117
118 static uint8_t btstack_audio_esp32_sink_num_channels;
119 static uint32_t btstack_audio_esp32_sink_samplerate;
120
121 static uint8_t btstack_audio_esp32_source_num_channels;
122 static uint32_t btstack_audio_esp32_source_samplerate;
123
124 static btstack_audio_esp32_state_t btstack_audio_esp32_sink_state;
125 static btstack_audio_esp32_state_t btstack_audio_esp32_source_state;
126
127 // client
128 static void (*btstack_audio_esp32_sink_playback_callback)(int16_t * buffer, uint16_t num_samples);
129 static void (*btstack_audio_esp32_source_recording_callback)(const int16_t * buffer, uint16_t num_samples);
130
131 // queue for RX/TX done events
132 static QueueHandle_t btstack_audio_esp32_i2s_event_queue;
133
134 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
135
136 static bool btstack_audio_esp32_es8388_initialized;
137
138 static es8388_config_t es8388_i2c_cfg = AUDIO_CODEC_ES8388_DEFAULT();
139
btstack_audio_esp32_set_i2s0_mclk(void)140 static void btstack_audio_esp32_set_i2s0_mclk(void)
141 {
142 PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
143 WRITE_PERI_REG(PIN_CTRL, 0xFFF0);
144 }
145
btstack_audio_esp32_es8388_init(void)146 void btstack_audio_esp32_es8388_init(void){
147 if (btstack_audio_esp32_es8388_initialized) return;
148 btstack_audio_esp32_es8388_initialized = true;
149
150 es8388_init(&es8388_i2c_cfg);
151 es8388_config_fmt(ES_MODULE_ADC_DAC, ES_I2S_NORMAL);
152 es8388_set_bits_per_sample(ES_MODULE_ADC_DAC, BIT_LENGTH_16BITS);
153 es8388_start(ES_MODULE_ADC_DAC);
154 es8388_set_volume(70);
155 es8388_set_mute(false);
156 }
157 #endif
158
btstack_audio_esp32_driver_timer_handler(btstack_timer_source_t * ts)159 static void btstack_audio_esp32_driver_timer_handler(btstack_timer_source_t * ts){
160 // read max 2 events from i2s event queue
161 i2s_event_t i2s_event;
162 int i;
163 for (i=0;i<2;i++){
164 if( xQueueReceive( btstack_audio_esp32_i2s_event_queue, &i2s_event, 0) == false) break;
165 switch (i2s_event.type){
166 case I2S_EVENT_TX_DONE:
167 log_debug("I2S_EVENT_TX_DONE");
168 btstack_audio_esp32_sink_fill_buffer();
169 break;
170 case I2S_EVENT_RX_DONE:
171 log_debug("I2S_EVENT_RX_DONE");
172 btstack_audio_esp32_source_process_buffer();
173 break;
174 default:
175 break;
176 }
177 }
178
179 // re-set timer
180 btstack_run_loop_set_timer(ts, DRIVER_POLL_INTERVAL_MS);
181 btstack_run_loop_add_timer(ts);
182 }
183
btstack_audio_esp32_stream_start(void)184 static void btstack_audio_esp32_stream_start(void){
185 if (btstack_audio_esp32_i2s_streaming) return;
186
187 // start i2s
188 log_info("i2s stream start");
189 i2s_start(BTSTACK_AUDIO_I2S_NUM);
190
191 // start timer
192 btstack_run_loop_set_timer_handler(&btstack_audio_esp32_driver_timer, &btstack_audio_esp32_driver_timer_handler);
193 btstack_run_loop_set_timer(&btstack_audio_esp32_driver_timer, DRIVER_POLL_INTERVAL_MS);
194 btstack_run_loop_add_timer(&btstack_audio_esp32_driver_timer);
195
196 btstack_audio_esp32_i2s_streaming = true;
197 }
198
btstack_audio_esp32_stream_stop(void)199 static void btstack_audio_esp32_stream_stop(void){
200 if (btstack_audio_esp32_i2s_streaming == false) return;
201
202 // check if still needed
203 bool still_needed = (btstack_audio_esp32_sink_state == BTSTACK_AUDIO_ESP32_STREAMING)
204 || (btstack_audio_esp32_source_state == BTSTACK_AUDIO_ESP32_STREAMING);
205 if (still_needed) return;
206
207 // stop timer
208 btstack_run_loop_remove_timer(&btstack_audio_esp32_driver_timer);
209
210 // stop i2s
211 log_info("i2s stream stop");
212 i2s_stop(BTSTACK_AUDIO_I2S_NUM);
213
214 btstack_audio_esp32_i2s_streaming = false;
215 }
216
btstack_audio_esp32_init(void)217 static void btstack_audio_esp32_init(void){
218
219 // de-register driver if already installed
220 if (btstack_audio_esp32_i2s_installed){
221 i2s_driver_uninstall(BTSTACK_AUDIO_I2S_NUM);
222 }
223
224 // set i2s mode, sample rate and pins based on sink / source config
225 i2s_mode_t i2s_mode = I2S_MODE_MASTER;
226 int i2s_data_out_pin = I2S_PIN_NO_CHANGE;
227 int i2s_data_in_pin = I2S_PIN_NO_CHANGE;
228 btstack_audio_esp32_i2s_samplerate = 0;
229
230 if (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_OFF){
231 i2s_mode |= I2S_MODE_TX; // playback
232 i2s_data_out_pin = BTSTACK_AUDIO_I2S_OUT;
233 if (btstack_audio_esp32_i2s_samplerate != 0){
234 btstack_assert(btstack_audio_esp32_i2s_samplerate == btstack_audio_esp32_sink_samplerate);
235 }
236 btstack_audio_esp32_i2s_samplerate = btstack_audio_esp32_sink_samplerate;
237 btstack_audio_esp32_samples_per_dma_buffer = btstack_audio_esp32_i2s_samplerate * 2 * DRIVER_POLL_INTERVAL_MS / 1000;
238 }
239
240 if (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_OFF){
241 i2s_mode |= I2S_MODE_RX; // recording
242 i2s_data_in_pin = BTSTACK_AUDIO_I2S_IN;
243 if (btstack_audio_esp32_i2s_samplerate != 0){
244 btstack_assert(btstack_audio_esp32_i2s_samplerate == btstack_audio_esp32_source_samplerate);
245 }
246 btstack_audio_esp32_i2s_samplerate = btstack_audio_esp32_source_samplerate;
247 btstack_audio_esp32_samples_per_dma_buffer = btstack_audio_esp32_i2s_samplerate * 2 * DRIVER_POLL_INTERVAL_MS / 1000;
248 }
249
250 btstack_assert(btstack_audio_esp32_samples_per_dma_buffer <= MAX_DMA_BUFFER_SAMPLES);
251
252 i2s_config_t config =
253 {
254 .mode = i2s_mode,
255 .sample_rate = btstack_audio_esp32_i2s_samplerate,
256 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
257 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
258 .communication_format = I2S_COMM_FORMAT_STAND_I2S,
259 .dma_buf_count = DMA_BUFFER_COUNT, // Number of DMA buffers. Max 128.
260 .dma_buf_len = btstack_audio_esp32_samples_per_dma_buffer, // Size of each DMA buffer in samples. Max 1024.
261 .use_apll = true,
262 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1
263 };
264
265 i2s_pin_config_t pins =
266 {
267 .bck_io_num = BTSTACK_AUDIO_I2S_BCK,
268 .ws_io_num = BTSTACK_AUDIO_I2S_WS,
269 .data_out_num = i2s_data_out_pin,
270 .data_in_num = i2s_data_in_pin
271 };
272
273 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
274 btstack_audio_esp32_set_i2s0_mclk();
275 #endif
276
277 log_info("i2s init mode 0x%02x, samplerate %" PRIu32 ", samples per DMA buffer: %u",
278 i2s_mode, btstack_audio_esp32_sink_samplerate, btstack_audio_esp32_samples_per_dma_buffer);
279
280 i2s_driver_install(BTSTACK_AUDIO_I2S_NUM, &config, DMA_BUFFER_COUNT, &btstack_audio_esp32_i2s_event_queue);
281 i2s_set_pin(BTSTACK_AUDIO_I2S_NUM, &pins);
282
283 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
284 btstack_audio_esp32_es8388_init();
285 #endif
286
287 btstack_audio_esp32_i2s_installed = true;
288 }
289
btstack_audio_esp32_deinit(void)290 static void btstack_audio_esp32_deinit(void){
291 if (btstack_audio_esp32_i2s_installed == false) return;
292
293 // check if still needed
294 bool still_needed = (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_OFF)
295 || (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_OFF);
296 if (still_needed) return;
297
298 // uninstall driver
299 log_info("i2s close");
300 i2s_driver_uninstall(BTSTACK_AUDIO_I2S_NUM);
301
302 btstack_audio_esp32_i2s_installed = false;
303 }
304
305 // SINK Implementation
306 // - with esp-idf v4.4.3, we occasionally get a TX_DONE but fail to write data without waiting for free buffers
307 // it's unclera why this happens. this code assumes that the TX_DONE event has been received prematurely and
308 // just retries the i2s_write the next time without blocking
309 static uint8_t btstack_audio_esp32_sink_buffer[MAX_DMA_BUFFER_SAMPLES * BYTES_PER_SAMPLE_STEREO];
310 static bool btstack_audio_esp32_sink_buffer_ready;
btstack_audio_esp32_sink_fill_buffer(void)311 static void btstack_audio_esp32_sink_fill_buffer(void){
312
313 btstack_assert(btstack_audio_esp32_samples_per_dma_buffer <= MAX_DMA_BUFFER_SAMPLES);
314
315 // fetch new data
316 size_t bytes_written;
317 uint16_t data_len = btstack_audio_esp32_samples_per_dma_buffer * BYTES_PER_SAMPLE_STEREO;
318 if (btstack_audio_esp32_sink_buffer_ready == false){
319 if (btstack_audio_esp32_sink_state == BTSTACK_AUDIO_ESP32_STREAMING){
320 (*btstack_audio_esp32_sink_playback_callback)((int16_t *) btstack_audio_esp32_sink_buffer, btstack_audio_esp32_samples_per_dma_buffer);
321 // duplicate samples for mono
322 if (btstack_audio_esp32_sink_num_channels == 1){
323 int16_t i;
324 int16_t * buffer16 = (int16_t *) btstack_audio_esp32_sink_buffer;
325 for (i=btstack_audio_esp32_samples_per_dma_buffer-1;i >= 0; i--){
326 buffer16[2*i ] = buffer16[i];
327 buffer16[2*i+1] = buffer16[i];
328 }
329 }
330 btstack_audio_esp32_sink_buffer_ready = true;
331 } else {
332 memset(btstack_audio_esp32_sink_buffer, 0, data_len);
333 }
334 }
335
336 i2s_write(BTSTACK_AUDIO_I2S_NUM, btstack_audio_esp32_sink_buffer, data_len, &bytes_written, 0);
337
338 // check if all data has been written. tolerate writing zero bytes (->retry), but assert on partial write
339 if (bytes_written == data_len){
340 btstack_audio_esp32_sink_buffer_ready = false;
341 } else if (bytes_written == 0){
342 ESP_LOGW(LOG_TAG, "i2s_write: couldn't write after I2S_EVENT_TX_DONE\n");
343 } else {
344 ESP_LOGE(LOG_TAG, "i2s_write: only %u of %u!!!\n", (int) bytes_written, data_len);
345 btstack_assert(false);
346 }
347 }
348
btstack_audio_esp32_sink_init(uint8_t channels,uint32_t samplerate,void (* playback)(int16_t * buffer,uint16_t num_samples))349 static int btstack_audio_esp32_sink_init(
350 uint8_t channels,
351 uint32_t samplerate,
352 void (*playback)(int16_t * buffer, uint16_t num_samples)){
353
354 btstack_assert(playback != NULL);
355 btstack_assert((1 <= channels) && (channels <= 2));
356
357 // store config
358 btstack_audio_esp32_sink_playback_callback = playback;
359 btstack_audio_esp32_sink_num_channels = channels;
360 btstack_audio_esp32_sink_samplerate = samplerate;
361
362 btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
363
364 // init i2s and codec
365 btstack_audio_esp32_init();
366 return 0;
367 }
368
btstack_audio_esp32_sink_get_samplerate(void)369 static uint32_t btstack_audio_esp32_sink_get_samplerate(void) {
370 return btstack_audio_esp32_sink_samplerate;
371 }
btstack_audio_esp32_sink_set_volume(uint8_t gain)372 static void btstack_audio_esp32_sink_set_volume(uint8_t gain) {
373 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
374 if (!btstack_audio_esp32_es8388_initialized) return;
375 uint8_t volume_0_100 = (uint8_t) ((((uint16_t) gain) * 100) / 128);
376 es8388_set_volume( volume_0_100 );
377 #else
378 UNUSED(gain);
379 #endif
380 }
381
btstack_audio_esp32_sink_start_stream(void)382 static void btstack_audio_esp32_sink_start_stream(void){
383
384 if (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_INITIALIZED) return;
385
386 // validate samplerate
387 btstack_assert(btstack_audio_esp32_sink_samplerate == btstack_audio_esp32_i2s_samplerate);
388
389 // state
390 btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_STREAMING;
391 btstack_audio_esp32_sink_buffer_ready = false;
392
393 // note: conceptually, it would make sense to pre-fill all I2S buffers and then feed new ones when they are
394 // marked as complete. However, it looks like we get additoinal events and then assert below,
395 // so we just don't pre-fill them here
396
397 btstack_audio_esp32_stream_start();
398 }
399
btstack_audio_esp32_sink_stop_stream(void)400 static void btstack_audio_esp32_sink_stop_stream(void){
401
402 if (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_STREAMING) return;
403
404 // state
405 btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
406
407 btstack_audio_esp32_stream_stop();
408 }
409
btstack_audio_esp32_sink_close(void)410 static void btstack_audio_esp32_sink_close(void){
411
412 if (btstack_audio_esp32_sink_state == BTSTACK_AUDIO_ESP32_STREAMING) {
413 btstack_audio_esp32_sink_stop_stream();
414 }
415
416 // state
417 btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_OFF;
418
419 btstack_audio_esp32_deinit();
420 }
421
422 static const btstack_audio_sink_t btstack_audio_esp32_sink = {
423 .init = &btstack_audio_esp32_sink_init,
424 .get_samplerate = &btstack_audio_esp32_sink_get_samplerate,
425 .set_volume = &btstack_audio_esp32_sink_set_volume,
426 .start_stream = &btstack_audio_esp32_sink_start_stream,
427 .stop_stream = &btstack_audio_esp32_sink_stop_stream,
428 .close = &btstack_audio_esp32_sink_close
429 };
430
btstack_audio_esp32_sink_get_instance(void)431 const btstack_audio_sink_t * btstack_audio_esp32_sink_get_instance(void){
432 return &btstack_audio_esp32_sink;
433 }
434
435 // SOURCE Implementation
436
btstack_audio_esp32_source_process_buffer(void)437 static void btstack_audio_esp32_source_process_buffer(void){
438 size_t bytes_read;
439 uint8_t buffer[MAX_DMA_BUFFER_SAMPLES * BYTES_PER_SAMPLE_STEREO];
440
441 btstack_assert(btstack_audio_esp32_samples_per_dma_buffer <= MAX_DMA_BUFFER_SAMPLES);
442
443 uint16_t data_len = btstack_audio_esp32_samples_per_dma_buffer * BYTES_PER_SAMPLE_STEREO;
444 i2s_read(BTSTACK_AUDIO_I2S_NUM, buffer, data_len, &bytes_read, 0);
445
446 // check if full buffer is ready. tolerate reading zero bytes (->retry), but assert on partial read
447 if (bytes_read == 0){
448 ESP_LOGW(LOG_TAG, "i2s_read: no data after I2S_EVENT_RX_DONE\n");
449 return;
450 } else if (bytes_read < data_len){
451 ESP_LOGE(LOG_TAG, "i2s_read: only %u of %u!!!\n", (int) bytes_read, data_len);
452 btstack_assert(false);
453 return;
454 }
455
456 int16_t * buffer16 = (int16_t *) buffer;
457 if (btstack_audio_esp32_source_state == BTSTACK_AUDIO_ESP32_STREAMING) {
458 // drop second channel if configured for mono
459 if (btstack_audio_esp32_source_num_channels == 1){
460 uint16_t i;
461 for (i=0;i<btstack_audio_esp32_samples_per_dma_buffer;i++){
462 buffer16[i] = buffer16[2*i];
463 }
464 }
465 (*btstack_audio_esp32_source_recording_callback)(buffer16, btstack_audio_esp32_samples_per_dma_buffer);
466 }
467 }
468
btstack_audio_esp32_source_init(uint8_t channels,uint32_t samplerate,void (* recording)(const int16_t * buffer,uint16_t num_samples))469 static int btstack_audio_esp32_source_init(
470 uint8_t channels,
471 uint32_t samplerate,
472 void (*recording)(const int16_t * buffer, uint16_t num_samples)
473 ){
474 btstack_assert(recording != NULL);
475
476 // store config
477 btstack_audio_esp32_source_recording_callback = recording;
478 btstack_audio_esp32_source_num_channels = channels;
479 btstack_audio_esp32_source_samplerate = samplerate;
480
481 btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
482
483 // init i2s and codec
484 btstack_audio_esp32_init();
485 return 0;
486 }
487
btstack_audio_esp32_source_get_samplerate(void)488 static uint32_t btstack_audio_esp32_source_get_samplerate(void) {
489 return btstack_audio_esp32_source_samplerate;
490 }
btstack_audio_esp32_source_set_gain(uint8_t gain)491 static void btstack_audio_esp32_source_set_gain(uint8_t gain) {
492 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
493 if (!btstack_audio_esp32_es8388_initialized) return;
494 // ES8388 supports 0..24 dB gain in 3 dB steps
495 uint8_t gain_db = (uint8_t) ( ((uint16_t) gain) * 24 / 127);
496 es8388_set_mic_gain( (es_codec_mic_gain_t) gain_db );
497 #else
498 UNUSED(gain);
499 #endif
500 }
501
btstack_audio_esp32_source_start_stream(void)502 static void btstack_audio_esp32_source_start_stream(void){
503
504 if (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_INITIALIZED) return;
505
506 // validate samplerate
507 btstack_assert(btstack_audio_esp32_source_samplerate == btstack_audio_esp32_i2s_samplerate);
508
509 // state
510 btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_STREAMING;
511
512 btstack_audio_esp32_stream_start();
513 }
514
btstack_audio_esp32_source_stop_stream(void)515 static void btstack_audio_esp32_source_stop_stream(void){
516
517 if (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_STREAMING) return;
518
519 // state
520 btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
521
522 btstack_audio_esp32_stream_stop();
523 }
524
btstack_audio_esp32_source_close(void)525 static void btstack_audio_esp32_source_close(void){
526
527 if (btstack_audio_esp32_source_state == BTSTACK_AUDIO_ESP32_STREAMING) {
528 btstack_audio_esp32_source_stop_stream();
529 }
530
531 // state
532 btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_OFF;
533
534 btstack_audio_esp32_deinit();
535 }
536
537 static const btstack_audio_source_t btstack_audio_esp32_source = {
538 .init = &btstack_audio_esp32_source_init,
539 .get_samplerate = &btstack_audio_esp32_source_get_samplerate,
540 .set_gain = &btstack_audio_esp32_source_set_gain,
541 .start_stream = &btstack_audio_esp32_source_start_stream,
542 .stop_stream = &btstack_audio_esp32_source_stop_stream,
543 .close = &btstack_audio_esp32_source_close
544 };
545
btstack_audio_esp32_source_get_instance(void)546 const btstack_audio_source_t * btstack_audio_esp32_source_get_instance(void){
547 return &btstack_audio_esp32_source;
548 }
549