Skip to content

Commit

Permalink
Handle negotiation_needed, add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
LVala committed Aug 23, 2024
1 parent 4d17dbc commit eafd2bd
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
15 changes: 14 additions & 1 deletion lib/ex_webrtc/data_channel.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule ExWebRTC.DataChannel do
@moduledoc """
TODO
Implementation of the [RTCDataChannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel).
"""

@type order() :: :ordered | :unordered
Expand All @@ -11,13 +11,26 @@ defmodule ExWebRTC.DataChannel do

@type ready_state() :: :connecting | :open | :closing | :closed

@typedoc """
Options used when creating a new DataChannel.
As of now, Elixir WebRTC does not support `negotiated: true` option, all DataChannels need to be
negotiated in-band.
"""
@type options() :: [
ordered: order(),
max_packet_life_time: non_neg_integer(),
max_retransmits: non_neg_integer(),
protocol: String.t()
]

@typedoc """
Struct representing the DataChannel.
All of the fields have the same meaning as in [RTCDataChannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel)
except for `ref` which is a local identifier used when refering to this DataChannel in
received messages or when calling `ExWebRTC.PeerConnection.send_data/3` function.
"""
@type t() :: %__MODULE__{
ref: ref(),
id: non_neg_integer() | nil,
Expand Down
32 changes: 25 additions & 7 deletions lib/ex_webrtc/peer_connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ defmodule ExWebRTC.PeerConnection do
Most of the messages match the [RTCPeerConnection events](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection#events),
except for:
* `:track_muted`, `:track_ended` - these match the [MediaStreamTrack events](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack#events).
* `:data` - data received from DataChannel identified by its `ref`.
* `:rtp` and `:rtcp` - these contain packets received by the PeerConnection. The third element of `:rtp` tuple is a simulcast RID and is set to `nil` if simulcast
is not used.
* each of the packets in `:rtcp` message is in the form of `{track_id, packet}` tuple, where `track_id` is the id of the corrsponding track.
Expand All @@ -79,9 +80,12 @@ defmodule ExWebRTC.PeerConnection do
| {:ice_gathering_state_change, ice_gathering_state()}
| :negotiation_needed
| {:signaling_state_change, signaling_state()}
| {:data_channel_state_change, DataChannel.ref(), DataChannel.ready_state()}
| {:data_channel, DataChannel.t()}
| {:track, MediaStreamTrack.t()}
| {:track_muted, MediaStreamTrack.id()}
| {:track_ended, MediaStreamTrack.id()}
| {:data, DataChannel.ref(), binary()}
| {:rtp, MediaStreamTrack.id(), String.t() | nil, ExRTP.Packet.t()}}
| {:rtcp, [{MediaStreamTrack.id() | nil, ExRTCP.Packet.packet()}]}

Expand Down Expand Up @@ -166,7 +170,9 @@ defmodule ExWebRTC.PeerConnection do
end

@doc """
TODO
Sends data over DataChannel, using channel identified by `ref`.
Requires the channel to be in `:open` state.
"""
@spec send_data(peer_connection(), DataChannel.ref(), binary()) :: :ok
def send_data(peer_connection, channel_ref, data) do
Expand Down Expand Up @@ -419,7 +425,9 @@ defmodule ExWebRTC.PeerConnection do
end

@doc """
TODO
Creates a new DataChannel.
For more information, refer to the [RTCPeerConnection: createDataChannel() method](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDataChannel).
"""
@spec create_data_channel(peer_connection(), String.t(), DataChannel.options()) ::
{:ok, DataChannel.t()} | {:error, atom()}
Expand Down Expand Up @@ -895,10 +903,10 @@ defmodule ExWebRTC.PeerConnection do
max_rtx
)

# TODO: negotiation needed
state = update_negotiation_needed(%{state | sctp_transport: sctp_transport})

handle_sctp_events(events, state)
{:reply, {:ok, channel}, %{state | sctp_transport: sctp_transport}}
{:reply, {:ok, channel}, state}
else
_other -> {:reply, :error, state}
end
Expand Down Expand Up @@ -1892,7 +1900,17 @@ defmodule ExWebRTC.PeerConnection do
do: state

defp update_negotiation_needed(state) do
negotiation_needed = negotiation_needed?(state.transceivers, state)
has_channels =
case state.current_local_desc do
nil -> false
{_, desc} -> Enum.any?(desc.media, &SDPUtils.data_channel?(&1))
end

first_channel = map_size(state.sctp_transport.channels) == 1

negotiation_needed =
negotiation_needed?(state.transceivers, state) ||
(first_channel and not has_channels)

cond do
negotiation_needed == true and state.negotiation_needed == true ->
Expand Down Expand Up @@ -2029,8 +2047,8 @@ defmodule ExWebRTC.PeerConnection do
{:state_change, ref, new_state} ->
notify(state.owner, {:data_channel_state_change, ref, new_state})

{:data, id, data} ->
notify(state.owner, {:data, id, data})
{:data, ref, data} ->
notify(state.owner, {:data, ref, data})
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions test/ex_webrtc/data_channel_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ defmodule ExWebRTC.DataChannelTest do

label1 = "my label 1"
{:ok, %DataChannel{ref: ref1}} = PeerConnection.create_data_channel(pc1, label1)
assert_receive {:ex_webrtc, ^pc1, :negotiation_needed}

:ok = negotiate(pc1, pc2)

Expand All @@ -28,13 +29,17 @@ defmodule ExWebRTC.DataChannelTest do
{:ok, %DataChannel{ref: ref2}} =
PeerConnection.create_data_channel(pc1, label2, protocol: protocol, ordered: false)

refute_receive {:ex_webrtc, ^pc1, :negotiation_needed}

assert_receive {:ex_webrtc, ^pc2, {:data_channel, chan2}}
assert %DataChannel{id: 3, label: ^label2, protocol: ^protocol, ordered: false} = chan2
assert_receive {:ex_webrtc, ^pc1, {:data_channel_state_change, ^ref2, :open}}

label3 = "my label 3"
{:ok, %DataChannel{ref: ref3}} = PeerConnection.create_data_channel(pc2, label3)

refute_receive {:ex_webrtc, ^pc2, :negotiation_needed}

assert_receive {:ex_webrtc, ^pc1, {:data_channel, chan3}}
assert %DataChannel{id: 4, label: ^label3} = chan3
assert_receive {:ex_webrtc, ^pc2, {:data_channel_state_change, ^ref3, :open}}
Expand Down

0 comments on commit eafd2bd

Please sign in to comment.