Skip to content

Commit 067ebd4

Browse files
authored
Always include track id in MSID/SSRC attributes (#221)
1 parent 5e20c3d commit 067ebd4

File tree

2 files changed

+91
-54
lines changed

2 files changed

+91
-54
lines changed

lib/ex_webrtc/rtp_transceiver.ex

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,8 @@ defmodule ExWebRTC.RTPTransceiver do
558558
else: transceiver.sender.codecs
559559

560560
get_sender_attrs(
561-
transceiver.sender.track,
562-
codecs,
563-
transceiver.sender.ssrc,
564-
transceiver.sender.rtx_ssrc
561+
transceiver.sender,
562+
codecs
565563
)
566564
else
567565
[]
@@ -577,75 +575,76 @@ defmodule ExWebRTC.RTPTransceiver do
577575
end
578576

579577
@doc false
580-
defp get_sender_attrs(track, codecs, ssrc, rtx_ssrc) do
581-
# Don't include track id. See RFC 8829 sec. 5.2.1
578+
defp get_sender_attrs(sender, codecs) do
579+
# According to RFC 8829 sec. 5.2.1, track IDs should not be included.
580+
# However, most browsers support track IDs in MSID. We will follow this practice.
582581
msid_attrs =
583-
case track do
584-
%MediaStreamTrack{streams: streams} when streams != [] ->
585-
Enum.map(streams, &ExSDP.Attribute.MSID.new(&1, nil))
582+
case sender.track do
583+
%MediaStreamTrack{streams: streams, id: id} when streams != [] ->
584+
Enum.map(streams, &ExSDP.Attribute.MSID.new(&1, id))
586585

587-
_other ->
586+
%MediaStreamTrack{id: id} ->
588587
# In theory, we should do this "for each MediaStream that was associated with the transceiver",
589588
# but web browsers (chrome, ff) include MSID even when there aren't any MediaStreams
590-
[ExSDP.Attribute.MSID.new("-", nil)]
589+
[ExSDP.Attribute.MSID.new("-", id)]
590+
591+
nil ->
592+
[ExSDP.Attribute.MSID.new("-", sender.id)]
591593
end
592594

593-
ssrc_attrs = get_ssrc_attrs(codecs, ssrc, rtx_ssrc, track)
595+
ssrc_attrs = get_ssrc_attrs(sender, codecs)
594596

595597
msid_attrs ++ ssrc_attrs
596598
end
597599

598-
defp get_ssrc_attrs(codecs, ssrc, rtx_ssrc, track) do
600+
defp get_ssrc_attrs(sender, codecs) do
599601
codec = Enum.any?(codecs, fn codec -> not String.ends_with?(codec.mime_type, "/rtx") end)
600602
rtx_codec = Enum.any?(codecs, fn codec -> String.ends_with?(codec.mime_type, "/rtx") end)
601603

602-
do_get_ssrc_attrs(codec, rtx_codec, ssrc, rtx_ssrc, track)
604+
do_get_ssrc_attrs(sender, codec, rtx_codec)
603605
end
604606

605607
# we didn't manage to negotiate any codec
606-
defp do_get_ssrc_attrs(false, _rtx_codec, _ssrc, _rtx_ssrc, _track) do
608+
defp do_get_ssrc_attrs(_sender, false, _rtx_codec) do
607609
[]
608610
end
609611

610612
# we have a codec but not rtx codec
611-
defp do_get_ssrc_attrs(_codec, false, ssrc, _rtx_ssrc, track) do
612-
streams = (track && track.streams) || []
613-
614-
case streams do
615-
[] ->
616-
[%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "-"}]
617-
618-
streams ->
613+
defp do_get_ssrc_attrs(%{ssrc: ssrc} = sender, _codec, false) do
614+
case sender.track do
615+
%MediaStreamTrack{streams: streams, id: id} when streams != [] ->
619616
Enum.map(streams, fn stream ->
620-
%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: stream}
617+
%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "#{stream} #{id}"}
621618
end)
619+
620+
%MediaStreamTrack{id: id} ->
621+
[%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "- #{id}"}]
622+
623+
nil ->
624+
# If the track_id is missing, we will default to using the sender_id, following Chromium's approach:
625+
# See: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/pc/sdp_offer_answer.cc;l=739;drc=b8b5768e5d0d1c2a84fe4896eae884d97fd1131e;bpv=1;bpt=1
626+
[%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "- #{sender.id}"}]
622627
end
623628
end
624629

625630
# we have both codec and rtx codec
626-
defp do_get_ssrc_attrs(_codec, _rtx_codec, ssrc, rtx_ssrc, track) do
627-
streams = (track && track.streams) || []
628-
631+
defp do_get_ssrc_attrs(%{ssrc: ssrc, rtx_ssrc: rtx_ssrc} = sender, _codec, _rtx_codec) do
629632
fid = %ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [ssrc, rtx_ssrc]}
630633

631634
ssrc_attrs =
632-
case streams do
633-
[] ->
634-
[
635-
%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "-"},
636-
%ExSDP.Attribute.SSRC{id: rtx_ssrc, attribute: "msid", value: "-"}
637-
]
638-
639-
streams ->
635+
case sender.track do
636+
%MediaStreamTrack{streams: streams, id: id} when streams != [] ->
640637
{ssrc_attrs, rtx_ssrc_attrs} =
641638
Enum.reduce(streams, {[], []}, fn stream, {ssrc_attrs, rtx_ssrc_attrs} ->
642-
ssrc_attr = %ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: stream}
639+
ssrc_value = "#{stream} #{id}"
640+
641+
ssrc_attr = %ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: ssrc_value}
643642
ssrc_attrs = [ssrc_attr | ssrc_attrs]
644643

645644
rtx_ssrc_attr = %ExSDP.Attribute.SSRC{
646645
id: rtx_ssrc,
647646
attribute: "msid",
648-
value: stream
647+
value: ssrc_value
649648
}
650649

651650
rtx_ssrc_attrs = [rtx_ssrc_attr | rtx_ssrc_attrs]
@@ -654,6 +653,18 @@ defmodule ExWebRTC.RTPTransceiver do
654653
end)
655654

656655
Enum.reverse(ssrc_attrs) ++ Enum.reverse(rtx_ssrc_attrs)
656+
657+
%MediaStreamTrack{id: id} ->
658+
[
659+
%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "- #{id}"},
660+
%ExSDP.Attribute.SSRC{id: rtx_ssrc, attribute: "msid", value: "- #{id}"}
661+
]
662+
663+
nil ->
664+
[
665+
%ExSDP.Attribute.SSRC{id: ssrc, attribute: "msid", value: "- #{sender.id}"},
666+
%ExSDP.Attribute.SSRC{id: rtx_ssrc, attribute: "msid", value: "- #{sender.id}"}
667+
]
657668
end
658669

659670
[fid | ssrc_attrs]

test/ex_webrtc/rtp_transceiver_test.exs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ defmodule ExWebRTC.RTPTransceiverTest do
7474
)
7575

7676
mline = RTPTransceiver.to_offer_mline(tr, @opts)
77+
ssrc_value = ssrc_msid_value(@stream_id, @track.id)
7778

7879
assert [%ExSDP.Attribute.MSID{id: @stream_id}] =
7980
ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
8081

8182
assert [] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
8283

83-
assert [%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: @stream_id}] =
84+
assert [%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^ssrc_value}] =
8485
ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
8586
end
8687

@@ -93,16 +94,17 @@ defmodule ExWebRTC.RTPTransceiverTest do
9394
)
9495

9596
mline = RTPTransceiver.to_offer_mline(tr, @opts)
97+
ssrc_value = ssrc_msid_value(@stream_id, @track.id)
9698

97-
assert [%ExSDP.Attribute.MSID{id: @stream_id, app_data: nil}] =
99+
assert [%ExSDP.Attribute.MSID{id: @stream_id, app_data: @track.id}] ==
98100
ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
99101

100102
assert [%ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [@ssrc, @rtx_ssrc]}] =
101103
ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
102104

103105
assert [
104-
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: @stream_id},
105-
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: @stream_id}
106+
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^ssrc_value},
107+
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ^ssrc_value}
106108
] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
107109
end
108110

@@ -118,16 +120,16 @@ defmodule ExWebRTC.RTPTransceiverTest do
118120

119121
mline = RTPTransceiver.to_offer_mline(tr, @opts)
120122

121-
assert [%ExSDP.Attribute.MSID{id: "-", app_data: nil}] =
123+
assert [%ExSDP.Attribute.MSID{id: "-", app_data: track.id}] ==
122124
ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
123125

124126
assert [%ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [@ssrc, @rtx_ssrc]}] =
125127
ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
126128

127129
assert [
128-
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: "-"},
129-
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: "-"}
130-
] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
130+
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: "- #{track.id}"},
131+
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: "- #{track.id}"}
132+
] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
131133
end
132134

133135
test "with multiple media streams" do
@@ -145,20 +147,23 @@ defmodule ExWebRTC.RTPTransceiverTest do
145147

146148
mline = RTPTransceiver.to_offer_mline(tr, @opts)
147149

150+
ssrc1_value = ssrc_msid_value(s1_id, track.id)
151+
ssrc2_value = ssrc_msid_value(s2_id, track.id)
152+
148153
assert [
149-
%ExSDP.Attribute.MSID{id: ^s1_id, app_data: nil},
150-
%ExSDP.Attribute.MSID{id: ^s2_id, app_data: nil}
151-
] = ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
154+
%ExSDP.Attribute.MSID{id: s1_id, app_data: track.id},
155+
%ExSDP.Attribute.MSID{id: s2_id, app_data: track.id}
156+
] == ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
152157

153158
assert [%ExSDP.Attribute.SSRCGroup{semantics: "FID", ssrcs: [@ssrc, @rtx_ssrc]}] =
154159
ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
155160

156161
assert [
157-
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^s1_id},
158-
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ^s2_id},
159-
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ^s1_id},
160-
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ^s2_id}
161-
] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
162+
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ssrc1_value},
163+
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: ssrc2_value},
164+
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ssrc1_value},
165+
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: ssrc2_value}
166+
] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
162167
end
163168

164169
test "without codecs" do
@@ -174,12 +179,31 @@ defmodule ExWebRTC.RTPTransceiverTest do
174179

175180
mline = RTPTransceiver.to_offer_mline(tr, @opts)
176181

177-
assert [%ExSDP.Attribute.MSID{id: @stream_id, app_data: nil}] =
182+
assert [%ExSDP.Attribute.MSID{id: @stream_id, app_data: @track.id}] ==
178183
ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
179184

180185
assert [] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
181186
assert [] = ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
182187
end
188+
189+
test "without track" do
190+
tr =
191+
RTPTransceiver.new(:video, nil, @config,
192+
ssrc: @ssrc,
193+
rtx_ssrc: @rtx_ssrc,
194+
direction: :sendrecv
195+
)
196+
197+
mline = RTPTransceiver.to_offer_mline(tr, @opts)
198+
199+
assert [%ExSDP.Attribute.MSID{id: "-", app_data: tr.sender.id}] ==
200+
ExSDP.get_attributes(mline, ExSDP.Attribute.MSID)
201+
202+
assert [
203+
%ExSDP.Attribute.SSRC{id: @ssrc, attribute: "msid", value: "- #{tr.sender.id}"},
204+
%ExSDP.Attribute.SSRC{id: @rtx_ssrc, attribute: "msid", value: "- #{tr.sender.id}"}
205+
] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
206+
end
183207
end
184208

185209
defp test_sender_attrs_present(tr) do
@@ -201,4 +225,6 @@ defmodule ExWebRTC.RTPTransceiverTest do
201225
assert [] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRCGroup)
202226
assert [] == ExSDP.get_attributes(mline, ExSDP.Attribute.SSRC)
203227
end
228+
229+
defp ssrc_msid_value(stream, app_data), do: "#{stream} #{app_data}"
204230
end

0 commit comments

Comments
 (0)