rtmp-runtime
Sans-IO RTMP 1.0 ingest (publish) session engine for Adobe's Real-Time Messaging Protocol, covering both ends of a publish exchange:
server— the ingest server side, for receiving a live push from an encoder or OBS.client— the publish client side, for pushing a live stream to a remote RTMP server.
rtmp-runtime owns the RTMP wire layer and session state machine — handshake,
chunk-stream (de)assembly, AMF0 command routing, and the publish flow. The
server hands the received media off as FLV bytes for a container demuxer
(e.g. transmux) to turn into samples;
the client accepts already-encoded audio/video/metadata to send. Both roles
are publish-only; egress/play (on either the client or server side) is
out of scope.
Design
A bytes-in → (bytes-out, events) engine, with no I/O of its own:
use ;
let mut session = with_defaults;
// Feed inbound TCP bytes; get bytes to write back + typed events.
let = session.handle_data?;
socket.write_all?;
for ev in events
handle_data drives the whole exchange internally and buffers partial input
across calls, so it runs against any transport. With the optional tokio
feature, io::AsyncRtmpServer binds a listener and drives one ServerSession
per connection.
What's implemented
- Handshake (§2): C0/S0, C1/S1, C2/S2 (simple handshake — interoperates with
ffmpeg/OBS
-f flvpublishers). - Chunk stream (§3): basic header (1/2/3-byte csid) + message header
fmt 0/1/2/3 + extended timestamp; incremental
ChunkAssembler(header inheritance,SetChunkSizetracking, partial-input buffering) +ChunkWriter. - Protocol control (§4): SetChunkSize / Abort / Acknowledgement / WindowAckSize / SetPeerBandwidth; User Control events (§5, StreamBegin …).
- AMF0 (§8): the value types +
Commandencode/decode for the ingest command set. (AMF3 is out of scope.) - Publish session (§7):
connect→createStream→publish(+ tolerated OBS extrasreleaseStream/FCPublish), with WindowAckSize / SetPeerBandwidth / SetChunkSize /_result/ StreamBegin /onStatusreplies,Acknowledgementaccounting, and optionalexpected_stream_keygating. Audio/Video/Data messages are emitted as FLV (ServerEvent::Media) — concatenating them yields a valid FLV stream fortransmux. tokioadapter:io::AsyncRtmpServer(listener) /RtmpConnection(featuretokio); the sans-IO core needs no runtime.- Publish client (§7):
client::ClientSessiondrives the client-side handshake and auto-advancesconnect→createStream→publish, then offerssend_audio/send_video/send_metadataonce publishing. Sans-IO only — there is notokioadapter for it yet, unlike the server side.
Every wire structure implements symmetric Parse/Serialize with byte-identical
round-trips, verified against a real ffmpeg RTMP publish capture
(tests/fixtures/obs-publish.bin).
Spec
Adobe Real-Time Messaging Protocol (RTMP) specification — transcribed for this
crate in docs/rtmp.md. (docs/rtmp.md uses its own §-numbering
for navigation, not the Adobe spec's own §5.x/§7.x numbering cited throughout
this README and the source doc comments.)
Features
| Feature | Default | Adds |
|---|---|---|
serde |
off | Serialize/Deserialize on the owned public wire/event types: ServerEvent, ServerConfig, Amf0Value, Command. |
tokio |
off | The real-socket adapter (io::AsyncRtmpServer / RtmpConnection); the sans-IO core itself needs no runtime. |
MSRV
Rust 1.95.0.
License
MIT OR Apache-2.0.