Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mickel8 committed Nov 4, 2023
1 parent 63cd945 commit f61be49
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 42 deletions.
7 changes: 4 additions & 3 deletions lib/ex_webrtc/peer_connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,8 @@ defmodule ExWebRTC.PeerConnection do
with :ok <- SDPUtils.ensure_mid(sdp),
:ok <- SDPUtils.ensure_bundle(sdp),
{:ok, {ice_ufrag, ice_pwd}} <- SDPUtils.get_ice_credentials(sdp),
{:ok, new_transceivers} <- update_remote_transceivers(state.transceivers, sdp) do
{:ok, new_transceivers} <-
update_remote_transceivers(state.transceivers, sdp, state.config) do
:ok = ICEAgent.set_remote_credentials(state.ice_agent, ice_ufrag, ice_pwd)
:ok = ICEAgent.gather_candidates(state.ice_agent)

Expand All @@ -437,11 +438,11 @@ defmodule ExWebRTC.PeerConnection do
end
end

defp update_remote_transceivers(transceivers, sdp) do
defp update_remote_transceivers(transceivers, sdp, config) do
Enum.reduce_while(sdp.media, {:ok, transceivers}, fn mline, {:ok, transceivers} ->
case ExSDP.Media.get_attribute(mline, :mid) do
{:mid, mid} ->
transceivers = RTPTransceiver.update_or_create(transceivers, mid, mline)
transceivers = RTPTransceiver.update_or_create(transceivers, mid, mline, config)
{:cont, {:ok, transceivers}}

_other ->
Expand Down
96 changes: 73 additions & 23 deletions lib/ex_webrtc/peer_connection/configuration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ defmodule ExWebRTC.PeerConnection.Configuration do
PeerConnection configuration
"""

@type bundle_policy() :: :balanced | :max_compat | :max_bundle
@default_codecs [:opus, :h264, :vp8]

@rtp_hdr_extensions %{
:mid => "urn:ietf:params:rtp-hdrext:sdes:mid",
:audio_level => "urn:ietf:params:rtp-hdrext:ssrc-audio-level"
}

@mandatory_rtp_hdr_exts [:mid]

@type bundle_policy() :: :max_bundle

@type ice_server() :: %{
optional(:credential) => String.t(),
Expand All @@ -14,9 +23,13 @@ defmodule ExWebRTC.PeerConnection.Configuration do
# TODO implement
@type certificate() :: :TODO

@type ice_transport_policy() :: :all | :relay
@type ice_transport_policy() :: :all

@type rtcp_mux_policy() :: :require

@type rtcp_mux_policy() :: :negotiate | :require
@type codec() :: :opus | :h264 | :vp8

@type rtp_hdr_extension() :: :audio_level

@typedoc """
Options that can be passed to `ExWebRTC.PeerConnection.start_link/1`.
Expand All @@ -28,47 +41,63 @@ defmodule ExWebRTC.PeerConnection.Configuration do
ice_servers: [ice_server()],
ice_transport_policy: ice_transport_policy(),
peer_identity: String.t(),
rtcp_mux_policy: rtcp_mux_policy()
rtcp_mux_policy: rtcp_mux_policy(),
codecs: [codec()],
rtp_hdr_extensions: [rtp_hdr_extension()]
]

@typedoc false
@type t() :: %__MODULE__{
bundle_policy: bundle_policy(),
certificates: [certificate()],
ice_candidate_pool_size: non_neg_integer(),
ice_servers: [ice_server()],
ice_transport_policy: ice_transport_policy(),
peer_identity: String.t(),
rtcp_mux_policy: rtcp_mux_policy()
}
bundle_policy: bundle_policy(),
certificates: [certificate()],
ice_candidate_pool_size: non_neg_integer(),
ice_servers: [ice_server()],
ice_transport_policy: ice_transport_policy(),
peer_identity: String.t(),
rtcp_mux_policy: rtcp_mux_policy(),
codecs: [codec()],
rtp_hdr_extensions: [rtp_hdr_extension()]
}

defstruct bundle_policy: :max_bundle,
certificates: nil,
ice_candidate_pool_size: 0,
ice_servers: [],
ice_transport_policy: :all,
peer_identity: nil,
rtcp_mux_policy: :require
rtcp_mux_policy: :require,
codecs: @default_codecs,
rtp_hdr_extensions: @mandatory_rtp_hdr_exts

@doc false
@spec from_options!(options()) :: t()
def from_options!(options) do
config = struct(__MODULE__, options)
options =
options
|> add_mandatory_rtp_hdr_extensions()
|> resolve_rtp_hdr_extensions()
# ATM, ExICE does not support relay via TURN
|> reject_turn_servers()

config = struct!(__MODULE__, options)

:ok = validate!(config)

# ATM, ExICE does not support relay via TURN
stun_servers =
config.ice_servers
|> Enum.flat_map(&List.wrap(&1.urls))
|> Enum.filter(&String.starts_with?(&1, "stun:"))
config
end

%__MODULE__{config | ice_servers: stun_servers}
def is_supported_codec(config, rtp_mapping) do
supported_codecs = Enum.map(config.codecs, fn codec -> "#{codec}" end)
rtp_mapping.encoding in supported_codecs
end

@doc false
@spec validate!(t()) :: :ok
def validate!(config) do
def is_supported_rtp_hdr_extension(config, rtp_hdr_extension) do
rtp_hdr_extension.uri in config.rtp_hdr_extensions
end

def is_supported_rtcp_feedback(_config, _rtcp_feedback), do: false

defp validate!(config) do
if config.ice_transport_policy != :all do
raise "#{inspect(config.ice_transport_policy)} ice transport policy is currently not supported"
end
Expand All @@ -95,4 +124,25 @@ defmodule ExWebRTC.PeerConnection.Configuration do

:ok
end

defp add_mandatory_rtp_hdr_extensions(options) do
Keyword.update(options, :rtp_hdr_extensions, @mandatory_rtp_hdr_exts, fn exts ->
exts ++ @mandatory_rtp_hdr_exts
end)
end

defp resolve_rtp_hdr_extensions(options) do
rtp_hdr_extensions =
Enum.map(options[:rtp_hdr_extensions], fn ext -> Map.fetch!(@rtp_hdr_extensions, ext) end)

Keyword.put(options, :rtp_hdr_extensions, rtp_hdr_extensions)
end

defp reject_turn_servers(options) do
Keyword.update(options, :ice_servers, [], fn ice_servers ->
ice_servers
|> Enum.flat_map(&List.wrap(&1.urls))
|> Enum.filter(&String.starts_with?(&1, "stun:"))
end)
end
end
43 changes: 27 additions & 16 deletions lib/ex_webrtc/rtp_transceiver.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule ExWebRTC.RTPTransceiver do
RTPTransceiver
"""

alias ExWebRTC.{RTPCodecParameters, RTPReceiver}
alias ExWebRTC.{RTPCodecParameters, RTPReceiver, PeerConnection.Configuration}

@type direction() :: :sendonly | :recvonly | :sendrecv | :inactive | :stopped
@type kind() :: :audio | :video
Expand Down Expand Up @@ -32,14 +32,14 @@ defmodule ExWebRTC.RTPTransceiver do
# if it doesn't exist, creats a new one
# returns list of updated transceivers
@doc false
def update_or_create(transceivers, mid, mline) do
def update_or_create(transceivers, mid, mline, config) do
case find_by_mid(transceivers, mid) do
{idx, %__MODULE__{} = tr} ->
List.replace_at(transceivers, idx, update(tr, mline))
List.replace_at(transceivers, idx, update(tr, mline, config))

nil ->
codecs = get_codecs(mline)
hdr_exts = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.Extmap)
codecs = get_codecs(mline, config)
hdr_exts = get_rtp_hdr_extensions(mline, config)
ssrc = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.SSRC)

tr = %__MODULE__{
Expand All @@ -55,26 +55,37 @@ defmodule ExWebRTC.RTPTransceiver do
end
end

defp update(transceiver, mline) do
codecs = get_codecs(mline)
hdr_exts = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.Extmap)
defp update(transceiver, mline, config) do
codecs = get_codecs(mline, config)
hdr_exts = get_rtp_hdr_extensions(mline, config)
ssrc = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.SSRC)
rtp_receiver = %RTPReceiver{ssrc: ssrc}
%__MODULE__{transceiver | codecs: codecs, hdr_exts: hdr_exts, rtp_receiver: rtp_receiver}
end

defp get_codecs(mline) do
defp get_codecs(mline, config) do
find_corresponding_rtcp_fbs = fn all_rtcp_fbs, rtp_mapping, config ->
all_rtcp_fbs
|> Stream.filter(&(&1.pt == rtp_mapping.payload_type))
|> Enum.filter(&Configuration.is_supported_rtcp_feedback(config, &1))
end

rtp_mappings = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.RTPMapping)
fmtps = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.FMTP)
all_rtcp_fbs = ExSDP.Media.get_attributes(mline, ExSDP.Attribute.RTCPFeedback)

for rtp_mapping <- rtp_mappings do
fmtp = Enum.find(fmtps, fn fmtp -> fmtp.pt == rtp_mapping.payload_type end)

rtcp_fbs =
Enum.filter(all_rtcp_fbs, fn rtcp_fb -> rtcp_fb.pt == rtp_mapping.payload_type end)

rtp_mappings
|> Stream.filter(fn rtp_mapping -> Configuration.is_supported_codec(config, rtp_mapping) end)
|> Enum.map(fn rtp_mapping ->
fmtp = Enum.find(fmtps, &(&1.pt == rtp_mapping.payload_type))
rtcp_fbs = find_corresponding_rtcp_fbs.(all_rtcp_fbs, rtp_mapping, config)
RTPCodecParameters.new(mline.type, rtp_mapping, fmtp, rtcp_fbs)
end
end)
end

defp get_rtp_hdr_extensions(mline, config) do
mline
|> ExSDP.Media.get_attributes(ExSDP.Attribute.Extmap)
|> Enum.filter(&Configuration.is_supported_rtp_hdr_extension(config, &1))
end
end

0 comments on commit f61be49

Please sign in to comment.