<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Developer Guide on go-rtmp</title><link>https://alxayo.github.io/rtmp-go/docs/developer/</link><description>Recent content in Developer Guide on go-rtmp</description><generator>Hugo</generator><language>en</language><atom:link href="https://alxayo.github.io/rtmp-go/docs/developer/index.xml" rel="self" type="application/rss+xml"/><item><title>Architecture</title><link>https://alxayo.github.io/rtmp-go/docs/developer/architecture/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alxayo.github.io/rtmp-go/docs/developer/architecture/</guid><description>&lt;h1 id="architecture"&gt;Architecture&lt;a class="anchor" href="#architecture"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="high-level-data-flow"&gt;High-Level Data Flow&lt;a class="anchor" href="#high-level-data-flow"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every RTMP connection follows this path:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;TCP Accept → Handshake → Control Burst → Command RPC → Media Relay/Recording&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TCP Accept&lt;/strong&gt; — the server accepts an inbound TCP connection&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handshake&lt;/strong&gt; — client and server exchange C0/C1/C2 ↔ S0/S1/S2 packets to establish the session&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control Burst&lt;/strong&gt; — both sides exchange Window Acknowledgement Size, Set Peer Bandwidth, and Set Chunk Size&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command RPC&lt;/strong&gt; — AMF0-encoded commands (&lt;code&gt;connect&lt;/code&gt;, &lt;code&gt;createStream&lt;/code&gt;, &lt;code&gt;publish&lt;/code&gt;/&lt;code&gt;play&lt;/code&gt;) negotiate the stream&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Relay/Recording&lt;/strong&gt; — audio (TypeID 8) and video (TypeID 9) messages flow through the relay to subscribers and optionally to disk as FLV&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="architecture-diagram"&gt;Architecture Diagram&lt;a class="anchor" href="#architecture-diagram"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; ┌──────────────────────────────────┐
 │ TCP Listener(s) │
 │ Plain (:1935) + TLS (:1936) │
 └──────────┬───────────────────────┘
 │ Accept()
 ▼
 ┌──────────────────────────────────┐
 │ Handshake Layer │
 │ C0/C1/C2 ↔ S0/S1/S2 exchange │
 └──────────┬───────────────────────┘
 │
 ▼
 ┌──────────────────────────────────┐
 │ Chunk Layer │
 │ Message ↔ Chunk fragmentation │
 └──────────┬───────────────────────┘
 │
 ┌──────────┴───────────────────────┐
 │ │
 ┌─────▼─────┐ ┌──────▼──────┐
 │ Commands │ │ Media │
 │ (TypeID │ │ (TypeID │
 │ 20) │ │ 8=audio │
 │ │ │ 9=video) │
 └─────┬──────┘ └──────┬──────┘
 │ │
 ┌─────▼──────┐ ┌──────▼──────┐
 │ RPC Layer │ │Media Dispatch│
 │ connect │ │ Record │
 │ createStream│ │ Broadcast │
 │ publish │ │ Relay │
 │ play │ │ │
 └──────┬─────┘ └─────────────┘
 │
 ┌──────▼──────┐
 │ Event Hooks │
 └─────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="package-map"&gt;Package Map&lt;a class="anchor" href="#package-map"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Package&lt;/th&gt;
 &lt;th&gt;Purpose&lt;/th&gt;
 &lt;th&gt;Key Types&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/handshake&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;RTMP v3 handshake (C0/C1/C2 ↔ S0/S1/S2)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Handshake&lt;/code&gt;, &lt;code&gt;State&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/chunk&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Message ↔ chunk fragmentation/reassembly&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Reader&lt;/code&gt;, &lt;code&gt;Writer&lt;/code&gt;, &lt;code&gt;ChunkHeader&lt;/code&gt;, &lt;code&gt;Message&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/amf&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;AMF0 binary codec&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;EncodeAll()&lt;/code&gt;, &lt;code&gt;DecodeAll()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/control&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Control messages (types 1-6)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Decode()&lt;/code&gt;, &lt;code&gt;Handle()&lt;/code&gt;, &lt;code&gt;Context&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/rpc&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Command parsing &amp;amp; response building&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Dispatcher&lt;/code&gt;, &lt;code&gt;ConnectCommand&lt;/code&gt;, &lt;code&gt;PublishCommand&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/conn&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Connection lifecycle&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Connection&lt;/code&gt;, &lt;code&gt;Session&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/server&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Listener, stream registry, pub/sub&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Server&lt;/code&gt;, &lt;code&gt;Registry&lt;/code&gt;, &lt;code&gt;Stream&lt;/code&gt;, &lt;code&gt;Config&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/server/auth&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Token-based authentication validators&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Validator&lt;/code&gt;, &lt;code&gt;TokenValidator&lt;/code&gt;, &lt;code&gt;FileValidator&lt;/code&gt;, &lt;code&gt;CallbackValidator&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/server/hooks&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Event notification&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;HookManager&lt;/code&gt;, &lt;code&gt;Event&lt;/code&gt;, &lt;code&gt;Hook&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/media&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Audio/video parsing, codec detection (Enhanced RTMP), FLV recording&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Recorder&lt;/code&gt;, &lt;code&gt;CodecDetector&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/relay&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Multi-destination relay&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;DestinationManager&lt;/code&gt;, &lt;code&gt;Destination&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/metrics&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Expvar counters&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ConnectionsActive&lt;/code&gt;, &lt;code&gt;BytesIngested&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/rtmp/client&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minimal RTMP client for testing&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Client&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/errors&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Domain-specific error types&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ProtocolError&lt;/code&gt;, &lt;code&gt;ChunkError&lt;/code&gt;, &lt;code&gt;AMFError&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;internal/logger&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Structured logging&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Init()&lt;/code&gt;, &lt;code&gt;Logger()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="connection-lifecycle"&gt;Connection Lifecycle&lt;a class="anchor" href="#connection-lifecycle"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what happens step-by-step when OBS connects and starts streaming:&lt;/p&gt;</description></item><item><title>Design Principles</title><link>https://alxayo.github.io/rtmp-go/docs/developer/design/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alxayo.github.io/rtmp-go/docs/developer/design/</guid><description>&lt;h1 id="design-principles"&gt;Design Principles&lt;a class="anchor" href="#design-principles"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;These principles guide every decision in the go-rtmp codebase. When in doubt, refer back to these.&lt;/p&gt;
&lt;h2 id="correctness-over-features"&gt;Correctness Over Features&lt;a class="anchor" href="#correctness-over-features"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every byte on the wire must match the RTMP specification. We will not ship a feature that compromises protocol correctness. If there&amp;rsquo;s a conflict between &amp;ldquo;works with most clients&amp;rdquo; and &amp;ldquo;matches the spec,&amp;rdquo; the spec wins. Golden binary vectors enforce this — every encoder and decoder is tested against exact byte sequences.&lt;/p&gt;</description></item><item><title>Testing Guide</title><link>https://alxayo.github.io/rtmp-go/docs/developer/testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alxayo.github.io/rtmp-go/docs/developer/testing/</guid><description>&lt;h1 id="testing-guide"&gt;Testing Guide&lt;a class="anchor" href="#testing-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="running-tests"&gt;Running Tests&lt;a class="anchor" href="#running-tests"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="all-tests"&gt;All Tests&lt;a class="anchor" href="#all-tests"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="all-tests-with-race-detector"&gt;All Tests with Race Detector&lt;a class="anchor" href="#all-tests-with-race-detector"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test -race ./...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The race detector is mandatory for CI. It catches data races that would otherwise be invisible.&lt;/p&gt;
&lt;h3 id="package-level-tests"&gt;Package-Level Tests&lt;a class="anchor" href="#package-level-tests"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run tests for a specific protocol layer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/handshake/ &lt;span style="color:#75715e"&gt;# Handshake FSM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/chunk/ &lt;span style="color:#75715e"&gt;# Chunk reader/writer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/amf/ &lt;span style="color:#75715e"&gt;# AMF0 codec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/control/ &lt;span style="color:#75715e"&gt;# Control messages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/rpc/ &lt;span style="color:#75715e"&gt;# Command dispatch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/conn/ &lt;span style="color:#75715e"&gt;# Connection lifecycle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/server/ &lt;span style="color:#75715e"&gt;# Server integration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/server/auth/ &lt;span style="color:#75715e"&gt;# Authentication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/server/hooks/ &lt;span style="color:#75715e"&gt;# Event hooks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/media/ &lt;span style="color:#75715e"&gt;# Media handling + recording&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/relay/ &lt;span style="color:#75715e"&gt;# Multi-destination relay&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/rtmp/metrics/ &lt;span style="color:#75715e"&gt;# Expvar counters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/errors/ &lt;span style="color:#75715e"&gt;# Error types&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="integration-tests"&gt;Integration Tests&lt;a class="anchor" href="#integration-tests"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./tests/integration/ -count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;-count=1&lt;/code&gt; flag disables test caching, ensuring tests always run fresh.&lt;/p&gt;</description></item><item><title>Contributing</title><link>https://alxayo.github.io/rtmp-go/docs/developer/contributing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alxayo.github.io/rtmp-go/docs/developer/contributing/</guid><description>&lt;h1 id="contributing"&gt;Contributing&lt;a class="anchor" href="#contributing"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="workflow"&gt;Workflow&lt;a class="anchor" href="#workflow"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fork&lt;/strong&gt; the repository on GitHub&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create a feature branch&lt;/strong&gt; from &lt;code&gt;main&lt;/code&gt;:
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git checkout -b feature/NNN-description&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;Where &lt;code&gt;NNN&lt;/code&gt; is the issue number (if applicable).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make your changes&lt;/strong&gt; — write tests first, then implementation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify&lt;/strong&gt; everything passes (see below)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Submit a Pull Request&lt;/strong&gt; back to &lt;code&gt;main&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="branch-naming"&gt;Branch Naming&lt;a class="anchor" href="#branch-naming"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use the pattern &lt;code&gt;feature/NNN-description&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;feature/042-rtmps-support
feature/099-configurable-backpressure
fix/117-amf0-null-decode
docs/update-troubleshooting&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="commit-messages"&gt;Commit Messages&lt;a class="anchor" href="#commit-messages"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Follow &lt;a href="https://www.conventionalcommits.org/"&gt;Conventional Commits&lt;/a&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;feat(relay): add reconnection with exponential backoff
fix(chunk): handle extended timestamp in FMT 3 continuation
test: add golden vectors for H.265 sequence headers
docs: update CLI reference with new auth flags
refactor(amf): simplify object end detection&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Scopes match package names: &lt;code&gt;handshake&lt;/code&gt;, &lt;code&gt;chunk&lt;/code&gt;, &lt;code&gt;amf&lt;/code&gt;, &lt;code&gt;control&lt;/code&gt;, &lt;code&gt;rpc&lt;/code&gt;, &lt;code&gt;conn&lt;/code&gt;, &lt;code&gt;server&lt;/code&gt;, &lt;code&gt;auth&lt;/code&gt;, &lt;code&gt;hooks&lt;/code&gt;, &lt;code&gt;media&lt;/code&gt;, &lt;code&gt;relay&lt;/code&gt;, &lt;code&gt;metrics&lt;/code&gt;.&lt;/p&gt;</description></item></channel></rss>