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