A small, correct, hard-to-crash RTMP ingest server.

It accepts publishes from OBS, FFmpeg and other encoders, takes care of the handshake, chunk streams, protocol control messages, AMF0 commands and FLV tag parsing, and hands you timestamped audio and video frames through a behaviour you implement. What you do with them — HLS, recording, relaying, analysis — is up to you.

Getting started

defmodule MyApp.RTMPHandler do
  use RTMP.Handler

  @impl true
  def handle_publish(_app, stream_key, state) do
    if stream_key == "secret", do: {:ok, state}, else: {:reject, :bad_key, state}
  end

  @impl true
  def handle_frame(frame, state) do
    IO.inspect({frame.type, frame.codec, frame.dts})
    {:ok, state}
  end
end

# in your application's supervision tree
{RTMP.Listener, port: 1935, handler: MyApp.RTMPHandler}

Then publish to it:

ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/secret

Where to look

Summary

Functions

Closes a connection from outside its handler — for example, when a stream key is revoked mid-stream.

Functions

disconnect(connection, reason)

@spec disconnect(pid(), term()) :: :ok

Closes a connection from outside its handler — for example, when a stream key is revoked mid-stream.

connection is the connection process; inside any handler callback that's self(), so a handler can register it somewhere to find it later. The handler's RTMP.Handler.handle_disconnect/2 receives {:disconnected, reason}.