Current section
Files
Jump to
Current section
Files
lib/gen_rtmp_server.ex
defmodule GenRtmpServer do
@moduledoc """
A behaviour module for implementing an RTMP server.
A GenRtmpServer abstracts out the the handling of RTMP connection handling
and data so that modules that implement this behaviour can focus on
the business logic of the actual RTMP events that are received and
should be sent.
Each client that connects is placed in it's own process.
"""
require Logger
@type session_id :: String.t
@type client_ip :: String.t
@type adopter_state :: any
@type command :: :ignore | :disconnect
@type request_result :: :accepted | {:rejected, command, String.t}
@type outbound_data :: GenRtmpServer.AudioVideoData.t | GenRtmpServer.MetaData.t
@type stream_id :: non_neg_integer
@type forced_timestamp :: non_neg_integer | nil
@type adopter_arguments :: [...]
@doc "Called when a new RTMP client connects"
@callback init(session_id, client_ip, adopter_arguments) :: {:ok, adopter_state}
@doc "Called when the client is requesting a connection to the specified application name"
@callback connection_requested(Rtmp.ServerSession.Events.ConnectionRequested.t, adopter_state)
:: {request_result, adopter_state}
@doc """
Called when a client wants to publish a stream to the specified application name
and stream key combination
"""
@callback publish_requested(Rtmp.ServerSession.Events.PublishStreamRequested.t, adopter_state)
:: {request_result, adopter_state}
@doc """
Called when the client is no longer publishing to the specified application name
and stream key
"""
@callback publish_finished(Rtmp.ServerSession.Events.PublishingFinished.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when the client is wanting to play a stream from the specified application
name and stream key combination
"""
@callback play_requested(Rtmp.ServerSession.Events.PlayStreamRequested.t, adopter_state)
:: {request_result, adopter_state}
@doc """
Called when the client no longer wants to play the stream from the specified
application name and stream key combination
"""
@callback play_finished(Rtmp.ServerSession.Events.PlayStreamFinished.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when a client publishing a stream has changed the metadata information
for that stream.
"""
@callback metadata_received(Rtmp.ServerSession.Events.StreamMetaDataChanged.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when audio or video data has been received on a published stream
"""
@callback audio_video_data_received(Rtmp.ServerSession.Events.AudioVideoDataReceived.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when the number of bytes sent and received to the client changes
"""
@callback byte_io_totals_updated(Rtmp.ServerSession.Events.NewByteIOTotals.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when the client sends an acknowledgement of bytes received
"""
@callback acknowledgement_received(Rtmp.ServerSession.Events.AcknowledgementReceived.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when the server has successfully sent a ping request. This is needed to be handled
if the server implementation wants track how long it's been since a ping request has gone
unresponded to, or if the server wants to get an idea of latency
"""
@callback ping_request_sent(Rtmp.ServerSession.Events.PingRequestSent.t, adopter_state)
:: {:ok, adopter_state}
@doc """
Called when the server has received a response to a ping request. Note that unsolicited
ping responses may come through, and it's up to the behavior implementor to decide how to
react to it.
"""
@callback ping_response_received(Rtmp.ServerSession.Events.PingResponseReceived.t, adopter_state)
:: {:ok, adopter_state}
@doc "Called when an code change is ocurring"
@callback code_change(any, adopter_state) :: {:ok, adopter_state} | {:error, String.t}
@doc """
Called when any BEAM message is received that is not handleable by the generic RTMP server,
and is thus being passed along to the module adopting this behaviour.
"""
@callback handle_message(any, adopter_state) :: {:ok, adopter_state}
@doc """
Called when the TCP socket is closed. Allows for any last minute cleanup before
the process is killed
"""
@callback handle_disconnection(adopter_state) :: {:ok, adopter_state}
@spec start_link(module(), %GenRtmpServer.RtmpOptions{}, adopter_arguments) :: Supervisor.on_start
@doc """
Starts the generic RTMP server using the provided RTMP options
"""
def start_link(module, options = %GenRtmpServer.RtmpOptions{}, additional_args \\ []) do
{:ok, _} = Application.ensure_all_started(:ranch)
_ = Logger.info "Starting RTMP listener on port #{options.port}"
:ranch.start_listener(module,
10,
:ranch_tcp,
[port: options.port],
GenRtmpServer.Protocol,
[module, options, additional_args])
end
@spec send_message(pid, outbound_data, stream_id, forced_timestamp) :: :ok
@doc """
Signals a specific RTMP server process to send an RTMP message to its client
"""
def send_message(pid, outbound_data, stream_id, forced_timestamp \\ nil) do
send(pid, {:rtmp_send, outbound_data, stream_id, forced_timestamp})
end
@spec send_ping_request(pid) :: :ok
@doc """
Sends a ping request to the client
"""
def send_ping_request(pid) do
send(pid, :send_ping_request)
end
end