Maintain the order of the m-lines in CreateOffer and CreateAnswer.
The order in the offer follows the order in the current local description.
The order in the answer follows the order in the current offer.

BUG=2395
R=wu@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6828 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/webrtcsdp_unittest.cc b/talk/app/webrtc/webrtcsdp_unittest.cc
index e018034..71ebe0d 100644
--- a/talk/app/webrtc/webrtcsdp_unittest.cc
+++ b/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -312,6 +312,39 @@
     "c=IN IP4 0.0.0.0\r\n"
     "a=x-google-flag:conference\r\n";
 
+static const char kSdpSessionString[] =
+    "v=0\r\n"
+    "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
+    "s=-\r\n"
+    "t=0 0\r\n"
+    "a=msid-semantic: WMS local_stream\r\n";
+
+static const char kSdpAudioString[] =
+    "m=audio 1 RTP/SAVPF 111\r\n"
+    "c=IN IP4 0.0.0.0\r\n"
+    "a=rtcp:1 IN IP4 0.0.0.0\r\n"
+    "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
+    "a=mid:audio_content_name\r\n"
+    "a=sendrecv\r\n"
+    "a=rtpmap:111 opus/48000/2\r\n"
+    "a=ssrc:1 cname:stream_1_cname\r\n"
+    "a=ssrc:1 msid:local_stream audio_track_id_1\r\n"
+    "a=ssrc:1 mslabel:local_stream\r\n"
+    "a=ssrc:1 label:audio_track_id_1\r\n";
+
+static const char kSdpVideoString[] =
+    "m=video 1 RTP/SAVPF 120\r\n"
+    "c=IN IP4 0.0.0.0\r\n"
+    "a=rtcp:1 IN IP4 0.0.0.0\r\n"
+    "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
+    "a=mid:video_content_name\r\n"
+    "a=sendrecv\r\n"
+    "a=rtpmap:120 VP8/90000\r\n"
+    "a=ssrc:2 cname:stream_1_cname\r\n"
+    "a=ssrc:2 msid:local_stream video_track_id_1\r\n"
+    "a=ssrc:2 mslabel:local_stream\r\n"
+    "a=ssrc:2 label:video_track_id_1\r\n";
+
 
 // One candidate reference string as per W3c spec.
 // candidate:<blah> not a=candidate:<blah>CRLF
@@ -2351,3 +2384,48 @@
   EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
             vtinfo->description.connection_role);
 }
+
+// Verifies that the order of the serialized m-lines follows the order of the
+// ContentInfo in SessionDescription, and vise versa for deserialization.
+TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
+  JsepSessionDescription jdesc(kDummyString);
+  const std::string media_content_sdps[3] = {
+    kSdpAudioString,
+    kSdpVideoString,
+    kSdpSctpDataChannelString
+  };
+  const cricket::MediaType media_types[3] = {
+    cricket::MEDIA_TYPE_AUDIO,
+    cricket::MEDIA_TYPE_VIDEO,
+    cricket::MEDIA_TYPE_DATA
+  };
+
+  // Verifies all 6 permutations.
+  for (size_t i = 0; i < 6; ++i) {
+    size_t media_content_in_sdp[3];
+    // The index of the first media content.
+    media_content_in_sdp[0] = i / 2;
+    // The index of the second media content.
+    media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
+    // The index of the third media content.
+    media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
+
+    std::string sdp_string = kSdpSessionString;
+    for (size_t i = 0; i < 3; ++i)
+      sdp_string += media_content_sdps[media_content_in_sdp[i]];
+
+    EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
+    cricket::SessionDescription* desc = jdesc.description();
+    EXPECT_EQ(3u, desc->contents().size());
+
+    for (size_t i = 0; i < 3; ++i) {
+      const cricket::MediaContentDescription* mdesc =
+          static_cast<const cricket::MediaContentDescription*>(
+              desc->contents()[i].description);
+      EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
+    }
+
+    std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
+    EXPECT_EQ(sdp_string, serialized_sdp);
+  }
+}