Skip to content

Commit 37db947

Browse files
authored
Add outbound RTX (#101)
1 parent 945615b commit 37db947

File tree

12 files changed

+300
-82
lines changed

12 files changed

+300
-82
lines changed

examples/echo/lib/echo/peer_handler.ex

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ defmodule Echo.PeerHandler do
1919
%RTPCodecParameters{
2020
payload_type: 96,
2121
mime_type: "video/VP8",
22-
clock_rate: 90_000
22+
clock_rate: 90_000,
23+
rtcp_fbs: [%ExSDP.Attribute.RTCPFeedback{pt: 96, feedback_type: :nack}]
2324
},
2425
%RTPCodecParameters{
2526
payload_type: 97,
2627
mime_type: "video/rtx",
2728
clock_rate: 90_000,
28-
sdp_fmtp_line: %{pt: 97, apt: 96}
29+
sdp_fmtp_line: %ExSDP.Attribute.FMTP{pt: 97, apt: 96}
2930
}
3031
]
3132

@@ -35,12 +36,6 @@ defmodule Echo.PeerHandler do
3536
mime_type: "audio/opus",
3637
clock_rate: 48_000,
3738
channels: 2
38-
},
39-
%RTPCodecParameters{
40-
payload_type: 112,
41-
mime_type: "audio/rtx",
42-
clock_rate: 48_000,
43-
sdp_fmtp_line: %{pt: 112, apt: 111}
4439
}
4540
]
4641

examples/echo/mix.lock

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@
22
"bandit": {:hex, :bandit, "1.2.3", "a98d664a96fec23b68e776062296d76a94b4459795b38209f4ae89cb4225709c", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "3e29150245a9b5f56944434e5240966e75c917dad248f689ab589b32187a81af"},
33
"bunch": {:hex, :bunch, "1.6.1", "5393d827a64d5f846092703441ea50e65bc09f37fd8e320878f13e63d410aec7", [:mix], [], "hexpm", "286cc3add551628b30605efbe2fca4e38cc1bea89bcd0a1a7226920b3364fe4a"},
44
"bunch_native": {:hex, :bunch_native, "0.5.0", "8ac1536789a597599c10b652e0b526d8833348c19e4739a0759a2bedfd924e63", [:mix], [{:bundlex, "~> 1.0", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "24190c760e32b23b36edeb2dc4852515c7c5b3b8675b1a864e0715bdd1c8f80d"},
5-
"bundlex": {:hex, :bundlex, "1.5.0", "295472109d6c8a2fb59712523f20f9502105e3306edc3b490aa1cc4df3f9c5cf", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}, {:req, "~> 0.4.0", [hex: :req, repo: "hexpm", optional: false]}, {:zarex, "~> 1.0", [hex: :zarex, repo: "hexpm", optional: false]}], "hexpm", "e5841de5380b9e99eef347656a71f3d6fab7ff34dee41da3e70c256d39cfdf77"},
5+
"bundlex": {:hex, :bundlex, "1.5.1", "a85890a9d0a70366afa538c8589a4ba75e1319d32a771e1f5f3b7566beea9c26", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}, {:req, "~> 0.4.0", [hex: :req, repo: "hexpm", optional: false]}, {:zarex, "~> 1.0", [hex: :zarex, repo: "hexpm", optional: false]}], "hexpm", "aae447d63230fe1f3b788c429ac02bc696f30163d0f23f52fcfe6ed38372c7ea"},
66
"castore": {:hex, :castore, "1.0.6", "ffc42f110ebfdafab0ea159cd43d31365fa0af0ce4a02ecebf1707ae619ee727", [:mix], [], "hexpm", "374c6e7ca752296be3d6780a6d5b922854ffcc74123da90f2f328996b962d33a"},
77
"crc": {:hex, :crc, "0.10.5", "ee12a7c056ac498ef2ea985ecdc9fa53c1bfb4e53a484d9f17ff94803707dfd8", [:mix, :rebar3], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3e673b6495a9525c5c641585af1accba59a1eb33de697bedf341e247012c2c7f"},
88
"elixir_make": {:hex, :elixir_make, "0.8.3", "d38d7ee1578d722d89b4d452a3e36bcfdc644c618f0d063b874661876e708683", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "5c99a18571a756d4af7a4d89ca75c28ac899e6103af6f223982f09ce44942cc9"},
99
"elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"},
1010
"ex_dtls": {:hex, :ex_dtls, "0.15.1", "34b3600ff13eebf6c96be033005cc110ea5beef98394631365ec26b493df80c5", [:mix], [{:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "9cfebdfe9111c0f68c77667cb9366e4a6f17e8a240975ffd100148de57478a29"},
11-
"ex_ice": {:git, "https://github.com/elixir-webrtc/ex_ice.git", "1b57c79effb762ea71df79390605a52065b60821", []},
11+
"ex_ice": {:git, "https://github.com/elixir-webrtc/ex_ice.git", "2d762caec5a00bdc99fb8df5051c0ff42b93c33f", []},
1212
"ex_libsrtp": {:hex, :ex_libsrtp, "0.7.2", "211bd89c08026943ce71f3e2c0231795b99cee748808ed3ae7b97cd8d2450b6b", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "2e20645d0d739a4ecdcf8d4810a0c198120c8a2f617f2b75b2e2e704d59f492a"},
13-
"ex_rtcp": {:git, "https://github.com/elixir-webrtc/ex_rtcp.git", "67fe8320302fa240e190eb97b95bbabf6bebc2fd", []},
13+
"ex_rtcp": {:git, "https://github.com/elixir-webrtc/ex_rtcp.git", "323873e4d9be018bd742c633d3feed0db40625e8", []},
1414
"ex_rtp": {:git, "https://github.com/elixir-webrtc/ex_rtp.git", "eb9b49d8e53ba92bcd31e7d015473ae10a26707d", []},
1515
"ex_sdp": {:hex, :ex_sdp, "0.15.0", "53815fb5b5e4fae0f3b26de90f372446bb8e0eed62a3cc20394d3c29519698be", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}], "hexpm", "d3f23596b73e7057521ff0f0d55b1189c6320a2f04388aa3a80a0aa97ffb379f"},
16-
"ex_stun": {:hex, :ex_stun, "0.1.0", "252474bf4c8519fbf4bc0fbfc6a1b846a634b1478c65dbbfb4b6ab4e33c2a95a", [:mix], [], "hexpm", "629fc8be45b624a92522f81d85ba001877b1f0745889a2419bdb678790d7480c"},
16+
"ex_stun": {:hex, :ex_stun, "0.2.0", "feb1fc7db0356406655b2a617805e6c712b93308c8ea2bf0ba1197b1f0866deb", [:mix], [], "hexpm", "1e01ba8290082ccbf37acaa5190d1f69b51edd6de2026a8d6d51368b29d115d0"},
17+
"ex_turn": {:hex, :ex_turn, "0.1.0", "177405aadf3d754567d0d37cf881a83f9cacf8f45314d188633b04c4a9e7c1ec", [:mix], [{:ex_stun, "~> 0.2.0", [hex: :ex_stun, repo: "hexpm", optional: false]}], "hexpm", "d677737fb7d45274d5dac19fe3c26b9038b6effbc0a6b3e7417bccc76b6d1cd3"},
1718
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
1819
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
1920
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},

examples/save_to_file/lib/save_to_file/peer_handler.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ defmodule SaveToFile.PeerHandler do
2525
%RTPCodecParameters{
2626
payload_type: 96,
2727
mime_type: "video/VP8",
28-
clock_rate: 90_000
28+
clock_rate: 90_000,
29+
rtcp_fbs: [%ExSDP.Attribute.RTCPFeedback{pt: 96, feedback_type: :nack}]
30+
},
31+
%RTPCodecParameters{
32+
payload_type: 97,
33+
mime_type: "video/rtx",
34+
clock_rate: 90_000,
35+
sdp_fmtp_line: %ExSDP.Attribute.FMTP{pt: 97, apt: 96}
2936
}
3037
]
3138

examples/send_from_file/lib/send_from_file/peer_handler.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ defmodule SendFromFile.PeerHandler do
3030
%RTPCodecParameters{
3131
payload_type: 96,
3232
mime_type: "video/VP8",
33-
clock_rate: 90_000
33+
clock_rate: 90_000,
34+
rtcp_fbs: [%ExSDP.Attribute.RTCPFeedback{pt: 96, feedback_type: :nack}]
35+
},
36+
%RTPCodecParameters{
37+
payload_type: 97,
38+
mime_type: "video/rtx",
39+
clock_rate: 90_000,
40+
sdp_fmtp_line: %ExSDP.Attribute.FMTP{pt: 97, apt: 96}
3441
}
3542
]
3643

examples/send_from_file/mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"ex_dtls": {:hex, :ex_dtls, "0.15.1", "34b3600ff13eebf6c96be033005cc110ea5beef98394631365ec26b493df80c5", [:mix], [{:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "9cfebdfe9111c0f68c77667cb9366e4a6f17e8a240975ffd100148de57478a29"},
1111
"ex_ice": {:git, "https://github.com/elixir-webrtc/ex_ice.git", "1b57c79effb762ea71df79390605a52065b60821", []},
1212
"ex_libsrtp": {:hex, :ex_libsrtp, "0.7.2", "211bd89c08026943ce71f3e2c0231795b99cee748808ed3ae7b97cd8d2450b6b", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "2e20645d0d739a4ecdcf8d4810a0c198120c8a2f617f2b75b2e2e704d59f492a"},
13-
"ex_rtcp": {:git, "https://github.com/elixir-webrtc/ex_rtcp.git", "67fe8320302fa240e190eb97b95bbabf6bebc2fd", []},
13+
"ex_rtcp": {:git, "https://github.com/elixir-webrtc/ex_rtcp.git", "323873e4d9be018bd742c633d3feed0db40625e8", []},
1414
"ex_rtp": {:git, "https://github.com/elixir-webrtc/ex_rtp.git", "eb9b49d8e53ba92bcd31e7d015473ae10a26707d", []},
1515
"ex_sdp": {:hex, :ex_sdp, "0.15.0", "53815fb5b5e4fae0f3b26de90f372446bb8e0eed62a3cc20394d3c29519698be", [:mix], [{:bunch, "~> 1.3", [hex: :bunch, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}], "hexpm", "d3f23596b73e7057521ff0f0d55b1189c6320a2f04388aa3a80a0aa97ffb379f"},
1616
"ex_stun": {:hex, :ex_stun, "0.1.0", "252474bf4c8519fbf4bc0fbfc6a1b846a634b1478c65dbbfb4b6ab4e33c2a95a", [:mix], [], "hexpm", "629fc8be45b624a92522f81d85ba001877b1f0745889a2419bdb678790d7480c"},

lib/ex_webrtc/peer_connection.ex

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,18 @@ defmodule ExWebRTC.PeerConnection do
198198

199199
@doc """
200200
Send an RTP packet to the remote peer using specified track or its id.
201+
202+
Options:
203+
* `rtx?` - send the packet as if it was retransmited (use SSRC and payload type specific to RTX)
201204
"""
202205
@spec send_rtp(
203206
peer_connection(),
204-
MediaStreamTrack.t() | MediaStreamTrack.id(),
205-
ExRTP.Packet.t()
207+
MediaStreamTrack.id(),
208+
ExRTP.Packet.t(),
209+
rtx?: boolean()
206210
) :: :ok
207-
def send_rtp(peer_connection, %MediaStreamTrack{id: track_id}, packet),
208-
do: send_rtp(peer_connection, track_id, packet)
209-
210-
def send_rtp(peer_connection, track_id, packet) when is_integer(track_id) do
211-
GenServer.cast(peer_connection, {:send_rtp, track_id, packet})
211+
def send_rtp(peer_connection, track_id, packet, opts \\ []) do
212+
GenServer.cast(peer_connection, {:send_rtp, track_id, packet, opts})
212213
end
213214

214215
@doc """
@@ -245,9 +246,6 @@ defmodule ExWebRTC.PeerConnection do
245246
# route data to the DTLSTransport
246247
:ok = DefaultICETransport.on_data(ice_pid, dtls_transport)
247248

248-
# TODO: should keep track of previous ice candidates
249-
# and add them to local description
250-
251249
state = %{
252250
owner: owner,
253251
config: config,
@@ -479,7 +477,9 @@ defmodule ExWebRTC.PeerConnection do
479477
@impl true
480478
def handle_call({:add_transceiver, kind, options}, _from, state)
481479
when kind in [:audio, :video] do
482-
options = Keyword.put(options, :ssrc, generate_ssrc(state))
480+
{ssrc, rtx_ssrc} = generate_ssrcs(state)
481+
options = [{:ssrc, ssrc}, {:rtx_ssrc, rtx_ssrc} | options]
482+
483483
transceiver = RTPTransceiver.new(kind, nil, state.config, options)
484484
state = %{state | transceivers: state.transceivers ++ [transceiver]}
485485

@@ -490,7 +490,9 @@ defmodule ExWebRTC.PeerConnection do
490490

491491
@impl true
492492
def handle_call({:add_transceiver, %MediaStreamTrack{} = track, options}, _from, state) do
493-
options = Keyword.put(options, :ssrc, generate_ssrc(state))
493+
{ssrc, rtx_ssrc} = generate_ssrcs(state)
494+
options = [{:ssrc, ssrc}, {:rtx_ssrc, rtx_ssrc} | options]
495+
494496
transceiver = RTPTransceiver.new(track.kind, track, state.config, options)
495497
state = %{state | transceivers: state.transceivers ++ [transceiver]}
496498

@@ -558,16 +560,24 @@ defmodule ExWebRTC.PeerConnection do
558560
false
559561
end)
560562

563+
{ssrc, rtx_ssrc} = generate_ssrcs(state)
564+
561565
{transceivers, sender} =
562566
case free_transceiver_idx do
563567
nil ->
564-
options = [direction: :sendrecv, ssrc: generate_ssrc(state), added_by_add_track: true]
568+
options = [
569+
direction: :sendrecv,
570+
added_by_add_track: true,
571+
ssrc: ssrc,
572+
rtx_ssrc: rtx_ssrc
573+
]
574+
565575
tr = RTPTransceiver.new(kind, track, state.config, options)
566576
{state.transceivers ++ [tr], tr.sender}
567577

568578
idx ->
569579
tr = Enum.at(state.transceivers, idx)
570-
tr = RTPTransceiver.add_track(tr, track, generate_ssrc(state))
580+
tr = RTPTransceiver.add_track(tr, track, ssrc, rtx_ssrc)
571581
{List.replace_at(state.transceivers, idx, tr), tr.sender}
572582
end
573583

@@ -594,7 +604,8 @@ defmodule ExWebRTC.PeerConnection do
594604
{:reply, {:error, :invalid_track_type}, state}
595605

596606
tr.direction in [:sendrecv, :sendonly] ->
597-
tr = RTPTransceiver.replace_track(tr, track, generate_ssrc(state))
607+
{ssrc, rtx_ssrc} = generate_ssrcs(state)
608+
tr = RTPTransceiver.replace_track(tr, track, ssrc, rtx_ssrc)
598609
transceivers = List.replace_at(state.transceivers, tr_idx, tr)
599610
state = %{state | transceivers: transceivers}
600611
{:reply, :ok, state}
@@ -760,7 +771,9 @@ defmodule ExWebRTC.PeerConnection do
760771
end
761772

762773
@impl true
763-
def handle_cast({:send_rtp, track_id, packet}, state) do
774+
def handle_cast({:send_rtp, track_id, packet, opts}, state) do
775+
rtx? = Keyword.get(opts, :rtx?, false)
776+
764777
# TODO: iterating over transceivers is not optimal
765778
# but this is, most likely, going to be refactored anyways
766779
{transceiver, idx} =
@@ -792,7 +805,7 @@ defmodule ExWebRTC.PeerConnection do
792805
{packet, state}
793806
end
794807

795-
{packet, transceiver} = RTPTransceiver.send_packet(transceiver, packet)
808+
{packet, transceiver} = RTPTransceiver.send_packet(transceiver, packet, rtx?)
796809
:ok = DTLSTransport.send_rtp(state.dtls_transport, packet)
797810

798811
transceivers = List.replace_at(state.transceivers, idx, transceiver)
@@ -932,13 +945,13 @@ defmodule ExWebRTC.PeerConnection do
932945
def handle_info({:dtls_transport, _pid, {:rtcp, data}}, state) do
933946
case ExRTCP.CompoundPacket.decode(data) do
934947
{:ok, packets} ->
935-
transceivers =
936-
Enum.reduce(packets, state.transceivers, fn packet, transceivers ->
937-
handle_report(packet, transceivers)
948+
state =
949+
Enum.reduce(packets, state, fn packet, state ->
950+
handle_rtcp_packet(state, packet)
938951
end)
939952

940953
notify(state.owner, {:rtcp, packets})
941-
{:noreply, %{state | transceivers: transceivers}}
954+
{:noreply, state}
942955

943956
{:error, _res} ->
944957
case data do
@@ -1588,23 +1601,47 @@ defmodule ExWebRTC.PeerConnection do
15881601
end
15891602
end
15901603

1591-
defp handle_report(%ExRTCP.Packet.SenderReport{} = report, transceivers) do
1604+
defp handle_rtcp_packet(state, %ExRTCP.Packet.SenderReport{} = report) do
15921605
transceiver =
1593-
transceivers
1606+
state.transceivers
15941607
|> Enum.with_index()
15951608
|> Enum.find(fn {tr, _idx} -> tr.receiver.ssrc == report.ssrc end)
15961609

15971610
case transceiver do
15981611
nil ->
1599-
transceivers
1612+
state
16001613

16011614
{tr, idx} ->
16021615
tr = RTPTransceiver.receive_report(tr, report)
1603-
List.replace_at(transceivers, idx, tr)
1616+
transceivers = List.replace_at(state.transceivers, idx, tr)
1617+
%{state | transceivers: transceivers}
1618+
end
1619+
end
1620+
1621+
defp handle_rtcp_packet(state, %ExRTCP.Packet.TransportFeedback.NACK{} = nack) do
1622+
transceiver =
1623+
state.transceivers
1624+
|> Enum.with_index()
1625+
|> Enum.find(fn {tr, _idx} -> tr.sender.ssrc == nack.media_ssrc end)
1626+
1627+
case transceiver do
1628+
nil ->
1629+
state
1630+
1631+
# in case NACK was received, but RTX was not negotiated
1632+
# as NACK and RTX are negotited independently
1633+
{%RTPTransceiver{sender: %RTPSender{rtx_pt: nil}}, _idx} ->
1634+
state
1635+
1636+
{tr, idx} ->
1637+
{packets, tr} = RTPTransceiver.receive_nack(tr, nack)
1638+
for packet <- packets, do: send_rtp(self(), tr.sender.track.id, packet, rtx?: true)
1639+
transceivers = List.replace_at(state.transceivers, idx, tr)
1640+
%{state | transceivers: transceivers}
16041641
end
16051642
end
16061643

1607-
defp handle_report(_report, transceivers), do: transceivers
1644+
defp handle_rtcp_packet(state, _packet), do: state
16081645

16091646
defp do_get_description(nil, _candidates), do: nil
16101647

@@ -1613,10 +1650,12 @@ defmodule ExWebRTC.PeerConnection do
16131650
%SessionDescription{type: type, sdp: to_string(sdp)}
16141651
end
16151652

1616-
defp generate_ssrc(state) do
1653+
defp generate_ssrcs(state) do
16171654
rtp_sender_ssrcs = Enum.map(state.transceivers, & &1.sender.ssrc)
16181655
ssrcs = MapSet.new(Map.keys(state.demuxer.ssrc_to_mid) ++ rtp_sender_ssrcs)
1619-
do_generate_ssrc(ssrcs, 200)
1656+
ssrc = do_generate_ssrc(ssrcs, 200)
1657+
rtx_ssrc = do_generate_ssrc(MapSet.put(ssrcs, ssrc), 200)
1658+
{ssrc, rtx_ssrc}
16201659
end
16211660

16221661
# this is practically impossible so it's easier to raise

0 commit comments

Comments
 (0)