← All tools
SLM protocol icon

The SLM Protocol

OpenUDPSHM LZ4H.264 / H.265v4

Two transports, one job: move live video and audio from a sender to its receivers with as little delay as possible.

Discovery: ANNOUNCE to 239.255.77.43:9878 (multicast). Both transports run at once. Sender Cart, Camera, OBS same machine SHM ring buffer zero-copy, 16 slots Receiver e.g. OBS, same PC across the network UDP unicast LAN or remote Receiver across the network

A sender streams over shared memory and UDP simultaneously; a receiver picks SHM when it is on the same machine and tells the sender via a flag, so no UDP is wasted on it.

What SLM is

SLM (SLAY Media) is the wire protocol underneath every SLAY tool. It carries video — raw NV12, or hardware H.264/H.265 — and 48 kHz stereo f32 audio from one sender to one or more receivers, over two transports that run at the same time:

  • SHM — a shared-memory ring buffer for receivers on the same machine (POSIX shared memory on Linux/macOS, a Win32 named file mapping on Windows). Zero-copy, and free of the kernel UDP socket buffer limit.
  • UDP — unicast datagrams for receivers on the LAN or further away, discovered automatically over multicast.

Everything in the design bends toward one goal: low latency. In our tests about 1 ms over shared memory and ~3 ms to a laptop over WiFi with H.264 (around 20 ms for uncompressed NV12 on a gigabit LAN), with a connect-time handshake the steady-state media path never pays for again.

Two transports, one stream

A sender always offers both transports. A receiver signals which one it is using with the SLM_HELLO_FLAG_SHM bit in its HELLO packet; the sender then skips UDP for that receiver. The shared-memory layout — header, slot ring, frame headers, payloads — is byte-for-byte identical on every platform; only the OS primitives that create and signal the region differ.

Session lifecycle (the flow)

A UDP session moves through four phases: the sender advertises itself, the receiver proves it owns its address (the v4 return-routability check that defeats spoofed-source reflection attacks), the sender streams, and finally tears down. Validation is a one-time, connect-time cost — once an address is validated the media path adds no further round trips.

Sender Receiver DISCOVERY ANNOUNCE - multicast, ~250 ms receiver discovers the sender ADDRESS VALIDATION (v4) HELLO - echo_nonce = 0 receiver registers (pending) CHALLENGE - random nonce HELLO - echo_nonce = nonce receiver echoes the challenge STREAMING CAPS address validated; receiver configures its pipeline VIDEO / AUDIO - per frame continuous stream, validated receivers only HELLO / KEEPALIVE - ~250 ms receiver stays registered (10 s expiry) TEARDOWN BYE

Amber arrows are sender → receiver; red arrows are receiver → sender. A spoofer that forges a victim's address never receives the CHALLENGE, so it can never echo the nonce and the flood never starts.

Packet types

Every UDP datagram starts with the 12-byte common header below; the type byte selects one of these. Multi-byte integers are little-endian.

TypeNameDirectionPurpose
0x01ANNOUNCEsender → multicastAdvertise the sender for discovery
0x02HELLOreceiver → senderRegister / keepalive; carries the echo nonce
0x03CAPSsender → receiverStream format: size, fps, pixel format, codec
0x04CHALLENGEsender → receiverRandom nonce for address validation
0x10VIDEOsender → receiversOne chunk of a video frame
0x11AUDIOsender → receiversInterleaved f32le PCM, 48 kHz stereo
0x12FECsender → receiversXOR parity for the video path (lossy links)
0x20KEEPALIVEreceiver → senderLiveness; structurally identical to HELLO
0x30TALLYreceiver → senderOn-air status (off / preview / program)
0x31MSGreceiver → senderShort free-text operator message
0x32STATreceiver → senderEchoes a send timestamp for latency measurement
0xFFBYEsender → receiversClean shutdown; flush buffers

The common header

Twelve bytes prefix every UDP datagram. The random stream_id lets a receiver notice a sender restart, and the version byte gates the whole data path: a receiver silently ignores any packet whose version does not match its own.

magic
4 B · "SLM\x01"
type
1 B
version
1 B · 4
flags
2 B
stream_id
4 B · u32

Offsets 0..11. The media payloads add their own headers after this: a VIDEO chunk adds 36 bytes (then up to 1400 bytes of frame data), AUDIO adds 24 bytes.

The data path

Codecs and pixel formats

The codec field in CAPS selects how a receiver reads VIDEO payloads. A receiver that does not support the offered codec disconnects cleanly rather than render garbage.

CodecVIDEO payload
0 RAWNV12 (per pixel_fmt), optionally LZ4-compressed per frame
1 H.264H.264 Annex B access units, no container
2 H.265H.265 Annex B access units, no container
Pixel formatDescription
1 NV12Y plane, then interleaved UV. The only format the current sender produces for RAW.
2 I420Planar YUV 4:2:0
3 BGRA32-bit packed
4 YUY2Packed 4:2:2

Color matrix is BT.709, limited range for YUV. For H.264/H.265 the payload is an encoded bitstream and pixel_fmt is ignored.

Constants

ConstantValueDescription
SLM_MCAST_GROUP239.255.77.43Multicast group for ANNOUNCE
SLM_MCAST_PORT9878Multicast port
SLM_MAX_UDP_PAYLOAD1400 BMax chunk payload; fits a 1500-byte MTU
SLM_PROTOCOL_VERSION4UDP protocol version
SLM_SHM_MAGIC0x534C4D02SHM region magic (distinct from UDP "SLM\x01")
SLM_SHM_VERSION2SHM header version
SLM_SHM_SLOTS16Ring buffer slot count
SLM_SHM_STALE_SECS5 sHeartbeat age that marks a dead producer
Audio sample rate48000 HzFixed for all streams
Audio channels2Stereo, interleaved
Receiver expiry10 sHELLO / KEEPALIVE timeout

Build on it

SLM is open, with reference implementations in C and Rust. The full byte-level specification — every field offset, the SHM region layout, and the version history — lives in PROTOCOL.md. Write your own sender or receiver, or drop the OBS plugin into OBS Studio.