Build a Bluetooth A2DP Audio Receiver with ESP32
Most ESP32 audio tutorials cover playing files you already have on the device: a WAV from SPIFFS, a text-to-speech clip, an alarm tone. This project is different — it turns an ESP32 into a Bluetooth speaker's brain, receiving A2DP audio streamed from a phone, tablet, or laptop and pushing it out through a real I2S DAC and amplifier into a speaker. It's the guts of a commercial Bluetooth speaker, built from parts you can source individually and understand completely.
Why A2DP, and Which ESP32
A2DP (Advanced Audio Distribution Profile) is the Bluetooth Classic profile that carries stereo audio from a source device to a sink. Critically, A2DP is part of Bluetooth Classic, not Bluetooth Low Energy — so this only works on ESP32 variants with a Classic Bluetooth radio. The original ESP32 (and ESP32-WROOM/WROVER modules) support both BR/EDR Classic and BLE. The newer ESP32-S3, S2, C3, and C6 chips dropped Classic Bluetooth entirely in favor of BLE-only radios, so they cannot act as an A2DP sink. If you've been using an S3 for other projects, you'll need a plain ESP32 dev board for this one.
ChipClassic Bluetooth (A2DP)BLEUse for this project? ESP32 (original)YesYesYes ESP32-S2No (no BT radio)NoNo ESP32-S3NoYesNo ESP32-C3 / C6NoYes (C6 adds 802.15.4)NoSignal Path
The audio path looks like this: phone streams A2DP over Bluetooth Classic → ESP32's Bluetooth stack decodes the SBC (or optionally AAC) audio frames → decoded PCM samples get written to the I2S peripheral → an I2S DAC converts that digital stream to an analog line-level signal → a Class-D amplifier board boosts it to speaker level. Using I2S end-to-end (rather than ESP32's onboard 8-bit DAC pins) is what makes the difference between "acceptable" and "surprisingly good" sound quality — the built-in DAC is genuinely low-fi, while a dedicated I2S DAC like the PCM5102A gives you real 16 or 24-bit resolution.
Firmware
The ESP-IDF Bluetooth stack (BTDM controller) exposes an A2DP sink API directly — Espressif ships an a2dp_sink example that handles pairing, connection state, and streaming callbacks. In Arduino IDE, the ESP32-A2DP library by pschatzmann wraps the same functionality with a much friendlier interface and is the fastest path to a working build. The core of the sketch is short:
- Instantiate BluetoothA2DPSink and set an I2S pin configuration (BCLK, LRCLK/WS, DOUT).
- Call a2dp_sink.start("Shop Speaker") in setup() — this is the Bluetooth device name that will show up when your phone scans.
- Optionally register an avrc_metadata_callback to pull track title/artist metadata for a small display, and a volume_changed_callback to sync the phone's volume control with a local indicator.
Wiring the I2S DAC and Amp
A PCM5102A breakout is the easiest I2S DAC to source and wire — no I2C configuration needed, it self-configures over hardware pins. Typical wiring to an ESP32:
PCM5102A PinESP32 PinNotes VIN3.3VSome boards accept 5V — check silkscreen GNDGNDCommon ground with amp and battery BCKGPIO 27 (example)Bit clock LCKGPIO 25 (example)Word select / LRCLK DINGPIO 26 (example)Data out from ESP32 SCKGNDTies chip to internal system clock modeFrom the DAC's line-level stereo output, feed a TPA3116 or PAM8403-based Class-D amp board, then to your speaker(s). If you're building a mono speaker, sum the left/right channels in software or with a simple resistor mixing network rather than wiring only one channel — you'll lose whatever content was panned to the other side.
Power and Enclosure
Budget for the ESP32 (roughly 120-180mA active with Bluetooth radio on), the DAC (a few mA), and the amp board under load — a TPA3116 pushing a 4Ω speaker at moderate volume can pull over an amp of current at 12V. A single-cell LiPo with a boost converter works for a small battery build; for a shop speaker that lives on a shelf, a 12V wall adapter feeding both the amp and a 5V buck regulator for the ESP32 is simpler and avoids battery management entirely. Print or laser-cut an enclosure with a vented rear panel behind the amp board — Class-D amps run warm at sustained volume, and completely sealing them in a small box invites thermal shutdown.
Common Problems
SymptomLikely Cause Choppy, stuttering audioWiFi and Bluetooth radios sharing the 2.4GHz antenna — disable WiFi in firmware if you're not using it, or add delay/priority tuning to the I2S task No sound, but phone shows "connected"I2S pin config mismatch, or amp board not receiving power Loud hum or buzzGround loop between DAC, amp, and power supply — run a single-point star ground Device won't pair a second timeStale bonding info on the phone; forget the device on the phone side and reset the ESP32's NVS with nvs_flash_erase()Once it's working, this is a genuinely useful shop accessory — pair your phone, stream a podcast or music while you're at the bench, and you've got a fully understood, field-repairable audio system instead of a sealed commercial speaker. It's also a solid stepping stone toward more ambitious ESP32 audio projects, like a multi-room synced speaker system or a voice-controlled shop assistant.
Related Guides
- ESP32 I2S Audio: Playing and Recording Sound with a MAX98357A DAC and INMP441 Microphone
- How to Build a Class-D Audio Amplifier: TPA3116, Power Supply, and Speaker Matching
- How to Hack Wi-Fi and Bluetooth with the Flipper Zero and Wi-Fi Marauder
- ESP32 BLE Basics: Scanning, Advertising, and Custom Services
- Choosing the Right ESP32 Variant: ESP32, S2, S3, C3, and C6 Compared
- How to Build a Class-D Audio Amplifier: TPA3116, Power Supply, and Speaker Matching
- How to Program Addressable LED Strips: WS2812B Patterns, Effects, and Power Design
- I2C vs SPI vs UART: How to Choose and Use Serial Communication Protocols