The ESP32 provides a Bluetooth A2DP API that receives sound data e.g. from your Mobile Phone and makes it available via a callback method. The output is a PCM data stream decoded from SBC format. The documentation can be found here. 

I2S is an electrical serial bus interface standard used for connecting digital audio devices together. It is used to communicate PCM audio data between integrated circuits in an electronic device.

So we can just feed the input from Bluetooth to the I2S output: An example for this A2DP Data Sink from Expressive can be found on Github.

Unfortunately this example did not make me happy so I decided to convert it into a simple C++ class that is very easy to use from an Arduino Software IDE.

A Simple I2S Example

Here is the simplest example which just uses the proper default settings:

#include "BluetoothA2DPSink.h"

BluetoothA2DPSink a2dp_sink;

void setup() {
a2dp_sink.start("MyMusic");
}

void loop() {
}

This creates a new Bluetooth device with the name “MyMusic” and the output will be sent to the following default I2S pins:
– bck_io_num => GPIO 26,
– ws_io_num => GPIO 25,
– data_out_num => GPIO 22

These need to be connected to an external external DAC. You can define your own pins easily by calling the set_pin_config method.

Output to the Internal DAC

You can also send the output directly to the internal DAC of the ESP32 by providing the corresponding i2s_config:

#include "BluetoothA2DPSink.h"

BluetoothA2DPSink a2dp_sink;

void setup() {
static const i2s_config_t i2s_config = {
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = 44100, // corrected by info from bluetooth
.bits_per_sample = (i2s_bits_per_sample_t) 16, /* the DAC module will only take the 8bits from MSB */
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};

a2dp_sink.set_i2s_config(i2s_config);
a2dp_sink.start("MyMusic");

}

void loop() {
}

The output goes now to the DAC pins G26/G27.

Installation

The library with the examples can be found on Github

Conclusion

This is the perfect functionality to revive my old Technics SU-Z2 Amplifier: I can use it now by streaming my music from my Android Phone or IPAD.

Initially I wanted to use the ESP32 also to stream some Internet Radios via WIFI using http – but in the end it turned out to be much simpler to use one of the many Music Apps from a Mobile Phone  with Bluetooth as output!

The only task left now is to build a casing…


6 Comments

Michael Telatynski · 22. October 2020 at 17:44

How was the audio quality out of the internal DACs. Any complaints for music?

kjs · 9. October 2020 at 10:01

This is amazing, thank you so much! I’m looking at using this in a project I am working on, would you happen to know how I can add getting song data (artist, title, etc.) and sending instructions (volume up/down, play, etc.) to this?

Gertjan · 2. October 2020 at 13:30

Is it also possible to get the meta data of the audio stream? Like artist, title, etc.? That would be awesome.

Cemoi · 15. September 2020 at 17:24

A thousand thank you for this very good job.
Merci mille fois pour ce merveilleux travail.
I love.

i2c · 11. August 2020 at 18:00

Great documentation and excellent work! I’ve been looking for this exact esp-idf code to use as an Arduino library in my projects. I would have to use both Arduino and the entire ESP-IDF if I wanted to add this bluetooth receiving functionality, but nope! You’ve done it, thanks Phil!

Leave a Reply

Your email address will not be published.