Bug 1437741 - Part 1: Expect datachannel m-sections to be last. r?drno draft
authorByron Campen [:bwc] <docfaraday@gmail.com>
Thu, 15 Feb 2018 10:23:49 -0600
changeset 755858 b273c7bb771d6de4d3d12e6545060d3503d173f1
parent 755347 0cd7406c124f4f11eca9cc898bd42a3531456c0b
child 755859 ad3c52c64284abbacb4bbb1d2b20c361aedfbda3
push id99306
push userbcampen@mozilla.com
push dateThu, 15 Feb 2018 21:38:14 +0000
reviewersdrno
bugs1437741
milestone60.0a1
Bug 1437741 - Part 1: Expect datachannel m-sections to be last. r?drno MozReview-Commit-ID: At6HhsLsJQn
media/webrtc/signaling/gtest/jsep_session_unittest.cpp
--- a/media/webrtc/signaling/gtest/jsep_session_unittest.cpp
+++ b/media/webrtc/signaling/gtest/jsep_session_unittest.cpp
@@ -230,16 +230,24 @@ protected:
   void
   AddTracks(JsepSessionImpl& side, AddTrackMagic magic = ADDTRACK_MAGIC)
   {
     // Add tracks.
     if (types.empty()) {
       types = BuildTypes(GetParam());
     }
     AddTracks(side, types, magic);
+
+    // Now, we move datachannel to the end
+    auto it = std::find(types.begin(), types.end(),
+                        SdpMediaSection::kApplication);
+    if (it != types.end()) {
+      types.erase(it);
+      types.push_back(SdpMediaSection::kApplication);
+    }
   }
 
   void
   AddTracks(JsepSessionImpl& side,
             const std::string& mediatypes,
             AddTrackMagic magic = ADDTRACK_MAGIC)
   {
     AddTracks(side, BuildTypes(mediatypes), magic);
@@ -277,27 +285,25 @@ protected:
   {
     std::vector<SdpMediaSection::MediaType> result;
     size_t ptr = 0;
 
     for (;;) {
       size_t comma = mediatypes.find(',', ptr);
       std::string chunk = mediatypes.substr(ptr, comma - ptr);
 
-      SdpMediaSection::MediaType type;
       if (chunk == "audio") {
-        type = SdpMediaSection::kAudio;
+        result.push_back(SdpMediaSection::kAudio);
       } else if (chunk == "video") {
-        type = SdpMediaSection::kVideo;
+        result.push_back(SdpMediaSection::kVideo);
       } else if (chunk == "datachannel") {
-        type = SdpMediaSection::kApplication;
+        result.push_back(SdpMediaSection::kApplication);
       } else {
         MOZ_CRASH();
       }
-      result.push_back(type);
 
       if (comma == std::string::npos)
         break;
       ptr = comma + 1;
     }
 
     return result;
   }
@@ -350,17 +356,17 @@ protected:
       size_t i = transceivers.size();
       if (magic == ADDTRACK_MAGIC) {
         for (i = 0; i < transceivers.size(); ++i) {
           if (transceivers[i]->mSendTrack.GetMediaType() != type) {
             continue;
           }
 
           if (IsNull(transceivers[i]->mSendTrack) ||
-              type == SdpMediaSection::MediaType::kApplication) {
+              transceivers[i]->GetMediaType() == SdpMediaSection::kApplication) {
             break;
           }
         }
       }
 
       if (i == transceivers.size()) {
         side.AddTransceiver(new JsepTransceiver(type));
         MOZ_ASSERT(i < transceivers.size());
@@ -437,16 +443,34 @@ protected:
 
         return transceiver.get();
       }
     }
 
     return nullptr;
   }
 
+  JsepTransceiver*
+  GetTransceiverByLevel(
+      const std::vector<RefPtr<JsepTransceiver>>& transceivers,
+      size_t level) {
+    for (auto& transceiver : transceivers) {
+      if (transceiver->HasLevel() && transceiver->GetLevel() == level) {
+        return transceiver.get();
+      }
+    }
+
+    return nullptr;
+  }
+
+  JsepTransceiver*
+  GetTransceiverByLevel(JsepSession& side, size_t level) {
+    return GetTransceiverByLevel(side.GetTransceivers(), level);
+  }
+
   std::vector<std::string>
   GetMediaStreamIds(const std::vector<JsepTrack>& tracks) const {
     std::vector<std::string> ids;
     for (const auto& track : tracks) {
       // data channels don't have msid's
       if (track.GetMediaType() == SdpMediaSection::kApplication) {
         continue;
       }
@@ -1390,17 +1414,17 @@ protected:
         std::cerr << std::endl;
       }
     }
   }
 
   void
   DumpTransceivers(const JsepSessionImpl& session)
   {
-    for (const auto& transceiver : mSessionAns->GetTransceivers()) {
+    for (const auto& transceiver : session.GetTransceivers()) {
       std::cerr << "Transceiver ";
       if (transceiver->HasLevel()) {
         std::cerr << transceiver->GetLevel() << std::endl;
       } else {
         std::cerr << "<NO LEVEL>" << std::endl;
       }
       if (transceiver->HasBundleLevel()) {
         std::cerr << "(bundle level is " << transceiver->BundleLevel() << ")"
@@ -1887,28 +1911,28 @@ TEST_P(JsepSessionTest, RenegotiationBot
 // The JSEP draft explicitly forbids changing the msid on an m-section, but
 // that is a new restriction that older versions of Firefox do not follow.
 // JS will not see the msid change, since that is filtered out (except for
 // RTCRtpTransceiver.remoteTrackId)
 TEST_P(JsepSessionTest, RenegotiationOffererChangesMsid)
 {
   AddTracks(*mSessionOff);
   AddTracks(*mSessionAns);
-  if (types.front() == SdpMediaSection::kApplication) {
-    return;
-  }
 
   OfferAnswer();
 
   std::string offer = CreateOffer();
   SetLocalOffer(offer);
 
   RefPtr<JsepTransceiver> transceiver =
     GetNegotiatedTransceiver(*mSessionOff, 0);
   ASSERT_TRUE(transceiver);
+  if (transceiver->GetMediaType() == SdpMediaSection::kApplication) {
+    return;
+  }
   std::string streamId = transceiver->mSendTrack.GetStreamIds()[0];
   std::string trackId = transceiver->mSendTrack.GetTrackId();
   std::string msidToReplace("a=msid:");
   msidToReplace += streamId;
   msidToReplace += " ";
   msidToReplace += trackId;
   size_t msidOffset = offer.find(msidToReplace);
   ASSERT_NE(std::string::npos, msidOffset);
@@ -1925,31 +1949,37 @@ TEST_P(JsepSessionTest, RenegotiationOff
 }
 
 // The JSEP draft explicitly forbids changing the msid on an m-section, but
 // that is a new restriction that older versions of Firefox do not follow.
 TEST_P(JsepSessionTest, RenegotiationAnswererChangesMsid)
 {
   AddTracks(*mSessionOff);
   AddTracks(*mSessionAns);
-  if (types.front() == SdpMediaSection::kApplication) {
+
+  OfferAnswer();
+
+  RefPtr<JsepTransceiver> transceiver =
+    GetNegotiatedTransceiver(*mSessionOff, 0);
+  ASSERT_TRUE(transceiver);
+  if (transceiver->GetMediaType() == SdpMediaSection::kApplication) {
     return;
   }
 
-  OfferAnswer();
-
   std::string offer = CreateOffer();
   SetLocalOffer(offer);
   SetRemoteOffer(offer);
   std::string answer = CreateAnswer();
   SetLocalAnswer(answer);
 
-  RefPtr<JsepTransceiver> transceiver =
-    GetNegotiatedTransceiver(*mSessionAns, 0);
+  transceiver = GetNegotiatedTransceiver(*mSessionAns, 0);
   ASSERT_TRUE(transceiver);
+  if (transceiver->GetMediaType() == SdpMediaSection::kApplication) {
+    return;
+  }
   std::string streamId = transceiver->mSendTrack.GetStreamIds()[0];
   std::string trackId = transceiver->mSendTrack.GetTrackId();
   std::string msidToReplace("a=msid:");
   msidToReplace += streamId;
   msidToReplace += " ";
   msidToReplace += trackId;
   size_t msidOffset = answer.find(msidToReplace);
   ASSERT_NE(std::string::npos, msidOffset);
@@ -2176,18 +2206,20 @@ TEST_P(JsepSessionTest, RenegotiationBot
 {
   AddTracks(*mSessionOff);
   AddTracks(*mSessionAns);
 
   if (types.size() < 2) {
     return;
   }
 
-  if (types[0] == SdpMediaSection::kApplication ||
-      types[1] == SdpMediaSection::kApplication) {
+  if (mSessionOff->GetTransceivers()[0]->GetMediaType() ==
+        SdpMediaSection::kApplication ||
+      mSessionOff->GetTransceivers()[1]->GetMediaType() ==
+        SdpMediaSection::kApplication) {
     return;
   }
 
   OfferAnswer();
 
   mSessionOff->GetTransceivers()[0]->Stop();
   mSessionOff->GetTransceivers()[1]->Stop();
 
@@ -2196,17 +2228,18 @@ TEST_P(JsepSessionTest, RenegotiationBot
   ASSERT_TRUE(mSessionAns->GetTransceivers()[1]->IsStopped());
 }
 
 TEST_P(JsepSessionTest, RenegotiationOffererReplacesTrack)
 {
   AddTracks(*mSessionOff);
   AddTracks(*mSessionAns);
 
-  if (types.front() == SdpMediaSection::kApplication) {
+  if (mSessionOff->GetTransceivers()[0]->GetMediaType() ==
+        SdpMediaSection::kApplication) {
     return;
   }
 
   OfferAnswer();
 
   mSessionOff->GetTransceivers()[0]->mSendTrack.UpdateTrackIds(
       std::vector<std::string>(1, "newstream"), "newtrack");
 
@@ -2220,17 +2253,18 @@ TEST_P(JsepSessionTest, RenegotiationOff
       mSessionAns->GetTransceivers()[0]->mRecvTrack.GetStreamIds()[0]);
 }
 
 TEST_P(JsepSessionTest, RenegotiationAnswererReplacesTrack)
 {
   AddTracks(*mSessionOff);
   AddTracks(*mSessionAns);
 
-  if (types.front() == SdpMediaSection::kApplication) {
+  if (mSessionOff->GetTransceivers()[0]->GetMediaType() ==
+        SdpMediaSection::kApplication) {
     return;
   }
 
   OfferAnswer();
 
   mSessionAns->GetTransceivers()[0]->mSendTrack.UpdateTrackIds(
       std::vector<std::string>(1, "newstream"), "newtrack");
 
@@ -2507,52 +2541,56 @@ TEST_P(JsepSessionTest, RenegotiationOff
   AddTracks(*mSessionAns);
 
   if (types.size() < 2) {
     return;
   }
 
   OfferAnswer();
 
-  mSessionOff->GetTransceivers()[0]->Stop();
+  GetTransceiverByLevel(*mSessionOff, 0)->Stop();
 
   std::vector<RefPtr<JsepTransceiver>> origOffererTransceivers
     = DeepCopy(mSessionOff->GetTransceivers());
   std::vector<RefPtr<JsepTransceiver>> origAnswererTransceivers
     = DeepCopy(mSessionAns->GetTransceivers());
 
   OfferAnswer(CHECK_SUCCESS);
 
   auto newOffererTransceivers = mSessionOff->GetTransceivers();
   auto newAnswererTransceivers = mSessionAns->GetTransceivers();
 
   ASSERT_EQ(newOffererTransceivers.size(), newAnswererTransceivers.size());
   ASSERT_EQ(origOffererTransceivers.size(), newOffererTransceivers.size());
   ASSERT_EQ(origAnswererTransceivers.size(), newAnswererTransceivers.size());
 
-  ASSERT_FALSE(newOffererTransceivers[0]->HasBundleLevel());
-  ASSERT_FALSE(newAnswererTransceivers[0]->HasBundleLevel());
-
-  ASSERT_NE(newOffererTransceivers[0]->mTransport.get(),
-            origOffererTransceivers[0]->mTransport.get());
-  ASSERT_NE(newAnswererTransceivers[0]->mTransport.get(),
-            origAnswererTransceivers[0]->mTransport.get());
-
-  ASSERT_EQ(0U, newOffererTransceivers[0]->mTransport->mComponents);
-  ASSERT_EQ(0U, newAnswererTransceivers[0]->mTransport->mComponents);
-
-  for (size_t i = 1; i < newOffererTransceivers.size(); ++i) {
-    ASSERT_TRUE(newOffererTransceivers[i]->HasBundleLevel());
-    ASSERT_TRUE(newAnswererTransceivers[i]->HasBundleLevel());
-    ASSERT_EQ(1U, newOffererTransceivers[i]->BundleLevel());
-    ASSERT_EQ(1U, newAnswererTransceivers[i]->BundleLevel());
-    ASSERT_NE(newOffererTransceivers[0]->mTransport.get(),
-              newOffererTransceivers[i]->mTransport.get());
-    ASSERT_NE(newAnswererTransceivers[0]->mTransport.get(),
-              newAnswererTransceivers[i]->mTransport.get());
+  JsepTransceiver* ot0 = GetTransceiverByLevel(newOffererTransceivers, 0);
+  JsepTransceiver* at0 = GetTransceiverByLevel(newAnswererTransceivers, 0);
+  ASSERT_FALSE(ot0->HasBundleLevel());
+  ASSERT_FALSE(at0->HasBundleLevel());
+
+  ASSERT_NE(
+      ot0->mTransport.get(),
+      GetTransceiverByLevel(origOffererTransceivers, 0)->mTransport.get());
+  ASSERT_NE(
+      at0->mTransport.get(),
+      GetTransceiverByLevel(origAnswererTransceivers, 0)->mTransport.get());
+
+  ASSERT_EQ(0U, ot0->mTransport->mComponents);
+  ASSERT_EQ(0U, at0->mTransport->mComponents);
+
+  for (size_t i = 1; i < types.size() - 1; ++i) {
+    JsepTransceiver* ot = GetTransceiverByLevel(newOffererTransceivers, i);
+    JsepTransceiver* at = GetTransceiverByLevel(newAnswererTransceivers, i);
+    ASSERT_TRUE(ot->HasBundleLevel());
+    ASSERT_TRUE(at->HasBundleLevel());
+    ASSERT_EQ(1U, ot->BundleLevel());
+    ASSERT_EQ(1U, at->BundleLevel());
+    ASSERT_NE(ot0->mTransport.get(), ot->mTransport.get());
+    ASSERT_NE(at0->mTransport.get(), at->mTransport.get());
   }
 }
 
 TEST_P(JsepSessionTest, RenegotiationAnswererDisablesBundleTransport)
 {
   AddTracks(*mSessionOff);
   AddTracks(*mSessionAns);
 
@@ -2562,47 +2600,51 @@ TEST_P(JsepSessionTest, RenegotiationAns
 
   OfferAnswer();
 
   std::vector<RefPtr<JsepTransceiver>> origOffererTransceivers
     = DeepCopy(mSessionOff->GetTransceivers());
   std::vector<RefPtr<JsepTransceiver>> origAnswererTransceivers
     = DeepCopy(mSessionAns->GetTransceivers());
 
-  mSessionAns->GetTransceivers()[0]->Stop();
+  GetTransceiverByLevel(*mSessionAns, 0)->Stop();
 
   OfferAnswer(CHECK_SUCCESS);
 
   auto newOffererTransceivers = mSessionOff->GetTransceivers();
   auto newAnswererTransceivers = mSessionAns->GetTransceivers();
 
   ASSERT_EQ(newOffererTransceivers.size(), newAnswererTransceivers.size());
   ASSERT_EQ(origOffererTransceivers.size(), newOffererTransceivers.size());
   ASSERT_EQ(origAnswererTransceivers.size(), newAnswererTransceivers.size());
 
-  ASSERT_FALSE(newOffererTransceivers[0]->HasBundleLevel());
-  ASSERT_FALSE(newAnswererTransceivers[0]->HasBundleLevel());
-
-  ASSERT_NE(newOffererTransceivers[0]->mTransport.get(),
-            origOffererTransceivers[0]->mTransport.get());
-  ASSERT_NE(newAnswererTransceivers[0]->mTransport.get(),
-            origAnswererTransceivers[0]->mTransport.get());
-
-  ASSERT_EQ(0U, newOffererTransceivers[0]->mTransport->mComponents);
-  ASSERT_EQ(0U, newAnswererTransceivers[0]->mTransport->mComponents);
+  JsepTransceiver* ot0 = GetTransceiverByLevel(newOffererTransceivers, 0);
+  JsepTransceiver* at0 = GetTransceiverByLevel(newAnswererTransceivers, 0);
+  ASSERT_FALSE(ot0->HasBundleLevel());
+  ASSERT_FALSE(at0->HasBundleLevel());
+
+  ASSERT_NE(
+      ot0->mTransport.get(),
+      GetTransceiverByLevel(origOffererTransceivers, 0)->mTransport.get());
+  ASSERT_NE(
+      at0->mTransport.get(),
+      GetTransceiverByLevel(origAnswererTransceivers, 0)->mTransport.get());
+
+  ASSERT_EQ(0U, ot0->mTransport->mComponents);
+  ASSERT_EQ(0U, at0->mTransport->mComponents);
 
   for (size_t i = 1; i < newOffererTransceivers.size(); ++i) {
-    ASSERT_TRUE(newOffererTransceivers[i]->HasBundleLevel());
-    ASSERT_TRUE(newAnswererTransceivers[i]->HasBundleLevel());
-    ASSERT_EQ(1U, newOffererTransceivers[i]->BundleLevel());
-    ASSERT_EQ(1U, newAnswererTransceivers[i]->BundleLevel());
-    ASSERT_NE(newOffererTransceivers[0]->mTransport.get(),
-              newOffererTransceivers[i]->mTransport.get());
-    ASSERT_NE(newAnswererTransceivers[0]->mTransport.get(),
-              newAnswererTransceivers[i]->mTransport.get());
+    JsepTransceiver* ot = GetTransceiverByLevel(newOffererTransceivers, i);
+    JsepTransceiver* at = GetTransceiverByLevel(newAnswererTransceivers, i);
+    ASSERT_TRUE(ot->HasBundleLevel());
+    ASSERT_TRUE(at->HasBundleLevel());
+    ASSERT_EQ(1U, ot->BundleLevel());
+    ASSERT_EQ(1U, at->BundleLevel());
+    ASSERT_NE(ot0->mTransport.get(), ot->mTransport.get());
+    ASSERT_NE(at0->mTransport.get(), at->mTransport.get());
   }
 }
 
 TEST_P(JsepSessionTest, ParseRejectsBadMediaFormat)
 {
   AddTracks(*mSessionOff);
   if (types.front() == SdpMediaSection::MediaType::kApplication) {
     return;
@@ -4028,17 +4070,19 @@ TEST_F(JsepSessionTest, TestH264LevelAsy
   // elsewhere
 }
 
 TEST_P(JsepSessionTest, TestRejectMline)
 {
   // We need to do this before adding tracks
   types = BuildTypes(GetParam());
 
-  switch (types.front()) {
+  SdpMediaSection::MediaType type = types.front();
+
+  switch (type) {
     case SdpMediaSection::kAudio:
       // Sabotage audio
       EnsureNegotiationFailure(types.front(), "opus");
       break;
     case SdpMediaSection::kVideo:
       // Sabotage video
       EnsureNegotiationFailure(types.front(), "H264");
       break;
@@ -4061,33 +4105,33 @@ TEST_P(JsepSessionTest, TestRejectMline)
 
   UniquePtr<Sdp> outputSdp(Parse(answer));
   ASSERT_TRUE(!!outputSdp);
 
   ASSERT_NE(0U, outputSdp->GetMediaSectionCount());
   SdpMediaSection* failed_section = nullptr;
 
   for (size_t i = 0; i < outputSdp->GetMediaSectionCount(); ++i) {
-    if (outputSdp->GetMediaSection(i).GetMediaType() == types.front()) {
+    if (outputSdp->GetMediaSection(i).GetMediaType() == type) {
       failed_section = &outputSdp->GetMediaSection(i);
     }
   }
 
   ASSERT_TRUE(failed_section) << "Failed type was entirely absent from SDP";
   auto& failed_attrs = failed_section->GetAttributeList();
   ASSERT_EQ(SdpDirectionAttribute::kInactive, failed_attrs.GetDirection());
   ASSERT_EQ(0U, failed_section->GetPort());
 
   mSessionAns->SetLocalDescription(kJsepSdpAnswer, answer);
   mSessionOff->SetRemoteDescription(kJsepSdpAnswer, answer);
 
-  size_t numRejected = std::count(types.begin(), types.end(), types.front());
+  size_t numRejected = std::count(types.begin(), types.end(), type);
   size_t numAccepted = types.size() - numRejected;
 
-  if (types.front() == SdpMediaSection::MediaType::kApplication) {
+  if (type == SdpMediaSection::MediaType::kApplication) {
     ASSERT_TRUE(GetDatachannelTransceiver(*mSessionOff));
     ASSERT_FALSE(
         GetDatachannelTransceiver(*mSessionOff)->mRecvTrack.GetActive());
     ASSERT_TRUE(GetDatachannelTransceiver(*mSessionAns));
     ASSERT_FALSE(
         GetDatachannelTransceiver(*mSessionAns)->mRecvTrack.GetActive());
   } else {
     ASSERT_EQ(types.size(), GetLocalTracks(*mSessionOff).size());