Back to Snapcast

Snapcast binary protocol

doc/binary_protocol.md

0.35.09.6 KB
Original Source

Snapcast binary protocol

Each message sent with the Snapcast binary protocol is split up into two parts:

  • A base message that provides general information like time sent/received, type of the message, message size, etc
  • A typed message that carries the rest of the information

The protocol is using little endian.

Client joining process

When a client joins a server, the following exchanges happen

  1. Client opens a TCP socket to the server (default port is 1704)
  2. Client sends a Hello message
  3. Server sends a Server Settings message
  4. Server sends a Codec Header message
    1. Until the server sends this, the client shouldn't play any Wire Chunk messages
  5. The server will now send Wire Chunk messages, which can be fed to the audio decoder.
  6. When it comes time for the client to disconnect, the socket can just be closed.
  7. Client periodically sends a Time message, carrying a sent timestamp t_client-sent
    1. Receives a Time response containing the client to server time delta latency_c2s = t_server-recv - t_client-sent + t_network-latency and the server sent timestamp t_server-sent
    2. Calculates latency_s2c = t_client-recv - t_server-sent + t_network_latency
    3. Calcutates the time diff between server and client as (latency_c2s - latency_s2c) / 2, eliminating the network latency (assumed to be symmetric)
mermaid
sequenceDiagram
    participant Client as Snapclient
    participant Server as Snapserver
    Note over Client,Server: Client connects to the server
over TCP or WS
    Client ->> Server: Hello
    Server ->> Client: Server Settings
    Server ->> Client: Codec Header
    loop Time sync
        Client ->> Server: Time
        Server ->> Client: Time
    end
    Note over Client,Server: Audio starts playing on the server
Time sync continues
    loop Stream
        Server ->> Client: Wire Chunk
    end
    Note over Client,Server: Client closes the connection

Messages

Typed Message IDNameDirNotes
0BaseThe beginning of every message containing data about the typed message
1Codec HeaderS->CThe codec-specific data to put at the start of a stream to allow decoding
2Wire ChunkS->CA part of an audio stream
3Server SettingsS->CSettings set from the server like volume, latency, etc
4TimeC->S
S->CUsed for synchronizing time with the server
5HelloC->SSent by the client when connecting with the server
7Client InfoC->SUpdate the server when relevant information changes (e.g. client volume)
8ErrorS->CError response, used e.g. for missing authentication

Base

FieldTypeDescription
typeuint16Should be one of the typed message IDs
iduint16Used in requests to identify the message (not always used)
refersTouint16Used in responses to identify which request message ID this is responding to
sent.secint32The second value of the timestamp when this message was sent. Filled in by the sender.
sent.usecint32The microsecond value of the timestamp when this message was sent. Filled in by the sender.
received.secint32The second value of the timestamp when this message was received. Filled in by the receiver.
received.usecint32The microsecond value of the timestamp when this message was received. Filled in by the receiver.
sizeuint32Total number of bytes of the following typed message

Codec Header

FieldTypeDescription
codec_sizeunint32Length of the codec string (not including a null character)
codecchar[]String describing the codec (not null terminated)
sizeuint32Size of the following payload
payloadchar[]Buffer of data containing the codec header

The payload depends on the used codec:

  • Flac: the FLAC audio file header, as described here. The decoder must be initialized with this header.
  • Ogg: the vorbis stream header, as described here. The decoder must be initialized with this header.
  • PCM: a RIFF WAVE header, as described here. PCM is not encoded, but the decoder must know the samplerate, bit depth and number of channels, which is encoded into the header
  • Opus: a dummy header is sent, containing a 4 byte ID (0x4F505553, ascii for "OPUS"), 4 byte samplerate, 2 byte bit depth, 2 byte channel count (all little endian)

Wire Chunk

FieldTypeDescription
timestamp.secint32The second value of the timestamp when this part of the stream was recorded
timestamp.usecint32The microsecond value of the timestamp when this part of the stream was recorded
sizeuint32Size of the following payload
payloadchar[]Buffer of data containing the encoded PCM data (a decodable chunk per message)

Server Settings

FieldTypeDescription
sizeuint32Size of the following JSON string
payloadchar[]JSON string containing the message (not null terminated)

Sample JSON payload (whitespace added for readability):

json
{
    "bufferMs": 1000,
    "latency": 0,
    "muted": false,
    "volume": 100
}
  • volume can have a value between 0-100 inclusive

Time

FieldTypeDescription
latency.secint32The second value of the latency between the server and the client
latency.usecint32The microsecond value of the latency between the server and the client

Hello

FieldTypeDescription
sizeuint32Size of the following JSON string
payloadchar[]JSON string containing the message (not null terminated)

Sample JSON payload (whitespace added for readability):

json
{
    "Arch": "x86_64",
    "Auth": {
        "param": "YmFkYWl4OnBhc3N3ZA==",
        "scheme": "Basic"
    },
    "ClientName": "Snapclient",
    "HostName": "my_hostname",
    "ID": "00:11:22:33:44:55",
    "Instance": 1,
    "MAC": "00:11:22:33:44:55",
    "OS": "Arch Linux",
    "SnapStreamProtocolVersion": 2,
    "Version": "0.32.0"
}

The field Auth is optional and only used if authentication and authorization is enabled on the server.

Client Info

FieldTypeDescription
sizeuint32Size of the following JSON string
payloadchar[]JSON string containing the message (not null terminated)

Sample JSON payload (whitespace added for readability):

json
{
    "volume": 100,
    "muted": false,
}
  • volume can have a value between 0-100 inclusive

Error

FieldTypeDescription
codeuint32Error code
sizeuint32Size of the following error string
errorchar[]string containing the error (not null terminated)
sizeuint32Size of the following error message
errorchar[]string containing error details (not null terminated)