Skip to content

Commit 15875fb

Browse files
committed
Refactor the public modules, use internal maps for transceivers, senders and receivers
1 parent f21de60 commit 15875fb

File tree

8 files changed

+291
-186
lines changed

8 files changed

+291
-186
lines changed

lib/ex_webrtc/peer_connection.ex

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,26 @@ defmodule ExWebRTC.PeerConnection do
465465
{:reply, :ok, state}
466466
end
467467

468+
@impl true
469+
def handle_call(:get_connection_state, _from, state) do
470+
{:reply, state.conn_state, state}
471+
end
472+
473+
@impl true
474+
def handle_call(:get_ice_connection_state, _from, state) do
475+
{:reply, state.ice_state, state}
476+
end
477+
478+
@impl true
479+
def handle_call(:get_ice_gathering_state, _from, state) do
480+
{:reply, state.ice_gathering_state, state}
481+
end
482+
483+
@impl true
484+
def handle_call(:get_signaling_state, _from, state) do
485+
{:reply, state.signaling_state, state}
486+
end
487+
468488
@impl true
469489
def handle_call({:create_offer, _options}, _from, %{signaling_state: ss} = state)
470490
when ss not in [:stable, :have_local_offer] do
@@ -658,7 +678,8 @@ defmodule ExWebRTC.PeerConnection do
658678

659679
@impl true
660680
def handle_call(:get_transceivers, _from, state) do
661-
{:reply, state.transceivers, state}
681+
transceivers = Enum.map(state.transceivers, &RTPTransceiver.to_struct/1)
682+
{:reply, transceivers, state}
662683
end
663684

664685
@impl true
@@ -667,25 +688,25 @@ defmodule ExWebRTC.PeerConnection do
667688
{ssrc, rtx_ssrc} = generate_ssrcs(state)
668689
options = [{:ssrc, ssrc}, {:rtx_ssrc, rtx_ssrc} | options]
669690

670-
transceiver = RTPTransceiver.new(kind, nil, state.config, options)
671-
state = %{state | transceivers: state.transceivers ++ [transceiver]}
691+
tr = RTPTransceiver.new(kind, nil, state.config, options)
692+
state = %{state | transceivers: state.transceivers ++ [tr]}
672693

673694
state = update_negotiation_needed(state)
674695

675-
{:reply, {:ok, transceiver}, state}
696+
{:reply, {:ok, RTPTransceiver.to_struct(tr)}, state}
676697
end
677698

678699
@impl true
679700
def handle_call({:add_transceiver, %MediaStreamTrack{} = track, options}, _from, state) do
680701
{ssrc, rtx_ssrc} = generate_ssrcs(state)
681702
options = [{:ssrc, ssrc}, {:rtx_ssrc, rtx_ssrc} | options]
682703

683-
transceiver = RTPTransceiver.new(track.kind, track, state.config, options)
684-
state = %{state | transceivers: state.transceivers ++ [transceiver]}
704+
tr = RTPTransceiver.new(track.kind, track, state.config, options)
705+
state = %{state | transceivers: state.transceivers ++ [tr]}
685706

686707
state = update_negotiation_needed(state)
687708

688-
{:reply, {:ok, transceiver}, state}
709+
{:reply, {:ok, RTPTransceiver.to_struct(tr)}, state}
689710
end
690711

691712
@impl true
@@ -698,7 +719,7 @@ defmodule ExWebRTC.PeerConnection do
698719

699720
idx ->
700721
tr = Enum.at(state.transceivers, idx)
701-
tr = %RTPTransceiver{tr | direction: direction}
722+
tr = %{tr | direction: direction}
702723
transceivers = List.replace_at(state.transceivers, idx, tr)
703724
state = %{state | transceivers: transceivers}
704725
state = update_negotiation_needed(state)
@@ -735,9 +756,9 @@ defmodule ExWebRTC.PeerConnection do
735756
# we ignore the condition that sender has never been used to send
736757
free_transceiver_idx =
737758
Enum.find_index(state.transceivers, fn
738-
%RTPTransceiver{
759+
%{
739760
kind: ^kind,
740-
sender: %RTPSender{track: nil},
761+
sender: %{track: nil},
741762
current_direction: direction
742763
}
743764
when direction not in [:sendrecv, :sendonly] ->
@@ -972,7 +993,12 @@ defmodule ExWebRTC.PeerConnection do
972993
end)
973994

974995
case transceiver do
975-
%RTPTransceiver{} ->
996+
nil ->
997+
Logger.warning(
998+
"Attempted to send packet to track with unrecognized id: #{inspect(track_id)}"
999+
)
1000+
1001+
_other ->
9761002
{packet, state} =
9771003
case Map.fetch(state.config.video_rtp_hdr_exts, @twcc_uri) do
9781004
{:ok, %{id: id}} ->
@@ -1000,11 +1026,6 @@ defmodule ExWebRTC.PeerConnection do
10001026

10011027
{:noreply, state}
10021028

1003-
nil ->
1004-
Logger.warning(
1005-
"Attempted to send packet to track with unrecognized id: #{inspect(track_id)}"
1006-
)
1007-
10081029
{:noreply, state}
10091030
end
10101031
end
@@ -1083,7 +1104,7 @@ defmodule ExWebRTC.PeerConnection do
10831104
@impl true
10841105
def handle_info({:dtls_transport, _pid, {:rtp, data}}, state) do
10851106
with {:ok, demuxer, mid, packet} <- Demuxer.demux(state.demuxer, data),
1086-
{idx, %RTPTransceiver{} = t} <- find_transceiver(state.transceivers, mid) do
1107+
{idx, t} <- find_transceiver(state.transceivers, mid) do
10871108
# we always update the ssrc's for the one's from the latest packet
10881109
# although this is not a necessity, the feedbacks are transport-wide
10891110
twcc_recorder = %TWCCRecorder{
@@ -1248,13 +1269,13 @@ defmodule ExWebRTC.PeerConnection do
12481269
Enum.map_reduce(state.transceivers, next_mid, fn
12491270
# In the initial offer, we can't have stopped transceivers, only stopping ones.
12501271
# Also, stopped transceivers are immediately removed.
1251-
%RTPTransceiver{stopping: true, mid: nil} = tr, nm ->
1272+
%{stopping: true, mid: nil} = tr, nm ->
12521273
{tr, nm}
12531274

1254-
%RTPTransceiver{stopping: false, mid: nil} = tr, nm ->
1275+
%{stopping: false, mid: nil} = tr, nm ->
12551276
tr = RTPTransceiver.assign_mid(tr, to_string(nm))
12561277
# in the initial offer, mline_idx is the same as mid
1257-
tr = %RTPTransceiver{tr | mline_idx: nm}
1278+
tr = %{tr | mline_idx: nm}
12581279
{tr, nm + 1}
12591280
end)
12601281

@@ -1326,7 +1347,7 @@ defmodule ExWebRTC.PeerConnection do
13261347
defp assign_mlines([], _, _, _, _, result), do: Enum.reverse(result)
13271348

13281349
defp assign_mlines(
1329-
[%RTPTransceiver{mid: nil, mline_idx: nil, stopped: false} = tr | trs],
1350+
[%{mid: nil, mline_idx: nil, stopped: false} = tr | trs],
13301351
last_answer,
13311352
next_mid,
13321353
next_mline_idx,
@@ -1337,12 +1358,12 @@ defmodule ExWebRTC.PeerConnection do
13371358

13381359
case SDPUtils.find_free_mline_idx(last_answer, recycled_mlines) do
13391360
nil ->
1340-
tr = %RTPTransceiver{tr | mline_idx: next_mline_idx}
1361+
tr = %{tr | mline_idx: next_mline_idx}
13411362
result = [tr | result]
13421363
assign_mlines(trs, last_answer, next_mid + 1, next_mline_idx + 1, recycled_mlines, result)
13431364

13441365
idx ->
1345-
tr = %RTPTransceiver{tr | mline_idx: idx}
1366+
tr = %{tr | mline_idx: idx}
13461367
result = [tr | result]
13471368
recycled_mlines = [idx | recycled_mlines]
13481369
assign_mlines(trs, last_answer, next_mid + 1, next_mline_idx, recycled_mlines, result)
@@ -1448,7 +1469,7 @@ defmodule ExWebRTC.PeerConnection do
14481469
# This might result in unremovable transceiver when
14491470
# we add and stop it before the first offer.
14501471
# See https://github.com/w3c/webrtc-pc/issues/2923
1451-
%RTPTransceiver{mid: nil} ->
1472+
%{mid: nil} ->
14521473
false
14531474

14541475
tr ->
@@ -1566,7 +1587,7 @@ defmodule ExWebRTC.PeerConnection do
15661587
notify(owner, {:track_muted, tr.receiver.track.id})
15671588
end
15681589

1569-
tr = %RTPTransceiver{tr | current_direction: direction, fired_direction: direction}
1590+
tr = %{tr | current_direction: direction, fired_direction: direction}
15701591

15711592
# This is not defined in the W3C but see https://github.com/w3c/webrtc-pc/issues/2927
15721593
tr =
@@ -1596,12 +1617,12 @@ defmodule ExWebRTC.PeerConnection do
15961617
# after processing remote track but this shouldn't have any impact
15971618
{idx, tr} =
15981619
case find_transceiver_from_remote(transceivers, mline) do
1599-
{idx, %RTPTransceiver{} = tr} -> {idx, RTPTransceiver.update(tr, mline, config)}
1620+
{idx, tr} -> {idx, RTPTransceiver.update(tr, mline, config)}
16001621
nil -> {nil, RTPTransceiver.from_mline(mline, idx, config)}
16011622
end
16021623

16031624
tr = process_remote_track(tr, direction, owner)
1604-
tr = if sdp_type == :answer, do: %RTPTransceiver{tr | current_direction: direction}, else: tr
1625+
tr = if sdp_type == :answer, do: %{tr | current_direction: direction}, else: tr
16051626

16061627
tr =
16071628
if SDPUtils.rejected?(mline),
@@ -1623,7 +1644,7 @@ defmodule ExWebRTC.PeerConnection do
16231644
{:mid, mid} = ExSDP.get_attribute(mline, :mid)
16241645

16251646
case find_transceiver(transceivers, mid) do
1626-
{idx, %RTPTransceiver{} = tr} -> {idx, tr}
1647+
{idx, tr} -> {idx, tr}
16271648
nil -> find_associable_transceiver(transceivers, mline)
16281649
end
16291650
end
@@ -1649,7 +1670,7 @@ defmodule ExWebRTC.PeerConnection do
16491670
:ok
16501671
end
16511672

1652-
%RTPTransceiver{transceiver | fired_direction: direction}
1673+
%{transceiver | fired_direction: direction}
16531674
end
16541675

16551676
defp reverse_direction(:recvonly), do: :sendonly
@@ -1819,7 +1840,7 @@ defmodule ExWebRTC.PeerConnection do
18191840

18201841
# in case NACK was received, but RTX was not negotiated
18211842
# as NACK and RTX are negotited independently
1822-
{%RTPTransceiver{sender: %RTPSender{rtx_pt: nil}}, _idx} ->
1843+
{%{sender: %{rtx_pt: nil}}, _idx} ->
18231844
state
18241845

18251846
{tr, idx} ->

lib/ex_webrtc/rtp_receiver.ex

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ defmodule ExWebRTC.RTPReceiver do
88
alias ExWebRTC.{MediaStreamTrack, Utils, RTPCodecParameters}
99
alias __MODULE__.{NACKGenerator, ReportRecorder}
1010

11-
@type t() :: %__MODULE__{
11+
@type id() :: integer()
12+
13+
@typedoc false
14+
@type receiver() :: %{
15+
id: id(),
1216
track: MediaStreamTrack.t(),
1317
codec: RTPCodecParameters.t() | nil,
1418
ssrc: non_neg_integer() | nil,
@@ -19,42 +23,64 @@ defmodule ExWebRTC.RTPReceiver do
1923
nack_generator: NACKGenerator.t()
2024
}
2125

22-
@enforce_keys [:track, :codec, :report_recorder]
23-
defstruct [
24-
ssrc: nil,
25-
bytes_received: 0,
26-
packets_received: 0,
27-
markers_received: 0,
28-
nack_generator: %NACKGenerator{}
29-
] ++ @enforce_keys
26+
@typedoc """
27+
Struct representing a receiver.
28+
29+
The fields mostly match these of [RTCRtpReceiver](https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpReceiver),
30+
except for:
31+
* `id` - to uniquely identify the receiver.
32+
* `codec` - codec this receiver is expected to receive.
33+
"""
34+
@type t() :: %__MODULE__{
35+
id: id(),
36+
track: MediaStreamTrack.t(),
37+
codec: RTPCodecParameters.t() | nil
38+
}
39+
40+
@enforce_keys [:id, :track, :codec]
41+
defstruct @enforce_keys
42+
43+
@doc false
44+
@spec to_struct(receiver()) :: t()
45+
def to_struct(receiver) do
46+
receiver
47+
|> Map.take([:id, :track, :codec])
48+
|> then(&struct!(__MODULE__, &1))
49+
end
3050

3151
@doc false
32-
@spec new(MediaStreamTrack.t(), RTPCodecParameters.t() | nil) :: t()
52+
@spec new(MediaStreamTrack.t(), RTPCodecParameters.t() | nil) :: receiver()
3353
def new(track, codec) do
3454
report_recorder = %ReportRecorder{
3555
clock_rate: codec && codec.clock_rate
3656
}
3757

38-
%__MODULE__{
58+
%{
59+
id: Utils.generate_id(),
3960
track: track,
4061
codec: codec,
41-
report_recorder: report_recorder
62+
ssrc: nil,
63+
bytes_received: 0,
64+
packets_received: 0,
65+
markers_received: 0,
66+
report_recorder: report_recorder,
67+
nack_generator: %NACKGenerator{}
4268
}
4369
end
4470

4571
@doc false
46-
@spec update(t(), RTPCodecParameters.t() | nil) :: t()
72+
@spec update(receiver(), RTPCodecParameters.t() | nil) :: receiver()
4773
def update(receiver, codec) do
4874
report_recorder = %ReportRecorder{
4975
receiver.report_recorder
5076
| clock_rate: codec && codec.clock_rate
5177
}
5278

53-
%__MODULE__{receiver | codec: codec, report_recorder: report_recorder}
79+
%{receiver | codec: codec, report_recorder: report_recorder}
5480
end
5581

5682
@doc false
57-
@spec receive_packet(t(), ExRTP.Packet.t(), non_neg_integer()) :: t()
83+
@spec receive_packet(receiver(), ExRTP.Packet.t(), non_neg_integer()) :: receiver()
5884
def receive_packet(receiver, packet, size) do
5985
if packet.payload_type != receiver.codec.payload_type do
6086
Logger.warning("Received packet with unexpected payload_type \
@@ -65,7 +91,7 @@ defmodule ExWebRTC.RTPReceiver do
6591
nack_generator = NACKGenerator.record_packet(receiver.nack_generator, packet)
6692

6793
# TODO assign ssrc when applying local/remote description.
68-
%__MODULE__{
94+
%{
6995
receiver
7096
| ssrc: packet.ssrc,
7197
bytes_received: receiver.bytes_received + size,
@@ -76,7 +102,8 @@ defmodule ExWebRTC.RTPReceiver do
76102
}
77103
end
78104

79-
@spec receive_rtx(t(), ExRTP.Packet.t(), non_neg_integer()) :: {:ok, ExRTP.Packet.t()} | :error
105+
@spec receive_rtx(receiver(), ExRTP.Packet.t(), non_neg_integer()) ::
106+
{:ok, ExRTP.Packet.t()} | :error
80107
def receive_rtx(receiver, rtx_packet, apt) do
81108
with <<seq_no::16, rest::binary>> <- rtx_packet.payload,
82109
ssrc when ssrc != nil <- receiver.ssrc do
@@ -94,23 +121,24 @@ defmodule ExWebRTC.RTPReceiver do
94121
end
95122
end
96123

97-
@spec receive_report(t(), ExRTCP.Packet.SenderReport.t()) :: t()
124+
@spec receive_report(receiver(), ExRTCP.Packet.SenderReport.t()) :: receiver()
98125
def receive_report(receiver, report) do
99126
report_recorder = ReportRecorder.record_report(receiver.report_recorder, report)
100127

101-
%__MODULE__{receiver | report_recorder: report_recorder}
128+
%{receiver | report_recorder: report_recorder}
102129
end
103130

104131
@doc false
105-
@spec update_sender_ssrc(t(), non_neg_integer()) :: t()
132+
@spec update_sender_ssrc(receiver(), non_neg_integer()) :: receiver()
106133
def update_sender_ssrc(receiver, ssrc) do
107134
report_recorder = %ReportRecorder{receiver.report_recorder | sender_ssrc: ssrc}
108135
nack_generator = %NACKGenerator{receiver.nack_generator | sender_ssrc: ssrc}
109-
%__MODULE__{receiver | report_recorder: report_recorder, nack_generator: nack_generator}
136+
137+
%{receiver | report_recorder: report_recorder, nack_generator: nack_generator}
110138
end
111139

112140
@doc false
113-
@spec get_stats(t(), non_neg_integer()) :: map()
141+
@spec get_stats(receiver(), non_neg_integer()) :: map()
114142
def get_stats(receiver, timestamp) do
115143
%{
116144
id: receiver.track.id,

lib/ex_webrtc/rtp_receiver/nack_generator.ex

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule ExWebRTC.RTPReceiver.NACKGenerator do
2-
@moduledoc nil
2+
@moduledoc false
33
# for now, it mimics the Pion implementation, but there's some issues and remarks
44
# 1) NACKs are send at constant interval
55
# 2) no timing rules (like rtt) are taken into account
@@ -25,9 +25,6 @@ defmodule ExWebRTC.RTPReceiver.NACKGenerator do
2525
last_sn: nil,
2626
max_nack: @max_nack
2727

28-
@doc """
29-
Records incoming RTP Packet.
30-
"""
3128
@spec record_packet(t(), ExRTP.Packet.t()) :: t()
3229
def record_packet(generator, packet)
3330

0 commit comments

Comments
 (0)