Skip to content

Commit e79d429

Browse files
authored
Include DataChannel stats in PeerConnection.get_stats (#162)
1 parent 8109856 commit e79d429

File tree

3 files changed

+85
-9
lines changed

3 files changed

+85
-9
lines changed

lib/ex_webrtc/peer_connection.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,11 @@ defmodule ExWebRTC.PeerConnection do
10181018
|> Enum.flat_map(&RTPTransceiver.get_stats(&1, timestamp))
10191019
|> Map.new(fn stats -> {stats.id, stats} end)
10201020

1021+
data_channel_stats =
1022+
state.sctp_transport
1023+
|> SCTPTransport.get_stats(timestamp)
1024+
|> Map.new(fn stats -> {stats.id, stats} end)
1025+
10211026
stats = %{
10221027
peer_connection: %{
10231028
id: :peer_connection,
@@ -1057,6 +1062,7 @@ defmodule ExWebRTC.PeerConnection do
10571062
|> Map.merge(local_cands)
10581063
|> Map.merge(remote_cands)
10591064
|> Map.merge(rtp_stats)
1065+
|> Map.merge(data_channel_stats)
10601066

10611067
{:reply, stats, state}
10621068
end

lib/ex_webrtc/sctp_transport.ex

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ defmodule ExWebRTC.SCTPTransport do
2323
connected: false,
2424
id_type: nil,
2525
timer: nil,
26-
channels: %{}
26+
channels: %{},
27+
stats: %{}
2728
}
2829
end
2930

@@ -45,6 +46,24 @@ defmodule ExWebRTC.SCTPTransport do
4546
sctp_transport.channels != %{}
4647
end
4748

49+
@spec get_stats(t(), non_neg_integer()) :: [map()]
50+
def get_stats(sctp_transport, timestamp) do
51+
Enum.map(sctp_transport.channels, fn {ref, channel} ->
52+
stats = Map.fetch!(sctp_transport.stats, ref)
53+
54+
%{
55+
id: inspect(channel.ref),
56+
type: :data_channel,
57+
timestamp: timestamp,
58+
data_channel_identifier: channel.id,
59+
label: channel.label,
60+
protocol: channel.protocol,
61+
state: channel.ready_state
62+
}
63+
|> Map.merge(stats)
64+
end)
65+
end
66+
4867
@spec add_channel(
4968
t(),
5069
String.t(),
@@ -67,7 +86,8 @@ defmodule ExWebRTC.SCTPTransport do
6786
}
6887

6988
channels = Map.put(sctp_transport.channels, channel.ref, channel)
70-
sctp_transport = %{sctp_transport | channels: channels}
89+
stats = Map.put(sctp_transport.stats, channel.ref, initial_stats())
90+
sctp_transport = %{sctp_transport | channels: channels, stats: stats}
7191

7292
{events, sctp_transport} =
7393
if sctp_transport.connected do
@@ -90,7 +110,8 @@ defmodule ExWebRTC.SCTPTransport do
90110
{[], sctp_transport}
91111

92112
{%DataChannel{id: id}, channels} ->
93-
sctp_transport = %{sctp_transport | channels: channels}
113+
stats = Map.delete(sctp_transport.stats, ref)
114+
sctp_transport = %{sctp_transport | channels: channels, stats: stats}
94115

95116
{events, sctp_transport} =
96117
if id != nil do
@@ -114,8 +135,9 @@ defmodule ExWebRTC.SCTPTransport do
114135

115136
case Map.fetch(sctp_transport.channels, ref) do
116137
{:ok, %DataChannel{ready_state: :open, id: id}} when id != nil ->
138+
stats = update_stats(sctp_transport.stats, ref, data, :sent)
117139
:ok = ExSCTP.send(sctp_transport.ref, id, ppi, data)
118-
handle_events(sctp_transport)
140+
handle_events(%{sctp_transport | stats: stats})
119141

120142
{:ok, %DataChannel{id: id}} ->
121143
Logger.warning(
@@ -207,8 +229,9 @@ defmodule ExWebRTC.SCTPTransport do
207229
case Enum.find(sctp_transport.channels, fn {_k, v} -> v.id == id end) do
208230
{ref, %DataChannel{ref: ref}} ->
209231
channels = Map.delete(sctp_transport.channels, ref)
232+
stats = Map.delete(sctp_transport.stats, ref)
210233
event = {:state_change, ref, :closed}
211-
{event, %{sctp_transport | channels: channels}}
234+
{event, %{sctp_transport | channels: channels, stats: stats}}
212235

213236
_other ->
214237
{nil, sctp_transport}
@@ -257,7 +280,9 @@ defmodule ExWebRTC.SCTPTransport do
257280
case Enum.find_value(sctp_transport.channels, fn {_k, v} -> v.id == id end) do
258281
{ref, %DataChannel{}} ->
259282
channels = Map.delete(sctp_transport.channels, ref)
260-
{{:state_change, ref, :closed}, %{sctp_transport | channels: channels}}
283+
stats = Map.delete(sctp_transport.stats, ref)
284+
sctp_transport = %{sctp_transport | channels: channels, stats: stats}
285+
{{:state_change, ref, :closed}, sctp_transport}
261286

262287
nil ->
263288
{nil, sctp_transport}
@@ -269,7 +294,8 @@ defmodule ExWebRTC.SCTPTransport do
269294
with {:ok, data} <- from_raw_data(data, ppi),
270295
{ref, %DataChannel{ready_state: :open}} <-
271296
Enum.find(sctp_transport.channels, fn {_k, v} -> v.id == id end) do
272-
{{:data, ref, data}, sctp_transport}
297+
stats = update_stats(sctp_transport.stats, ref, data, :received)
298+
{{:data, ref, data}, %{sctp_transport | stats: stats}}
273299
else
274300
{_ref, %DataChannel{}} ->
275301
Logger.warning("Received data on DataChannel with id #{id} that is not open. Discarding")
@@ -309,7 +335,8 @@ defmodule ExWebRTC.SCTPTransport do
309335
# In theory, we should also send the :open event here (W3C 6.2.3)
310336
# TODO
311337
channels = Map.put(sctp_transport.channels, channel.ref, channel)
312-
sctp_transport = %{sctp_transport | channels: channels}
338+
stats = Map.put(sctp_transport.stats, channel.ref, initial_stats())
339+
sctp_transport = %{sctp_transport | channels: channels, stats: stats}
313340

314341
case ExSCTP.configure_stream(
315342
sctp_transport.ref,
@@ -396,4 +423,31 @@ defmodule ExWebRTC.SCTPTransport do
396423
{:odd, 1} -> max_id + 2
397424
end
398425
end
426+
427+
defp initial_stats() do
428+
%{
429+
messages_sent: 0,
430+
messages_received: 0,
431+
bytes_sent: 0,
432+
bytes_received: 0
433+
}
434+
end
435+
436+
defp update_stats(stats, ref, data, type) do
437+
Map.update!(stats, ref, fn stat ->
438+
if type == :sent do
439+
%{
440+
stat
441+
| messages_sent: stat.messages_sent + 1,
442+
bytes_sent: stat.bytes_sent + byte_size(data)
443+
}
444+
else
445+
%{
446+
stat
447+
| messages_received: stat.messages_received + 1,
448+
bytes_received: stat.bytes_received + byte_size(data)
449+
}
450+
end
451+
end)
452+
end
399453
end

test/ex_webrtc/data_channel_test.exs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ defmodule ExWebRTC.DataChannelTest do
157157
%{pc1: pc1, pc2: pc2, ref1: ref1, ref2: ref2}
158158
end
159159

160-
test "message from initiating peer", %{pc1: pc1, pc2: pc2, ref1: ref1, ref2: ref2} do
160+
test "from initiating peer", %{pc1: pc1, pc2: pc2, ref1: ref1, ref2: ref2} do
161161
data1 = <<1, 2, 3>>
162162
:ok = PeerConnection.send_data(pc1, ref1, data1)
163163
assert_receive {:ex_webrtc, ^pc2, {:data, ^ref2, ^data1}}
@@ -200,5 +200,21 @@ defmodule ExWebRTC.DataChannelTest do
200200
:ok = PeerConnection.send_data(pc2, ref2, msg)
201201
assert_receive {:ex_webrtc, ^pc1, {:data, ^ref1, ^data}}
202202
end
203+
204+
test "and collecting stats about it", %{pc1: pc1, pc2: pc2, ref1: ref1} do
205+
for _ <- 1..10 do
206+
:ok = PeerConnection.send_data(pc1, ref1, <<1, 2, 3>>)
207+
end
208+
209+
stats1 = PeerConnection.get_stats(pc1)
210+
assert {_ref, channel_stats1} = Enum.find(stats1, fn {_, v} -> v.type == :data_channel end)
211+
assert channel_stats1.bytes_sent == 30
212+
assert channel_stats1.messages_sent == 10
213+
214+
stats2 = PeerConnection.get_stats(pc2)
215+
assert {_ref, channel_stats2} = Enum.find(stats2, fn {_, v} -> v.type == :data_channel end)
216+
assert channel_stats2.bytes_received == 30
217+
assert channel_stats2.messages_received == 10
218+
end
203219
end
204220
end

0 commit comments

Comments
 (0)