Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2011, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <set>
     29 #include <string>
     30 #include <vector>
     31 
     32 #include "talk/app/webrtc/jsepsessiondescription.h"
     33 #include "talk/app/webrtc/webrtcsdp.h"
     34 #include "talk/base/gunit.h"
     35 #include "talk/base/logging.h"
     36 #include "talk/base/messagedigest.h"
     37 #include "talk/base/scoped_ptr.h"
     38 #include "talk/base/sslfingerprint.h"
     39 #include "talk/base/stringencode.h"
     40 #include "talk/base/stringutils.h"
     41 #include "talk/media/base/constants.h"
     42 #include "talk/p2p/base/constants.h"
     43 #include "talk/session/media/mediasession.h"
     44 
     45 using cricket::AudioCodec;
     46 using cricket::AudioContentDescription;
     47 using cricket::Candidate;
     48 using cricket::ContentInfo;
     49 using cricket::CryptoParams;
     50 using cricket::ContentGroup;
     51 using cricket::DataCodec;
     52 using cricket::DataContentDescription;
     53 using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
     54 using cricket::ICE_CANDIDATE_COMPONENT_RTP;
     55 using cricket::kFecSsrcGroupSemantics;
     56 using cricket::LOCAL_PORT_TYPE;
     57 using cricket::NS_JINGLE_DRAFT_SCTP;
     58 using cricket::NS_JINGLE_ICE_UDP;
     59 using cricket::NS_JINGLE_RTP;
     60 using cricket::RtpHeaderExtension;
     61 using cricket::RELAY_PORT_TYPE;
     62 using cricket::SessionDescription;
     63 using cricket::StreamParams;
     64 using cricket::STUN_PORT_TYPE;
     65 using cricket::TransportDescription;
     66 using cricket::TransportInfo;
     67 using cricket::VideoCodec;
     68 using cricket::VideoContentDescription;
     69 using webrtc::IceCandidateCollection;
     70 using webrtc::IceCandidateInterface;
     71 using webrtc::JsepIceCandidate;
     72 using webrtc::JsepSessionDescription;
     73 using webrtc::SdpParseError;
     74 using webrtc::SessionDescriptionInterface;
     75 
     76 typedef std::vector<AudioCodec> AudioCodecs;
     77 typedef std::vector<Candidate> Candidates;
     78 
     79 static const uint32 kDefaultSctpPort = 5000;
     80 static const char kSessionTime[] = "t=0 0\r\n";
     81 static const uint32 kCandidatePriority = 2130706432U;  // pref = 1.0
     82 static const char kCandidateUfragVoice[] = "ufrag_voice";
     83 static const char kCandidatePwdVoice[] = "pwd_voice";
     84 static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
     85 static const char kCandidateUfragVideo[] = "ufrag_video";
     86 static const char kCandidatePwdVideo[] = "pwd_video";
     87 static const char kCandidateUfragData[] = "ufrag_data";
     88 static const char kCandidatePwdData[] = "pwd_data";
     89 static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
     90 static const uint32 kCandidateGeneration = 2;
     91 static const char kCandidateFoundation1[] = "a0+B/1";
     92 static const char kCandidateFoundation2[] = "a0+B/2";
     93 static const char kCandidateFoundation3[] = "a0+B/3";
     94 static const char kCandidateFoundation4[] = "a0+B/4";
     95 static const char kAttributeCryptoVoice[] =
     96     "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
     97     "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
     98     "dummy_session_params\r\n";
     99 static const char kAttributeCryptoVideo[] =
    100     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    101     "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
    102 static const char kFingerprint[] = "a=fingerprint:sha-1 "
    103     "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n";
    104 static const int kExtmapId = 1;
    105 static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
    106 static const char kExtmap[] =
    107     "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
    108 static const char kExtmapWithDirectionAndAttribute[] =
    109     "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
    110 
    111 static const uint8 kIdentityDigest[] = {0x4A, 0xAD, 0xB9, 0xB1,
    112                                         0x3F, 0x82, 0x18, 0x3B,
    113                                         0x54, 0x02, 0x12, 0xDF,
    114                                         0x3E, 0x5D, 0x49, 0x6B,
    115                                         0x19, 0xE5, 0x7C, 0xAB};
    116 
    117 struct CodecParams {
    118   int max_ptime;
    119   int ptime;
    120   int min_ptime;
    121   int sprop_stereo;
    122   int stereo;
    123   int useinband;
    124   int maxaveragebitrate;
    125 };
    126 
    127 // Reference sdp string
    128 static const char kSdpFullString[] =
    129     "v=0\r\n"
    130     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
    131     "s=-\r\n"
    132     "t=0 0\r\n"
    133     "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
    134     "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
    135     "c=IN IP4 74.125.127.126\r\n"
    136     "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
    137     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
    138     "generation 2\r\n"
    139     "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
    140     "generation 2\r\n"
    141     "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
    142     "generation 2\r\n"
    143     "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
    144     "generation 2\r\n"
    145     "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
    146     "raddr 192.168.1.5 rport 2346 "
    147     "generation 2\r\n"
    148     "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
    149     "raddr 192.168.1.5 rport 2348 "
    150     "generation 2\r\n"
    151     "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
    152     "a=mid:audio_content_name\r\n"
    153     "a=sendrecv\r\n"
    154     "a=rtcp-mux\r\n"
    155     "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
    156     "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
    157     "dummy_session_params\r\n"
    158     "a=rtpmap:111 opus/48000/2\r\n"
    159     "a=rtpmap:103 ISAC/16000\r\n"
    160     "a=rtpmap:104 CELT/32000/2\r\n"
    161     "a=ssrc:1 cname:stream_1_cname\r\n"
    162     "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
    163     "a=ssrc:1 mslabel:local_stream_1\r\n"
    164     "a=ssrc:1 label:audio_track_id_1\r\n"
    165     "a=ssrc:4 cname:stream_2_cname\r\n"
    166     "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
    167     "a=ssrc:4 mslabel:local_stream_2\r\n"
    168     "a=ssrc:4 label:audio_track_id_2\r\n"
    169     "m=video 3457 RTP/SAVPF 120\r\n"
    170     "c=IN IP4 74.125.224.39\r\n"
    171     "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
    172     "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
    173     "generation 2\r\n"
    174     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
    175     "generation 2\r\n"
    176     "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
    177     "generation 2\r\n"
    178     "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
    179     "generation 2\r\n"
    180     "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
    181     "generation 2\r\n"
    182     "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
    183     "generation 2\r\n"
    184     "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
    185     "a=mid:video_content_name\r\n"
    186     "a=sendrecv\r\n"
    187     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    188     "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
    189     "a=rtpmap:120 VP8/90000\r\n"
    190     "a=ssrc:2 cname:stream_1_cname\r\n"
    191     "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
    192     "a=ssrc:2 mslabel:local_stream_1\r\n"
    193     "a=ssrc:2 label:video_track_id_1\r\n"
    194     "a=ssrc:3 cname:stream_1_cname\r\n"
    195     "a=ssrc:3 msid:local_stream_1 video_track_id_2\r\n"
    196     "a=ssrc:3 mslabel:local_stream_1\r\n"
    197     "a=ssrc:3 label:video_track_id_2\r\n"
    198     "a=ssrc-group:FEC 5 6\r\n"
    199     "a=ssrc:5 cname:stream_2_cname\r\n"
    200     "a=ssrc:5 msid:local_stream_2 video_track_id_3\r\n"
    201     "a=ssrc:5 mslabel:local_stream_2\r\n"
    202     "a=ssrc:5 label:video_track_id_3\r\n"
    203     "a=ssrc:6 cname:stream_2_cname\r\n"
    204     "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
    205     "a=ssrc:6 mslabel:local_stream_2\r\n"
    206     "a=ssrc:6 label:video_track_id_3\r\n";
    207 
    208 // SDP reference string without the candidates.
    209 static const char kSdpString[] =
    210     "v=0\r\n"
    211     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
    212     "s=-\r\n"
    213     "t=0 0\r\n"
    214     "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
    215     "m=audio 1 RTP/SAVPF 111 103 104\r\n"
    216     "c=IN IP4 0.0.0.0\r\n"
    217     "a=rtcp:1 IN IP4 0.0.0.0\r\n"
    218     "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
    219     "a=mid:audio_content_name\r\n"
    220     "a=sendrecv\r\n"
    221     "a=rtcp-mux\r\n"
    222     "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
    223     "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
    224     "dummy_session_params\r\n"
    225     "a=rtpmap:111 opus/48000/2\r\n"
    226     "a=rtpmap:103 ISAC/16000\r\n"
    227     "a=rtpmap:104 CELT/32000/2\r\n"
    228     "a=ssrc:1 cname:stream_1_cname\r\n"
    229     "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
    230     "a=ssrc:1 mslabel:local_stream_1\r\n"
    231     "a=ssrc:1 label:audio_track_id_1\r\n"
    232     "a=ssrc:4 cname:stream_2_cname\r\n"
    233     "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
    234     "a=ssrc:4 mslabel:local_stream_2\r\n"
    235     "a=ssrc:4 label:audio_track_id_2\r\n"
    236     "m=video 1 RTP/SAVPF 120\r\n"
    237     "c=IN IP4 0.0.0.0\r\n"
    238     "a=rtcp:1 IN IP4 0.0.0.0\r\n"
    239     "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
    240     "a=mid:video_content_name\r\n"
    241     "a=sendrecv\r\n"
    242     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    243     "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
    244     "a=rtpmap:120 VP8/90000\r\n"
    245     "a=ssrc:2 cname:stream_1_cname\r\n"
    246     "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
    247     "a=ssrc:2 mslabel:local_stream_1\r\n"
    248     "a=ssrc:2 label:video_track_id_1\r\n"
    249     "a=ssrc:3 cname:stream_1_cname\r\n"
    250     "a=ssrc:3 msid:local_stream_1 video_track_id_2\r\n"
    251     "a=ssrc:3 mslabel:local_stream_1\r\n"
    252     "a=ssrc:3 label:video_track_id_2\r\n"
    253     "a=ssrc-group:FEC 5 6\r\n"
    254     "a=ssrc:5 cname:stream_2_cname\r\n"
    255     "a=ssrc:5 msid:local_stream_2 video_track_id_3\r\n"
    256     "a=ssrc:5 mslabel:local_stream_2\r\n"
    257     "a=ssrc:5 label:video_track_id_3\r\n"
    258     "a=ssrc:6 cname:stream_2_cname\r\n"
    259     "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
    260     "a=ssrc:6 mslabel:local_stream_2\r\n"
    261     "a=ssrc:6 label:video_track_id_3\r\n";
    262 
    263 static const char kSdpRtpDataChannelString[] =
    264     "m=application 1 RTP/SAVPF 101\r\n"
    265     "c=IN IP4 0.0.0.0\r\n"
    266     "a=rtcp:1 IN IP4 0.0.0.0\r\n"
    267     "a=ice-ufrag:ufrag_data\r\n"
    268     "a=ice-pwd:pwd_data\r\n"
    269     "a=mid:data_content_name\r\n"
    270     "a=sendrecv\r\n"
    271     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    272     "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5\r\n"
    273     "a=rtpmap:101 google-data/90000\r\n"
    274     "a=ssrc:10 cname:data_channel_cname\r\n"
    275     "a=ssrc:10 msid:data_channel data_channeld0\r\n"
    276     "a=ssrc:10 mslabel:data_channel\r\n"
    277     "a=ssrc:10 label:data_channeld0\r\n";
    278 
    279 static const char kSdpSctpDataChannelString[] =
    280     "m=application 1 DTLS/SCTP 5000\r\n"
    281     "c=IN IP4 0.0.0.0\r\n"
    282     "a=ice-ufrag:ufrag_data\r\n"
    283     "a=ice-pwd:pwd_data\r\n"
    284     "a=mid:data_content_name\r\n"
    285     "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
    286 
    287 static const char kSdpSctpDataChannelWithCandidatesString[] =
    288     "m=application 2345 DTLS/SCTP 5000\r\n"
    289     "c=IN IP4 74.125.127.126\r\n"
    290     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
    291     "generation 2\r\n"
    292     "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
    293     "generation 2\r\n"
    294     "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
    295     "raddr 192.168.1.5 rport 2346 "
    296     "generation 2\r\n"
    297     "a=ice-ufrag:ufrag_data\r\n"
    298     "a=ice-pwd:pwd_data\r\n"
    299     "a=mid:data_content_name\r\n"
    300     "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
    301 
    302 
    303 // One candidate reference string as per W3c spec.
    304 // candidate:<blah> not a=candidate:<blah>CRLF
    305 static const char kRawCandidate[] =
    306     "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
    307 // One candidate reference string.
    308 static const char kSdpOneCandidate[] =
    309     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
    310     "generation 2\r\n";
    311 
    312 // One candidate reference string.
    313 static const char kSdpOneCandidateOldFormat[] =
    314     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
    315     " eth0 username user_rtp password password_rtp generation 2\r\n";
    316 
    317 // Session id and version
    318 static const char kSessionId[] = "18446744069414584320";
    319 static const char kSessionVersion[] = "18446462598732840960";
    320 
    321 // Ice options
    322 static const char kIceOption1[] = "iceoption1";
    323 static const char kIceOption2[] = "iceoption2";
    324 static const char kIceOption3[] = "iceoption3";
    325 
    326 // Content name
    327 static const char kAudioContentName[] = "audio_content_name";
    328 static const char kVideoContentName[] = "video_content_name";
    329 static const char kDataContentName[] = "data_content_name";
    330 
    331 // MediaStream 1
    332 static const char kStreamLabel1[] = "local_stream_1";
    333 static const char kStream1Cname[] = "stream_1_cname";
    334 static const char kAudioTrackId1[] = "audio_track_id_1";
    335 static const uint32 kAudioTrack1Ssrc = 1;
    336 static const char kVideoTrackId1[] = "video_track_id_1";
    337 static const uint32 kVideoTrack1Ssrc = 2;
    338 static const char kVideoTrackId2[] = "video_track_id_2";
    339 static const uint32 kVideoTrack2Ssrc = 3;
    340 
    341 // MediaStream 2
    342 static const char kStreamLabel2[] = "local_stream_2";
    343 static const char kStream2Cname[] = "stream_2_cname";
    344 static const char kAudioTrackId2[] = "audio_track_id_2";
    345 static const uint32 kAudioTrack2Ssrc = 4;
    346 static const char kVideoTrackId3[] = "video_track_id_3";
    347 static const uint32 kVideoTrack3Ssrc = 5;
    348 static const uint32 kVideoTrack4Ssrc = 6;
    349 
    350 // DataChannel
    351 static const char kDataChannelLabel[] = "data_channel";
    352 static const char kDataChannelMsid[] = "data_channeld0";
    353 static const char kDataChannelCname[] = "data_channel_cname";
    354 static const uint32 kDataChannelSsrc = 10;
    355 
    356 // Candidate
    357 static const char kDummyMid[] = "dummy_mid";
    358 static const int kDummyIndex = 123;
    359 
    360 // Misc
    361 static const char kDummyString[] = "dummy";
    362 
    363 // Helper functions
    364 
    365 static bool SdpDeserialize(const std::string& message,
    366                            JsepSessionDescription* jdesc) {
    367   return webrtc::SdpDeserialize(message, jdesc, NULL);
    368 }
    369 
    370 static bool SdpDeserializeCandidate(const std::string& message,
    371                                     JsepIceCandidate* candidate) {
    372   return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
    373 }
    374 
    375 // Add some extra |newlines| to the |message| after |line|.
    376 static void InjectAfter(const std::string& line,
    377                         const std::string& newlines,
    378                         std::string* message) {
    379   const std::string tmp = line + newlines;
    380   talk_base::replace_substrs(line.c_str(), line.length(),
    381                              tmp.c_str(), tmp.length(), message);
    382 }
    383 
    384 static void Replace(const std::string& line,
    385                     const std::string& newlines,
    386                     std::string* message) {
    387   talk_base::replace_substrs(line.c_str(), line.length(),
    388                              newlines.c_str(), newlines.length(), message);
    389 }
    390 
    391 static void ReplaceAndTryToParse(const char* search, const char* replace) {
    392   JsepSessionDescription desc(kDummyString);
    393   std::string sdp = kSdpFullString;
    394   Replace(search, replace, &sdp);
    395   SdpParseError error;
    396   bool ret = webrtc::SdpDeserialize(sdp, &desc, &error);
    397   EXPECT_FALSE(ret);
    398   EXPECT_NE(std::string::npos, error.line.find(replace));
    399 }
    400 
    401 static void ReplaceDirection(cricket::MediaContentDirection direction,
    402                              std::string* message) {
    403   std::string new_direction;
    404   switch (direction) {
    405     case cricket::MD_INACTIVE:
    406       new_direction = "a=inactive";
    407       break;
    408     case cricket::MD_SENDONLY:
    409       new_direction = "a=sendonly";
    410       break;
    411     case cricket::MD_RECVONLY:
    412       new_direction = "a=recvonly";
    413       break;
    414     case cricket::MD_SENDRECV:
    415     default:
    416       new_direction = "a=sendrecv";
    417       break;
    418   }
    419   Replace("a=sendrecv", new_direction, message);
    420 }
    421 
    422 static void ReplaceRejected(bool audio_rejected, bool video_rejected,
    423                             std::string* message) {
    424   if (audio_rejected) {
    425     Replace("m=audio 2345", "m=audio 0", message);
    426   }
    427   if (video_rejected) {
    428     Replace("m=video 3457", "m=video 0", message);
    429   }
    430 }
    431 
    432 // WebRtcSdpTest
    433 
    434 class WebRtcSdpTest : public testing::Test {
    435  public:
    436   WebRtcSdpTest()
    437      : jdesc_(kDummyString) {
    438     // AudioContentDescription
    439     audio_desc_ = CreateAudioContentDescription();
    440     AudioCodec opus(111, "opus", 48000, 0, 2, 3);
    441     audio_desc_->AddCodec(opus);
    442     audio_desc_->AddCodec(AudioCodec(103, "ISAC", 16000, 32000, 1, 2));
    443     audio_desc_->AddCodec(AudioCodec(104, "CELT", 32000, 0, 2, 1));
    444     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_desc_);
    445 
    446     // VideoContentDescription
    447     talk_base::scoped_ptr<VideoContentDescription> video(
    448         new VideoContentDescription());
    449     video_desc_ = video.get();
    450     StreamParams video_stream1;
    451     video_stream1.id = kVideoTrackId1;
    452     video_stream1.cname = kStream1Cname;
    453     video_stream1.sync_label = kStreamLabel1;
    454     video_stream1.ssrcs.push_back(kVideoTrack1Ssrc);
    455     video->AddStream(video_stream1);
    456     StreamParams video_stream2;
    457     video_stream2.id = kVideoTrackId2;
    458     video_stream2.cname = kStream1Cname;
    459     video_stream2.sync_label = kStreamLabel1;
    460     video_stream2.ssrcs.push_back(kVideoTrack2Ssrc);
    461     video->AddStream(video_stream2);
    462     StreamParams video_stream3;
    463     video_stream3.id = kVideoTrackId3;
    464     video_stream3.cname = kStream2Cname;
    465     video_stream3.sync_label = kStreamLabel2;
    466     video_stream3.ssrcs.push_back(kVideoTrack3Ssrc);
    467     video_stream3.ssrcs.push_back(kVideoTrack4Ssrc);
    468     cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream3.ssrcs);
    469     video_stream3.ssrc_groups.push_back(ssrc_group);
    470     video->AddStream(video_stream3);
    471     video->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_80",
    472         "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
    473     video->set_protocol(cricket::kMediaProtocolSavpf);
    474     video->AddCodec(VideoCodec(
    475         120,
    476         JsepSessionDescription::kDefaultVideoCodecName,
    477         JsepSessionDescription::kMaxVideoCodecWidth,
    478         JsepSessionDescription::kMaxVideoCodecHeight,
    479         JsepSessionDescription::kDefaultVideoCodecFramerate,
    480         JsepSessionDescription::kDefaultVideoCodecPreference));
    481 
    482     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP,
    483                      video.release());
    484 
    485     // TransportInfo
    486     EXPECT_TRUE(desc_.AddTransportInfo(
    487         TransportInfo(kAudioContentName,
    488                       TransportDescription(NS_JINGLE_ICE_UDP,
    489                                            kCandidateUfragVoice,
    490                                            kCandidatePwdVoice))));
    491     EXPECT_TRUE(desc_.AddTransportInfo(
    492         TransportInfo(kVideoContentName,
    493                       TransportDescription(NS_JINGLE_ICE_UDP,
    494                                            kCandidateUfragVideo,
    495                                            kCandidatePwdVideo))));
    496 
    497     // v4 host
    498     int port = 1234;
    499     talk_base::SocketAddress address("192.168.1.5", port++);
    500     Candidate candidate1(
    501         "", ICE_CANDIDATE_COMPONENT_RTP, "udp", address, kCandidatePriority,
    502         "", "", LOCAL_PORT_TYPE,
    503         "", kCandidateGeneration, kCandidateFoundation1);
    504     address.SetPort(port++);
    505     Candidate candidate2(
    506         "", ICE_CANDIDATE_COMPONENT_RTCP, "udp", address, kCandidatePriority,
    507         "", "", LOCAL_PORT_TYPE,
    508         "", kCandidateGeneration, kCandidateFoundation1);
    509     address.SetPort(port++);
    510     Candidate candidate3(
    511         "", ICE_CANDIDATE_COMPONENT_RTCP, "udp", address, kCandidatePriority,
    512         "", "", LOCAL_PORT_TYPE,
    513         "", kCandidateGeneration, kCandidateFoundation1);
    514     address.SetPort(port++);
    515     Candidate candidate4(
    516         "", ICE_CANDIDATE_COMPONENT_RTP, "udp", address, kCandidatePriority,
    517         "", "", LOCAL_PORT_TYPE,
    518         "", kCandidateGeneration, kCandidateFoundation1);
    519 
    520     // v6 host
    521     talk_base::SocketAddress v6_address("::1", port++);
    522     cricket::Candidate candidate5(
    523         "", cricket::ICE_CANDIDATE_COMPONENT_RTP,
    524         "udp", v6_address, kCandidatePriority,
    525         "", "", cricket::LOCAL_PORT_TYPE,
    526         "", kCandidateGeneration, kCandidateFoundation2);
    527     v6_address.SetPort(port++);
    528     cricket::Candidate candidate6(
    529         "", cricket::ICE_CANDIDATE_COMPONENT_RTCP,
    530         "udp", v6_address, kCandidatePriority,
    531         "", "", cricket::LOCAL_PORT_TYPE,
    532         "", kCandidateGeneration, kCandidateFoundation2);
    533     v6_address.SetPort(port++);
    534     cricket::Candidate candidate7(
    535         "", cricket::ICE_CANDIDATE_COMPONENT_RTCP,
    536         "udp", v6_address, kCandidatePriority,
    537         "", "", cricket::LOCAL_PORT_TYPE,
    538         "", kCandidateGeneration, kCandidateFoundation2);
    539     v6_address.SetPort(port++);
    540     cricket::Candidate candidate8(
    541         "", cricket::ICE_CANDIDATE_COMPONENT_RTP,
    542         "udp", v6_address, kCandidatePriority,
    543         "", "", cricket::LOCAL_PORT_TYPE,
    544         "", kCandidateGeneration, kCandidateFoundation2);
    545 
    546     // stun
    547     int port_stun = 2345;
    548     talk_base::SocketAddress address_stun("74.125.127.126", port_stun++);
    549     talk_base::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
    550     cricket::Candidate candidate9
    551         ("", cricket::ICE_CANDIDATE_COMPONENT_RTP,
    552          "udp", address_stun, kCandidatePriority,
    553          "", "", STUN_PORT_TYPE,
    554          "", kCandidateGeneration, kCandidateFoundation3);
    555     candidate9.set_related_address(rel_address_stun);
    556 
    557     address_stun.SetPort(port_stun++);
    558     rel_address_stun.SetPort(port_stun++);
    559     cricket::Candidate candidate10(
    560         "", cricket::ICE_CANDIDATE_COMPONENT_RTCP,
    561         "udp", address_stun, kCandidatePriority,
    562         "", "", STUN_PORT_TYPE,
    563         "", kCandidateGeneration, kCandidateFoundation3);
    564     candidate10.set_related_address(rel_address_stun);
    565 
    566     // relay
    567     int port_relay = 3456;
    568     talk_base::SocketAddress address_relay("74.125.224.39", port_relay++);
    569     cricket::Candidate candidate11(
    570         "", cricket::ICE_CANDIDATE_COMPONENT_RTCP,
    571         "udp", address_relay, kCandidatePriority,
    572         "", "",
    573         cricket::RELAY_PORT_TYPE, "",
    574         kCandidateGeneration, kCandidateFoundation4);
    575     address_relay.SetPort(port_relay++);
    576     cricket::Candidate candidate12(
    577         "", cricket::ICE_CANDIDATE_COMPONENT_RTP,
    578         "udp", address_relay, kCandidatePriority,
    579         "", "",
    580         RELAY_PORT_TYPE, "",
    581         kCandidateGeneration, kCandidateFoundation4);
    582 
    583     // voice
    584     candidates_.push_back(candidate1);
    585     candidates_.push_back(candidate2);
    586     candidates_.push_back(candidate5);
    587     candidates_.push_back(candidate6);
    588     candidates_.push_back(candidate9);
    589     candidates_.push_back(candidate10);
    590 
    591     // video
    592     candidates_.push_back(candidate3);
    593     candidates_.push_back(candidate4);
    594     candidates_.push_back(candidate7);
    595     candidates_.push_back(candidate8);
    596     candidates_.push_back(candidate11);
    597     candidates_.push_back(candidate12);
    598 
    599     jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"),
    600                                            0, candidate1));
    601 
    602     // Set up JsepSessionDescription.
    603     jdesc_.Initialize(desc_.Copy(), kSessionId, kSessionVersion);
    604     std::string mline_id;
    605     int mline_index = 0;
    606     for (size_t i = 0; i< candidates_.size(); ++i) {
    607       // In this test, the audio m line index will be 0, and the video m line
    608       // will be 1.
    609       bool is_video = (i > 5);
    610       mline_id = is_video ? "video_content_name" : "audio_content_name";
    611       mline_index = is_video ? 1 : 0;
    612       JsepIceCandidate jice(mline_id,
    613                             mline_index,
    614                             candidates_.at(i));
    615       jdesc_.AddCandidate(&jice);
    616     }
    617   }
    618 
    619   AudioContentDescription* CreateAudioContentDescription() {
    620     AudioContentDescription* audio = new AudioContentDescription();
    621     audio->set_rtcp_mux(true);
    622     StreamParams audio_stream1;
    623     audio_stream1.id = kAudioTrackId1;
    624     audio_stream1.cname = kStream1Cname;
    625     audio_stream1.sync_label = kStreamLabel1;
    626     audio_stream1.ssrcs.push_back(kAudioTrack1Ssrc);
    627     audio->AddStream(audio_stream1);
    628     StreamParams audio_stream2;
    629     audio_stream2.id = kAudioTrackId2;
    630     audio_stream2.cname = kStream2Cname;
    631     audio_stream2.sync_label = kStreamLabel2;
    632     audio_stream2.ssrcs.push_back(kAudioTrack2Ssrc);
    633     audio->AddStream(audio_stream2);
    634     audio->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_32",
    635         "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
    636         "dummy_session_params"));
    637     audio->set_protocol(cricket::kMediaProtocolSavpf);
    638     return audio;
    639   }
    640 
    641   template <class MCD>
    642   void CompareMediaContentDescription(const MCD* cd1,
    643                                       const MCD* cd2) {
    644     // type
    645     EXPECT_EQ(cd1->type(), cd1->type());
    646 
    647     // content direction
    648     EXPECT_EQ(cd1->direction(), cd2->direction());
    649 
    650     // rtcp_mux
    651     EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
    652 
    653     // cryptos
    654     EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
    655     if (cd1->cryptos().size() != cd2->cryptos().size()) {
    656       ADD_FAILURE();
    657       return;
    658     }
    659     for (size_t i = 0; i< cd1->cryptos().size(); ++i) {
    660       const CryptoParams c1 = cd1->cryptos().at(i);
    661       const CryptoParams c2 = cd2->cryptos().at(i);
    662       EXPECT_TRUE(c1.Matches(c2));
    663       EXPECT_EQ(c1.key_params, c2.key_params);
    664       EXPECT_EQ(c1.session_params, c2.session_params);
    665     }
    666     // protocol
    667     EXPECT_EQ(cd1->protocol(), cd2->protocol());
    668 
    669     // codecs
    670     EXPECT_EQ(cd1->codecs(), cd2->codecs());
    671 
    672     // bandwidth
    673     EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
    674 
    675     // streams
    676     EXPECT_EQ(cd1->streams(), cd2->streams());
    677 
    678     // extmap
    679     ASSERT_EQ(cd1->rtp_header_extensions().size(),
    680               cd2->rtp_header_extensions().size());
    681     for (size_t i = 0; i< cd1->rtp_header_extensions().size(); ++i) {
    682       const RtpHeaderExtension ext1 = cd1->rtp_header_extensions().at(i);
    683       const RtpHeaderExtension ext2 = cd2->rtp_header_extensions().at(i);
    684       EXPECT_EQ(ext1.uri, ext2.uri);
    685       EXPECT_EQ(ext1.id, ext2.id);
    686     }
    687 
    688     // buffered mode latency
    689     EXPECT_EQ(cd1->buffered_mode_latency(), cd2->buffered_mode_latency());
    690   }
    691 
    692 
    693   void CompareSessionDescription(const SessionDescription& desc1,
    694                                  const SessionDescription& desc2) {
    695     // Compare content descriptions.
    696     if (desc1.contents().size() != desc2.contents().size()) {
    697       ADD_FAILURE();
    698       return;
    699     }
    700     for (size_t i = 0 ; i < desc1.contents().size(); ++i) {
    701       const cricket::ContentInfo& c1 = desc1.contents().at(i);
    702       const cricket::ContentInfo& c2 = desc2.contents().at(i);
    703       // content name
    704       EXPECT_EQ(c1.name, c2.name);
    705       // content type
    706       // Note, ASSERT will return from the function, but will not stop the test.
    707       ASSERT_EQ(c1.type, c2.type);
    708 
    709       ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
    710       if (IsAudioContent(&c1)) {
    711         const AudioContentDescription* acd1 =
    712             static_cast<const AudioContentDescription*>(c1.description);
    713         const AudioContentDescription* acd2 =
    714             static_cast<const AudioContentDescription*>(c2.description);
    715         CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
    716       }
    717 
    718       ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
    719       if (IsVideoContent(&c1)) {
    720         const VideoContentDescription* vcd1 =
    721             static_cast<const VideoContentDescription*>(c1.description);
    722         const VideoContentDescription* vcd2 =
    723             static_cast<const VideoContentDescription*>(c2.description);
    724         CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
    725       }
    726 
    727       ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
    728       if (IsDataContent(&c1)) {
    729         const DataContentDescription* dcd1 =
    730             static_cast<const DataContentDescription*>(c1.description);
    731         const DataContentDescription* dcd2 =
    732             static_cast<const DataContentDescription*>(c2.description);
    733         CompareMediaContentDescription<DataContentDescription>(dcd1, dcd2);
    734       }
    735     }
    736 
    737     // group
    738     const cricket::ContentGroups groups1 = desc1.groups();
    739     const cricket::ContentGroups groups2 = desc2.groups();
    740     EXPECT_EQ(groups1.size(), groups1.size());
    741     if (groups1.size() != groups2.size()) {
    742       ADD_FAILURE();
    743       return;
    744     }
    745     for (size_t i = 0; i < groups1.size(); ++i) {
    746       const cricket::ContentGroup group1 = groups1.at(i);
    747       const cricket::ContentGroup group2 = groups2.at(i);
    748       EXPECT_EQ(group1.semantics(), group2.semantics());
    749       const cricket::ContentNames names1 = group1.content_names();
    750       const cricket::ContentNames names2 = group2.content_names();
    751       EXPECT_EQ(names1.size(), names2.size());
    752       if (names1.size() != names2.size()) {
    753         ADD_FAILURE();
    754         return;
    755       }
    756       cricket::ContentNames::const_iterator iter1 = names1.begin();
    757       cricket::ContentNames::const_iterator iter2 = names2.begin();
    758       while (iter1 != names1.end()) {
    759         EXPECT_EQ(*iter1++, *iter2++);
    760       }
    761     }
    762 
    763     // transport info
    764     const cricket::TransportInfos transports1 = desc1.transport_infos();
    765     const cricket::TransportInfos transports2 = desc2.transport_infos();
    766     EXPECT_EQ(transports1.size(), transports2.size());
    767     if (transports1.size() != transports2.size()) {
    768       ADD_FAILURE();
    769       return;
    770     }
    771     for (size_t i = 0; i < transports1.size(); ++i) {
    772       const cricket::TransportInfo transport1 = transports1.at(i);
    773       const cricket::TransportInfo transport2 = transports2.at(i);
    774       EXPECT_EQ(transport1.content_name, transport2.content_name);
    775       EXPECT_EQ(transport1.description.transport_type,
    776                 transport2.description.transport_type);
    777       EXPECT_EQ(transport1.description.ice_ufrag,
    778                 transport2.description.ice_ufrag);
    779       EXPECT_EQ(transport1.description.ice_pwd,
    780                 transport2.description.ice_pwd);
    781       if (transport1.description.identity_fingerprint) {
    782         EXPECT_EQ(*transport1.description.identity_fingerprint,
    783                   *transport2.description.identity_fingerprint);
    784       } else {
    785         EXPECT_EQ(transport1.description.identity_fingerprint.get(),
    786                   transport2.description.identity_fingerprint.get());
    787       }
    788       EXPECT_EQ(transport1.description.transport_options,
    789                 transport2.description.transport_options);
    790       EXPECT_TRUE(CompareCandidates(transport1.description.candidates,
    791                                     transport2.description.candidates));
    792     }
    793   }
    794 
    795   bool CompareCandidates(const Candidates& cs1, const Candidates& cs2) {
    796     EXPECT_EQ(cs1.size(), cs2.size());
    797     if (cs1.size() != cs2.size())
    798       return false;
    799     for (size_t i = 0; i< cs1.size(); ++i) {
    800       const Candidate c1 = cs1.at(i);
    801       const Candidate c2 = cs2.at(i);
    802       EXPECT_TRUE(c1.IsEquivalent(c2));
    803     }
    804     return true;
    805   }
    806 
    807   bool CompareSessionDescription(
    808       const JsepSessionDescription& desc1,
    809       const JsepSessionDescription& desc2) {
    810     EXPECT_EQ(desc1.session_id(), desc2.session_id());
    811     EXPECT_EQ(desc1.session_version(), desc2.session_version());
    812     CompareSessionDescription(*desc1.description(), *desc2.description());
    813     if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
    814       return false;
    815     for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
    816       const IceCandidateCollection* cc1 = desc1.candidates(i);
    817       const IceCandidateCollection* cc2 = desc2.candidates(i);
    818       if (cc1->count() != cc2->count())
    819         return false;
    820       for (size_t j = 0; j < cc1->count(); ++j) {
    821         const IceCandidateInterface* c1 = cc1->at(j);
    822         const IceCandidateInterface* c2 = cc2->at(j);
    823         EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
    824         EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
    825         EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
    826       }
    827     }
    828     return true;
    829   }
    830 
    831   // Disable the ice-ufrag and ice-pwd in given |sdp| message by replacing
    832   // them with invalid keywords so that the parser will just ignore them.
    833   bool RemoveCandidateUfragPwd(std::string* sdp) {
    834     const char ice_ufrag[] = "a=ice-ufrag";
    835     const char ice_ufragx[] = "a=xice-ufrag";
    836     const char ice_pwd[] = "a=ice-pwd";
    837     const char ice_pwdx[] = "a=xice-pwd";
    838     talk_base::replace_substrs(ice_ufrag, strlen(ice_ufrag),
    839         ice_ufragx, strlen(ice_ufragx), sdp);
    840     talk_base::replace_substrs(ice_pwd, strlen(ice_pwd),
    841         ice_pwdx, strlen(ice_pwdx), sdp);
    842     return true;
    843   }
    844 
    845   // Update the candidates in |jdesc| to use the given |ufrag| and |pwd|.
    846   bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc, int mline_index,
    847       const std::string& ufrag, const std::string& pwd) {
    848     std::string content_name;
    849     if (mline_index == 0) {
    850       content_name = kAudioContentName;
    851     } else if (mline_index == 1) {
    852       content_name = kVideoContentName;
    853     } else {
    854       ASSERT(false);
    855     }
    856     TransportInfo transport_info(
    857         content_name, TransportDescription(NS_JINGLE_ICE_UDP,
    858                                            ufrag, pwd));
    859     SessionDescription* desc =
    860         const_cast<SessionDescription*>(jdesc->description());
    861     desc->RemoveTransportInfoByName(content_name);
    862     EXPECT_TRUE(desc->AddTransportInfo(transport_info));
    863     for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
    864       const IceCandidateCollection* cc = jdesc_.candidates(i);
    865       for (size_t j = 0; j < cc->count(); ++j) {
    866         if (cc->at(j)->sdp_mline_index() == mline_index) {
    867           const_cast<Candidate&>(cc->at(j)->candidate()).set_username(
    868               ufrag);
    869           const_cast<Candidate&>(cc->at(j)->candidate()).set_password(
    870               pwd);
    871         }
    872       }
    873     }
    874     return true;
    875   }
    876 
    877   void AddIceOptions(const std::string& content_name,
    878                      const std::vector<std::string>& transport_options) {
    879     ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
    880     cricket::TransportInfo transport_info =
    881         *(desc_.GetTransportInfoByName(content_name));
    882     desc_.RemoveTransportInfoByName(content_name);
    883     transport_info.description.transport_options = transport_options;
    884     desc_.AddTransportInfo(transport_info);
    885   }
    886 
    887   void AddFingerprint() {
    888     desc_.RemoveTransportInfoByName(kAudioContentName);
    889     desc_.RemoveTransportInfoByName(kVideoContentName);
    890     talk_base::SSLFingerprint fingerprint(talk_base::DIGEST_SHA_1,
    891                                           kIdentityDigest,
    892                                           sizeof(kIdentityDigest));
    893     EXPECT_TRUE(desc_.AddTransportInfo(
    894         TransportInfo(kAudioContentName,
    895                       TransportDescription(NS_JINGLE_ICE_UDP,
    896                                            std::vector<std::string>(),
    897                                            kCandidateUfragVoice,
    898                                            kCandidatePwdVoice,
    899                                            cricket::ICEMODE_FULL,
    900                                            cricket::CONNECTIONROLE_NONE,
    901                                            &fingerprint, Candidates()))));
    902     EXPECT_TRUE(desc_.AddTransportInfo(
    903         TransportInfo(kVideoContentName,
    904                       TransportDescription(NS_JINGLE_ICE_UDP,
    905                                            std::vector<std::string>(),
    906                                            kCandidateUfragVideo,
    907                                            kCandidatePwdVideo,
    908                                            cricket::ICEMODE_FULL,
    909                                            cricket::CONNECTIONROLE_NONE,
    910                                            &fingerprint, Candidates()))));
    911   }
    912 
    913   void AddExtmap() {
    914     audio_desc_ = static_cast<AudioContentDescription*>(
    915         audio_desc_->Copy());
    916     video_desc_ = static_cast<VideoContentDescription*>(
    917         video_desc_->Copy());
    918     audio_desc_->AddRtpHeaderExtension(
    919         RtpHeaderExtension(kExtmapUri, kExtmapId));
    920     video_desc_->AddRtpHeaderExtension(
    921         RtpHeaderExtension(kExtmapUri, kExtmapId));
    922     desc_.RemoveContentByName(kAudioContentName);
    923     desc_.RemoveContentByName(kVideoContentName);
    924     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_desc_);
    925     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_desc_);
    926   }
    927 
    928   void RemoveCryptos() {
    929     audio_desc_->set_cryptos(std::vector<CryptoParams>());
    930     video_desc_->set_cryptos(std::vector<CryptoParams>());
    931   }
    932 
    933   bool TestSerializeDirection(cricket::MediaContentDirection direction) {
    934     audio_desc_->set_direction(direction);
    935     video_desc_->set_direction(direction);
    936     std::string new_sdp = kSdpFullString;
    937     ReplaceDirection(direction, &new_sdp);
    938 
    939     if (!jdesc_.Initialize(desc_.Copy(),
    940                            jdesc_.session_id(),
    941                            jdesc_.session_version())) {
    942       return false;
    943     }
    944     std::string message = webrtc::SdpSerialize(jdesc_);
    945     EXPECT_EQ(new_sdp, message);
    946     return true;
    947   }
    948 
    949   bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
    950     audio_desc_ = static_cast<AudioContentDescription*>(
    951         audio_desc_->Copy());
    952     video_desc_ = static_cast<VideoContentDescription*>(
    953         video_desc_->Copy());
    954     desc_.RemoveContentByName(kAudioContentName);
    955     desc_.RemoveContentByName(kVideoContentName);
    956     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_rejected,
    957                      audio_desc_);
    958     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
    959                      video_desc_);
    960     std::string new_sdp = kSdpFullString;
    961     ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
    962 
    963     if (!jdesc_.Initialize(desc_.Copy(),
    964                            jdesc_.session_id(),
    965                            jdesc_.session_version())) {
    966       return false;
    967     }
    968     std::string message = webrtc::SdpSerialize(jdesc_);
    969     EXPECT_EQ(new_sdp, message);
    970     return true;
    971   }
    972 
    973   void AddSctpDataChannel() {
    974     talk_base::scoped_ptr<DataContentDescription> data(
    975         new DataContentDescription());
    976     data_desc_ = data.get();
    977     data_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp);
    978     DataCodec codec(cricket::kGoogleSctpDataCodecId,
    979                     cricket::kGoogleSctpDataCodecName, 0);
    980     codec.SetParam(cricket::kCodecParamPort, kDefaultSctpPort);
    981     data_desc_->AddCodec(codec);
    982     desc_.AddContent(kDataContentName, NS_JINGLE_DRAFT_SCTP, data.release());
    983     EXPECT_TRUE(desc_.AddTransportInfo(
    984            TransportInfo(kDataContentName,
    985                          TransportDescription(NS_JINGLE_ICE_UDP,
    986                                               kCandidateUfragData,
    987                                               kCandidatePwdData))));
    988   }
    989 
    990   void AddRtpDataChannel() {
    991     talk_base::scoped_ptr<DataContentDescription> data(
    992         new DataContentDescription());
    993     data_desc_ = data.get();
    994 
    995     data_desc_->AddCodec(DataCodec(101, "google-data", 1));
    996     StreamParams data_stream;
    997     data_stream.id = kDataChannelMsid;
    998     data_stream.cname = kDataChannelCname;
    999     data_stream.sync_label = kDataChannelLabel;
   1000     data_stream.ssrcs.push_back(kDataChannelSsrc);
   1001     data_desc_->AddStream(data_stream);
   1002     data_desc_->AddCrypto(CryptoParams(
   1003         1, "AES_CM_128_HMAC_SHA1_80",
   1004         "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5", ""));
   1005     data_desc_->set_protocol(cricket::kMediaProtocolSavpf);
   1006     desc_.AddContent(kDataContentName, NS_JINGLE_RTP, data.release());
   1007     EXPECT_TRUE(desc_.AddTransportInfo(
   1008            TransportInfo(kDataContentName,
   1009                          TransportDescription(NS_JINGLE_ICE_UDP,
   1010                                               kCandidateUfragData,
   1011                                               kCandidatePwdData))));
   1012   }
   1013 
   1014   bool TestDeserializeDirection(cricket::MediaContentDirection direction) {
   1015     std::string new_sdp = kSdpFullString;
   1016     ReplaceDirection(direction, &new_sdp);
   1017     JsepSessionDescription new_jdesc(kDummyString);
   1018 
   1019     EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
   1020 
   1021     audio_desc_->set_direction(direction);
   1022     video_desc_->set_direction(direction);
   1023     if (!jdesc_.Initialize(desc_.Copy(),
   1024                            jdesc_.session_id(),
   1025                            jdesc_.session_version())) {
   1026       return false;
   1027     }
   1028     EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
   1029     return true;
   1030   }
   1031 
   1032   bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
   1033     std::string new_sdp = kSdpFullString;
   1034     ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
   1035     JsepSessionDescription new_jdesc(JsepSessionDescription::kOffer);
   1036 
   1037     EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
   1038     audio_desc_ = static_cast<AudioContentDescription*>(
   1039         audio_desc_->Copy());
   1040     video_desc_ = static_cast<VideoContentDescription*>(
   1041         video_desc_->Copy());
   1042     desc_.RemoveContentByName(kAudioContentName);
   1043     desc_.RemoveContentByName(kVideoContentName);
   1044     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_rejected,
   1045                      audio_desc_);
   1046     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
   1047                      video_desc_);
   1048     if (!jdesc_.Initialize(desc_.Copy(),
   1049                            jdesc_.session_id(),
   1050                            jdesc_.session_version())) {
   1051       return false;
   1052     }
   1053     EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
   1054     return true;
   1055   }
   1056 
   1057   void TestDeserializeExtmap(bool session_level, bool media_level) {
   1058     AddExtmap();
   1059     JsepSessionDescription new_jdesc("dummy");
   1060     ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
   1061                                      jdesc_.session_id(),
   1062                                      jdesc_.session_version()));
   1063     JsepSessionDescription jdesc_with_extmap("dummy");
   1064     std::string sdp_with_extmap = kSdpString;
   1065     if (session_level) {
   1066       InjectAfter(kSessionTime, kExtmapWithDirectionAndAttribute,
   1067                   &sdp_with_extmap);
   1068     }
   1069     if (media_level) {
   1070       InjectAfter(kAttributeIcePwdVoice, kExtmapWithDirectionAndAttribute,
   1071                   &sdp_with_extmap);
   1072       InjectAfter(kAttributeIcePwdVideo, kExtmapWithDirectionAndAttribute,
   1073                   &sdp_with_extmap);
   1074     }
   1075     // The extmap can't be present at the same time in both session level and
   1076     // media level.
   1077     if (session_level && media_level) {
   1078       SdpParseError error;
   1079       EXPECT_FALSE(webrtc::SdpDeserialize(sdp_with_extmap,
   1080                    &jdesc_with_extmap, &error));
   1081       EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
   1082     } else {
   1083       EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
   1084       EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
   1085     }
   1086   }
   1087 
   1088   void VerifyCodecParameter(const cricket::CodecParameterMap& params,
   1089       const std::string& name, int expected_value) {
   1090     cricket::CodecParameterMap::const_iterator found = params.find(name);
   1091     ASSERT_TRUE(found != params.end());
   1092     EXPECT_EQ(found->second, talk_base::ToString<int>(expected_value));
   1093   }
   1094 
   1095   void TestDeserializeCodecParams(const CodecParams& params,
   1096                                   JsepSessionDescription* jdesc_output) {
   1097     std::string sdp =
   1098         "v=0\r\n"
   1099         "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1100         "s=-\r\n"
   1101         "t=0 0\r\n"
   1102         // Include semantics for WebRTC Media Streams since it is supported by
   1103         // this parser, and will be added to the SDP when serializing a session
   1104         // description.
   1105         "a=msid-semantic: WMS\r\n"
   1106         // Pl type 111 preferred.
   1107         "m=audio 1 RTP/SAVPF 111 104 103 102\r\n"
   1108         // Pltype 111 listed before 103 and 104 in the map.
   1109         "a=rtpmap:111 opus/48000/2\r\n"
   1110         // Pltype 103 listed before 104.
   1111         "a=rtpmap:103 ISAC/16000\r\n"
   1112         "a=rtpmap:104 CELT/32000/2\r\n"
   1113         "a=rtpmap:102 ISAC/32000/1\r\n"
   1114         "a=fmtp:111 0-15,66,70\r\n"
   1115         "a=fmtp:111 ";
   1116     std::ostringstream os;
   1117     os << "minptime=" << params.min_ptime
   1118        << "; stereo=" << params.stereo
   1119        << "; sprop-stereo=" << params.sprop_stereo
   1120        << "; useinbandfec=" << params.useinband
   1121        << " maxaveragebitrate=" << params.maxaveragebitrate << "\r\n"
   1122        << "a=ptime:" << params.ptime << "\r\n"
   1123        << "a=maxptime:" << params.max_ptime << "\r\n";
   1124     sdp += os.str();
   1125 
   1126     // Deserialize
   1127     SdpParseError error;
   1128     EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
   1129 
   1130     const ContentInfo* ac = GetFirstAudioContent(jdesc_output->description());
   1131     ASSERT_TRUE(ac != NULL);
   1132     const AudioContentDescription* acd =
   1133         static_cast<const AudioContentDescription*>(ac->description);
   1134     ASSERT_FALSE(acd->codecs().empty());
   1135     cricket::AudioCodec opus = acd->codecs()[0];
   1136     EXPECT_EQ("opus", opus.name);
   1137     EXPECT_EQ(111, opus.id);
   1138     VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
   1139     VerifyCodecParameter(opus.params, "stereo", params.stereo);
   1140     VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
   1141     VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
   1142     VerifyCodecParameter(opus.params, "maxaveragebitrate",
   1143                          params.maxaveragebitrate);
   1144     for (size_t i = 0; i < acd->codecs().size(); ++i) {
   1145       cricket::AudioCodec codec = acd->codecs()[i];
   1146       VerifyCodecParameter(codec.params, "ptime", params.ptime);
   1147       VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
   1148       if (codec.name == "ISAC") {
   1149         if (codec.clockrate == 16000) {
   1150           EXPECT_EQ(32000, codec.bitrate);
   1151         } else {
   1152           EXPECT_EQ(56000, codec.bitrate);
   1153         }
   1154       }
   1155     }
   1156   }
   1157 
   1158   void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
   1159                              bool use_wildcard) {
   1160     std::string sdp =
   1161         "v=0\r\n"
   1162         "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1163         "s=-\r\n"
   1164         "t=0 0\r\n"
   1165         // Include semantics for WebRTC Media Streams since it is supported by
   1166         // this parser, and will be added to the SDP when serializing a session
   1167         // description.
   1168         "a=msid-semantic: WMS\r\n"
   1169         "m=audio 1 RTP/SAVPF 111\r\n"
   1170         "a=rtpmap:111 opus/48000/2\r\n"
   1171         "a=rtcp-fb:111 nack\r\n"
   1172         "m=video 3457 RTP/SAVPF 101\r\n"
   1173         "a=rtpmap:101 VP8/90000\r\n"
   1174         "a=rtcp-fb:101 nack\r\n"
   1175         "a=rtcp-fb:101 goog-remb\r\n"
   1176         "a=rtcp-fb:101 ccm fir\r\n";
   1177     std::ostringstream os;
   1178     os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") <<  " ccm fir\r\n";
   1179     sdp += os.str();
   1180     // Deserialize
   1181     SdpParseError error;
   1182     EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
   1183     const ContentInfo* ac = GetFirstAudioContent(jdesc_output->description());
   1184     ASSERT_TRUE(ac != NULL);
   1185     const AudioContentDescription* acd =
   1186         static_cast<const AudioContentDescription*>(ac->description);
   1187     ASSERT_FALSE(acd->codecs().empty());
   1188     cricket::AudioCodec opus = acd->codecs()[0];
   1189     EXPECT_EQ(111, opus.id);
   1190     EXPECT_TRUE(opus.HasFeedbackParam(
   1191         cricket::FeedbackParam(cricket::kRtcpFbParamNack,
   1192                                cricket::kParamValueEmpty)));
   1193 
   1194     const ContentInfo* vc = GetFirstVideoContent(jdesc_output->description());
   1195     ASSERT_TRUE(vc != NULL);
   1196     const VideoContentDescription* vcd =
   1197         static_cast<const VideoContentDescription*>(vc->description);
   1198     ASSERT_FALSE(vcd->codecs().empty());
   1199     cricket::VideoCodec vp8 = vcd->codecs()[0];
   1200     EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
   1201                  vp8.name.c_str());
   1202     EXPECT_EQ(101, vp8.id);
   1203     EXPECT_TRUE(vp8.HasFeedbackParam(
   1204         cricket::FeedbackParam(cricket::kRtcpFbParamNack,
   1205                                cricket::kParamValueEmpty)));
   1206     EXPECT_TRUE(vp8.HasFeedbackParam(
   1207         cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
   1208                                cricket::kParamValueEmpty)));
   1209     EXPECT_TRUE(vp8.HasFeedbackParam(
   1210         cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
   1211                                cricket::kRtcpFbCcmParamFir)));
   1212   }
   1213 
   1214   // Two SDP messages can mean the same thing but be different strings, e.g.
   1215   // some of the lines can be serialized in different order.
   1216   // However, a deserialized description can be compared field by field and has
   1217   // no order. If deserializer has already been tested, serializing then
   1218   // deserializing and comparing JsepSessionDescription will test
   1219   // the serializer sufficiently.
   1220   void TestSerialize(const JsepSessionDescription& jdesc) {
   1221     std::string message = webrtc::SdpSerialize(jdesc);
   1222     JsepSessionDescription jdesc_output_des(kDummyString);
   1223     SdpParseError error;
   1224     EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
   1225     EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
   1226   }
   1227 
   1228  protected:
   1229   SessionDescription desc_;
   1230   AudioContentDescription* audio_desc_;
   1231   VideoContentDescription* video_desc_;
   1232   DataContentDescription* data_desc_;
   1233   Candidates candidates_;
   1234   talk_base::scoped_ptr<IceCandidateInterface> jcandidate_;
   1235   JsepSessionDescription jdesc_;
   1236 };
   1237 
   1238 void TestMismatch(const std::string& string1, const std::string& string2) {
   1239   int position = 0;
   1240   for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
   1241     if (string1.c_str()[i] != string2.c_str()[i]) {
   1242       position = static_cast<int>(i);
   1243       break;
   1244     }
   1245   }
   1246   EXPECT_EQ(0, position) << "Strings mismatch at the " << position
   1247                          << " character\n"
   1248                          << " 1: " << string1.substr(position, 20) << "\n"
   1249                          << " 2: " << string2.substr(position, 20) << "\n";
   1250 }
   1251 
   1252 std::string GetLine(const std::string& message,
   1253                     const std::string& session_description_name) {
   1254   size_t start = message.find(session_description_name);
   1255   if (std::string::npos == start) {
   1256     return "";
   1257   }
   1258   size_t stop = message.find("\r\n", start);
   1259   if (std::string::npos == stop) {
   1260     return "";
   1261   }
   1262   if (stop <= start) {
   1263     return "";
   1264   }
   1265   return message.substr(start, stop - start);
   1266 }
   1267 
   1268 TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
   1269   // SessionDescription with desc and candidates.
   1270   std::string message = webrtc::SdpSerialize(jdesc_);
   1271   TestMismatch(std::string(kSdpFullString), message);
   1272 }
   1273 
   1274 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
   1275   JsepSessionDescription jdesc_empty(kDummyString);
   1276   EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
   1277 }
   1278 
   1279 // This tests serialization of SDP with a=crypto and a=fingerprint, as would be
   1280 // the case in a DTLS offer.
   1281 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
   1282   AddFingerprint();
   1283   JsepSessionDescription jdesc_with_fingerprint(kDummyString);
   1284   ASSERT_TRUE(jdesc_with_fingerprint.Initialize(desc_.Copy(),
   1285                                                 kSessionId, kSessionVersion));
   1286   std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
   1287 
   1288   std::string sdp_with_fingerprint = kSdpString;
   1289   InjectAfter(kAttributeIcePwdVoice,
   1290               kFingerprint, &sdp_with_fingerprint);
   1291   InjectAfter(kAttributeIcePwdVideo,
   1292               kFingerprint, &sdp_with_fingerprint);
   1293 
   1294   EXPECT_EQ(sdp_with_fingerprint, message);
   1295 }
   1296 
   1297 // This tests serialization of SDP with a=fingerprint with no a=crypto, as would
   1298 // be the case in a DTLS answer.
   1299 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
   1300   AddFingerprint();
   1301   RemoveCryptos();
   1302   JsepSessionDescription jdesc_with_fingerprint(kDummyString);
   1303   ASSERT_TRUE(jdesc_with_fingerprint.Initialize(desc_.Copy(),
   1304                                                 kSessionId, kSessionVersion));
   1305   std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
   1306 
   1307   std::string sdp_with_fingerprint = kSdpString;
   1308   Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
   1309   Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
   1310   InjectAfter(kAttributeIcePwdVoice,
   1311               kFingerprint, &sdp_with_fingerprint);
   1312   InjectAfter(kAttributeIcePwdVideo,
   1313               kFingerprint, &sdp_with_fingerprint);
   1314 
   1315   EXPECT_EQ(sdp_with_fingerprint, message);
   1316 }
   1317 
   1318 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
   1319   // JsepSessionDescription with desc but without candidates.
   1320   JsepSessionDescription jdesc_no_candidates(kDummyString);
   1321   ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
   1322                                              kSessionId, kSessionVersion));
   1323   std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
   1324   EXPECT_EQ(std::string(kSdpString), message);
   1325 }
   1326 
   1327 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundle) {
   1328   ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
   1329   group.AddContentName(kAudioContentName);
   1330   group.AddContentName(kVideoContentName);
   1331   desc_.AddGroup(group);
   1332   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1333                                 jdesc_.session_id(),
   1334                                 jdesc_.session_version()));
   1335   std::string message = webrtc::SdpSerialize(jdesc_);
   1336   std::string sdp_with_bundle = kSdpFullString;
   1337   InjectAfter(kSessionTime,
   1338               "a=group:BUNDLE audio_content_name video_content_name\r\n",
   1339               &sdp_with_bundle);
   1340   EXPECT_EQ(sdp_with_bundle, message);
   1341 }
   1342 
   1343 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
   1344   VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
   1345       GetFirstVideoContent(&desc_)->description);
   1346   vcd->set_bandwidth(100 * 1000);
   1347   AudioContentDescription* acd = static_cast<AudioContentDescription*>(
   1348       GetFirstAudioContent(&desc_)->description);
   1349   acd->set_bandwidth(50 * 1000);
   1350   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1351                                 jdesc_.session_id(),
   1352                                 jdesc_.session_version()));
   1353   std::string message = webrtc::SdpSerialize(jdesc_);
   1354   std::string sdp_with_bandwidth = kSdpFullString;
   1355   InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
   1356               "b=AS:100\r\n",
   1357               &sdp_with_bandwidth);
   1358   InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
   1359               "b=AS:50\r\n",
   1360               &sdp_with_bandwidth);
   1361   EXPECT_EQ(sdp_with_bandwidth, message);
   1362 }
   1363 
   1364 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
   1365   std::vector<std::string> transport_options;
   1366   transport_options.push_back(kIceOption1);
   1367   transport_options.push_back(kIceOption3);
   1368   AddIceOptions(kAudioContentName, transport_options);
   1369   transport_options.clear();
   1370   transport_options.push_back(kIceOption2);
   1371   transport_options.push_back(kIceOption3);
   1372   AddIceOptions(kVideoContentName, transport_options);
   1373   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1374                                 jdesc_.session_id(),
   1375                                 jdesc_.session_version()));
   1376   std::string message = webrtc::SdpSerialize(jdesc_);
   1377   std::string sdp_with_ice_options = kSdpFullString;
   1378   InjectAfter(kAttributeIcePwdVoice,
   1379               "a=ice-options:iceoption1 iceoption3\r\n",
   1380               &sdp_with_ice_options);
   1381   InjectAfter(kAttributeIcePwdVideo,
   1382               "a=ice-options:iceoption2 iceoption3\r\n",
   1383               &sdp_with_ice_options);
   1384   EXPECT_EQ(sdp_with_ice_options, message);
   1385 }
   1386 
   1387 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
   1388   EXPECT_TRUE(TestSerializeDirection(cricket::MD_RECVONLY));
   1389 }
   1390 
   1391 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
   1392   EXPECT_TRUE(TestSerializeDirection(cricket::MD_SENDONLY));
   1393 }
   1394 
   1395 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
   1396   EXPECT_TRUE(TestSerializeDirection(cricket::MD_INACTIVE));
   1397 }
   1398 
   1399 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
   1400   EXPECT_TRUE(TestSerializeRejected(true, false));
   1401 }
   1402 
   1403 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
   1404   EXPECT_TRUE(TestSerializeRejected(false, true));
   1405 }
   1406 
   1407 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
   1408   EXPECT_TRUE(TestSerializeRejected(true, true));
   1409 }
   1410 
   1411 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRtpDataChannel) {
   1412   AddRtpDataChannel();
   1413   JsepSessionDescription jsep_desc(kDummyString);
   1414 
   1415   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1416   std::string message = webrtc::SdpSerialize(jsep_desc);
   1417 
   1418   std::string expected_sdp = kSdpString;
   1419   expected_sdp.append(kSdpRtpDataChannelString);
   1420   EXPECT_EQ(expected_sdp, message);
   1421 }
   1422 
   1423 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
   1424   AddSctpDataChannel();
   1425   JsepSessionDescription jsep_desc(kDummyString);
   1426 
   1427   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1428   std::string message = webrtc::SdpSerialize(jsep_desc);
   1429 
   1430   std::string expected_sdp = kSdpString;
   1431   expected_sdp.append(kSdpSctpDataChannelString);
   1432   EXPECT_EQ(message, expected_sdp);
   1433 }
   1434 
   1435 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
   1436   AddRtpDataChannel();
   1437   data_desc_->set_bandwidth(100*1000);
   1438   JsepSessionDescription jsep_desc(kDummyString);
   1439 
   1440   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1441   std::string message = webrtc::SdpSerialize(jsep_desc);
   1442 
   1443   std::string expected_sdp = kSdpString;
   1444   expected_sdp.append(kSdpRtpDataChannelString);
   1445   // We want to test that serializing data content ignores bandwidth
   1446   // settings (it should always be the default).  Thus, we don't do
   1447   // the following:
   1448   // TODO(pthatcher): We need to temporarily allow the SDP to control
   1449   // this for backwards-compatibility.  Once we don't need that any
   1450   // more, remove this.
   1451   InjectAfter("a=mid:data_content_name\r\na=sendrecv\r\n",
   1452               "b=AS:100\r\n",
   1453               &expected_sdp);
   1454   EXPECT_EQ(expected_sdp, message);
   1455 }
   1456 
   1457 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
   1458   AddExtmap();
   1459   JsepSessionDescription desc_with_extmap("dummy");
   1460   ASSERT_TRUE(desc_with_extmap.Initialize(desc_.Copy(),
   1461                                           kSessionId, kSessionVersion));
   1462   std::string message = webrtc::SdpSerialize(desc_with_extmap);
   1463 
   1464   std::string sdp_with_extmap = kSdpString;
   1465   InjectAfter("a=mid:audio_content_name\r\n",
   1466               kExtmap, &sdp_with_extmap);
   1467   InjectAfter("a=mid:video_content_name\r\n",
   1468               kExtmap, &sdp_with_extmap);
   1469 
   1470   EXPECT_EQ(sdp_with_extmap, message);
   1471 }
   1472 
   1473 
   1474 TEST_F(WebRtcSdpTest, SerializeCandidates) {
   1475   std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
   1476   EXPECT_EQ(std::string(kSdpOneCandidate), message);
   1477 }
   1478 
   1479 TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
   1480   JsepSessionDescription jdesc(kDummyString);
   1481   // Deserialize
   1482   EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
   1483   // Verify
   1484   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
   1485 }
   1486 
   1487 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
   1488   JsepSessionDescription jdesc(kDummyString);
   1489   const char kSdpWithoutMline[] =
   1490     "v=0\r\n"
   1491     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1492     "s=-\r\n"
   1493     "t=0 0\r\n"
   1494     "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
   1495   // Deserialize
   1496   EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
   1497   EXPECT_EQ(0u, jdesc.description()->contents().size());
   1498 }
   1499 
   1500 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
   1501   JsepSessionDescription jdesc(kDummyString);
   1502   std::string sdp_without_carriage_return = kSdpFullString;
   1503   Replace("\r\n", "\n", &sdp_without_carriage_return);
   1504   // Deserialize
   1505   EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
   1506   // Verify
   1507   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
   1508 }
   1509 
   1510 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
   1511   // SessionDescription with desc but without candidates.
   1512   JsepSessionDescription jdesc_no_candidates(kDummyString);
   1513   ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
   1514                                              kSessionId, kSessionVersion));
   1515   JsepSessionDescription new_jdesc(kDummyString);
   1516   EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
   1517   EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
   1518 }
   1519 
   1520 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
   1521   static const char kSdpNoRtpmapString[] =
   1522       "v=0\r\n"
   1523       "o=- 11 22 IN IP4 127.0.0.1\r\n"
   1524       "s=-\r\n"
   1525       "t=0 0\r\n"
   1526       "m=audio 49232 RTP/AVP 0 18 103\r\n"
   1527       // Codec that doesn't appear in the m= line will be ignored.
   1528       "a=rtpmap:104 CELT/32000/2\r\n"
   1529       // The rtpmap line for static payload codec is optional.
   1530       "a=rtpmap:18 G729/16000\r\n"
   1531       "a=rtpmap:103 ISAC/16000\r\n";
   1532 
   1533   JsepSessionDescription jdesc(kDummyString);
   1534   EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
   1535   cricket::AudioContentDescription* audio =
   1536     static_cast<AudioContentDescription*>(
   1537         jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
   1538   AudioCodecs ref_codecs;
   1539   // The codecs in the AudioContentDescription will be sorted by preference.
   1540   ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1, 3));
   1541   ref_codecs.push_back(AudioCodec(18, "G729", 16000, 0, 1, 2));
   1542   ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 32000, 1, 1));
   1543   EXPECT_EQ(ref_codecs, audio->codecs());
   1544 }
   1545 
   1546 // Ensure that we can deserialize SDP with a=fingerprint properly.
   1547 TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
   1548   // Add a DTLS a=fingerprint attribute to our session description.
   1549   AddFingerprint();
   1550   JsepSessionDescription new_jdesc(kDummyString);
   1551   ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
   1552                                    jdesc_.session_id(),
   1553                                    jdesc_.session_version()));
   1554 
   1555   JsepSessionDescription jdesc_with_fingerprint(kDummyString);
   1556   std::string sdp_with_fingerprint = kSdpString;
   1557   InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
   1558   InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
   1559   EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
   1560   EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
   1561 }
   1562 
   1563 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
   1564   JsepSessionDescription jdesc_with_bundle(kDummyString);
   1565   std::string sdp_with_bundle = kSdpFullString;
   1566   InjectAfter(kSessionTime,
   1567               "a=group:BUNDLE audio_content_name video_content_name\r\n",
   1568               &sdp_with_bundle);
   1569   EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
   1570   ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
   1571   group.AddContentName(kAudioContentName);
   1572   group.AddContentName(kVideoContentName);
   1573   desc_.AddGroup(group);
   1574   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1575                                 jdesc_.session_id(),
   1576                                 jdesc_.session_version()));
   1577   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
   1578 }
   1579 
   1580 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
   1581   JsepSessionDescription jdesc_with_bandwidth(kDummyString);
   1582   std::string sdp_with_bandwidth = kSdpFullString;
   1583   InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
   1584               "b=AS:100\r\n",
   1585               &sdp_with_bandwidth);
   1586   InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
   1587               "b=AS:50\r\n",
   1588               &sdp_with_bandwidth);
   1589   EXPECT_TRUE(
   1590       SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
   1591   VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
   1592       GetFirstVideoContent(&desc_)->description);
   1593   vcd->set_bandwidth(100 * 1000);
   1594   AudioContentDescription* acd = static_cast<AudioContentDescription*>(
   1595       GetFirstAudioContent(&desc_)->description);
   1596   acd->set_bandwidth(50 * 1000);
   1597   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1598                                 jdesc_.session_id(),
   1599                                 jdesc_.session_version()));
   1600   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
   1601 }
   1602 
   1603 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
   1604   JsepSessionDescription jdesc_with_ice_options(kDummyString);
   1605   std::string sdp_with_ice_options = kSdpFullString;
   1606   InjectAfter(kSessionTime,
   1607               "a=ice-options:iceoption3\r\n",
   1608               &sdp_with_ice_options);
   1609   InjectAfter(kAttributeIcePwdVoice,
   1610               "a=ice-options:iceoption1\r\n",
   1611               &sdp_with_ice_options);
   1612   InjectAfter(kAttributeIcePwdVideo,
   1613               "a=ice-options:iceoption2\r\n",
   1614               &sdp_with_ice_options);
   1615   EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
   1616   std::vector<std::string> transport_options;
   1617   transport_options.push_back(kIceOption3);
   1618   transport_options.push_back(kIceOption1);
   1619   AddIceOptions(kAudioContentName, transport_options);
   1620   transport_options.clear();
   1621   transport_options.push_back(kIceOption3);
   1622   transport_options.push_back(kIceOption2);
   1623   AddIceOptions(kVideoContentName, transport_options);
   1624   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1625                                 jdesc_.session_id(),
   1626                                 jdesc_.session_version()));
   1627   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
   1628 }
   1629 
   1630 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
   1631   // Remove the original ice-ufrag and ice-pwd
   1632   JsepSessionDescription jdesc_with_ufrag_pwd(kDummyString);
   1633   std::string sdp_with_ufrag_pwd = kSdpFullString;
   1634   EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
   1635   // Add session level ufrag and pwd
   1636   InjectAfter(kSessionTime,
   1637       "a=ice-pwd:session+level+icepwd\r\n"
   1638       "a=ice-ufrag:session+level+iceufrag\r\n",
   1639       &sdp_with_ufrag_pwd);
   1640   // Add media level ufrag and pwd for audio
   1641   InjectAfter("a=mid:audio_content_name\r\n",
   1642       "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
   1643       &sdp_with_ufrag_pwd);
   1644   // Update the candidate ufrag and pwd to the expected ones.
   1645   EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0,
   1646       "media+level+iceufrag", "media+level+icepwd"));
   1647   EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1,
   1648       "session+level+iceufrag", "session+level+icepwd"));
   1649   EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
   1650   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
   1651 }
   1652 
   1653 
   1654 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
   1655   EXPECT_TRUE(TestDeserializeDirection(cricket::MD_RECVONLY));
   1656 }
   1657 
   1658 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
   1659   EXPECT_TRUE(TestDeserializeDirection(cricket::MD_SENDONLY));
   1660 }
   1661 
   1662 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
   1663   EXPECT_TRUE(TestDeserializeDirection(cricket::MD_INACTIVE));
   1664 }
   1665 
   1666 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
   1667   EXPECT_TRUE(TestDeserializeRejected(true, false));
   1668 }
   1669 
   1670 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
   1671   EXPECT_TRUE(TestDeserializeRejected(false, true));
   1672 }
   1673 
   1674 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
   1675   EXPECT_TRUE(TestDeserializeRejected(true, true));
   1676 }
   1677 
   1678 // Tests that we can still handle the sdp uses mslabel and label instead of
   1679 // msid for backward compatibility.
   1680 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMsid) {
   1681   JsepSessionDescription jdesc(kDummyString);
   1682   std::string sdp_without_msid = kSdpFullString;
   1683   Replace("msid", "xmsid", &sdp_without_msid);
   1684   // Deserialize
   1685   EXPECT_TRUE(SdpDeserialize(sdp_without_msid, &jdesc));
   1686   // Verify
   1687   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
   1688 }
   1689 
   1690 TEST_F(WebRtcSdpTest, DeserializeCandidate) {
   1691   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   1692 
   1693   std::string sdp = kSdpOneCandidate;
   1694   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   1695   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1696   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1697   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   1698 
   1699   // Candidate line without generation extension.
   1700   sdp = kSdpOneCandidate;
   1701   Replace(" generation 2", "", &sdp);
   1702   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   1703   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1704   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1705   Candidate expected = jcandidate_->candidate();
   1706   expected.set_generation(0);
   1707   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
   1708 
   1709   // Multiple candidate lines.
   1710   // Only the first line will be deserialized. The rest will be ignored.
   1711   sdp = kSdpOneCandidate;
   1712   sdp.append("a=candidate:1 2 tcp 1234 192.168.1.100 5678 typ host\r\n");
   1713   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   1714   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1715   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1716   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   1717 }
   1718 
   1719 // This test verifies the deserialization of candidate-attribute
   1720 // as per RFC 5245. Candiate-attribute will be of the format
   1721 // candidate:<blah>. This format will be used when candidates
   1722 // are trickled.
   1723 TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
   1724   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   1725 
   1726   std::string candidate_attribute = kRawCandidate;
   1727   EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   1728   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1729   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1730   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   1731   EXPECT_EQ(2u, jcandidate.candidate().generation());
   1732 
   1733   // Candidate line without generation extension.
   1734   candidate_attribute = kRawCandidate;
   1735   Replace(" generation 2", "", &candidate_attribute);
   1736   EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   1737   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1738   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1739   Candidate expected = jcandidate_->candidate();
   1740   expected.set_generation(0);
   1741   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
   1742 
   1743   // Candidate line without candidate:
   1744   candidate_attribute = kRawCandidate;
   1745   Replace("candidate:", "", &candidate_attribute);
   1746   EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   1747 
   1748   // Concatenating additional candidate. Expecting deserialization to fail.
   1749   candidate_attribute = kRawCandidate;
   1750   candidate_attribute.append("candidate:1 2 udp 1234 192.168.1.1 typ host");
   1751   EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   1752 }
   1753 
   1754 TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannels) {
   1755   AddRtpDataChannel();
   1756   JsepSessionDescription jdesc(kDummyString);
   1757   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1758 
   1759   std::string sdp_with_data = kSdpString;
   1760   sdp_with_data.append(kSdpRtpDataChannelString);
   1761   JsepSessionDescription jdesc_output(kDummyString);
   1762 
   1763   // Deserialize
   1764   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   1765   // Verify
   1766   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   1767 }
   1768 
   1769 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
   1770   AddSctpDataChannel();
   1771   JsepSessionDescription jdesc(kDummyString);
   1772   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1773 
   1774   std::string sdp_with_data = kSdpString;
   1775   sdp_with_data.append(kSdpSctpDataChannelString);
   1776   JsepSessionDescription jdesc_output(kDummyString);
   1777 
   1778   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   1779   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   1780 }
   1781 
   1782 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
   1783   AddSctpDataChannel();
   1784   const uint16 kUnusualSctpPort = 9556;
   1785   char default_portstr[16];
   1786   char unusual_portstr[16];
   1787   talk_base::sprintfn(default_portstr, sizeof(default_portstr), "%d",
   1788                       kDefaultSctpPort);
   1789   talk_base::sprintfn(unusual_portstr, sizeof(unusual_portstr), "%d",
   1790                       kUnusualSctpPort);
   1791 
   1792   JsepSessionDescription jdesc(kDummyString);
   1793   // take our pre-built session description and change the SCTP port.
   1794   cricket::SessionDescription* mutant = desc_.Copy();
   1795   DataContentDescription* dcdesc = static_cast<DataContentDescription*>(
   1796       mutant->GetContentDescriptionByName(kDataContentName));
   1797   std::vector<cricket::DataCodec> codecs(dcdesc->codecs());
   1798   EXPECT_EQ(codecs.size(), 1UL);
   1799   EXPECT_EQ(codecs[0].id, cricket::kGoogleSctpDataCodecId);
   1800   codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort);
   1801 
   1802   // note: mutant's owned by jdesc now.
   1803   ASSERT_TRUE(jdesc.Initialize(mutant, kSessionId, kSessionVersion));
   1804   mutant = NULL;
   1805 
   1806   std::string sdp_with_data = kSdpString;
   1807   sdp_with_data.append(kSdpSctpDataChannelString);
   1808   talk_base::replace_substrs(default_portstr, strlen(default_portstr),
   1809                              unusual_portstr, strlen(unusual_portstr),
   1810                              &sdp_with_data);
   1811   JsepSessionDescription jdesc_output(kDummyString);
   1812 
   1813   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   1814   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   1815 }
   1816 
   1817 TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
   1818   AddRtpDataChannel();
   1819   JsepSessionDescription jdesc(kDummyString);
   1820   // We want to test that deserializing data content ignores bandwidth
   1821   // settings (it should always be the default).  Thus, we don't do
   1822   // the following:
   1823   // TODO(pthatcher): We need to temporarily allow the SDP to control
   1824   // this for backwards-compatibility.  Once we don't need that any
   1825   // more, remove this.
   1826   DataContentDescription* dcd = static_cast<DataContentDescription*>(
   1827      GetFirstDataContent(&desc_)->description);
   1828   dcd->set_bandwidth(100 * 1000);
   1829   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1830 
   1831   std::string sdp_with_bandwidth = kSdpString;
   1832   sdp_with_bandwidth.append(kSdpRtpDataChannelString);
   1833   InjectAfter("a=mid:data_content_name\r\n",
   1834               "b=AS:100\r\n",
   1835               &sdp_with_bandwidth);
   1836   JsepSessionDescription jdesc_with_bandwidth(kDummyString);
   1837 
   1838   EXPECT_TRUE(
   1839       SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
   1840   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
   1841 }
   1842 
   1843 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSessionLevelExtmap) {
   1844   TestDeserializeExtmap(true, false);
   1845 }
   1846 
   1847 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
   1848   TestDeserializeExtmap(false, true);
   1849 }
   1850 
   1851 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInvalidExtmap) {
   1852   TestDeserializeExtmap(true, true);
   1853 }
   1854 
   1855 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
   1856   JsepSessionDescription jdesc(kDummyString);
   1857   std::string sdp = kSdpFullString;
   1858   sdp = sdp.substr(0, sdp.size() - 2);  // Remove \r\n at the end.
   1859   // Deserialize
   1860   SdpParseError error;
   1861   EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
   1862   const std::string lastline = "a=ssrc:6 label:video_track_id_3";
   1863   EXPECT_EQ(lastline, error.line);
   1864   EXPECT_EQ("Invalid SDP line.", error.description);
   1865 }
   1866 
   1867 TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
   1868   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   1869   std::string new_sdp = kSdpOneCandidate;
   1870   Replace("udp", "unsupported_transport", &new_sdp);
   1871   EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
   1872   new_sdp = kSdpOneCandidate;
   1873   Replace("udp", "uDP", &new_sdp);
   1874   EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
   1875   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1876   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1877   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   1878 }
   1879 
   1880 TEST_F(WebRtcSdpTest, DeserializeCandidateOldFormat) {
   1881   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   1882   EXPECT_TRUE(SdpDeserializeCandidate(kSdpOneCandidateOldFormat,&jcandidate));
   1883   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   1884   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   1885   Candidate ref_candidate = jcandidate_->candidate();
   1886   ref_candidate.set_username("user_rtp");
   1887   ref_candidate.set_password("password_rtp");
   1888   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
   1889 }
   1890 
   1891 TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
   1892   const char kSdpDestroyer[] = "!@#$%^&";
   1893   const char kSdpInvalidLine1[] = " =candidate";
   1894   const char kSdpInvalidLine2[] = "a+candidate";
   1895   const char kSdpInvalidLine3[] = "a= candidate";
   1896   // Broken fingerprint.
   1897   const char kSdpInvalidLine4[] = "a=fingerprint:sha-1 "
   1898       "4AAD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
   1899   // Extra field.
   1900   const char kSdpInvalidLine5[] = "a=fingerprint:sha-1 "
   1901       "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB XXX";
   1902   // Missing space.
   1903   const char kSdpInvalidLine6[] = "a=fingerprint:sha-1"
   1904       "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
   1905 
   1906   // Broken session description
   1907   ReplaceAndTryToParse("v=", kSdpDestroyer);
   1908   ReplaceAndTryToParse("o=", kSdpDestroyer);
   1909   ReplaceAndTryToParse("s=-", kSdpDestroyer);
   1910   // Broken time description
   1911   ReplaceAndTryToParse("t=", kSdpDestroyer);
   1912 
   1913   // Broken media description
   1914   ReplaceAndTryToParse("m=audio", "c=IN IP4 74.125.224.39");
   1915   ReplaceAndTryToParse("m=video", kSdpDestroyer);
   1916 
   1917   // Invalid lines
   1918   ReplaceAndTryToParse("a=candidate", kSdpInvalidLine1);
   1919   ReplaceAndTryToParse("a=candidate", kSdpInvalidLine2);
   1920   ReplaceAndTryToParse("a=candidate", kSdpInvalidLine3);
   1921 
   1922   // Bogus fingerprint replacing a=sendrev. We selected this attribute
   1923   // because it's orthogonal to what we are replacing and hence
   1924   // safe.
   1925   ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine4);
   1926   ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine5);
   1927   ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine6);
   1928 }
   1929 
   1930 TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
   1931   JsepSessionDescription jdesc_output(kDummyString);
   1932 
   1933   const char kSdpWithReorderedPlTypesString[] =
   1934       "v=0\r\n"
   1935       "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1936       "s=-\r\n"
   1937       "t=0 0\r\n"
   1938       "m=audio 1 RTP/SAVPF 104 103\r\n"  // Pl type 104 preferred.
   1939       "a=rtpmap:111 opus/48000/2\r\n"  // Pltype 111 listed before 103 and 104
   1940                                        // in the map.
   1941       "a=rtpmap:103 ISAC/16000\r\n"  // Pltype 103 listed before 104 in the map.
   1942       "a=rtpmap:104 CELT/32000/2\r\n";
   1943 
   1944   // Deserialize
   1945   EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
   1946 
   1947   const ContentInfo* ac = GetFirstAudioContent(jdesc_output.description());
   1948   ASSERT_TRUE(ac != NULL);
   1949   const AudioContentDescription* acd =
   1950       static_cast<const AudioContentDescription*>(ac->description);
   1951   ASSERT_FALSE(acd->codecs().empty());
   1952   EXPECT_EQ("CELT", acd->codecs()[0].name);
   1953   EXPECT_EQ(104, acd->codecs()[0].id);
   1954 }
   1955 
   1956 TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
   1957   JsepSessionDescription jdesc_output(kDummyString);
   1958   CodecParams params;
   1959   params.max_ptime = 40;
   1960   params.ptime = 30;
   1961   params.min_ptime = 10;
   1962   params.sprop_stereo = 1;
   1963   params.stereo = 1;
   1964   params.useinband = 1;
   1965   params.maxaveragebitrate = 128000;
   1966   TestDeserializeCodecParams(params, &jdesc_output);
   1967   TestSerialize(jdesc_output);
   1968 }
   1969 
   1970 TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
   1971   const bool kUseWildcard = false;
   1972   JsepSessionDescription jdesc_output(kDummyString);
   1973   TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
   1974   TestSerialize(jdesc_output);
   1975 }
   1976 
   1977 TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
   1978   const bool kUseWildcard = true;
   1979   JsepSessionDescription jdesc_output(kDummyString);
   1980   TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
   1981   TestSerialize(jdesc_output);
   1982 }
   1983 
   1984 TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
   1985   JsepSessionDescription jdesc_output(kDummyString);
   1986 
   1987   const char kSdpWithFmtpString[] =
   1988       "v=0\r\n"
   1989       "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1990       "s=-\r\n"
   1991       "t=0 0\r\n"
   1992       "m=video 3457 RTP/SAVPF 120\r\n"
   1993       "a=rtpmap:120 VP8/90000\r\n"
   1994       "a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
   1995 
   1996   // Deserialize
   1997   SdpParseError error;
   1998   EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output,
   1999                                      &error));
   2000 
   2001   const ContentInfo* vc = GetFirstVideoContent(jdesc_output.description());
   2002   ASSERT_TRUE(vc != NULL);
   2003   const VideoContentDescription* vcd =
   2004       static_cast<const VideoContentDescription*>(vc->description);
   2005   ASSERT_FALSE(vcd->codecs().empty());
   2006   cricket::VideoCodec vp8 = vcd->codecs()[0];
   2007   EXPECT_EQ("VP8", vp8.name);
   2008   EXPECT_EQ(120, vp8.id);
   2009   cricket::CodecParameterMap::iterator found =
   2010       vp8.params.find("x-google-min-bitrate");
   2011   ASSERT_TRUE(found != vp8.params.end());
   2012   EXPECT_EQ(found->second, "10");
   2013   found = vp8.params.find("x-google-max-quantization");
   2014   ASSERT_TRUE(found != vp8.params.end());
   2015   EXPECT_EQ(found->second, "40");
   2016 }
   2017 
   2018 TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
   2019   VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
   2020       GetFirstVideoContent(&desc_)->description);
   2021 
   2022   cricket::VideoCodecs codecs = vcd->codecs();
   2023   codecs[0].params["x-google-min-bitrate"] = "10";
   2024   vcd->set_codecs(codecs);
   2025 
   2026   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   2027                                 jdesc_.session_id(),
   2028                                 jdesc_.session_version()));
   2029   std::string message = webrtc::SdpSerialize(jdesc_);
   2030   std::string sdp_with_fmtp = kSdpFullString;
   2031   InjectAfter("a=rtpmap:120 VP8/90000\r\n",
   2032               "a=fmtp:120 x-google-min-bitrate=10\r\n",
   2033               &sdp_with_fmtp);
   2034   EXPECT_EQ(sdp_with_fmtp, message);
   2035 }
   2036 
   2037 TEST_F(WebRtcSdpTest, DeserializeSdpWithIceLite) {
   2038   JsepSessionDescription jdesc_with_icelite(kDummyString);
   2039   std::string sdp_with_icelite = kSdpFullString;
   2040   EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
   2041   cricket::SessionDescription* desc = jdesc_with_icelite.description();
   2042   const cricket::TransportInfo* tinfo1 =
   2043       desc->GetTransportInfoByName("audio_content_name");
   2044   EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
   2045   const cricket::TransportInfo* tinfo2 =
   2046       desc->GetTransportInfoByName("video_content_name");
   2047   EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
   2048   InjectAfter(kSessionTime,
   2049               "a=ice-lite\r\n",
   2050               &sdp_with_icelite);
   2051   EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
   2052   desc = jdesc_with_icelite.description();
   2053   const cricket::TransportInfo* atinfo =
   2054       desc->GetTransportInfoByName("audio_content_name");
   2055   EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
   2056   const cricket::TransportInfo* vtinfo =
   2057         desc->GetTransportInfoByName("video_content_name");
   2058   EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
   2059 }
   2060 
   2061 // Verifies that the candidates in the input SDP are parsed and serialized
   2062 // correctly in the output SDP.
   2063 TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
   2064   std::string sdp_with_data = kSdpString;
   2065   sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
   2066   JsepSessionDescription jdesc_output(kDummyString);
   2067 
   2068   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2069   EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
   2070 }
   2071 
   2072 TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
   2073   AddFingerprint();
   2074   TransportInfo audio_transport_info =
   2075       *(desc_.GetTransportInfoByName(kAudioContentName));
   2076   EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
   2077             audio_transport_info.description.connection_role);
   2078   audio_transport_info.description.connection_role =
   2079         cricket::CONNECTIONROLE_ACTIVE;
   2080 
   2081   TransportInfo video_transport_info =
   2082       *(desc_.GetTransportInfoByName(kVideoContentName));
   2083   EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
   2084             video_transport_info.description.connection_role);
   2085   video_transport_info.description.connection_role =
   2086         cricket::CONNECTIONROLE_ACTIVE;
   2087 
   2088   desc_.RemoveTransportInfoByName(kAudioContentName);
   2089   desc_.RemoveTransportInfoByName(kVideoContentName);
   2090 
   2091   desc_.AddTransportInfo(audio_transport_info);
   2092   desc_.AddTransportInfo(video_transport_info);
   2093 
   2094   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   2095                                 jdesc_.session_id(),
   2096                                 jdesc_.session_version()));
   2097   std::string message = webrtc::SdpSerialize(jdesc_);
   2098   std::string sdp_with_dtlssetup = kSdpFullString;
   2099 
   2100   // Fingerprint attribute is necessary to add DTLS setup attribute.
   2101   InjectAfter(kAttributeIcePwdVoice,
   2102               kFingerprint, &sdp_with_dtlssetup);
   2103   InjectAfter(kAttributeIcePwdVideo,
   2104               kFingerprint, &sdp_with_dtlssetup);
   2105   // Now adding |setup| attribute.
   2106   InjectAfter(kFingerprint,
   2107               "a=setup:active\r\n", &sdp_with_dtlssetup);
   2108   EXPECT_EQ(sdp_with_dtlssetup, message);
   2109 }
   2110 
   2111 TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttribute) {
   2112   JsepSessionDescription jdesc_with_dtlssetup(kDummyString);
   2113   std::string sdp_with_dtlssetup = kSdpFullString;
   2114   InjectAfter(kSessionTime,
   2115               "a=setup:actpass\r\n",
   2116               &sdp_with_dtlssetup);
   2117   EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
   2118   cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
   2119   const cricket::TransportInfo* atinfo =
   2120       desc->GetTransportInfoByName("audio_content_name");
   2121   EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
   2122             atinfo->description.connection_role);
   2123   const cricket::TransportInfo* vtinfo =
   2124         desc->GetTransportInfoByName("video_content_name");
   2125   EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
   2126             vtinfo->description.connection_role);
   2127 }
   2128