Skip to content

Commit

Permalink
Dynamic dispatch for (de)payloaders
Browse files Browse the repository at this point in the history
  • Loading branch information
sgfn committed Aug 8, 2024
1 parent fa717fa commit 9b1c327
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 10 deletions.
13 changes: 8 additions & 5 deletions examples/save_to_file/lib/save_to_file/peer_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule SaveToFile.PeerHandler do
}

alias ExWebRTC.Media.{IVF, Ogg}
alias ExWebRTC.RTP.{Opus, VP8}
alias ExWebRTC.RTP.Depayloader

@behaviour WebSock

Expand Down Expand Up @@ -141,9 +141,11 @@ defmodule SaveToFile.PeerHandler do
timebase_num: 1
)

{:ok, video_depayloader} = @video_codecs |> hd() |> Depayloader.new()

state = %{
state
| video_depayloader: VP8.Depayloader.new(),
| video_depayloader: video_depayloader,
video_writer: video_writer,
video_track_id: id
}
Expand All @@ -154,10 +156,11 @@ defmodule SaveToFile.PeerHandler do
defp handle_webrtc_msg({:track, %MediaStreamTrack{kind: :audio, id: id}}, state) do
# by default uses 1 mono channel and 48k clock rate
{:ok, audio_writer} = Ogg.Writer.open(@audio_file)
{:ok, audio_depayloader} = @audio_codecs |> hd() |> Depayloader.new()

state = %{
state
| audio_depayloader: Opus.Depayloader.new(),
| audio_depayloader: audio_depayloader,
audio_writer: audio_writer,
audio_track_id: id
}
Expand All @@ -173,7 +176,7 @@ defmodule SaveToFile.PeerHandler do

defp handle_webrtc_msg({:rtp, id, nil, packet}, %{video_track_id: id} = state) do
state =
case VP8.Depayloader.depayload(state.video_depayloader, packet) do
case Depayloader.depayload(state.video_depayloader, packet) do
{nil, video_depayloader} ->
%{state | video_depayloader: video_depayloader}

Expand All @@ -193,7 +196,7 @@ defmodule SaveToFile.PeerHandler do
end

defp handle_webrtc_msg({:rtp, id, nil, packet}, %{audio_track_id: id} = state) do
{opus_packet, depayloader} = Opus.Depayloader.depayload(state.audio_depayloader, packet)
{opus_packet, depayloader} = Depayloader.depayload(state.audio_depayloader, packet)
{:ok, audio_writer} = Ogg.Writer.write_packet(state.audio_writer, opus_packet)

{:ok, %{state | audio_depayloader: depayloader, audio_writer: audio_writer}}
Expand Down
10 changes: 5 additions & 5 deletions examples/send_from_file/lib/send_from_file/peer_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defmodule SendFromFile.PeerHandler do
}

alias ExWebRTC.Media.{IVF, Ogg}
alias ExWebRTC.RTP.{Opus, VP8}
alias ExWebRTC.RTP.Payloader

@behaviour WebSock

Expand Down Expand Up @@ -60,10 +60,10 @@ defmodule SendFromFile.PeerHandler do
{:ok, _sender} = PeerConnection.add_track(pc, audio_track)

{:ok, _header, video_reader} = IVF.Reader.open(@video_file)
video_payloader = VP8.Payloader.new(800)
{:ok, video_payloader} = @video_codecs |> hd() |> Payloader.new(800)

{:ok, audio_reader} = Ogg.Reader.open(@audio_file)
audio_payloader = Opus.Payloader.new()
{:ok, audio_payloader} = @audio_codecs |> hd() |> Payloader.new()

state = %{
peer_connection: pc,
Expand Down Expand Up @@ -114,7 +114,7 @@ defmodule SendFromFile.PeerHandler do

case IVF.Reader.next_frame(state.video_reader) do
{:ok, frame} ->
{rtp_packets, payloader} = VP8.Payloader.payload(state.video_payloader, frame.data)
{rtp_packets, payloader} = Payloader.payload(state.video_payloader, frame.data)

# 3_000 = 90_000 (VP8 clock rate) / 30 FPS
next_sequence_number =
Expand Down Expand Up @@ -160,7 +160,7 @@ defmodule SendFromFile.PeerHandler do
# and time spent on reading and parsing the file
Process.send_after(self(), :send_audio, duration)

{[rtp_packet], payloader} = Opus.Payloader.payload(state.audio_payloader, packet)
{[rtp_packet], payloader} = Payloader.payload(state.audio_payloader, packet)

rtp_packet = %{
rtp_packet
Expand Down
31 changes: 31 additions & 0 deletions lib/ex_webrtc/rtp/depayloader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule ExWebRTC.RTP.Depayloader do
Behaviour for ExWebRTC Depayloaders.
"""

alias ExWebRTC.RTPCodecParameters

@type depayloader :: struct()

@doc """
Expand All @@ -20,4 +22,33 @@ defmodule ExWebRTC.RTP.Depayloader do
"""
@callback depayload(depayloader(), packet :: ExRTP.Packet.t()) ::
{binary() | nil, depayloader()}

@doc """
TODO WRITEME
"""
@spec new(RTPCodecParameters.t(), any()) ::
{: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)

{:ok, depayloader}
end
end

@doc """
TODO WRITEME
"""
@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
case String.downcase(mime_type) do
"video/vp8" -> {:ok, ExWebRTC.RTP.VP8.Depayloader}
"audio/opus" -> {:ok, ExWebRTC.RTP.Opus.Depayloader}
_other -> {:error, :no_depayloader_for_codec}
end
end
end
31 changes: 31 additions & 0 deletions lib/ex_webrtc/rtp/payloader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule ExWebRTC.RTP.Payloader do
Behaviour for ExWebRTC Payloaders.
"""

alias ExWebRTC.RTPCodecParameters

@type payloader :: struct()

@doc """
Expand All @@ -18,4 +20,33 @@ defmodule ExWebRTC.RTP.Payloader do
Returns the packets together with the updated payloader struct.
"""
@callback payload(payloader(), frame :: binary()) :: {[ExRTP.Packet.t()], payloader()}

@doc """
TODO WRITEME
"""
@spec new(RTPCodecParameters.t(), any()) ::
{: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)

{:ok, payloader}
end
end

@doc """
TODO WRITEME
"""
@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
case String.downcase(mime_type) do
"video/vp8" -> {:ok, ExWebRTC.RTP.VP8.Payloader}
"audio/opus" -> {:ok, ExWebRTC.RTP.Opus.Payloader}
_other -> {:error, :no_payloader_for_codec}
end
end
end
Empty file.
Empty file.

0 comments on commit 9b1c327

Please sign in to comment.