-
Notifications
You must be signed in to change notification settings - Fork 14
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
Add/refactor set_local_description
and create_answer
#7
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,8 +12,8 @@ defmodule ExWebRTC.PeerConnection do | |
IceCandidate, | ||
MediaStreamTrack, | ||
RTPTransceiver, | ||
SessionDescription, | ||
SDPUtils, | ||
SessionDescription, | ||
Utils | ||
} | ||
|
||
|
@@ -192,26 +192,34 @@ defmodule ExWebRTC.PeerConnection do | |
@impl true | ||
def handle_call({:create_answer, _options}, _from, state) | ||
when state.signaling_state in [:have_remote_offer, :have_local_pranswer] do | ||
{:offer, remote_offer} = state.pending_remote_desc | ||
|
||
{:ok, ice_ufrag, ice_pwd} = ICEAgent.get_local_credentials(state.ice_agent) | ||
{:ok, dtls_fingerprint} = ExDTLS.get_cert_fingerprint(state.dtls_client) | ||
|
||
answer = %ExSDP{ExSDP.new() | timing: %ExSDP.Timing{start_time: 0, stop_time: 0}} | ||
|
||
answer = | ||
case ExSDP.get_attribute(remote_offer, :ice_options) do | ||
{:ice_options, "trickle"} = attr -> ExSDP.add_attribute(answer, attr) | ||
_other -> answer | ||
end | ||
|
||
config = | ||
[ | ||
ice_ufrag: ice_ufrag, | ||
ice_pwd: ice_pwd, | ||
ice_options: "trickle", | ||
fingerprint: {:sha256, Utils.hex_dump(dtls_fingerprint)}, | ||
# TODO offer will always contain actpass | ||
# and answer should contain active | ||
# see RFC 8829 sec. 5.3.1 | ||
setup: :passive | ||
setup: :active | ||
] | ||
|
||
# TODO: rejected media sections | ||
mlines = | ||
Enum.map(state.transceivers, fn transceiver -> | ||
RTPTransceiver.to_mline(transceiver, config) | ||
Enum.map(remote_offer.media, fn mline -> | ||
{:mid, mid} = ExSDP.Media.get_attribute(mline, :mid) | ||
{_ix, transceiver} = RTPTransceiver.find_by_mid(state.transceivers, mid) | ||
SDPUtils.get_answer_mline(mline, transceiver, config) | ||
end) | ||
|
||
mids = | ||
|
@@ -381,7 +389,7 @@ defmodule ExWebRTC.PeerConnection do | |
%{dtls_buffered_packets: packets} = state | ||
) do | ||
# we got DTLS packets from the other side but | ||
# we haven't established ICE connection yet so | ||
# we haven't established ICE connection yet so | ||
# packets to retransmit have to be the same as dtls_buffered_packets | ||
{:noreply, state} | ||
end | ||
|
@@ -392,17 +400,33 @@ defmodule ExWebRTC.PeerConnection do | |
{:noreply, state} | ||
end | ||
|
||
defp apply_local_description(_type, _sdp, state) do | ||
# TODO: implement | ||
{:ok, state} | ||
defp apply_local_description(type, sdp, state) do | ||
new_transceivers = update_local_transceivers(type, state.transceivers, sdp) | ||
state = set_description(:local, type, sdp, state) | ||
|
||
{:ok, %{state | transceivers: new_transceivers}} | ||
end | ||
|
||
defp update_local_transceivers(:offer, transceivers, sdp) do | ||
sdp.media | ||
|> Enum.zip(transceivers) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am really not sure about zipping those two lists. We can discuss this offline but consider the following scenario:
Does it make sense? That's why I didn't decide to zip those two lists in We can also merge this as is and go back to the problem once it appears i.e. when we support track removal or stopping transceivers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applying the local offer is the moment when mids are assigned to the transceivers, so if we want to prevent the issues that you have mentioned (so basically order of transceivers != order of mlines) we would need to map mline <-> transceiver in some other way (keep the mline index in transceiver state?). For now I would probably leave it as it is, as that a bigger issue. Also there's question: what if I create an offer, remove a transceiver and then apply the offer? Should it fail? Will need to take care of such cases in the near future probably. |
||
|> Enum.map(fn {mline, transceiver} -> | ||
{:mid, mid} = ExSDP.Media.get_attribute(mline, :mid) | ||
# TODO: check if mid from mline == mid from transceiver | ||
%{transceiver | mid: mid} | ||
end) | ||
end | ||
|
||
defp apply_remote_description(_type, sdp, state) do | ||
defp update_local_transceivers(:answer, transceivers, _sdp) do | ||
transceivers | ||
end | ||
|
||
defp apply_remote_description(type, sdp, state) do | ||
# TODO apply steps listed in RFC 8829 5.10 | ||
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_transceivers(state.transceivers, sdp) do | ||
{:ok, new_transceivers} <- update_remote_transceivers(state.transceivers, sdp) do | ||
:ok = ICEAgent.set_remote_credentials(state.ice_agent, ice_ufrag, ice_pwd) | ||
:ok = ICEAgent.gather_candidates(state.ice_agent) | ||
|
||
|
@@ -419,13 +443,15 @@ defmodule ExWebRTC.PeerConnection do | |
notify(state.owner, {:track, track}) | ||
end | ||
|
||
{:ok, %{state | current_remote_desc: sdp, transceivers: new_transceivers}} | ||
state = set_description(:remote, type, sdp, state) | ||
|
||
{:ok, %{state | transceivers: new_transceivers}} | ||
else | ||
error -> error | ||
end | ||
end | ||
|
||
defp update_transceivers(transceivers, sdp) do | ||
defp update_remote_transceivers(transceivers, sdp) do | ||
Enum.reduce_while(sdp.media, {:ok, transceivers}, fn mline, {:ok, transceivers} -> | ||
case ExSDP.Media.get_attribute(mline, :mid) do | ||
{:mid, mid} -> | ||
|
@@ -504,5 +530,40 @@ defmodule ExWebRTC.PeerConnection do | |
defp maybe_next_state(:have_remote_pranswer, :remote, :answer), do: {:ok, :stable} | ||
defp maybe_next_state(:have_remote_pranswer, _, _), do: {:error, :invalid_transition} | ||
|
||
defp set_description(:local, :answer, sdp, state) do | ||
# NOTICE: internaly, we don't create SessionDescription | ||
# as it would require serialization of sdp | ||
%{ | ||
state | ||
| current_local_desc: {:answer, sdp}, | ||
current_remote_desc: state.pending_remote_desc, | ||
pending_local_desc: nil, | ||
pending_remote_desc: nil, | ||
# W3C 4.4.1.5 (.4.7.5.2) suggests setting these to "", not nil | ||
last_offer: nil, | ||
last_answer: nil | ||
} | ||
end | ||
|
||
defp set_description(:local, other, sdp, state) when other in [:offer, :pranswer] do | ||
%{state | pending_local_desc: {other, sdp}} | ||
end | ||
|
||
defp set_description(:remote, :answer, sdp, state) do | ||
%{ | ||
state | ||
| current_remote_desc: {:answer, sdp}, | ||
current_local_desc: state.pending_local_desc, | ||
pending_remote_desc: nil, | ||
pending_local_desc: nil, | ||
last_offer: nil, | ||
last_answer: nil | ||
} | ||
end | ||
|
||
defp set_description(:remote, other, sdp, state) when other in [:offer, :pranswer] do | ||
%{state | pending_remote_desc: {other, sdp}} | ||
end | ||
|
||
defp notify(pid, msg), do: send(pid, {:ex_webrtc, self(), msg}) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI we don't support anything other than
trickle
ice so this attribute has to always be in offer/answer