Current section

Files

Jump to
membrane_rtc_engine_webrtc lib webrtc forwarder.ex
Raw

lib/webrtc/forwarder.ex

defmodule Membrane.RTC.Engine.Endpoint.WebRTC.Forwarder do
@moduledoc false
# Module responsible for forwarding RTP/RTCP packets.
# It takes care of rewriting RTP/RTCP header and parts of RTP/RTCP payload.
require Membrane.Pad
require Membrane.Logger
alias Membrane.Buffer
alias Membrane.RTC.Engine.Endpoint.WebRTC.RTPMunger
alias Membrane.RTC.Engine.Endpoint.WebRTC.VP8Munger
alias Membrane.RTC.Engine.Track
alias Membrane.RTCP.SenderReportPacket
@opaque t() :: %__MODULE__{
codec: :H264 | :VP8 | :OPUS,
rtp_munger: RTPMunger.t(),
vp8_munger: VP8Munger.t(),
started?: boolean()
}
@enforce_keys [:codec]
defstruct @enforce_keys ++
[
:rtp_munger,
:vp8_munger,
started?: false
]
@doc """
Creates a new forwarder.
"""
@spec new(:H264 | :VP8 | :OPUS, Membrane.RTP.clock_rate_t()) :: t()
def new(codec, clock_rate)
def new(:VP8, clock_rate) do
%__MODULE__{
codec: :VP8,
rtp_munger: RTPMunger.new(clock_rate),
vp8_munger: VP8Munger.new()
}
end
def new(:H264, clock_rate) do
%__MODULE__{
codec: :H264,
rtp_munger: RTPMunger.new(clock_rate)
}
end
def new(:OPUS, _clock_rate) do
%__MODULE__{codec: :OPUS}
end
@doc """
Reconfigures forwarder after encoding switch.
"""
@spec reconfigure(t(), Membrane.Buffer.t()) :: t()
def reconfigure(%__MODULE__{started?: false} = forwarder, buffer) do
Membrane.Logger.debug("Initializing RTP and VP8 mungers")
%__MODULE__{
rtp_munger: rtp_munger,
vp8_munger: vp8_munger
} = forwarder
rtp_munger = if rtp_munger, do: RTPMunger.init(rtp_munger, buffer)
vp8_munger = if vp8_munger, do: VP8Munger.init(vp8_munger, buffer)
%{
forwarder
| rtp_munger: rtp_munger,
vp8_munger: vp8_munger
}
end
def reconfigure(%__MODULE__{} = forwarder, buffer) do
Membrane.Logger.debug("Reconfiguring forwader with buffer: #{inspect(buffer)}")
%__MODULE__{
rtp_munger: rtp_munger,
vp8_munger: vp8_munger
} = forwarder
rtp_munger = if rtp_munger, do: RTPMunger.update(rtp_munger, buffer)
vp8_munger = if vp8_munger, do: VP8Munger.update(vp8_munger, buffer)
%__MODULE__{forwarder | rtp_munger: rtp_munger, vp8_munger: vp8_munger}
end
@spec generate_padding_packet(t(), Track.t(), boolean()) :: {t(), Buffer.t() | nil}
def generate_padding_packet(%__MODULE__{} = forwarder, %Track{} = track, force_marker?) do
{rtp_munger, buffer} =
RTPMunger.generate_padding_packet(forwarder.rtp_munger, track, force_marker?)
{%{forwarder | rtp_munger: rtp_munger}, buffer}
end
@spec can_generate_padding_packet?(t()) :: boolean()
def can_generate_padding_packet?(%__MODULE__{} = forwarder) do
RTPMunger.can_generate_padding_packet?(forwarder.rtp_munger)
end
@doc """
Adjusts RTP packet header and payload.
"""
@spec align(t(), Buffer.t() | SenderReportPacket.t()) :: {t(), Buffer.t() | nil}
def align(
%__MODULE__{started?: false} = forwarder,
%{metadata: %{is_keyframe: true}} = buffer
) do
forwarder = %{forwarder | started?: true}
{forwarder, buffer}
end
def align(%__MODULE__{} = forwarder, buffer) do
%__MODULE__{
rtp_munger: rtp_munger,
vp8_munger: vp8_munger
} = forwarder
{rtp_munger, buffer} =
if rtp_munger do
RTPMunger.munge(rtp_munger, buffer)
else
{rtp_munger, buffer}
end
{vp8_munger, buffer} =
case {vp8_munger, buffer} do
{nil, _buffer} ->
{vp8_munger, buffer}
{_vp8_munger, nil} ->
{vp8_munger, buffer}
{_vp8_munger, %SenderReportPacket{}} ->
{vp8_munger, buffer}
_else ->
VP8Munger.munge(vp8_munger, buffer)
end
forwarder = %{forwarder | rtp_munger: rtp_munger, vp8_munger: vp8_munger}
{forwarder, buffer}
end
end