Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide VP8 and Opus Payloader/Depayloader modules #154

Merged
merged 2 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 14 additions & 30 deletions lib/ex_webrtc/rtp/depayloader.ex
Original file line number Diff line number Diff line change
@@ -1,57 +1,41 @@
defmodule ExWebRTC.RTP.Depayloader do
@moduledoc """
Dispatcher module and behaviour for ExWebRTC Depayloaders.
"""

alias ExWebRTC.RTPCodecParameters

@type depayloader :: struct()
RTP depayloader.

@doc """
Creates a new depayloader struct.
It unpacks RTP pakcets into audio/video frames.
"""
@callback new(options :: any()) :: depayloader()

@doc """
Processes binary data from a single RTP packet, and outputs a frame if assembled.
alias ExWebRTC.RTPCodecParameters

Returns the frame (or `nil` if a frame could not be depayloaded yet)
together with the updated depayloader struct.
"""
@callback depayload(depayloader(), packet :: ExRTP.Packet.t()) ::
{binary() | nil, depayloader()}
@opaque depayloader :: struct()

@doc """
Creates a new depayloader struct that matches the passed codec parameters.

Refer to the modules implementing the behaviour for available options.
Creates a new depayloader that matches the passed codec parameters.
"""
@spec new(RTPCodecParameters.t(), any()) ::
@spec new(RTPCodecParameters.t()) ::
{:ok, depayloader()} | {:error, :no_depayloader_for_codec}
def new(codec_params, options \\ nil) do
with {:ok, module} <- match_depayloader_module(codec_params.mime_type) do
depayloader = if is_nil(options), do: module.new(), else: module.new(options)

def new(codec_params) do
with {:ok, module} <- to_depayloader_module(codec_params.mime_type) do
depayloader = module.new()
{:ok, depayloader}
end
end

@doc """
Processes binary data from a single RTP packet using the depayloader's module,
and outputs a frame if assembled.
Processes binary data from a single RTP packet, and outputs a frame if assembled.

Returns the frame (or `nil` if a frame could not be depayloaded yet)
together with the updated depayloader struct.
together with the updated depayloader.
"""
@spec depayload(depayloader(), ExRTP.Packet.t()) :: {binary() | nil, depayloader()}
def depayload(%module{} = depayloader, packet) do
module.depayload(depayloader, packet)
end

defp match_depayloader_module(mime_type) do
defp to_depayloader_module(mime_type) do
case String.downcase(mime_type) do
"video/vp8" -> {:ok, ExWebRTC.RTP.VP8.Depayloader}
"audio/opus" -> {:ok, ExWebRTC.RTP.Opus.Depayloader}
"video/vp8" -> {:ok, ExWebRTC.RTP.Depayloader.VP8}
"audio/opus" -> {:ok, ExWebRTC.RTP.Depayloader.Opus}
_other -> {:error, :no_depayloader_for_codec}
end
end
Expand Down
19 changes: 19 additions & 0 deletions lib/ex_webrtc/rtp/depayloader_behaviour.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule ExWebRTC.RTP.Depayloader.Behaviour do
@moduledoc false

@type depayloader :: struct()

@doc """
Creates a new depayloader struct.
"""
@callback new() :: depayloader()

@doc """
Processes binary data from a single RTP packet, and outputs a frame if assembled.

Returns the frame (or `nil` if a frame could not be depayloaded yet)
together with the updated depayloader struct.
"""
@callback depayload(depayloader(), packet :: ExRTP.Packet.t()) ::
{binary() | nil, depayloader()}
end
29 changes: 9 additions & 20 deletions lib/ex_webrtc/rtp/opus/depayloader.ex
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
defmodule ExWebRTC.RTP.Opus.Depayloader do
@moduledoc """
Decapsualtes Opus audio out of RTP packet.

Based on [RFC 7587: RTP Payload Format for the Opus Speech and Audio Codec](https://datatracker.ietf.org/doc/html/rfc7587).
"""
defmodule ExWebRTC.RTP.Depayloader.Opus do
@moduledoc false
# Decapsualtes Opus audio out of RTP packet.
#
# Based on [RFC 7587: RTP Payload Format for the Opus Speech and Audio Codec](https://datatracker.ietf.org/doc/html/rfc7587).

alias ExRTP.Packet

@behaviour ExWebRTC.RTP.Depayloader
@behaviour ExWebRTC.RTP.Depayloader.Behaviour

@opaque t :: %__MODULE__{}
@type t :: %__MODULE__{}

defstruct []

@doc """
Creates a new Opus depayloader struct.

Does not take any options/parameters.
"""
@impl true
@spec new(any()) :: t()
def new(_unused \\ nil) do
@spec new() :: t()
def new() do
%__MODULE__{}
end

@doc """
Takes Opus packet out of an RTP packet.

Always returns a binary as the first element.
"""
@impl true
@spec depayload(t(), Packet.t()) :: {binary(), t()}
def depayload(%__MODULE__{} = depayloader, %Packet{payload: payload}),
Expand Down
29 changes: 8 additions & 21 deletions lib/ex_webrtc/rtp/opus/payloader.ex
Original file line number Diff line number Diff line change
@@ -1,33 +1,20 @@
defmodule ExWebRTC.RTP.Opus.Payloader do
@moduledoc """
Encapsulates Opus audio packet into an RTP packet.
defmodule ExWebRTC.RTP.Payloader.Opus do
@moduledoc false
# Encapsulates Opus audio packet into an RTP packet.
#
# Based on [RFC 7587: RTP Payload Format for the Opus Speech and Audio Codec](https://datatracker.ietf.org/doc/html/rfc7587).

Based on [RFC 7587: RTP Payload Format for the Opus Speech and Audio Codec](https://datatracker.ietf.org/doc/html/rfc7587).
"""
@behaviour ExWebRTC.RTP.Payloader.Behaviour

@behaviour ExWebRTC.RTP.Payloader

@opaque t :: %__MODULE__{}
@type t :: %__MODULE__{}

defstruct []

@doc """
Creates a new Opus payloader struct.

Does not take any options/parameters.
"""
@impl true
@spec new(any()) :: t()
def new(_unused \\ nil) do
def new(_max_payload_size) do
%__MODULE__{}
end

@doc """
Packs Opus packet into an RTP packet.

Fields from RTP header like ssrc, timestamp etc. are set to 0.
Always returns a single RTP packet.
"""
@impl true
@spec payload(t(), binary()) :: {[ExRTP.Packet.t()], t()}
def payload(%__MODULE__{} = payloader, packet) when packet != <<>> do
Expand Down
42 changes: 16 additions & 26 deletions lib/ex_webrtc/rtp/payloader.ex
Original file line number Diff line number Diff line change
@@ -1,53 +1,43 @@
defmodule ExWebRTC.RTP.Payloader do
@moduledoc """
Dispatcher module and behaviour for ExWebRTC Payloaders.
"""

alias ExWebRTC.RTPCodecParameters
RTP payloader.

@type payloader :: struct()

@doc """
Creates a new payloader struct.
It packs audio/video frames into one or more RTP packets.
"""
@callback new(options :: any()) :: payloader()

@doc """
Packs a frame into one or more RTP packets.
alias ExWebRTC.RTPCodecParameters

Returns the packets together with the updated payloader struct.
"""
@callback payload(payloader(), frame :: binary()) :: {[ExRTP.Packet.t()], payloader()}
@opaque payloader :: struct()

@doc """
Creates a new payloader struct that matches the passed codec parameters.
Creates a new payloader that matches the passed codec parameters.

Refer to the modules implementing the behaviour for available options.
* max_payload_size - determines the maximum size of a single RTP packet outputted by the payloader.
It must be greater than `100`, and is set to `1000` by default.
"""
@spec new(RTPCodecParameters.t(), any()) ::
@spec new(RTPCodecParameters.t(), integer()) ::
{:ok, payloader()} | {:error, :no_payloader_for_codec}
def new(codec_params, options \\ nil) do
with {:ok, module} <- match_payloader_module(codec_params.mime_type) do
payloader = if is_nil(options), do: module.new(), else: module.new(options)

def new(codec_params, max_payload_size \\ 1000) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather see the max_payload_size as an option in a keyword list. It makes it easier to add/remove options later on and is more conventional.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless you expect that there will never be a new option for the payloaders..

with {:ok, module} <- to_payloader_module(codec_params.mime_type) do
payloader = module.new(max_payload_size)
{:ok, payloader}
end
end

@doc """
Packs a frame into one or more RTP packets using the payloader's module.
Packs a frame into one or more RTP packets.

Returns the packets together with the updated payloader struct.
Returns the packets together with the updated payloader.
"""
@spec payload(payloader(), binary()) :: {[ExRTP.Packet.t()], payloader()}
def payload(%module{} = payloader, frame) do
module.payload(payloader, frame)
end

defp match_payloader_module(mime_type) do
defp to_payloader_module(mime_type) do
case String.downcase(mime_type) do
"video/vp8" -> {:ok, ExWebRTC.RTP.VP8.Payloader}
"audio/opus" -> {:ok, ExWebRTC.RTP.Opus.Payloader}
"video/vp8" -> {:ok, ExWebRTC.RTP.Payloader.VP8}
"audio/opus" -> {:ok, ExWebRTC.RTP.Payloader.Opus}
_other -> {:error, :no_payloader_for_codec}
end
end
Expand Down
17 changes: 17 additions & 0 deletions lib/ex_webrtc/rtp/payloader_behaviour.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule ExWebRTC.RTP.Payloader.Behaviour do
@moduledoc false

@type payloader :: struct()

@doc """
Creates a new payloader struct.
"""
@callback new(max_payload_size :: integer()) :: payloader()

@doc """
Packs a frame into one or more RTP packets.

Returns the packets together with the updated payloader struct.
"""
@callback payload(payloader(), frame :: binary()) :: {[ExRTP.Packet.t()], payloader()}
end
40 changes: 13 additions & 27 deletions lib/ex_webrtc/rtp/vp8/depayloader.ex
Original file line number Diff line number Diff line change
@@ -1,50 +1,36 @@
defmodule ExWebRTC.RTP.VP8.Depayloader do
@moduledoc """
Reassembles VP8 frames from RTP packets.
defmodule ExWebRTC.RTP.Depayloader.VP8 do
@moduledoc false
# Reassembles VP8 frames from RTP packets.
#
# Based on [RFC 7741: RTP Payload Format for VP8 Video](https://datatracker.ietf.org/doc/html/rfc7741).

Based on [RFC 7741: RTP Payload Format for VP8 Video](https://datatracker.ietf.org/doc/html/rfc7741).
"""

@behaviour ExWebRTC.RTP.Depayloader
@behaviour ExWebRTC.RTP.Depayloader.Behaviour

require Logger

alias ExWebRTC.RTP.VP8.Payload

@opaque t() :: %__MODULE__{
current_frame: nil,
current_timestamp: nil
}
@type t() :: %__MODULE__{
current_frame: nil,
current_timestamp: nil
}

defstruct [:current_frame, :current_timestamp]

@doc """
Creates a new VP8 depayloader struct.

Does not take any options/parameters.
"""
@impl true
@spec new(any()) :: t()
def new(_unused \\ nil) do
def new() do
%__MODULE__{}
end

@doc """
Reassembles VP8 frames from subsequent RTP packets.

Returns the frame (or `nil` if a frame could not be depayloaded yet)
together with the updated depayloader struct.
"""
@impl true
@spec depayload(t(), ExRTP.Packet.t()) :: {binary() | nil, t()}
def depayload(depayloader, packet)

def depayload(depayloader, %ExRTP.Packet{payload: <<>>, padding: true}), do: {nil, depayloader}

def depayload(depayloader, packet) do
case Payload.parse(packet.payload) do
{:ok, vp8_payload} ->
do_write(depayloader, packet, vp8_payload)
do_depayload(depayloader, packet, vp8_payload)

{:error, reason} ->
Logger.warning("""
Expand All @@ -56,7 +42,7 @@ defmodule ExWebRTC.RTP.VP8.Depayloader do
end
end

defp do_write(depayloader, packet, vp8_payload) do
defp do_depayload(depayloader, packet, vp8_payload) do
depayloader =
case {depayloader.current_frame, vp8_payload} do
{nil, %Payload{s: 1, pid: 0}} ->
Expand Down
9 changes: 4 additions & 5 deletions lib/ex_webrtc/rtp/vp8/payload.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
defmodule ExWebRTC.RTP.VP8.Payload do
@moduledoc """
Defines VP8 payload structure stored in RTP packet payload.

Based on [RFC 7741: RTP Payload Format for VP8 Video](https://datatracker.ietf.org/doc/html/rfc7741).
"""
@moduledoc false
# Defines VP8 payload structure stored in RTP packet payload.
#
# Based on [RFC 7741: RTP Payload Format for VP8 Video](https://datatracker.ietf.org/doc/html/rfc7741).

@type t() :: %__MODULE__{
n: 0 | 1,
Expand Down
Loading