Remove RTX SSRC when deleting the default receive stream.
BUG=crbug 448632
TEST=New unittest hitting assert without this change.
R=stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/34749004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8059 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc
index 7026417..ec8445e 100644
--- a/talk/media/webrtc/webrtcvideoengine.cc
+++ b/talk/media/webrtc/webrtcvideoengine.cc
@@ -2243,6 +2243,17 @@
}
bool WebRtcVideoMediaChannel::RemoveRecvStreamInternal(uint32 ssrc) {
+ // First remove the RTX SSRC mapping, to include this step even if exiting in
+ // the default receive channel logic below.
+ SsrcMap::iterator rtx_it = rtx_to_primary_ssrc_.begin();
+ while (rtx_it != rtx_to_primary_ssrc_.end()) {
+ if (rtx_it->second == ssrc) {
+ rtx_to_primary_ssrc_.erase(rtx_it++);
+ } else {
+ ++rtx_it;
+ }
+ }
+
WebRtcVideoChannelRecvInfo* recv_channel = GetRecvChannelBySsrc(ssrc);
if (!recv_channel) {
// TODO(perkj): Remove this once BWE works properly across different send
@@ -2263,16 +2274,6 @@
return false;
}
- // Remove any RTX SSRC mappings to this stream.
- SsrcMap::iterator rtx_it = rtx_to_primary_ssrc_.begin();
- while (rtx_it != rtx_to_primary_ssrc_.end()) {
- if (rtx_it->second == ssrc) {
- rtx_to_primary_ssrc_.erase(rtx_it++);
- } else {
- ++rtx_it;
- }
- }
-
int channel_id = recv_channel->channel_id();
if (engine()->vie()->render()->RemoveRenderer(channel_id) != 0) {
LOG_RTCERR1(RemoveRenderer, channel_id);
diff --git a/talk/media/webrtc/webrtcvideoengine_unittest.cc b/talk/media/webrtc/webrtcvideoengine_unittest.cc
index 24e9af2..e98d779 100644
--- a/talk/media/webrtc/webrtcvideoengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine_unittest.cc
@@ -793,6 +793,46 @@
EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num));
}
+// Verify we don't crash when inserting packets after removing the default
+// receive channel.
+TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxWithRemovedDefaultChannel) {
+ EXPECT_TRUE(SetupEngine());
+
+ // Setup one channel with an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
+ EXPECT_TRUE(channel_->AddRecvStream(params));
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]),
+ vie_.GetRemoteRtxSsrc(channel_num));
+
+ // Register codecs.
+ std::vector<cricket::VideoCodec> codec_list;
+ codec_list.push_back(kVP8Codec720p);
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ rtx_codec.SetParam("apt", kVP8Codec.id);
+ codec_list.push_back(rtx_codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
+
+ // Construct a fake RTX packet and verify that it is passed to the
+ // right WebRTC channel.
+ const size_t kDataLength = 12;
+ uint8_t data[kDataLength];
+ memset(data, 0, sizeof(data));
+ data[0] = 0x80;
+ data[1] = rtx_codec.id;
+ rtc::SetBE32(&data[8], kRtxSsrcs1[0]);
+ rtc::Buffer packet(data, kDataLength);
+ rtc::PacketTime packet_time;
+ channel_->OnPacketReceived(&packet, packet_time);
+ EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num));
+
+ // Remove the default channel and insert one more packet.
+ EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcs1[0]));
+ channel_->OnPacketReceived(&packet, packet_time);
+}
+
// Test that RTX packets are routed to the correct video channel.
TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxThreeStreams) {
EXPECT_TRUE(SetupEngine());