TrackMediaInfoMap: Allow same SSRC for send and receive side.
Running video loopback on https://appr.tc/ revealed that it is possible
to use the same SSRC for a local and remote audio or video track. This
caused a DCHECK crash. The constructor of TrackMediaInfoMap is updated
to support this mapping and the unittest is updated (moved and modified
a test from being a death test to being a non-death test).
I've verified that this fixes the bug.
BUG=chromium:693087
Review-Url: https://codereview.webrtc.org/2703783002
Cr-Commit-Position: refs/heads/master@{#16713}
diff --git a/webrtc/pc/trackmediainfomap.cc b/webrtc/pc/trackmediainfomap.cc
index d296c7f..33880b9 100644
--- a/webrtc/pc/trackmediainfomap.cc
+++ b/webrtc/pc/trackmediainfomap.cc
@@ -31,10 +31,14 @@
void GetAudioAndVideoTrackBySsrc(
const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& rtp_senders,
const std::vector<rtc::scoped_refptr<RtpReceiverInterface>>& rtp_receivers,
- std::map<uint32_t, AudioTrackInterface*>* audio_track_by_ssrc,
- std::map<uint32_t, VideoTrackInterface*>* video_track_by_ssrc) {
- RTC_DCHECK(audio_track_by_ssrc->empty());
- RTC_DCHECK(video_track_by_ssrc->empty());
+ std::map<uint32_t, AudioTrackInterface*>* local_audio_track_by_ssrc,
+ std::map<uint32_t, VideoTrackInterface*>* local_video_track_by_ssrc,
+ std::map<uint32_t, AudioTrackInterface*>* remote_audio_track_by_ssrc,
+ std::map<uint32_t, VideoTrackInterface*>* remote_video_track_by_ssrc) {
+ RTC_DCHECK(local_audio_track_by_ssrc->empty());
+ RTC_DCHECK(local_video_track_by_ssrc->empty());
+ RTC_DCHECK(remote_audio_track_by_ssrc->empty());
+ RTC_DCHECK(remote_video_track_by_ssrc->empty());
// TODO(hbos): RTP senders/receivers uses a proxy to the signaling thread, and
// our sender/receiver implementations invokes on the worker thread. (This
// means one thread jump if on signaling thread and two thread jumps if on any
@@ -53,13 +57,15 @@
uint32_t ssrc = rtp_sender->ssrc();
if (ssrc != 0) {
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- RTC_DCHECK(audio_track_by_ssrc->find(ssrc) ==
- audio_track_by_ssrc->end());
- (*audio_track_by_ssrc)[ssrc] = static_cast<AudioTrackInterface*>(track);
+ RTC_DCHECK(local_audio_track_by_ssrc->find(ssrc) ==
+ local_audio_track_by_ssrc->end());
+ (*local_audio_track_by_ssrc)[ssrc] =
+ static_cast<AudioTrackInterface*>(track);
} else {
- RTC_DCHECK(video_track_by_ssrc->find(ssrc) ==
- video_track_by_ssrc->end());
- (*video_track_by_ssrc)[ssrc] = static_cast<VideoTrackInterface*>(track);
+ RTC_DCHECK(local_video_track_by_ssrc->find(ssrc) ==
+ local_video_track_by_ssrc->end());
+ (*local_video_track_by_ssrc)[ssrc] =
+ static_cast<VideoTrackInterface*>(track);
}
}
}
@@ -77,14 +83,14 @@
continue;
}
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- RTC_DCHECK(audio_track_by_ssrc->find(*encoding.ssrc) ==
- audio_track_by_ssrc->end());
- (*audio_track_by_ssrc)[*encoding.ssrc] =
+ RTC_DCHECK(remote_audio_track_by_ssrc->find(*encoding.ssrc) ==
+ remote_audio_track_by_ssrc->end());
+ (*remote_audio_track_by_ssrc)[*encoding.ssrc] =
static_cast<AudioTrackInterface*>(track);
} else {
- RTC_DCHECK(video_track_by_ssrc->find(*encoding.ssrc) ==
- video_track_by_ssrc->end());
- (*video_track_by_ssrc)[*encoding.ssrc] =
+ RTC_DCHECK(remote_video_track_by_ssrc->find(*encoding.ssrc) ==
+ remote_video_track_by_ssrc->end());
+ (*remote_video_track_by_ssrc)[*encoding.ssrc] =
static_cast<VideoTrackInterface*>(track);
}
}
@@ -100,14 +106,20 @@
const std::vector<rtc::scoped_refptr<RtpReceiverInterface>>& rtp_receivers)
: voice_media_info_(std::move(voice_media_info)),
video_media_info_(std::move(video_media_info)) {
- std::map<uint32_t, AudioTrackInterface*> audio_track_by_ssrc;
- std::map<uint32_t, VideoTrackInterface*> video_track_by_ssrc;
- GetAudioAndVideoTrackBySsrc(rtp_senders, rtp_receivers, &audio_track_by_ssrc,
- &video_track_by_ssrc);
+ std::map<uint32_t, AudioTrackInterface*> local_audio_track_by_ssrc;
+ std::map<uint32_t, VideoTrackInterface*> local_video_track_by_ssrc;
+ std::map<uint32_t, AudioTrackInterface*> remote_audio_track_by_ssrc;
+ std::map<uint32_t, VideoTrackInterface*> remote_video_track_by_ssrc;
+ GetAudioAndVideoTrackBySsrc(rtp_senders,
+ rtp_receivers,
+ &local_audio_track_by_ssrc,
+ &local_video_track_by_ssrc,
+ &remote_audio_track_by_ssrc,
+ &remote_video_track_by_ssrc);
if (voice_media_info_) {
for (auto& sender_info : voice_media_info_->senders) {
AudioTrackInterface* associated_track =
- FindValueOrNull(audio_track_by_ssrc, sender_info.ssrc());
+ FindValueOrNull(local_audio_track_by_ssrc, sender_info.ssrc());
if (associated_track) {
// One sender is associated with at most one track.
// One track may be associated with multiple senders.
@@ -117,7 +129,7 @@
}
for (auto& receiver_info : voice_media_info_->receivers) {
AudioTrackInterface* associated_track =
- FindValueOrNull(audio_track_by_ssrc, receiver_info.ssrc());
+ FindValueOrNull(remote_audio_track_by_ssrc, receiver_info.ssrc());
if (associated_track) {
// One receiver is associated with at most one track, which is uniquely
// associated with that receiver.
@@ -131,7 +143,7 @@
if (video_media_info_) {
for (auto& sender_info : video_media_info_->senders) {
VideoTrackInterface* associated_track =
- FindValueOrNull(video_track_by_ssrc, sender_info.ssrc());
+ FindValueOrNull(local_video_track_by_ssrc, sender_info.ssrc());
if (associated_track) {
// One sender is associated with at most one track.
// One track may be associated with multiple senders.
@@ -141,7 +153,7 @@
}
for (auto& receiver_info : video_media_info_->receivers) {
VideoTrackInterface* associated_track =
- FindValueOrNull(video_track_by_ssrc, receiver_info.ssrc());
+ FindValueOrNull(remote_video_track_by_ssrc, receiver_info.ssrc());
if (associated_track) {
// One receiver is associated with at most one track, which is uniquely
// associated with that receiver.
diff --git a/webrtc/pc/trackmediainfomap_unittest.cc b/webrtc/pc/trackmediainfomap_unittest.cc
index 2786214..0743680 100644
--- a/webrtc/pc/trackmediainfomap_unittest.cc
+++ b/webrtc/pc/trackmediainfomap_unittest.cc
@@ -345,6 +345,43 @@
local_video_track_.get());
}
+// SSRCs can be reused for send and receive in loopback.
+TEST_F(TrackMediaInfoMapTest, SingleSenderReceiverPerTrackWithSsrcNotUnique) {
+ AddRtpSenderWithSsrcs({1}, local_audio_track_);
+ AddRtpReceiverWithSsrcs({1}, remote_audio_track_);
+ AddRtpSenderWithSsrcs({2}, local_video_track_);
+ AddRtpReceiverWithSsrcs({2}, remote_video_track_);
+ CreateMap();
+
+ // Local audio track <-> RTP audio senders
+ ASSERT_TRUE(map_->GetVoiceSenderInfos(*local_audio_track_));
+ EXPECT_EQ(
+ *map_->GetVoiceSenderInfos(*local_audio_track_),
+ std::vector<cricket::VoiceSenderInfo*>({&voice_media_info_->senders[0]}));
+ EXPECT_EQ(map_->GetAudioTrack(voice_media_info_->senders[0]),
+ local_audio_track_.get());
+
+ // Remote audio track <-> RTP audio receiver
+ EXPECT_EQ(map_->GetVoiceReceiverInfo(*remote_audio_track_),
+ &voice_media_info_->receivers[0]);
+ EXPECT_EQ(map_->GetAudioTrack(voice_media_info_->receivers[0]),
+ remote_audio_track_.get());
+
+ // Local video track <-> RTP video senders
+ ASSERT_TRUE(map_->GetVideoSenderInfos(*local_video_track_));
+ EXPECT_EQ(
+ *map_->GetVideoSenderInfos(*local_video_track_),
+ std::vector<cricket::VideoSenderInfo*>({&video_media_info_->senders[0]}));
+ EXPECT_EQ(map_->GetVideoTrack(video_media_info_->senders[0]),
+ local_video_track_.get());
+
+ // Remote video track <-> RTP video receiver
+ EXPECT_EQ(map_->GetVideoReceiverInfo(*remote_video_track_),
+ &video_media_info_->receivers[0]);
+ EXPECT_EQ(map_->GetVideoTrack(video_media_info_->receivers[0]),
+ remote_video_track_.get());
+}
+
// Death tests.
// Disabled on Android because death tests misbehave on Android, see
// base/test/gtest_util.h.
@@ -368,15 +405,6 @@
EXPECT_DEATH(CreateMap(), "");
}
-TEST_F(TrackMediaInfoMapDeathTest,
- SingleSenderReceiverPerTrackWithSsrcNotUnique) {
- AddRtpSenderWithSsrcs({1}, local_audio_track_);
- AddRtpReceiverWithSsrcs({1}, remote_audio_track_);
- AddRtpSenderWithSsrcs({2}, local_video_track_);
- AddRtpReceiverWithSsrcs({2}, remote_video_track_);
- EXPECT_DEATH(CreateMap(), "");
-}
-
#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
} // namespace webrtc