diff --git a/examples/bluetooth/a2dp_sink/README.rst b/examples/bluetooth/a2dp_sink/README.rst index a1f08c24f8..b27393a73c 100755 --- a/examples/bluetooth/a2dp_sink/README.rst +++ b/examples/bluetooth/a2dp_sink/README.rst @@ -11,4 +11,19 @@ Options choose step: 3. enter menu Bluetooth, choose "Classic Bluetooth" and do not choose "Release DRAM from Classic BT controller" 4. choose your options. +For the I2S codec, pick whatever chip or board works for you; this code was written using a PCM5102 chip, but other I2S boards and chips will probably work as well. The default I2S connections are shown below, but these can be changed in menuconfig: + ++-----------+--------------+ +| ESP pin | I2S signal | ++===========+==============+ +| GPIO22 | LRCK | ++-----------+--------------+ +| GPIO25 | DATA | ++-----------+--------------+ +| GPIO26 | BCK | ++-----------+--------------+ + +If the internal DAC is selected, analog audio will be available on GPIO25 and GPIO26. The output resolution on these pins will always be limited to 8 bit because of the internal structure of the DACs. + + After the program started, other bluetooth devices such as smart phones can discover this device named "ESP_SPEAKER", and after connection is established, audio data can be transmitted and there will occur a count of audio data packets printed. diff --git a/examples/bluetooth/a2dp_sink/main/Kconfig.projbuild b/examples/bluetooth/a2dp_sink/main/Kconfig.projbuild new file mode 100644 index 0000000000..c984308d24 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/Kconfig.projbuild @@ -0,0 +1,43 @@ +menu "A2DP Example Configuration" + +choice A2DP_SINK_OUTPUT + prompt "A2DP Sink Output" + default A2DP_SINK_OUTPUT_EXTERNAL_I2S + help + Select to use Internal DAC or external I2S driver + +config A2DP_SINK_OUTPUT_INTERNAL_DAC + bool "Internal DAC" + help + Select this to use Internal DAC sink output + +config A2DP_SINK_OUTPUT_EXTERNAL_I2S + bool "External I2S Codec" + help + Select this to use External I2S sink output + +endchoice + +config I2S_LRCK_PIN + int "I2S LRCK (WS) GPIO" + default 22 + depends on A2DP_SINK_OUTPUT_EXTERNAL_I2S + help + GPIO number to use for I2S LRCK(WS) Driver. + +config I2S_BCK_PIN + int "I2S BCK GPIO" + default 26 + depends on A2DP_SINK_OUTPUT_EXTERNAL_I2S + help + GPIO number to use for I2S BCK Driver. + +config I2S_DATA_PIN + int "I2S DATA GPIO" + default 25 + depends on A2DP_SINK_OUTPUT_EXTERNAL_I2S + help + GPIO number to use for I2S Data Driver. + + +endmenu diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_av.c b/examples/bluetooth/a2dp_sink/main/bt_app_av.c index bb6bb90c7c..ae76977529 100644 --- a/examples/bluetooth/a2dp_sink/main/bt_app_av.c +++ b/examples/bluetooth/a2dp_sink/main/bt_app_av.c @@ -26,6 +26,10 @@ #include "esp_a2dp_api.h" #include "esp_avrc_api.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2s.h" + /* a2dp event handler */ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param); /* avrc event handler */ @@ -53,6 +57,7 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len) { + i2s_write_bytes(0, (const char *)data, len, portMAX_DELAY); if (++m_pkt_cnt % 100 == 0) { ESP_LOGE(BT_AV_TAG, "audio data pkt cnt %u", m_pkt_cnt); } @@ -96,7 +101,23 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param) ESP_LOGI(BT_AV_TAG, "a2dp audio_cfg_cb , codec type %d", a2d->audio_cfg.mcc.type); // for now only SBC stream is supported if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) { - ESP_LOGI(BT_AV_TAG, "audio player configured"); + int sample_rate = 16000; + char oct0 = a2d->audio_cfg.mcc.cie.sbc[0]; + if (oct0 & (0x01 << 6)) { + sample_rate = 32000; + } else if (oct0 & (0x01 << 5)) { + sample_rate = 44100; + } else if (oct0 & (0x01 << 4)) { + sample_rate = 48000; + } + i2s_set_clk(0, sample_rate, 16, 2); + + ESP_LOGI(BT_AV_TAG, "configure audio player %x-%x-%x-%x\n", + a2d->audio_cfg.mcc.cie.sbc[0], + a2d->audio_cfg.mcc.cie.sbc[1], + a2d->audio_cfg.mcc.cie.sbc[2], + a2d->audio_cfg.mcc.cie.sbc[3]); + ESP_LOGI(BT_AV_TAG, "audio player configured, samplerate=%d", sample_rate); } break; } diff --git a/examples/bluetooth/a2dp_sink/main/main.c b/examples/bluetooth/a2dp_sink/main/main.c index e8d579c8b0..9febabae23 100644 --- a/examples/bluetooth/a2dp_sink/main/main.c +++ b/examples/bluetooth/a2dp_sink/main/main.c @@ -31,6 +31,7 @@ #include "esp_gap_bt_api.h" #include "esp_a2dp_api.h" #include "esp_avrc_api.h" +#include "driver/i2s.h" /* event for handler "bt_av_hdl_stack_up */ enum { @@ -51,6 +52,37 @@ void app_main() } ESP_ERROR_CHECK( ret ); + i2s_config_t i2s_config = { +#ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC + .mode = I2S_MODE_DAC_BUILT_IN, +#else + .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX +#endif + .sample_rate = 44100, + .bits_per_sample = 16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB, + .dma_buf_count = 6, + .dma_buf_len = 60, // + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 + }; + + + i2s_driver_install(0, &i2s_config, 0, NULL); +#ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC + i2s_set_pin(0, NULL); +#else + i2s_pin_config_t pin_config = { + .bck_io_num = CONFIG_I2S_BCK_PIN, + .ws_io_num = CONFIG_I2S_LRCK_PIN, + .data_out_num = CONFIG_I2S_DATA_PIN, + .data_in_num = -1 //Not used + }; + + i2s_set_pin(0, &pin_config); +#endif + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); if (esp_bt_controller_init(&bt_cfg) != ESP_OK) { diff --git a/examples/bluetooth/a2dp_sink/sdkconfig.defaults b/examples/bluetooth/a2dp_sink/sdkconfig.defaults index dd570f866e..fe6bb31d11 100644 --- a/examples/bluetooth/a2dp_sink/sdkconfig.defaults +++ b/examples/bluetooth/a2dp_sink/sdkconfig.defaults @@ -2,4 +2,3 @@ # Classic BT is enabled and BT_DRAM_RELEASE is disabled CONFIG_BT_ENABLED=y CONFIG_CLASSIC_BT_ENABLED=y -