Build an ESP32 Internet Radio Streamer: I2S DAC, WiFi Station Presets, and Rotary Encoder Control
An internet radio streamer is a genuinely satisfying weekend ESP32 build: point it at a handful of streaming station URLs, and you get a dedicated little appliance that plays them over a real speaker with a knob to change stations and volume, no phone or app required. This build uses an ESP32 to decode and stream MP3/AAC internet radio stations over WiFi, output clean audio through an I2S DAC, and control station selection and volume with a rotary encoder and a small display.
This is a different kind of ESP32 audio project from playing local files or recording — it's a real-time network streaming and decoding pipeline, which puts more load on the chip's WiFi stack and available RAM than a typical sensor or automation project, so board and library choice matter more here than usual.
How It Works
The ESP32 connects to WiFi, opens an HTTP(S) connection to an internet radio stream URL (most stations serve plain MP3 or AAC over HTTP, sometimes via a playlist file like .pls or .m3u that needs to be resolved to the actual stream URL first), and feeds the incoming compressed audio data into a decoder library running on the chip. The decoded PCM audio is then pushed out over I2S to a DAC module, which converts it to an analog line-level or amplified signal for a speaker. A rotary encoder with a push button handles station cycling (turn) and play/pause or menu select (press), while a small OLED or TFT display shows the current station name and a simple menu.
Wiring
ComponentESP32 Connection I2S DAC (MAX98357A for amplified output, or PCM5102 for line-level)I2S pins — BCLK, LRCLK/WS, DOUT to the DAC's DIN, plus 3.3V/5V and GND per the DAC's requirements Rotary encoder with push buttonTwo GPIO pins for the quadrature encoder signals, one GPIO for the push button, with pull-ups enabled OLED display (SSD1306, I2C)I2C SDA/SCL pins, 3.3V, GND Speaker (if using an amplified DAC like the MAX98357A)Direct to the DAC's speaker output terminalsSoftware Setup
- Set up the ESP32 in the Arduino IDE or PlatformIO, and install an audio streaming library that supports I2S output and MP3/AAC decoding — the ESP32-audioI2S library (and similar community libraries built around it) is a common and well-documented starting point specifically built for this internet-radio-streaming use case.
- Write the WiFi connection logic first and confirm a stable connection before adding streaming — a flaky WiFi connection is the most common source of stuttering audio, and it's much easier to debug connectivity issues in isolation.
- Build a small array or config file of station presets — station name paired with stream URL — and write the logic to resolve playlist files (.pls/.m3u) to their actual underlying stream URL if a station serves one of those instead of a direct audio stream.
- Wire up the streaming call: open the HTTP connection to the current station's URL, and feed the response body into the audio library's streaming decode-and-play function, which handles buffering, decoding, and pushing samples out over I2S internally.
- Add the rotary encoder handling: turning changes the station index and triggers a reconnect to the new stream URL, tearing down the old HTTP connection cleanly before opening the new one; the push button can toggle play/pause or step into a simple settings/volume mode.
- Add the OLED display logic showing the current station name (and optionally, if the stream provides ICY metadata, the current track/show info) so you always know what's playing without needing a phone nearby.
- Handle disconnects and stream errors gracefully — internet radio streams do occasionally drop or hiccup, and the firmware should automatically attempt a reconnect rather than locking up or requiring a power cycle.
Buffering and Audio Quality Notes
- Give the streaming library a reasonably sized buffer — too small and you get audible dropouts on WiFi jitter, too large and you get a noticeable lag when switching stations. A few seconds of buffer is a typical starting point to tune from.
- An ESP32 with PSRAM (many WROVER-based boards, and the S3 variants with PSRAM) gives noticeably more headroom for buffering and is worth the small extra cost over a base WROOM module for this specific project — audio streaming is one of the more RAM-hungry things you'll ask a hobby ESP32 to do.
- Not every internet radio station stream is equally clean — bitrate, codec, and server reliability vary a lot station to station, so test with a handful of known-reliable stations first before assuming a build issue if one particular station stutters.
Enclosure
A simple 3D-printed enclosure with a speaker grille, a cutout for the OLED display, and a knob for the rotary encoder turns this from a breadboard project into something that looks at home on a kitchen counter or workbench. Leave ventilation near the amplifier DAC if you're driving a speaker directly, since Class D amp chips like the one on the MAX98357A do generate some heat under sustained volume.
Troubleshooting
SymptomLikely Cause Audio stutters or drops out regularlyWeak WiFi signal, buffer too small, or too many other tasks competing for CPU time — check signal strength and try increasing buffer size first No audio at allI2S wiring mismatch (BCLK/WS/DOUT swapped), or the DAC not receiving power — verify with a multimeter before assuming it's a software issue Station won't play, others doThat station serves a .pls/.m3u playlist file rather than a direct stream, and the resolver logic needs to parse it, or the station requires HTTPS that the library isn't configured to trust Board resets/crashes when switching stations rapidlyOld HTTP connection and audio buffers not being torn down cleanly before the new one starts — add proper cleanup in the station-change handlerOnce it's working, this is one of those ESP32 builds that quietly earns a permanent spot in the kitchen or workshop — a dedicated little radio with your own curated station presets, built entirely from parts that would otherwise be sitting in the project bin.
Related Guides
- ESP32 I2S Audio: Playing and Recording Sound with a MAX98357A DAC and INMP441 Microphone
- Rotary Encoders for Makers: Incremental vs Absolute, Debouncing, and Reading with Arduino/ESP32
- Potentiometers and Trimmers for Makers: Types, Tapers, Wiring, and Pots vs Encoders
- Build a Physical Jog Pendant for GRBL CNC Routers: Rotary Encoder, Feed Override, and Wireless Option
- Build a Bluetooth A2DP Audio Receiver with ESP32
- 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
- How to Use Sensors with Arduino and ESP32: Temperature, Distance, Load, Current, and Hall Effect