From 0e615c50c5f61066bfad0cd0d4da5165e82ff7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=9Aled=C5=BA?= Date: Tue, 17 Oct 2023 18:49:49 +0200 Subject: [PATCH] Create transceivers on set_remote_description --- lib/ex_webrtc/peer_connection.ex | 47 ++++++++++++++++++++++++++++++-- lib/ex_webrtc/rtp_transceiver.ex | 9 ++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 lib/ex_webrtc/rtp_transceiver.ex diff --git a/lib/ex_webrtc/peer_connection.ex b/lib/ex_webrtc/peer_connection.ex index 6564083e..cee8caaa 100644 --- a/lib/ex_webrtc/peer_connection.ex +++ b/lib/ex_webrtc/peer_connection.ex @@ -7,7 +7,7 @@ defmodule ExWebRTC.PeerConnection do alias __MODULE__.Configuration alias ExICE.ICEAgent - alias ExWebRTC.{IceCandidate, SessionDescription} + alias ExWebRTC.{IceCandidate, RTPTransceiver, SessionDescription} import ExWebRTC.Utils @@ -28,7 +28,7 @@ defmodule ExWebRTC.PeerConnection do :dtls_client, :dtls_buffered_packets, dtls_finished: false, - transceivers: [], + transceivers: %{}, signaling_state: :stable ] @@ -299,7 +299,48 @@ defmodule ExWebRTC.PeerConnection do :ok = ICEAgent.set_remote_credentials(state.ice_agent, ufrag, pwd) :ok = ICEAgent.gather_candidates(state.ice_agent) - {:ok, %{state | current_remote_desc: sdp}} + transceivers = + sdp.media + |> Enum.reduce(%{}, fn media -> + {:mid, mid} = ExSDP.Media.get_attribute(media, :mid) + # if there is no direction, the default is sendrecv + # see RFC 3264, sec. 6.1 + direction = get_media_direction(media) || :sendrecv + + if mid == nil or direction == :inactive do + # FIXME instead of raising return an error; + # FIXME what about inactive mlines? + # Should we create transceivers for them too?; + raise "Invalid remote description: missing or invalid mid or direction" + end + + tr = + Map.get(state.transceivers, mid) || + find_or_create_transceiver(mid, direction, state.transceivers) + + {tr.mid, tr} + end) + |> Map.merge(state.transceivers) + + {:ok, %{state | current_remote_desc: sdp, transceivers: transceivers}} + end + + defp find_or_create_transceiver(mid, direction, transceivers) + when direction in [:sendrecv, :recvonly] do + Enum.find(transceivers, %RTPTransceiver{mid: mid, direction: :recvonly}, fn + {nil, tr} when tr.direction == direction -> tr + _other -> nil + end) + end + + defp find_or_create_transceiver(mid, :sendonly, _transceivers) do + %RTPTransceiver{mid: mid, direction: :recvonly} + end + + defp get_media_direction(media) do + Enum.find(media.attributes, fn attr -> + attr in [:sendrecv, :sendonly, :recvonly, :inactive] + end) end # Signaling state machine, RFC 8829 3.2 diff --git a/lib/ex_webrtc/rtp_transceiver.ex b/lib/ex_webrtc/rtp_transceiver.ex new file mode 100644 index 00000000..777e47f2 --- /dev/null +++ b/lib/ex_webrtc/rtp_transceiver.ex @@ -0,0 +1,9 @@ +defmodule ExWebRTC.RTPTransceiver do + @type t() :: %__MODULE__{ + mid: String.t(), + direction: :sendonly | :recvonly | :sendrecv | :inactive | :stopped + } + + @enforce_keys [:mid, :direction] + defstruct @enforce_keys +end