Modules
A pure-Elixir AirPlay (RAOP) audio sender — discover receivers on the LAN and
stream lossless audio to them, with no native dependencies (just :crypto,
:gen_udp and :gen_tcp).
Pack PCM into uncompressed ALAC frames for AirPlay/RAOP.
Play a PCM buffer to an AirPlay/RAOP receiver, end to end — a small session
GenServer exposing play/3, stop/1, set_volume/2.
Stream-decode an audio file to AirPlay frames with bounded memory.
Discover AirPlay/RAOP receivers on the LAN via mDNS (multicast DNS,
224.0.0.251:5353) — the Bonjour service browse Apple devices use. Queries the
_raop._tcp.local service and resolves each instance's SRV (host/port) + A
(address) from the responses.
NTP 64-bit timestamps for the AirPlay/RAOP timing channel.
Streams ALAC-over-RTP audio to an AirPlay/RAOP receiver after the RTSP handshake. Owns three UDP sockets
RAOP packet builders: audio (PT 0x60), control sync (0xd4), and timing
response (0xd3). All multi-byte fields are big-endian.
Minimal RTSP/1.0 client for the AirPlay/RAOP control plane.
Drives the AirPlay/RAOP control handshake against a receiver.
Decode a library track to the PCM format AirPlay/RAOP wants: 44.1 kHz, 16-bit,
stereo, little-endian, via ffmpeg. Returns the raw interleaved s16le bytes,
which AirPlay.Alac chops into 352-sample frames.
Crypto primitives for AirPlay 2 pairing + the encrypted channel, mapping the
AirPlay 2 scheme onto Erlang :crypto
AirPlay 2 transient pairing over RTSP (/pair-setup), porting
AirPlayClientV2.PairSetup1/PairSetup2. No PIN / Apple account:
SRP-6a with username "Pair-Setup", password "3939". On success the SRP
session key keys the ChaCha20-Poly1305 control + audio channel.
Minimal Apple binary property list (bplist00) codec for AirPlay 2 — enough for
the /info response and the /setup request body.
Minimal IEEE-1588v2 (PTP) grandmaster for AirPlay 2 — the timing gate for
HomePods. HomePods negotiate timingProtocol:"PTP" and schedule
playback against a PTP network clock; we advertise ourselves as the grandmaster
so the receiver slaves to our clock, then SETRATEANCHORTIME references a real
time on this clock.
Encrypted RTSP/1.0 over a paired AirPlay 2 connection. After
AirPlay.V2.Pairing, the whole RTSP message (request line + headers + body)
is wrapped through AirPlay.V2.SecureChannel (ChaCha20-Poly1305 block
framing); responses are decrypted and parsed the same way. Mirrors
RTSPClientV2.Request. Verified live against a real AirPlay 2
device (encrypted GET /info → decrypted 200 OK).
The encrypted RTSP control channel used after AirPlay 2 pairing — a port of
EncryptionContext. Once paired, every RTSP message is wrapped:
split into ≤1024-byte blocks, each emitted as
[len:u16-le][ciphertext][tag:16], ChaCha20-Poly1305 with a 12-byte nonce
<<0::32, counter::little-64>> (separate write/read counters) and AAD = the
2-byte length prefix.
AirPlay 2 stream setup over the encrypted RTSP channel, porting
SetupAirPlay2Session / SetupAirPlay2Stream
SRP-6a client for AirPlay 2 transient pairing, byte-exact to the AirPlay 2 SRP-6a parameters.
TLV8 encoding for AirPlay 2 / HomeKit pairing (/pair-setup, /pair-verify).