xref: /btstack/port/esp32/components/btstack/btstack_audio_esp32_v4.c (revision 0d72163bdf7f92cb151fc0c5da28623e9dfd80da)
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