xref: /btstack/port/esp32/components/btstack/btstack_audio_esp32_v5.c (revision df18f866005397c46f21e5073d4007142b09c254)
1 /*
2  * Copyright (C) 2023 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_std.h"
57 #include "esp_log.h"
58 
59 #include <inttypes.h>
60 #include <stdatomic.h>
61 #include <string.h>
62 
63 #define LOG_TAG "AUDIO"
64 
65 #ifdef CONFIG_I2S_ISR_IRAM_SAFE
66 #error CONFIG_I2S_ISR_IRAM_SAFE not supported
67 #endif
68 
69 i2s_chan_handle_t tx_handle = NULL;
70 i2s_chan_handle_t rx_handle = NULL;
71 
72 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
73 #include "driver/i2c.h"
74 #include "es8388.h"
75 #define IIC_DATA                    (GPIO_NUM_18)
76 #define IIC_CLK                     (GPIO_NUM_23)
77 #endif
78 
79 #if CONFIG_IDF_TARGET_ESP32C3
80 // Arbitrary choice - Strapping Pins 2,8,9 are used as outputs
81 #define BTSTACK_AUDIO_I2S_BCK GPIO_NUM_2
82 #define BTSTACK_AUDIO_I2S_WS  GPIO_NUM_8
83 #define BTSTACK_AUDIO_I2S_OUT GPIO_NUM_9
84 #define BTSTACK_AUDIO_I2S_IN  GPIO_NUM_10
85 #elif CONFIG_IDF_TARGET_ESP32S3
86 // ESP32-S3-Korvo-2 V3.0
87 #define BTSTACK_AUDIO_I2S_BCK GPIO_NUM_9
88 #define BTSTACK_AUDIO_I2S_WS  GPIO_NUM_45
89 #define BTSTACK_AUDIO_I2S_OUT GPIO_NUM_8
90 #define BTSTACK_AUDIO_I2S_IN  GPIO_NUM_10
91 #elif CONFIG_ESP_LYRAT_V4_3_BOARD
92 // ESP32-LyraT V4
93 #define BTSTACK_AUDIO_I2S_MCLK GPIO_NUM_0
94 #define BTSTACK_AUDIO_I2S_BCK  GPIO_NUM_5
95 #define BTSTACK_AUDIO_I2S_WS   GPIO_NUM_25
96 #define BTSTACK_AUDIO_I2S_OUT  GPIO_NUM_26
97 #define BTSTACK_AUDIO_I2S_IN   GPIO_NUM_35
98 #define HEADPHONE_DETECT       GPIO_NUM_19
99 #elif CONFIG_IDF_TARGET_ESP32
100 // Generic ESP32
101 #define BTSTACK_AUDIO_I2S_MCLK GPIO_NUM_0
102 #define BTSTACK_AUDIO_I2S_BCK  GPIO_NUM_5
103 #define BTSTACK_AUDIO_I2S_WS   GPIO_NUM_25
104 #define BTSTACK_AUDIO_I2S_OUT  GPIO_NUM_26
105 #define BTSTACK_AUDIO_I2S_IN   GPIO_NUM_35
106 #else
107 #error "No I2S configuration, if you don't use BTstack I2S audio please disable BTSTACK_AUDIO in Components->BTstack Configuration"
108 #endif
109 
110 // set MCLK unused
111 #ifndef BTSTACK_AUDIO_I2S_MCLK
112 #define BTSTACK_AUDIO_I2S_MCLK GPIO_NUM_NC
113 #endif
114 
115 #define BTSTACK_AUDIO_I2S_NUM  (I2S_NUM_0)
116 
117 #define DRIVER_ISR_INTERVAL_MS          10 // dma interrupt cycle time in ms
118 #define DMA_BUFFER_COUNT                 6
119 #define BYTES_PER_SAMPLE_STEREO          4
120 
121 // one DMA buffer for max sample rate
122 #define MAX_DMA_BUFFER_SAMPLES (48000 * 2 * DRIVER_ISR_INTERVAL_MS/ 1000)
123 
124 typedef enum {
125     BTSTACK_AUDIO_ESP32_OFF = 0,
126     BTSTACK_AUDIO_ESP32_INITIALIZED,
127     BTSTACK_AUDIO_ESP32_STREAMING
128 } btstack_audio_esp32_state_t;
129 
130 static bool btstack_audio_esp32_i2s_installed;
131 static bool btstack_audio_esp32_i2s_streaming;
132 static uint32_t btstack_audio_esp32_i2s_samplerate;
133 
134 static uint8_t  btstack_audio_esp32_sink_num_channels;
135 static uint32_t btstack_audio_esp32_sink_samplerate;
136 
137 static uint8_t  btstack_audio_esp32_source_num_channels;
138 static uint32_t btstack_audio_esp32_source_samplerate;
139 
140 static btstack_audio_esp32_state_t btstack_audio_esp32_sink_state;
141 static btstack_audio_esp32_state_t btstack_audio_esp32_source_state;
142 // client
143 static void (*btstack_audio_esp32_sink_playback_callback)(int16_t * buffer, uint16_t num_samples);
144 static void (*btstack_audio_esp32_source_recording_callback)(const int16_t * buffer, uint16_t num_samples);
145 
146 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
147 
148 static bool btstack_audio_esp32_es8388_initialized;
149 
150 static es8388_config_t es8388_i2c_cfg = AUDIO_CODEC_ES8388_DEFAULT();
151 
btstack_audio_esp32_es8388_init(void)152 void btstack_audio_esp32_es8388_init(void){
153     if (btstack_audio_esp32_es8388_initialized) return;
154 
155     btstack_audio_esp32_es8388_initialized = true;
156 
157     ESP_ERROR_CHECK(es8388_init(&es8388_i2c_cfg));
158     ESP_ERROR_CHECK(es8388_config_fmt(ES_MODULE_ADC_DAC, ES_I2S_NORMAL));
159     ESP_ERROR_CHECK(es8388_set_bits_per_sample(ES_MODULE_ADC_DAC, BIT_LENGTH_16BITS));
160     ESP_ERROR_CHECK(es8388_start(ES_MODULE_ADC_DAC));
161     ESP_ERROR_CHECK(es8388_set_volume(70));
162     ESP_ERROR_CHECK(es8388_set_mute(false));
163 }
164 #endif
165 
166 // data source for integration with btstack run-loop
167 static btstack_data_source_t transport_data_source;
168 static volatile _Atomic uint32_t isr_bytes_read = 0;
169 static volatile _Atomic uint32_t isr_bytes_written = 0;
170 
btstack_audio_esp32_stream_start(void)171 static void btstack_audio_esp32_stream_start(void){
172     if (btstack_audio_esp32_i2s_streaming) return;
173 
174     // check if needed
175     bool needed = (btstack_audio_esp32_sink_state   == BTSTACK_AUDIO_ESP32_STREAMING)
176                || (btstack_audio_esp32_source_state == BTSTACK_AUDIO_ESP32_STREAMING);
177     if (!needed) return;
178 
179     // clear isr exchange variables to avoid data source activation
180     atomic_store_explicit(&isr_bytes_written, 0, memory_order_relaxed);
181     atomic_store_explicit(&isr_bytes_read, 0, memory_order_relaxed);
182 
183     // start data source
184     btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_POLL);
185     btstack_run_loop_add_data_source(&transport_data_source);
186 
187     btstack_audio_esp32_i2s_streaming = true;
188 }
189 
btstack_audio_esp32_stream_stop(void)190 static void btstack_audio_esp32_stream_stop(void){
191     if (btstack_audio_esp32_i2s_streaming == false) return;
192 
193     // check if still needed
194     bool still_needed = (btstack_audio_esp32_sink_state   == BTSTACK_AUDIO_ESP32_STREAMING)
195                      || (btstack_audio_esp32_source_state == BTSTACK_AUDIO_ESP32_STREAMING);
196     if (still_needed) return;
197 
198     // stop data source
199     btstack_run_loop_disable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_POLL);
200     btstack_run_loop_remove_data_source(&transport_data_source);
201 
202     atomic_store_explicit(&isr_bytes_written, 0, memory_order_relaxed);
203     atomic_store_explicit(&isr_bytes_read, 0, memory_order_relaxed);
204 
205     btstack_audio_esp32_i2s_streaming = false;
206 }
207 
i2s_rx_callback(i2s_chan_handle_t handle,i2s_event_data_t * event,void * user_ctx)208 static IRAM_ATTR bool i2s_rx_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
209 {
210     size_t block_size = event->size;
211     atomic_fetch_add_explicit(&isr_bytes_read, block_size, memory_order_relaxed);
212     if( block_size > 0 ) {
213         btstack_run_loop_poll_data_sources_from_irq();
214         return true;
215     }
216     return false;
217 }
218 
i2s_tx_callback(i2s_chan_handle_t handle,i2s_event_data_t * event,void * user_ctx)219 static IRAM_ATTR bool i2s_tx_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
220 {
221     size_t block_size = event->size;
222     atomic_fetch_add_explicit(&isr_bytes_written, block_size, memory_order_relaxed);
223     if( block_size > 0 ) {
224         btstack_run_loop_poll_data_sources_from_irq();
225         return true;
226     }
227     return false;
228 }
229 
230 static uint8_t btstack_audio_esp32_buffer[MAX_DMA_BUFFER_SAMPLES * BYTES_PER_SAMPLE_STEREO * DMA_BUFFER_COUNT];
i2s_data_process(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)231 static void i2s_data_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
232 
233     size_t bytes_written = 0;
234     size_t bytes_read = 0;
235     uint32_t write_block_size = atomic_load_explicit(&isr_bytes_written, memory_order_relaxed);
236     uint32_t read_block_size = atomic_load_explicit(&isr_bytes_read, memory_order_relaxed);
237     switch (callback_type){
238         case DATA_SOURCE_CALLBACK_POLL: {
239             uint16_t num_samples = write_block_size/BYTES_PER_SAMPLE_STEREO;
240             if( num_samples > 0 ) {
241                 (*btstack_audio_esp32_sink_playback_callback)((int16_t *) btstack_audio_esp32_buffer, num_samples);
242                 // duplicate samples for mono
243                 if (btstack_audio_esp32_sink_num_channels == 1){
244                     int16_t *buffer16 = (int16_t *) btstack_audio_esp32_buffer;
245                     for (int16_t i=num_samples-1;i >= 0; i--){
246                         buffer16[2*i  ] = buffer16[i];
247                         buffer16[2*i+1] = buffer16[i];
248                     }
249                 }
250                 esp_err_t ret = i2s_channel_write(tx_handle, btstack_audio_esp32_buffer, write_block_size, &bytes_written, 0 );
251                 if( ret == ESP_OK ) {
252                     btstack_assert( bytes_written == write_block_size );
253                 } else if( ret == ESP_ERR_TIMEOUT ) {
254                     ESP_LOGW(LOG_TAG, "audio output buffer underrun");
255                 }
256                 atomic_fetch_sub_explicit( &isr_bytes_written, write_block_size, memory_order_relaxed );
257             }
258 
259             num_samples = read_block_size/BYTES_PER_SAMPLE_STEREO;
260             if( num_samples > 0 ) {
261                 esp_err_t ret = i2s_channel_read(rx_handle, btstack_audio_esp32_buffer, read_block_size, &bytes_read, 0 );
262                 if( ret == ESP_OK ) {
263                     btstack_assert( bytes_read == read_block_size );
264                 } else if( ret == ESP_ERR_TIMEOUT ) {
265                     ESP_LOGW(LOG_TAG, "audio input buffer overrun");
266                 }
267                 // drop second channel if configured for mono
268                 int16_t * buffer16 = (int16_t *)btstack_audio_esp32_buffer;
269                 if (btstack_audio_esp32_source_num_channels == 1){
270                     for (uint16_t i=0;i<num_samples;i++){
271                         buffer16[i] = buffer16[2*i];
272                     }
273                 }
274                 (*btstack_audio_esp32_source_recording_callback)((int16_t *) btstack_audio_esp32_buffer, num_samples);
275                 atomic_fetch_sub_explicit(&isr_bytes_read, read_block_size, memory_order_relaxed);
276             }
277             break;
278         }
279         default:
280             break;
281     }
282 }
283 
284 /**
285  * dma_frame_num * slot_num * data_bit_width / 8 = dma_buffer_size <= 4092
286  * dma_frame_num <= 511
287  * interrupt_interval = dma_frame_num / sample_rate = 511 / 144000 = 0.003549 s = 3.549 ms
288  * dma_desc_num > polling_cycle / interrupt_interval = cell(10 / 3.549) = cell(2.818) = 3
289  * recv_buffer_size > dma_desc_num * dma_buffer_size = 3 * 4092 = 12276 bytes
290  *
291  */
btstack_audio_esp32_init(void)292 static void btstack_audio_esp32_init(void) {
293     if (btstack_audio_esp32_i2s_installed) {
294         return;
295     }
296 
297     // set i2s mode, sample rate and pins based on sink / source config
298     btstack_audio_esp32_i2s_samplerate = 0;
299 
300     if (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_OFF){
301         if (btstack_audio_esp32_i2s_samplerate != 0){
302             btstack_assert(btstack_audio_esp32_i2s_samplerate == btstack_audio_esp32_sink_samplerate);
303         }
304         btstack_audio_esp32_i2s_samplerate = btstack_audio_esp32_sink_samplerate;
305     }
306 
307     if (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_OFF){
308         if (btstack_audio_esp32_i2s_samplerate != 0){
309             btstack_assert(btstack_audio_esp32_i2s_samplerate == btstack_audio_esp32_source_samplerate);
310         }
311         btstack_audio_esp32_i2s_samplerate = btstack_audio_esp32_source_samplerate;
312     }
313 
314     i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(BTSTACK_AUDIO_I2S_NUM, I2S_ROLE_MASTER);
315     chan_cfg.dma_frame_num = DRIVER_ISR_INTERVAL_MS * btstack_audio_esp32_i2s_samplerate / 1000;
316     chan_cfg.dma_desc_num = DMA_BUFFER_COUNT;
317     btstack_assert( chan_cfg.dma_frame_num <= 4092 ); // as of https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html
318     chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer
319     ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
320     i2s_std_config_t std_cfg = {
321         .clk_cfg = {
322             .sample_rate_hz = btstack_audio_esp32_i2s_samplerate,
323 #if SOC_I2S_SUPPORTS_APLL
324             .clk_src = I2S_CLK_SRC_APLL,
325 #else
326             .clk_src = I2S_CLK_SRC_DEFAULT,
327 #endif
328             .mclk_multiple = I2S_MCLK_MULTIPLE_256, // for 16bit data
329         },
330         .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
331         .gpio_cfg = {
332             .mclk = BTSTACK_AUDIO_I2S_MCLK,
333             .bclk = BTSTACK_AUDIO_I2S_BCK,
334             .ws = BTSTACK_AUDIO_I2S_WS,
335             .dout = BTSTACK_AUDIO_I2S_OUT,
336             .din = BTSTACK_AUDIO_I2S_IN,
337             .invert_flags = {
338                 .mclk_inv = false,
339                 .bclk_inv = false,
340                 .ws_inv = false,
341             },
342         },
343     };
344 
345     ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
346     ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
347 
348     i2s_event_callbacks_t cbs = {
349         .on_recv = i2s_rx_callback,
350         .on_recv_q_ovf = NULL,
351         .on_sent = i2s_tx_callback,
352         .on_send_q_ovf = NULL,
353     };
354     ESP_ERROR_CHECK(i2s_channel_register_event_callback(rx_handle, &cbs, NULL));
355     ESP_ERROR_CHECK(i2s_channel_register_event_callback(tx_handle, &cbs, NULL));
356 
357     log_info("i2s init samplerate %" PRIu32 ", samples per DMA buffer: %" PRIu32,
358         btstack_audio_esp32_sink_samplerate, chan_cfg.dma_frame_num);
359 
360 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
361     btstack_audio_esp32_es8388_init();
362 #endif
363 
364     btstack_audio_esp32_i2s_installed = true;
365 
366     btstack_run_loop_set_data_source_handler(&transport_data_source, i2s_data_process);
367 }
368 
btstack_audio_esp32_deinit(void)369 static void btstack_audio_esp32_deinit(void){
370     if  (btstack_audio_esp32_i2s_installed == false) return;
371 
372     // check if still needed
373     bool still_needed = (btstack_audio_esp32_sink_state   != BTSTACK_AUDIO_ESP32_OFF)
374                     ||  (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_OFF);
375     if (still_needed) return;
376 
377     log_info("i2s close");
378 
379     ESP_ERROR_CHECK(i2s_del_channel(rx_handle));
380     ESP_ERROR_CHECK(i2s_del_channel(tx_handle));
381 
382     btstack_run_loop_disable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_POLL);
383     btstack_run_loop_remove_data_source(&transport_data_source);
384 
385     btstack_audio_esp32_i2s_installed = false;
386 }
387 
btstack_audio_esp32_sink_init(uint8_t channels,uint32_t samplerate,void (* playback)(int16_t * buffer,uint16_t num_samples))388 static int btstack_audio_esp32_sink_init(
389     uint8_t channels,
390     uint32_t samplerate,
391     void (*playback)(int16_t * buffer, uint16_t num_samples)){
392 
393     btstack_assert(playback != NULL);
394     btstack_assert((1 <= channels) && (channels <= 2));
395     btstack_assert( samplerate <= 48000 );
396 
397     // store config
398     btstack_audio_esp32_sink_playback_callback  = playback;
399     btstack_audio_esp32_sink_num_channels       = channels;
400     btstack_audio_esp32_sink_samplerate         = samplerate;
401 
402     btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
403 
404     // init i2s and codec
405     btstack_audio_esp32_init();
406 
407     return 0;
408 }
409 
btstack_audio_esp32_sink_get_samplerate(void)410 static uint32_t btstack_audio_esp32_sink_get_samplerate(void) {
411     return btstack_audio_esp32_sink_samplerate;
412 }
413 
btstack_audio_esp32_sink_set_volume(uint8_t gain)414 static void btstack_audio_esp32_sink_set_volume(uint8_t gain) {
415 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
416     if (!btstack_audio_esp32_es8388_initialized) return;
417     uint8_t volume_0_100 = (uint8_t) ((((uint16_t) gain) * 100) / 128);
418     es8388_set_volume( volume_0_100 );
419 #else
420     UNUSED(gain);
421 #endif
422 }
423 
btstack_audio_esp32_sink_start_stream(void)424 static void btstack_audio_esp32_sink_start_stream(void){
425 
426     if (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_INITIALIZED) return;
427 
428     // validate samplerate
429     btstack_assert(btstack_audio_esp32_sink_samplerate == btstack_audio_esp32_i2s_samplerate);
430 
431     // state
432     btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_STREAMING;
433 
434     // note: conceptually, it would make sense to pre-fill all I2S buffers and then feed new ones when they are
435     // marked as complete. But the corresponding function i2s_channel_preload_data is not in the v5.0.1 release
436     // version
437 
438     btstack_audio_esp32_stream_start();
439     ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
440 }
441 
btstack_audio_esp32_sink_stop_stream(void)442 static void btstack_audio_esp32_sink_stop_stream(void){
443 
444     if (btstack_audio_esp32_sink_state != BTSTACK_AUDIO_ESP32_STREAMING) return;
445 
446     // state
447     btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
448 
449     ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
450     btstack_audio_esp32_stream_stop();
451 }
452 
btstack_audio_esp32_sink_close(void)453 static void btstack_audio_esp32_sink_close(void){
454 
455     if (btstack_audio_esp32_sink_state == BTSTACK_AUDIO_ESP32_STREAMING) {
456         btstack_audio_esp32_sink_stop_stream();
457     }
458 
459     // state
460     btstack_audio_esp32_sink_state = BTSTACK_AUDIO_ESP32_OFF;
461 
462     btstack_audio_esp32_deinit();
463 }
464 
465 static const btstack_audio_sink_t btstack_audio_esp32_sink = {
466     .init           = &btstack_audio_esp32_sink_init,
467     .get_samplerate = &btstack_audio_esp32_sink_get_samplerate,
468     .set_volume     = &btstack_audio_esp32_sink_set_volume,
469     .start_stream   = &btstack_audio_esp32_sink_start_stream,
470     .stop_stream    = &btstack_audio_esp32_sink_stop_stream,
471     .close          = &btstack_audio_esp32_sink_close
472 };
473 
btstack_audio_esp32_sink_get_instance(void)474 const btstack_audio_sink_t * btstack_audio_esp32_sink_get_instance(void){
475     return &btstack_audio_esp32_sink;
476 }
477 
btstack_audio_esp32_source_init(uint8_t channels,uint32_t samplerate,void (* recording)(const int16_t * buffer,uint16_t num_samples))478 static int btstack_audio_esp32_source_init(
479     uint8_t channels,
480     uint32_t samplerate,
481     void (*recording)(const int16_t * buffer, uint16_t num_samples)
482 ){
483     btstack_assert(recording != NULL);
484 
485     // store config
486     btstack_audio_esp32_source_recording_callback = recording;
487     btstack_audio_esp32_source_num_channels       = channels;
488     btstack_audio_esp32_source_samplerate         = samplerate;
489 
490     btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
491 
492     // init i2s and codec
493     btstack_audio_esp32_init();
494     return 0;
495 }
496 
btstack_audio_esp32_source_get_samplerate(void)497 static uint32_t btstack_audio_esp32_source_get_samplerate(void) {
498     return btstack_audio_esp32_source_samplerate;
499 }
500 
btstack_audio_esp32_source_set_gain(uint8_t gain)501 static void btstack_audio_esp32_source_set_gain(uint8_t gain) {
502 #ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
503     if (!btstack_audio_esp32_es8388_initialized) return;
504     // ES8388 supports 0..24 dB gain in 3 dB steps
505     uint8_t gain_db = (uint8_t) ( ((uint16_t) gain) * 24 / 127);
506     es8388_set_mic_gain( (es_codec_mic_gain_t) gain_db );
507 #else
508     UNUSED(gain);
509 #endif
510 }
511 
btstack_audio_esp32_source_start_stream(void)512 static void btstack_audio_esp32_source_start_stream(void){
513 
514     if (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_INITIALIZED) return;
515 
516     // validate samplerate
517     btstack_assert(btstack_audio_esp32_source_samplerate == btstack_audio_esp32_i2s_samplerate);
518 
519     // state
520     btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_STREAMING;
521 
522     btstack_audio_esp32_stream_start();
523     ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
524 }
525 
btstack_audio_esp32_source_stop_stream(void)526 static void btstack_audio_esp32_source_stop_stream(void){
527 
528     if (btstack_audio_esp32_source_state != BTSTACK_AUDIO_ESP32_STREAMING) return;
529 
530     // state
531     btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_INITIALIZED;
532 
533     ESP_ERROR_CHECK(i2s_channel_disable(rx_handle));
534     btstack_audio_esp32_stream_stop();
535 }
536 
btstack_audio_esp32_source_close(void)537 static void btstack_audio_esp32_source_close(void){
538 
539     if (btstack_audio_esp32_source_state == BTSTACK_AUDIO_ESP32_STREAMING) {
540         btstack_audio_esp32_source_stop_stream();
541     }
542 
543     // state
544     btstack_audio_esp32_source_state = BTSTACK_AUDIO_ESP32_OFF;
545 
546     btstack_audio_esp32_deinit();
547 }
548 
549 static const btstack_audio_source_t btstack_audio_esp32_source = {
550     .init           = &btstack_audio_esp32_source_init,
551     .get_samplerate = &btstack_audio_esp32_source_get_samplerate,
552     .set_gain       = &btstack_audio_esp32_source_set_gain,
553     .start_stream   = &btstack_audio_esp32_source_start_stream,
554     .stop_stream    = &btstack_audio_esp32_source_stop_stream,
555     .close          = &btstack_audio_esp32_source_close
556 };
557 
btstack_audio_esp32_source_get_instance(void)558 const btstack_audio_source_t * btstack_audio_esp32_source_get_instance(void){
559     return &btstack_audio_esp32_source;
560 }
561