Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mickel8 committed Jan 15, 2025
1 parent bc4a103 commit f03b4c2
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 22 deletions.
13 changes: 5 additions & 8 deletions lib/ex_webrtc/rtp_sender.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ defmodule ExWebRTC.RTPSender do
mid: String.t() | nil,
pt: non_neg_integer() | nil,
rtx_pt: non_neg_integer() | nil,
# ssrc and rtx_ssrc are always present, even if there is no track
# ssrc and rtx_ssrc are always present, even if there is no track,
# or transceiver direction is recvonly.
# We preallocate them so they can be included in SDP when needed.
ssrc: non_neg_integer(),
Expand Down Expand Up @@ -140,8 +140,8 @@ defmodule ExWebRTC.RTPSender do
msid_attrs =
case sender.track do
nil ->
# In theory, we should do this "for each MediaStream that was associated with the transceiver"
# but web browsers (chrome, ff), include MSID even when there aren't any MediaStreams
# In theory, we should do this "for each MediaStream that was associated with the transceiver",
# but web browsers (chrome, ff) include MSID even when there aren't any MediaStreams
[ExSDP.Attribute.MSID.new("-", nil)]

%MediaStreamTrack{streams: streams} ->
Expand Down Expand Up @@ -192,13 +192,10 @@ defmodule ExWebRTC.RTPSender do
streams ->
{ssrc_attrs, rtx_ssrc_attrs} =
Enum.reduce(streams, {[], []}, fn stream, {ssrc_attrs, rtx_ssrc_attrs} ->
ssrc_attr = [%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: stream}]
ssrc_attr = %ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: stream}
ssrc_attrs = [ssrc_attr | ssrc_attrs]

rtx_ssrc_attr = [
%ExSDP.Attribute.SSRC{id: rtx_ssrc, attribute: "msid", value: stream}
]

rtx_ssrc_attr = %ExSDP.Attribute.SSRC{id: rtx_ssrc, attribute: "msid", value: stream}
rtx_ssrc_attrs = [rtx_ssrc_attr | rtx_ssrc_attrs]

{ssrc_attrs, rtx_ssrc_attrs}
Expand Down
8 changes: 6 additions & 2 deletions lib/ex_webrtc/rtp_sender/nack_responder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ defmodule ExWebRTC.RTPSender.NACKResponder do

{packets, seq_no} =
seq_nos
|> Enum.map(fn seq_no -> {seq_no, Map.get(responder.packets, rem(seq_no, @max_packets))} end)
|> Enum.filter(fn {seq_no, packet} -> packet != nil and packet.sequence_number == seq_no end)
|> Enum.map(fn seq_no ->
{seq_no, Map.get(responder.packets, rem(seq_no, @max_packets))}
end)
|> Enum.filter(fn {seq_no, packet} ->
packet != nil and packet.sequence_number == seq_no
end)
# ssrc will be assigned by the sender
|> Enum.map_reduce(responder.seq_no, fn {seq_no, packet}, rtx_seq_no ->
rtx_packet = %Packet{
Expand Down
92 changes: 80 additions & 12 deletions test/ex_webrtc/rtp_sender_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@ defmodule ExWebRTC.RTPSenderTest do
@ssrc 354_947
@rtx_ssrc 123_455

setup do
track = MediaStreamTrack.new(:audio)

codec = %RTPCodecParameters{
payload_type: 111,
mime_type: "audio/opus",
clock_rate: 48_000,
channels: 2,
sdp_fmtp_line: %FMTP{pt: 111, minptime: 10, useinbandfec: true}
@rtp_hdr_exts [%Extmap{id: 1, uri: "urn:ietf:params:rtp-hdrext:sdes:mid"}]

@codec %RTPCodecParameters{
payload_type: 96,
mime_type: "video/VP8",
clock_rate: 90_000
}

@rtx_codec %ExWebRTC.RTPCodecParameters{
payload_type: 124,
mime_type: "video/rtx",
clock_rate: 90_000,
sdp_fmtp_line: %ExSDP.Attribute.FMTP{
pt: 124,
apt: 96
}
}

rtp_hdr_exts = [%Extmap{id: 1, uri: "urn:ietf:params:rtp-hdrext:sdes:mid"}]
setup do
track = MediaStreamTrack.new(:video)

sender = RTPSender.new(track, codec, nil, rtp_hdr_exts, "1", @ssrc, @rtx_ssrc, [])
sender = RTPSender.new(track, @codec, nil, @rtp_hdr_exts, "1", @ssrc, @rtx_ssrc, [])

%{sender: sender}
end
Expand All @@ -36,7 +44,7 @@ defmodule ExWebRTC.RTPSenderTest do

assert packet.ssrc == @ssrc
assert packet.marker == false
assert packet.payload_type == 111
assert packet.payload_type == 96
# timestamp and sequence number shouldn't be overwritten
assert packet.timestamp == 0
assert packet.sequence_number == 0
Expand All @@ -53,6 +61,66 @@ defmodule ExWebRTC.RTPSenderTest do
assert packet.marker == true
end

describe "get_mline_attrs/1" do
test "without rtx" do
stream_id = MediaStreamTrack.generate_stream_id()
track = MediaStreamTrack.new(:video, [stream_id])

sender = RTPSender.new(track, @codec, nil, @rtp_hdr_exts, "1", @ssrc, @rtx_ssrc, [])

assert [
%ExSDP.Attribute.MSID{id: ^stream_id, app_data: nil},
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^stream_id}
] = RTPSender.get_mline_attrs(sender)
end

test "with rtx" do
stream_id = MediaStreamTrack.generate_stream_id()
track = MediaStreamTrack.new(:video, [stream_id])

sender = RTPSender.new(track, @codec, @rtx_codec, @rtp_hdr_exts, "1", @ssrc, @rtx_ssrc, [])

assert [
%ExSDP.Attribute.MSID{id: ^stream_id, app_data: nil},
%ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [@ssrc, @rtx_ssrc]},
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^stream_id},
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ^stream_id}
] = RTPSender.get_mline_attrs(sender)
end

test "without media stream" do
track = MediaStreamTrack.new(:video)

sender = RTPSender.new(track, @codec, @rtx_codec, @rtp_hdr_exts, "1", @ssrc, @rtx_ssrc, [])

assert [
%ExSDP.Attribute.MSID{id: "-", app_data: nil},
%ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [@ssrc, @rtx_ssrc]},
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: "-"},
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: "-"}
] = RTPSender.get_mline_attrs(sender)
end

test "with multiple media streams" do
s1_id = MediaStreamTrack.generate_stream_id()
s2_id = MediaStreamTrack.generate_stream_id()

track = MediaStreamTrack.new(:video, [s1_id, s2_id])

sender = RTPSender.new(track, @codec, @rtx_codec, @rtp_hdr_exts, "1", @ssrc, @rtx_ssrc, [])

assert [
%ExSDP.Attribute.MSID{id: ^s1_id, app_data: nil},
%ExSDP.Attribute.MSID{id: ^s2_id, app_data: nil},
%ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [@ssrc, @rtx_ssrc]},
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^s1_id},
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^s2_id},
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ^s1_id},
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ^s2_id}
] = RTPSender.get_mline_attrs(sender)
end
end

test "get_stats/2", %{sender: sender} do
timestamp = System.os_time(:millisecond)
payload = <<1, 2, 3>>
Expand Down
85 changes: 85 additions & 0 deletions test/ex_webrtc/rtp_transceiver_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
defmodule ExWebRTC.RTPTransceiverTest do
use ExUnit.Case, async: true

alias ExWebRTC.{MediaStreamTrack, PeerConnection, RTPTransceiver, Utils}

{:ok, pc} = PeerConnection.start_link()
@config PeerConnection.get_configuration(pc)
:ok = PeerConnection.close(pc)

@ssrc 1234
@rtx_ssrc 2345

@track MediaStreamTrack.new(:video, [MediaStreamTrack.generate_stream_id()])

{_key, cert} = ExDTLS.generate_key_cert()

@opts [
ice_ufrag: "ice_ufrag",
ice_pwd: "ice_pwd",
ice_options: "trickle",
fingerprint: {:sha256, Utils.hex_dump(cert)},
setup: :actpass
]

describe "to_offer_mline/1" do
test "with sendrecv direction" do
tr = RTPTransceiver.new(:video, @track, @config, ssrc: @ssrc, rtx_ssrc: @rtx_ssrc)
test_sender_attrs(tr)
end

test "with sendonly direction" do
tr =
RTPTransceiver.new(:video, @track, @config,
ssrc: @ssrc,
rtx_ssrc: @rtx_ssrc,
direction: :sendonly
)

test_sender_attrs(tr)
end

test "with recvonly direction" do
tr =
RTPTransceiver.new(:video, @track, @config,
ssrc: @ssrc,
rtx_ssrc: @rtx_ssrc,
direction: :recvonly
)

test_no_sender_attrs(tr)
end

test "with inactive direction" do
tr =
RTPTransceiver.new(:video, @track, @config,
ssrc: @ssrc,
rtx_ssrc: @rtx_ssrc,
direction: :inactive
)

test_no_sender_attrs(tr)
end
end

defp test_sender_attrs(tr) do
mline = RTPTransceiver.to_offer_mline(tr, @opts)

# Assert rtp sender attributes are present.
# Their exact values are checked in rtp_sender_test.exs.
assert [%ExSDP.Attribute.MSID{}] = ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
assert [%ExSDP.Attribute.SSRCGroup{}] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)

assert [%ExSDP.Attribute.SSRC{}, %ExSDP.Attribute.SSRC{}] =
ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
end

defp test_no_sender_attrs(tr) do
mline = RTPTransceiver.to_offer_mline(tr, @opts)

# assert there are no sender attributes
assert [] == ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
assert [] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
assert [] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
end
end

0 comments on commit f03b4c2

Please sign in to comment.