Skip to content

Commit c2d6e5d

Browse files
authored
Improve the structs in the API, add docs (#104)
1 parent b158659 commit c2d6e5d

File tree

8 files changed

+592
-263
lines changed

8 files changed

+592
-263
lines changed

lib/ex_webrtc/peer_connection.ex

Lines changed: 336 additions & 125 deletions
Large diffs are not rendered by default.

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

lib/ex_webrtc/rtp_receiver/report_recorder.ex

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule ExWebRTC.RTPReceiver.ReportRecorder do
2-
@moduledoc nil
2+
@moduledoc false
33
# based on https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.1
44

55
import Bitwise
@@ -40,7 +40,8 @@ defmodule ExWebRTC.RTPReceiver.ReportRecorder do
4040
total_lost: 0
4141

4242
@doc """
43-
Records incoming RTP Packet.
43+
Records incoming RTP packet.
44+
4445
`time` parameter accepts output of `System.monotonic_time()` as a value.
4546
"""
4647
@spec record_packet(t(), ExRTP.Packet.t(), integer()) :: t()
@@ -68,6 +69,7 @@ defmodule ExWebRTC.RTPReceiver.ReportRecorder do
6869

6970
@doc """
7071
Records incoming RTCP Sender Report.
72+
7173
`time` parameter accepts output of `System.monotonic_time()` as a value.
7274
"""
7375
@spec record_report(t(), ExRTCP.Packet.SenderReport.t(), integer()) :: t()
@@ -79,7 +81,8 @@ defmodule ExWebRTC.RTPReceiver.ReportRecorder do
7981
end
8082

8183
@doc """
82-
Creates an RTCP Receiver Report.
84+
Generates RTCP Receiver Report.
85+
8386
`time` parameter accepts output of `System.monotonic_time()` as a value.
8487
"""
8588
@spec get_report(t(), integer()) :: {:ok, ReceiverReport.t(), t()} | {:error, term()}

lib/ex_webrtc/rtp_sender.ex

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ defmodule ExWebRTC.RTPSender do
1111

1212
@type id() :: integer()
1313

14-
@type t() :: %__MODULE__{
14+
@typedoc false
15+
@type sender() :: %{
1516
id: id(),
1617
track: MediaStreamTrack.t() | nil,
1718
codec: RTPCodecParameters.t() | nil,
@@ -28,21 +29,30 @@ defmodule ExWebRTC.RTPSender do
2829
nack_responder: NACKResponder.t()
2930
}
3031

31-
@enforce_keys [:id, :report_recorder, :nack_responder]
32-
defstruct @enforce_keys ++
33-
[
34-
:track,
35-
:codec,
36-
:mid,
37-
:pt,
38-
:rtx_pt,
39-
:ssrc,
40-
:rtx_ssrc,
41-
rtp_hdr_exts: %{},
42-
packets_sent: 0,
43-
bytes_sent: 0,
44-
markers_sent: 0
45-
]
32+
@typedoc """
33+
Struct representing a sender.
34+
35+
The fields mostly match these of [RTCRtpSender](https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender),
36+
except for:
37+
* `id` - to uniquely identify the sender.
38+
* `codec` - codec this sender is going to send.
39+
"""
40+
@type t() :: %__MODULE__{
41+
id: id(),
42+
track: MediaStreamTrack.t() | nil,
43+
codec: RTPCodecParameters.t() | nil
44+
}
45+
46+
@enforce_keys [:id, :track, :codec]
47+
defstruct @enforce_keys
48+
49+
@doc false
50+
@spec to_struct(sender()) :: t()
51+
def to_struct(sender) do
52+
sender
53+
|> Map.take([:id, :track, :codec])
54+
|> then(&struct!(__MODULE__, &1))
55+
end
4656

4757
@doc false
4858
@spec new(
@@ -53,15 +63,15 @@ defmodule ExWebRTC.RTPSender do
5363
String.t() | nil,
5464
non_neg_integer() | nil,
5565
non_neg_integer() | nil
56-
) :: t()
66+
) :: sender()
5767
def new(track, codec, rtx_codec, rtp_hdr_exts, mid \\ nil, ssrc, rtx_ssrc) do
5868
# convert to a map to be able to find extension id using extension uri
5969
rtp_hdr_exts = Map.new(rtp_hdr_exts, fn extmap -> {extmap.uri, extmap} end)
6070
# TODO: handle cases when codec == nil (no valid codecs after negotiation)
6171
pt = if codec != nil, do: codec.payload_type, else: nil
6272
rtx_pt = if rtx_codec != nil, do: rtx_codec.payload_type, else: nil
6373

64-
%__MODULE__{
74+
%{
6575
id: Utils.generate_id(),
6676
track: track,
6777
codec: codec,
@@ -71,15 +81,18 @@ defmodule ExWebRTC.RTPSender do
7181
ssrc: ssrc,
7282
rtx_ssrc: rtx_ssrc,
7383
mid: mid,
84+
packets_sent: 0,
85+
bytes_sent: 0,
86+
markers_sent: 0,
7487
report_recorder: %ReportRecorder{clock_rate: codec && codec.clock_rate},
7588
nack_responder: %NACKResponder{}
7689
}
7790
end
7891

7992
@doc false
80-
@spec update(t(), String.t(), RTPCodecParameters.t() | nil, RTPCodecParameters.t() | nil, [
93+
@spec update(sender(), String.t(), RTPCodecParameters.t() | nil, RTPCodecParameters.t() | nil, [
8194
Extmap.t()
82-
]) :: t()
95+
]) :: sender()
8396
def update(sender, mid, codec, rtx_codec, rtp_hdr_exts) do
8497
if sender.mid != nil and mid != sender.mid, do: raise(ArgumentError)
8598
# convert to a map to be able to find extension id using extension uri
@@ -93,7 +106,7 @@ defmodule ExWebRTC.RTPSender do
93106
| clock_rate: codec && codec.clock_rate
94107
}
95108

96-
%__MODULE__{
109+
%{
97110
sender
98111
| mid: mid,
99112
codec: codec,
@@ -104,11 +117,8 @@ defmodule ExWebRTC.RTPSender do
104117
}
105118
end
106119

107-
# Prepares packet for sending i.e.:
108-
# * assigns SSRC, pt, mid
109-
# * serializes to binary
110120
@doc false
111-
@spec send_packet(t(), ExRTP.Packet.t(), boolean()) :: {binary(), t()}
121+
@spec send_packet(sender(), ExRTP.Packet.t(), boolean()) :: {binary(), sender()}
112122
def send_packet(sender, packet, rtx?) do
113123
%Extmap{} = mid_extmap = Map.fetch!(sender.rtp_hdr_exts, @mid_uri)
114124

@@ -146,7 +156,8 @@ defmodule ExWebRTC.RTPSender do
146156
end
147157

148158
@doc false
149-
@spec receive_nack(t(), ExRTCP.Packet.TransportFeedback.NACK.t()) :: {[ExRTP.Packet.t()], t()}
159+
@spec receive_nack(sender(), ExRTCP.Packet.TransportFeedback.NACK.t()) ::
160+
{[ExRTP.Packet.t()], sender()}
150161
def receive_nack(sender, nack) do
151162
{packets, nack_responder} = NACKResponder.get_rtx(sender.nack_responder, nack)
152163
sender = %{sender | nack_responder: nack_responder}
@@ -155,7 +166,7 @@ defmodule ExWebRTC.RTPSender do
155166
end
156167

157168
@doc false
158-
@spec get_stats(t(), non_neg_integer()) :: map()
169+
@spec get_stats(sender(), non_neg_integer()) :: map()
159170
def get_stats(sender, timestamp) do
160171
%{
161172
timestamp: timestamp,

lib/ex_webrtc/rtp_sender/nack_responder.ex

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule ExWebRTC.RTPSender.NACKResponder do
2-
@moduledoc nil
2+
@moduledoc false
33

44
alias ExRTP.Packet
55
alias ExRTCP.Packet.TransportFeedback.NACK
@@ -14,7 +14,6 @@ defmodule ExWebRTC.RTPSender.NACKResponder do
1414
defstruct packets: %{},
1515
seq_no: Enum.random(0..0xFFFF)
1616

17-
@doc false
1817
@spec record_packet(t(), Packet.t()) :: t()
1918
def record_packet(responder, packet) do
2019
key = rem(packet.sequence_number, @max_packets)
@@ -23,7 +22,6 @@ defmodule ExWebRTC.RTPSender.NACKResponder do
2322
%__MODULE__{responder | packets: packets}
2423
end
2524

26-
@doc false
2725
@spec get_rtx(t(), NACK.t()) :: {[ExRTP.Packet.t()], t()}
2826
def get_rtx(responder, nack) do
2927
seq_nos = NACK.to_sequence_numbers(nack)

lib/ex_webrtc/rtp_sender/report_recorder.ex

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule ExWebRTC.RTPSender.ReportRecorder do
2-
@moduledoc nil
2+
@moduledoc false
33

44
import Bitwise
55

@@ -30,7 +30,8 @@ defmodule ExWebRTC.RTPSender.ReportRecorder do
3030
octet_count: 0
3131

3232
@doc """
33-
Records outgoing RTP Packet.
33+
Records incoming RTP packet.
34+
3435
`time` parameter accepts output of `System.os_time(:native)` as a value (UNIX timestamp in :native units).
3536
"""
3637
@spec record_packet(t(), ExRTP.Packet.t(), integer()) :: t()
@@ -81,9 +82,9 @@ defmodule ExWebRTC.RTPSender.ReportRecorder do
8182
end
8283

8384
@doc """
84-
Creates an RTCP Sender Report.
85-
`time` parameter accepts output of `System.os_time(:native)` as a value (UNIX timestamp in :native units).
85+
Generates a RTCP Sender Report.
8686
87+
`time` parameter accepts output of `System.os_time(:native)` as a value (UNIX timestamp in :native units).
8788
This function can be called only if at least one packet has been recorded,
8889
otherwise it will raise.
8990
"""

0 commit comments

Comments
 (0)