Turning a Raspberry Pi into an OAAT audio endpoint
Turning a Raspberry Pi into a bit-perfect audio endpoint with OAAT

This guide walks you step by step through setting up a Raspberry Pi 3B+ or 4 as a high-fidelity audio endpoint using the OAAT (Open Advanced Audio Transport) protocol.
OAAT is an open-source protocol designed as an open alternative to Roon's proprietary RAAT:
- Bit-perfect audio — PCM up to 768 kHz / 32 bits, native DSD up to DSD512
- Multi-room synchronisation — under 1 ms between endpoints, via PTP clock
- Format negotiation — the controller adapts automatically to the DAC's capabilities
- Gapless — seamless transitions, even across a format change
- Zero-config — mDNS/DNS-SD discovery, no IP address to enter
- Open source — Apache 2.0, Rust code on GitHub
OAAT vs. the other protocols
- OAAT: open source, bit-perfect, native DSD, multi-room sync under 1 ms
- RAAT (Roon): bit-perfect, DSD, multi-room — but proprietary and closed
- DLNA/UPnP: open source — but no multi-room sync, hit-and-miss gapless, DSD over DoP only
- AirPlay 2: Apple multi-room — but not bit-perfect, no DSD, closed ecosystem
The Raspberry Pi is the ideal companion: €35-75, silent (no fan), with a native I2S bus that connects the DAC directly to the GPIO — the shortest and purest audio path.
OAAT architecture
graph LR
A["🎵 Tune Server
(controller)"] -->|"TCP :9740
JSON control"| B["🔊 RPi Endpoint
(I2S DAC)"]
A -->|"UDP :9741
PCM/FLAC audio"| B
A <-->|"UDP :9742
PTP clock sync"| B
B -->|"I2S GPIO"| C["🎧 DAC
ESS 9038 / HifiBerry / ..."]
C --> D["🔈 Amp + Speakers"]
style A fill:#4a90d9,stroke:#333,color:#fff
style B fill:#50c878,stroke:#333,color:#fff
style C fill:#f5a623,stroke:#333,color:#fff
style D fill:#e8e8e8,stroke:#333,color:#333
Hardware required
The Raspberry Pi
- RPi 4B (2 or 4 GB) — max PCM: 384 kHz / 32 bits — ✅ Recommended
- RPi 3B+ — max PCM: 192 kHz / 32 bits — Budget / second-hand
- RPi 5 — max PCM: 384 kHz / 32 bits — Works too
The RPi 3B+ is limited to 192 kHz by its I2S bus. For hi-res beyond that (352.8 / 384 kHz), go for the RPi 4.
The I2S DAC (HAT)
OAAT supports every Raspberry Pi-compatible I2S DAC. Here are the most common ones:
- Audiophonics ESS 9038Q2M (ESS ES9038Q2M) — 384 kHz / 32 bits — ~€120 — overlay:
i-sabre-q2m— Linux driver - HifiBerry DAC2 HD (PCM1796) — 192 kHz / 24 bits — ~€65 — overlay:
hifiberry-dacplushd - HifiBerry DAC+ Pro (PCM5122) — 192 kHz / 32 bits — ~€45 — overlay:
hifiberry-dacplus - Allo Boss (PCM5122) — 384 kHz / 32 bits — ~€50 — overlay:
allo-boss-dac-pcm512x-audio - IQaudio DAC+ (PCM5122) — 192 kHz / 24 bits — ~€30 — overlay:
iqaudio-dacplus - JustBoom DAC HAT (PCM5122) — 384 kHz / 32 bits — ~€35 — overlay:
justboom-dac
⚠️ Important: the Linux overlay must match your DAC exactly. Wrong overlay = no sound (ALSA error -121 or -22).
Accessories
- microSD card: 8 GB minimum (16 GB recommended)
- Power supply: official RPi unit or 5V/3A USB-C (RPi 4) / micro-USB (RPi 3)
- Ethernet cable: recommended for audio stability (WiFi works but adds ~50 ms of jitter to the clock sync)
- Case (optional): Audiophonics offers integrated Pi + DAC enclosures
Flashing the SD card
1. Install Raspberry Pi Imager
- macOS:
brew install --cask raspberry-pi-imager - Windows: download the installer
- Linux:
sudo apt install rpi-imager
2. Configure and flash
- Open Raspberry Pi Imager
- Choose the device: Raspberry Pi 3 or 4
- Choose the OS:
Raspberry Pi OS (other)→ Raspberry Pi OS Lite (64-bit) — no need for the Desktop - Choose the storage: your microSD card
- Click the gear icon (⚙️) to configure:
- Hostname:
oaat-endpoint - Enable SSH: yes, with a password
- Username / password: your choice
- WiFi: configure if you have no Ethernet
- Time zone:
Europe/Paris
- Hostname:
- Flash — allow 2-3 minutes
3. First boot
- Insert the SD card into the Pi
- Plug the DAC HAT onto the GPIO (if not already mounted)
- Connect Ethernet + power
- Wait 1-2 minutes (the first boot takes a little longer)
- Connect over SSH:
ssh pi@oaat-endpoint.local
Tip: to find the Pi's IP address, check your router's admin interface, or use arp -a | grep raspberry.
Installation
Process overview
flowchart LR
A["📥 Flash SD
RPi Imager"] --> B["🔌 Boot + SSH"]
B --> C["⚙️ setup.sh
pick your DAC"]
C --> D["🔄 Reboot"]
D --> E["✅ Endpoint live
visible on the network"]
style A fill:#e8e8e8,stroke:#333
style B fill:#e8e8e8,stroke:#333
style C fill:#f5a623,stroke:#333,color:#fff
style D fill:#e8e8e8,stroke:#333
style E fill:#50c878,stroke:#333,color:#fff
Automatic installation (recommended)
A single command installs everything:
curl -sL https://raw.githubusercontent.com/renesenses/oaat/main/dist/rpi/setup.sh | sudo bash
The script asks you to pick your DAC from 6 supported models, then:
- Installs the system dependencies (ALSA, build tools)
- Configures the DAC overlay in
/boot/config.txt - Configures ALSA (
/etc/asound.conf) - Installs Rust and compiles OAAT from source
- Installs the systemd service
Compilation time:
- RPi 4: ~8 minutes in release
- RPi 3B+: ~20 minutes in release (the script handles swap automatically)
After installation:
sudo reboot
The reboot is required to activate the DAC overlay. Once restarted, the OAAT service starts automatically.
Manual installation (step by step)
If you'd rather control every step:
1. System dependencies
sudo apt-get update
sudo apt-get install -y libasound2 libasound2-dev alsa-utils curl git build-essential pkg-config
2. Configure the DAC
Edit /boot/firmware/config.txt (or /boot/config.txt depending on your OS version):
# Disable the onboard audio
#dtparam=audio=on
# Your DAC — uncomment ONE line only:
dtoverlay=i-sabre-q2m # Audiophonics ESS 9038Q2M
#dtoverlay=hifiberry-dacplus # HifiBerry DAC+ / DAC+ Pro
#dtoverlay=hifiberry-dacplushd # HifiBerry DAC2 HD
#dtoverlay=allo-boss-dac-pcm512x-audio # Allo Boss
#dtoverlay=iqaudio-dacplus # IQaudio DAC+
#dtoverlay=justboom-dac # JustBoom DAC HAT
3. Configure ALSA
sudo tee /etc/asound.conf << 'EOF'
pcm.!default {
type hw
card 0
device 0
format S32_LE
}
ctl.!default {
type hw
card 0
}
EOF
4. Install Rust and compile
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
sudo mkdir -p /opt/oaat
sudo chown $USER:$USER /opt/oaat
git clone https://github.com/renesenses/oaat.git /opt/oaat/src
cd /opt/oaat/src
cargo build --release --bin oaat
cp target/release/oaat /opt/oaat/oaat
cp dist/rpi/endpoint.toml /opt/oaat/endpoint.toml
5. systemd service and reboot
sudo cp dist/oaat-endpoint.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable oaat-endpoint
sudo reboot
Configuration
The configuration file lives at /opt/oaat/endpoint.toml:
[endpoint]
# Name shown in Tune and during mDNS discovery
name = "Salon DAC"
port = 9740
[capabilities]
# Adapt to your DAC:
pcm_max_rate = 384000 # Hz (384000, 192000...)
pcm_max_bits = 32 # bits (32, 24)
channels_max = 2
dsd = false
flac = true # Recommended: cuts bandwidth by ~50%
[logging]
level = "info"
Tips:
pcm_max_rate: don't declare more than your DAC actually supports. OAAT automatically negotiates downwards if the source exceeds it.flac = true: recommended, especially over WiFi. FLAC is lossless, zero quality loss, and cuts bandwidth by ~50-60%.name: pick a meaningful name — this is what shows up as a playback zone in Tune.
Examples by DAC
Audiophonics ESS 9038Q2M:
[endpoint]
name = "Audiophonics ESS 9038"
[capabilities]
pcm_max_rate = 384000
pcm_max_bits = 32
channels_max = 2
flac = true
HifiBerry DAC+ Pro / DAC2 HD:
[endpoint]
name = "HifiBerry DAC"
[capabilities]
pcm_max_rate = 192000
pcm_max_bits = 24
channels_max = 2
flac = true
Allo Boss / JustBoom:
[endpoint]
name = "Allo Boss DAC"
[capabilities]
pcm_max_rate = 384000
pcm_max_bits = 32
channels_max = 2
flac = true
Audiophonics ESS 9038Q2M — technical details
The ES9038Q2M supports the S16_LE and S32_LE formats, sample rates up to 384 kHz (even 1.536 MHz in DSD mode), and offers advanced ALSA controls:
- Digital volume: 0-100 (-100 dB to 0 dB)
- FIR filter: 7 types (brick wall, minimum phase, linear phase...)
- Input selection: I2S / SPDIF
The Linux driver uses I2C address 0x48. On recent Raspberry Pi OS Bookworm, the i-sabre-q2m overlay is generally included in the kernel. For an older kernel, build the module from the Audiophonics repository:
sudo apt-get install -y raspberrypi-kernel-headers
git clone https://github.com/audiophonics/I-Sabre_9038Q2M.git /tmp/i-sabre
cd /tmp/i-sabre
make
sudo make install
sudo reboot
Verification and first sound
1. Check that the DAC is detected:
aplay -l
# Should list your DAC as card 0
2. Test the sound directly (without OAAT):
speaker-test -D hw:0,0 -c 2 -t sine -f 440
# You should hear a 440 Hz A — Ctrl+C to stop
3. Check the OAAT service:
sudo systemctl status oaat-endpoint
# Active: active (running)
4. Check mDNS discovery (from another device):
# macOS
dns-sd -B _oaat._tcp
# Linux
avahi-browse -r _oaat._tcp
5. First sound over OAAT!
From your computer (with the oaat CLI installed):
# 440 Hz sine wave for 5 seconds
oaat controller --target PI_IP:9740 --freq 440 --duration 5
If you hear the 440 Hz A: your OAAT endpoint is up and running and bit-perfect! 🎉
6. Full conformance test:
oaat-test PI_IP:9740
# OAAT Conformance Test
# [Handshake] 4 PASS
# [Capabilities] 4 PASS
# [Format Nego] 3 PASS (accept, counter, reject)
# [Clock Sync] 1 PASS
# [Audio] 1 PASS
# [Gapless] 2 PASS (same format, diff format)
# [Volume] 3 PASS
# [Reconnect] 2 PASS
# 20 tests: 20 passed — Endpoint is CONFORMANT
Using it with Tune
Tune is a self-hosted music server with native OAAT support.
If Tune is running on the same local network as your RPi, the OAAT endpoint shows up automatically as a playback zone in the web interface. No further configuration needed.
The OAAT endpoint takes priority over DLNA and AirPlay in Tune, because it offers the most direct and most faithful audio path.
Format negotiation is entirely transparent:
- Source at 24/96, DAC supports 384/32 → playback at native 24/96 (no pointless upsampling)
- Source at 24/192, DAC supports 96 max → Tune downsamples to 24/96 (same 48 kHz family)
- Source in DSD, DAC doesn't support DSD → transparent PCM conversion
Troubleshooting
No sound
aplay -llists no card → Missing or wrong DAC overlay. Check/boot/firmware/config.txt, fix the overlay, reboot.speaker-testthrows a-121error → Wrong overlay for this DAC. Try another overlay (see the list above).speaker-testworks but OAAT doesn't → Service not started or bad config. Check withsystemctl status oaat-endpointandjournalctl -u oaat-endpoint -f.- Crackling or dropping out → Unstable WiFi. Switch to Ethernet.
The endpoint isn't discovered by Tune
- Check that Tune and the RPi are on the same subnet
- If you use a VPN (NordVPN, etc.): enable
nordvpn set lan-discovery on - Check the firewall: ports 9740 (TCP), 9741 (UDP), 9742 (UDP) and 5353 (mDNS) must be open
- Test mDNS discovery manually (see the Verification section)
The service won't start
# View detailed logs
journalctl -u oaat-endpoint -f
# Common errors:
# "No such device" → DAC not detected, check overlay + reboot
# "Address already in use" → another process is using port 9740
# "Permission denied" → check the User in the service file
RPi 3 vs RPi 4
- Max PCM over I2S: RPi 3B+ = 192 kHz / RPi 4 = 384 kHz
- Compilation time: RPi 3 ~20 min / RPi 4 ~8 min
- RAM: RPi 3 = 1 GB (swap recommended) / RPi 4 = 2-8 GB
- Ethernet: RPi 3 = 100 Mbps (over USB) / RPi 4 = native Gigabit
The RPi 3B+ works perfectly for 16/44.1 (CD) up to 24/192 (hi-res). If you mostly listen to CD-quality FLAC or Qobuz 24/96, a second-hand RPi 3 at €25 will do the job just fine.
Audiophonics ESS 9038Q2M: overlay not found
On some Raspberry Pi OS versions, the i-sabre-q2m overlay isn't included in the kernel. Symptom:
dtoverlay: failed to apply overlay 'i-sabre-q2m'
Fix: build the driver from source (see the Configuration section above).
Going further
Updating the endpoint
cd /opt/oaat/src
git pull
cargo build --release --bin oaat
cp target/release/oaat /opt/oaat/oaat
sudo systemctl restart oaat-endpoint
Synchronised multi-room
Two (or more) Raspberry Pis on the same network can be synchronised to within 1 ms:
graph TD
A["🎵 Tune Server"] -->|"same PTS"| B["🔊 RPi #1 — Living room
ESS 9038Q2M"]
A -->|"same PTS"| C["🔊 RPi #2 — Kitchen
HifiBerry DAC+"]
A -->|"same PTS"| D["🔊 RPi #3 — Bedroom
Allo Boss"]
B <-->|"clock sync
PTP"| A
C <-->|"clock sync
PTP"| A
D <-->|"clock sync
PTP"| A
E["⏱️ Sync < 1 ms
across all endpoints"]
style A fill:#4a90d9,stroke:#333,color:#fff
style B fill:#50c878,stroke:#333,color:#fff
style C fill:#50c878,stroke:#333,color:#fff
style D fill:#50c878,stroke:#333,color:#fff
style E fill:#fff3cd,stroke:#f5a623,color:#333
Each endpoint receives the same audio packets with the same presentation timestamp (PTS). PTP synchronisation automatically corrects clock differences between the Pis.
In Tune, simply create a zone grouping several endpoints to enable multi-room.
Network performance
- PCM 16/44.1 stereo: 1.41 Mbps
- PCM 24/192 stereo: 9.22 Mbps
- PCM 32/384 stereo: 24.58 Mbps
- FLAC 24/192 stereo: ~4 Mbps (~50% compression)
Ethernet is recommended for synchronised multi-room. WiFi is perfectly fine for a single endpoint.
Fully headless
The setup described here is already 100% headless. Once flashed and booted, the Pi is self-sufficient:
- The OAAT service starts at boot
- Automatic restart on crash (systemd
Restart=always) - Automatic reconnection if the controller drops off
- Updates can be done over SSH
Useful links:
- OAAT source code (Apache 2.0)
- OAAT RFC specification
- Audiophonics ESS 9038Q2M driver
- Audiophonics — I2S DACs and RPi enclosures
Guide written by MozAIk Labs — May 2026