Ensure mediasession generated offers with RTX contain an RTX ssrc for each video ssrc.

BUG=
R=pthatcher@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/49989004

Cr-Commit-Position: refs/heads/master@{#9210}
diff --git a/talk/session/media/mediasession.cc b/talk/session/media/mediasession.cc
index b728517..b299944 100644
--- a/talk/session/media/mediasession.cc
+++ b/talk/session/media/mediasession.cc
@@ -436,8 +436,8 @@
     StreamParamsVec* current_streams,
     MediaContentDescriptionImpl<C>* content_description,
     const bool add_legacy_stream) {
-  const bool include_rtx_stream =
-    ContainsRtxCodec(content_description->codecs());
+  const bool include_rtx_streams =
+      ContainsRtxCodec(content_description->codecs());
 
   if (streams.empty() && add_legacy_stream) {
     // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
@@ -445,10 +445,10 @@
     if (IsSctp(content_description)) {
       GenerateSctpSids(*current_streams, &ssrcs);
     } else {
-      int num_ssrcs = include_rtx_stream ? 2 : 1;
+      int num_ssrcs = include_rtx_streams ? 2 : 1;
       GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
     }
-    if (include_rtx_stream) {
+    if (include_rtx_streams) {
       content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
       content_description->set_multistream(true);
     } else {
@@ -492,11 +492,15 @@
         SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
         stream_param.ssrc_groups.push_back(group);
       }
-      // Generate an extra ssrc for include_rtx_stream case.
-      if (include_rtx_stream) {
-        std::vector<uint32> rtx_ssrc;
-        GenerateSsrcs(*current_streams, 1, &rtx_ssrc);
-        stream_param.AddFidSsrc(ssrcs[0], rtx_ssrc[0]);
+      // Generate extra ssrcs for include_rtx_streams case.
+      if (include_rtx_streams) {
+        // Generate an RTX ssrc for every ssrc in the group.
+        std::vector<uint32> rtx_ssrcs;
+        GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
+                      &rtx_ssrcs);
+        for (size_t i = 0; i < ssrcs.size(); ++i) {
+          stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
+        }
         content_description->set_multistream(true);
       }
       stream_param.cname = cname;
diff --git a/talk/session/media/mediasession_unittest.cc b/talk/session/media/mediasession_unittest.cc
index f487baa..7fd1d63 100644
--- a/talk/session/media/mediasession_unittest.cc
+++ b/talk/session/media/mediasession_unittest.cc
@@ -1767,6 +1767,47 @@
   EXPECT_EQ(expected_codecs, vcd->codecs());
 }
 
+// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
+// generated for each simulcast ssrc and correctly grouped.
+TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
+  MediaSessionOptions opts;
+  opts.recv_video = true;
+  opts.recv_audio = false;
+
+  // Add simulcast streams.
+  opts.AddSendVideoStream("stream1", "stream1label", 3);
+
+  // Use a single real codec, and then add RTX for it.
+  std::vector<VideoCodec> f1_codecs;
+  f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30, 1));
+  AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
+  f1_.set_video_codecs(f1_codecs);
+
+  // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
+  // is a FID ssrc + grouping for each.
+  rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  VideoContentDescription* desc = static_cast<VideoContentDescription*>(
+      offer->GetContentDescriptionByName(cricket::CN_VIDEO));
+  ASSERT_TRUE(desc != NULL);
+  EXPECT_TRUE(desc->multistream());
+  const StreamParamsVec& streams = desc->streams();
+  // Single stream.
+  ASSERT_EQ(1u, streams.size());
+  // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
+  EXPECT_EQ(6u, streams[0].ssrcs.size());
+  // And should have a SIM group for the simulcast.
+  EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
+  // And a FID group for RTX.
+  EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
+  std::vector<uint32> primary_ssrcs;
+  streams[0].GetPrimarySsrcs(&primary_ssrcs);
+  EXPECT_EQ(3u, primary_ssrcs.size());
+  std::vector<uint32> fid_ssrcs;
+  streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
+  EXPECT_EQ(3u, fid_ssrcs.size());
+}
+
 // Create an updated offer after creating an answer to the original offer and
 // verify that the RTP header extensions that were part of the original answer
 // are not changed in the updated offer.