Warning
Disclaimer: This document is the result of reverse engineering analysis and is NOT official documentation. It is published for educational purposes only, as anyone could repeat such an exercise.
This document provides a detailed technical specification of the Roon Advanced Audio Transport (RAAT) protocol, reconstructed from reverse-engineering the Roon Bridge and Roon Server codebases.
RAAT is Roon’s proprietary, high-performance audio transport protocol designed for bit-perfect audio streaming, low latency, and sample-accurate multi-room synchronization.
Before establishing an audio stream, the Roon Core discovers endpoints on the local network using the Sooloos Discovery (SOOD) protocol.
- Protocol: UDP
- Port:
9003(unicast & multicast) - Multicast IP:
239.255.90.90 - Network Fallback: If multicast is blocked by network infrastructure, the Core automatically performs "ARP trickling" (iterating and sending unicast UDP queries directly to IPs in the local ARP table and subnet ranges).
A SOOD packet consists of a magic header followed by a version number, message type, and a sequence of length-prefixed key-value attributes:
| Offset (Bytes) | Size (Bytes) | Field / Value | Description |
|---|---|---|---|
0 - 3 |
4 |
"SOOD" (ASCII) |
Protocol Magic Identifier |
4 |
1 |
0x02 (byte) |
Protocol Version |
5 |
1 |
0x51 ('Q') or 0x52 ('R') |
Message Type: Query (Q / 81) or Response (R / 82) |
6... |
Variable | Key-Value Pairs | Payload Attributes |
Each attribute in the payload is serialized as:
- Key Length: 1 byte (uint8)
- Key String: UTF-8 encoded string (length specified above)
- Value Length: 2 bytes (uint16, big-endian)
- Value String: UTF-8 encoded string (length specified above). A length of
0xFFFFindicatesnull.
For a discovered endpoint to be identified as a RAAT device, its SOOD response must contain a matching RAAT Service Identifier:
- RAAT Service UUID:
5e2042ad-9bc5-4508-be92-ff68f19bdc93(under the keyservice_id)
Key fields parsed from a RAAT endpoint's discovery response:
unique_id: Unique identifier of the device.tcp_port: The TCP port the device is listening on for control connections.vendor&model: Device descriptors.protocol_version&raat_version: Version compatibility flags.code_signing_keys: Signature validation keys.
Once an endpoint's TCP port is discovered via SOOD, the Core opens a TCP connection to establish a control session.
All control packets exchanged over the TCP session share an 8-byte big-endian framing header:
| Offset (Bytes) | Size (Bytes) | Type / Format | Description |
|---|---|---|---|
0 - 3 |
4 |
uint32 (big-endian) |
Message Length: Full message size (including these 8 bytes) |
4 - 7 |
4 |
uint32 (big-endian) |
Message Type: Control code identifying the frame action |
8... |
Variable | Binary / UTF-8 | Payload: Frame message body |
Low-level control commands use specific uint32 message type identifiers (most control types set the high bit 0x80000000):
0x80000001(LL_REQUEST): Low-level Request. Payload layout:0 - 3: 4-byte big-endian Request ID (rid).4...: UTF-8 encoded JSON string of request arguments.
0x80000002(LL_RESPONSE): Low-level Response. Payload layout:0 - 3: 4-byte big-endian Response ID (rid) matching the request.4: 1-byte flag indicator (body[4] & 1means this is the final chunk).5...: UTF-8 encoded JSON string of the response payload.
0x80000003(LL_KEEPALIVE): Heartbeat ping. Sent periodically to verify the session is active.0x80000004(LL_BEGIN_KEEPALIVE): Initiates the keepalive monitoring loop.0x80000005(LL_END_KEEPALIVE): Terminates keepalive monitoring.
When the session connects, Roon Core performs a security bootstrap:
- Lua Script Loading: Roon Core pushes several Lua script modules over TCP using the
load_scriptcommand (e.g.,base,dkjson,protocol,roon_tcp). - Code Signing: The Lua scripts must be signed with Roon's private key. The Core transmits the public
keypairname and RSA-SHA256signaturein the JSON request. The endpoint validates the signature against its built-in code signing keys before loading the script. - Core Query: The Core then queries the device capabilities using the JSON request
"request": "info".
To support multi-device grouped zones with sample-accurate alignment, RAAT operates a precision time synchronization loop.
- Protocol: UDP
- Port: Dynamically negotiated (Core starts a UDP listener on a random port and passes it to the receiver via the TCP
synccontrol command).
Once the receiver learns the Core's clock port, it enters a UDP exchange.
Sent by the client (receiver or sender) to query time:
0 - 7:"RAATCLKQ"(ASCII)8 - 11: 4-byte big-endian query ID (uint32).
Sent in response to a query:
0 - 7:"RAATCLKR"(ASCII)8 - 11: 4-byte big-endian query ID (uint32).12 - 19: 8-byte big-endian remote clock ticks (uint64/int64in 10-nanosecond units).20 - 27: 8-byte big-endian output hardware delay value (uint64/int64).
- The Core captures
xmit_time(local monotonic ticks) and sendsRAATCLKQ. - On receipt of
RAATCLKR, the Core capturesrecv_time. -
RTT Calculation: Round Trip Time (RTT) is calculated:
$$\text{RTT} = \frac{\text{recv_time} - \text{xmit_time}}{2}$$ -
Local Alignment: The estimated local time when the remote sampled its clock is:
$$\text{local_sample} = \text{xmit_time} + \text{RTT}$$ -
Clock Offset: The estimated clock offset is:
$$\text{offset} = \text{remote_time} - \text{local_sample}$$ -
Outlier Filtering: The Core fires up to 200 queries, keeps the 3 iterations with the lowest RTT (least network latency jitter), and uses the best offset to set
_clock_offset. It continually runs this loop to monitor and compensate for average drift over time.
Once the control and clock paths are synced, Roon Core sets up the audio stream.
The Core sends a "request": "setup" command over the TCP control path specifying the stream format:
{
"request": "setup",
"format": {
"sample_type": "pcm" | "dsd",
"sample_rate": 44100,
"bits_per_sample": 16,
"channels": 2,
"sample_subtype": "mqa" | "mqa_core" | "none",
"mqa_original_sample_rate": 192000
},
"wire_codec": "flac" | null
}The receiver initializes its audio hardware and responds with:
clock_port: The UDP port used for the clock synchronization described in Section 3.audio_port_tcp: The TCP port the receiver opened to accept audio stream connections.
The Core then opens a dedicated TCP socket to audio_port_tcp.
The audio streaming socket accepts structured binary commands. Each command starts with a 1-byte Command ID followed by its arguments and data payload:
+------------+--------------------+---------------------+
| Command ID | Payload Size (L) | Command Payload |
| (1 Byte) | (Big-Endian uint32)| (Variable Size L) |
+------------+--------------------+---------------------+
Carries actual audio samples.
Byte 0:0x00Bytes 1 - 4:nsamples(big-endian uint32) - Number of audio samples.Bytes 5 - 8:nbytes(big-endian uint32) - Payload byte size.Bytes 9...: Audio sample bytes (uncompressed PCM/DSD inter-leaved frames).
Informs the device of active audio channels.
Byte 0:0x01Bytes 1 - 4:channel_mask(big-endian uint32 bitmask of active audio channels).
Ties streaming frames to a control session stream.
Byte 0:0x02Bytes 1 - 4:stream_id(big-endian uint32).
Sets the starting frame alignment sample count.
Byte 0:0x03Bytes 1 - 8:streamsample(big-endian uint64 index).
Transmits normalization gain/peak details.
Byte 0:0x04Bytes 1 - 8:gain(double precision float serialized as 64-bit int bits).Bytes 9 - 16:peak(double precision float serialized as 64-bit int bits).
To conserve network bandwidth, RAAT supports streaming audio compressed on the fly (typically as FLAC).
Byte 0:0x05Bytes 1 - 4:nsamples(big-endian uint32).Bytes 5 - 8:nbytes(big-endian uint32).Bytes 9...: FLAC-encoded audio frames.
To start playback, the Core issues a JSON start request over the control session:
{
"request": "start",
"time": 6829103948500,
"stream_sample": 0,
"min_offset": 50000000
}time: The exact, absolute monotonic clock tick (in 10ns ticks) when the receiver's DAC should output the first audio sample ofstream_sample.stream_sample: The sample index mapping to the start boundary.
By calculating clock offsets across all endpoints, Roon Core schedules the time value in the future such that all devices output sample index 0 at the exact same physical moment, achieving flawless, drift-corrected multi-room synchronization.