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 #ifdef WEBRTC_ANDROID
     34 #include "talk/app/webrtc/test/androidtestinitializer.h"
     35 #endif
     36 #include "talk/app/webrtc/webrtcsdp.h"
     37 #include "talk/media/base/constants.h"
     38 #include "webrtc/p2p/base/constants.h"
     39 #include "talk/session/media/mediasession.h"
     40 #include "webrtc/base/gunit.h"
     41 #include "webrtc/base/logging.h"
     42 #include "webrtc/base/messagedigest.h"
     43 #include "webrtc/base/scoped_ptr.h"
     44 #include "webrtc/base/sslfingerprint.h"
     45 #include "webrtc/base/stringencode.h"
     46 #include "webrtc/base/stringutils.h"
     47 
     48 using cricket::AudioCodec;
     49 using cricket::AudioContentDescription;
     50 using cricket::Candidate;
     51 using cricket::ContentInfo;
     52 using cricket::CryptoParams;
     53 using cricket::ContentGroup;
     54 using cricket::DataCodec;
     55 using cricket::DataContentDescription;
     56 using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
     57 using cricket::ICE_CANDIDATE_COMPONENT_RTP;
     58 using cricket::kFecSsrcGroupSemantics;
     59 using cricket::LOCAL_PORT_TYPE;
     60 using cricket::NS_JINGLE_DRAFT_SCTP;
     61 using cricket::NS_JINGLE_RTP;
     62 using cricket::RtpHeaderExtension;
     63 using cricket::RELAY_PORT_TYPE;
     64 using cricket::SessionDescription;
     65 using cricket::StreamParams;
     66 using cricket::STUN_PORT_TYPE;
     67 using cricket::TransportDescription;
     68 using cricket::TransportInfo;
     69 using cricket::VideoCodec;
     70 using cricket::VideoContentDescription;
     71 using webrtc::IceCandidateCollection;
     72 using webrtc::IceCandidateInterface;
     73 using webrtc::JsepIceCandidate;
     74 using webrtc::JsepSessionDescription;
     75 using webrtc::SdpParseError;
     76 using webrtc::SessionDescriptionInterface;
     77 
     78 typedef std::vector<AudioCodec> AudioCodecs;
     79 typedef std::vector<Candidate> Candidates;
     80 
     81 static const uint32_t kDefaultSctpPort = 5000;
     82 static const char kSessionTime[] = "t=0 0\r\n";
     83 static const uint32_t kCandidatePriority = 2130706432U;  // pref = 1.0
     84 static const char kCandidateUfragVoice[] = "ufrag_voice";
     85 static const char kCandidatePwdVoice[] = "pwd_voice";
     86 static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
     87 static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
     88 static const char kCandidateUfragVideo[] = "ufrag_video";
     89 static const char kCandidatePwdVideo[] = "pwd_video";
     90 static const char kCandidateUfragData[] = "ufrag_data";
     91 static const char kCandidatePwdData[] = "pwd_data";
     92 static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
     93 static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
     94 static const uint32_t kCandidateGeneration = 2;
     95 static const char kCandidateFoundation1[] = "a0+B/1";
     96 static const char kCandidateFoundation2[] = "a0+B/2";
     97 static const char kCandidateFoundation3[] = "a0+B/3";
     98 static const char kCandidateFoundation4[] = "a0+B/4";
     99 static const char kAttributeCryptoVoice[] =
    100     "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
    101     "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
    102     "dummy_session_params\r\n";
    103 static const char kAttributeCryptoVideo[] =
    104     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    105     "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
    106 static const char kFingerprint[] = "a=fingerprint:sha-1 "
    107     "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n";
    108 static const int kExtmapId = 1;
    109 static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
    110 static const char kExtmap[] =
    111     "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
    112 static const char kExtmapWithDirectionAndAttribute[] =
    113     "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
    114 
    115 static const uint8_t kIdentityDigest[] = {
    116     0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
    117     0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
    118 
    119 static const char kDtlsSctp[] = "DTLS/SCTP";
    120 static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
    121 static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
    122 
    123 struct CodecParams {
    124   int max_ptime;
    125   int ptime;
    126   int min_ptime;
    127   int sprop_stereo;
    128   int stereo;
    129   int useinband;
    130   int maxaveragebitrate;
    131 };
    132 
    133 // Reference sdp string
    134 static const char kSdpFullString[] =
    135     "v=0\r\n"
    136     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
    137     "s=-\r\n"
    138     "t=0 0\r\n"
    139     "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
    140     "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
    141     "c=IN IP4 74.125.127.126\r\n"
    142     "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
    143     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
    144     "generation 2\r\n"
    145     "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
    146     "generation 2\r\n"
    147     "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
    148     "generation 2\r\n"
    149     "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
    150     "generation 2\r\n"
    151     "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
    152     "raddr 192.168.1.5 rport 2346 "
    153     "generation 2\r\n"
    154     "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
    155     "raddr 192.168.1.5 rport 2348 "
    156     "generation 2\r\n"
    157     "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
    158     "a=mid:audio_content_name\r\n"
    159     "a=sendrecv\r\n"
    160     "a=rtcp-mux\r\n"
    161     "a=rtcp-rsize\r\n"
    162     "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
    163     "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
    164     "dummy_session_params\r\n"
    165     "a=rtpmap:111 opus/48000/2\r\n"
    166     "a=rtpmap:103 ISAC/16000\r\n"
    167     "a=rtpmap:104 ISAC/32000\r\n"
    168     "a=ssrc:1 cname:stream_1_cname\r\n"
    169     "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
    170     "a=ssrc:1 mslabel:local_stream_1\r\n"
    171     "a=ssrc:1 label:audio_track_id_1\r\n"
    172     "a=ssrc:4 cname:stream_2_cname\r\n"
    173     "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
    174     "a=ssrc:4 mslabel:local_stream_2\r\n"
    175     "a=ssrc:4 label:audio_track_id_2\r\n"
    176     "m=video 3457 RTP/SAVPF 120\r\n"
    177     "c=IN IP4 74.125.224.39\r\n"
    178     "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
    179     "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
    180     "generation 2\r\n"
    181     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
    182     "generation 2\r\n"
    183     "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
    184     "generation 2\r\n"
    185     "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
    186     "generation 2\r\n"
    187     "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
    188     "generation 2\r\n"
    189     "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
    190     "generation 2\r\n"
    191     "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
    192     "a=mid:video_content_name\r\n"
    193     "a=sendrecv\r\n"
    194     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    195     "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
    196     "a=rtpmap:120 VP8/90000\r\n"
    197     "a=ssrc:2 cname:stream_1_cname\r\n"
    198     "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
    199     "a=ssrc:2 mslabel:local_stream_1\r\n"
    200     "a=ssrc:2 label:video_track_id_1\r\n"
    201     "a=ssrc:3 cname:stream_1_cname\r\n"
    202     "a=ssrc:3 msid:local_stream_1 video_track_id_2\r\n"
    203     "a=ssrc:3 mslabel:local_stream_1\r\n"
    204     "a=ssrc:3 label:video_track_id_2\r\n"
    205     "a=ssrc-group:FEC 5 6\r\n"
    206     "a=ssrc:5 cname:stream_2_cname\r\n"
    207     "a=ssrc:5 msid:local_stream_2 video_track_id_3\r\n"
    208     "a=ssrc:5 mslabel:local_stream_2\r\n"
    209     "a=ssrc:5 label:video_track_id_3\r\n"
    210     "a=ssrc:6 cname:stream_2_cname\r\n"
    211     "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
    212     "a=ssrc:6 mslabel:local_stream_2\r\n"
    213     "a=ssrc:6 label:video_track_id_3\r\n";
    214 
    215 // SDP reference string without the candidates.
    216 static const char kSdpString[] =
    217     "v=0\r\n"
    218     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
    219     "s=-\r\n"
    220     "t=0 0\r\n"
    221     "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
    222     "m=audio 9 RTP/SAVPF 111 103 104\r\n"
    223     "c=IN IP4 0.0.0.0\r\n"
    224     "a=rtcp:9 IN IP4 0.0.0.0\r\n"
    225     "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
    226     "a=mid:audio_content_name\r\n"
    227     "a=sendrecv\r\n"
    228     "a=rtcp-mux\r\n"
    229     "a=rtcp-rsize\r\n"
    230     "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
    231     "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
    232     "dummy_session_params\r\n"
    233     "a=rtpmap:111 opus/48000/2\r\n"
    234     "a=rtpmap:103 ISAC/16000\r\n"
    235     "a=rtpmap:104 ISAC/32000\r\n"
    236     "a=ssrc:1 cname:stream_1_cname\r\n"
    237     "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
    238     "a=ssrc:1 mslabel:local_stream_1\r\n"
    239     "a=ssrc:1 label:audio_track_id_1\r\n"
    240     "a=ssrc:4 cname:stream_2_cname\r\n"
    241     "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
    242     "a=ssrc:4 mslabel:local_stream_2\r\n"
    243     "a=ssrc:4 label:audio_track_id_2\r\n"
    244     "m=video 9 RTP/SAVPF 120\r\n"
    245     "c=IN IP4 0.0.0.0\r\n"
    246     "a=rtcp:9 IN IP4 0.0.0.0\r\n"
    247     "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
    248     "a=mid:video_content_name\r\n"
    249     "a=sendrecv\r\n"
    250     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    251     "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
    252     "a=rtpmap:120 VP8/90000\r\n"
    253     "a=ssrc:2 cname:stream_1_cname\r\n"
    254     "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
    255     "a=ssrc:2 mslabel:local_stream_1\r\n"
    256     "a=ssrc:2 label:video_track_id_1\r\n"
    257     "a=ssrc:3 cname:stream_1_cname\r\n"
    258     "a=ssrc:3 msid:local_stream_1 video_track_id_2\r\n"
    259     "a=ssrc:3 mslabel:local_stream_1\r\n"
    260     "a=ssrc:3 label:video_track_id_2\r\n"
    261     "a=ssrc-group:FEC 5 6\r\n"
    262     "a=ssrc:5 cname:stream_2_cname\r\n"
    263     "a=ssrc:5 msid:local_stream_2 video_track_id_3\r\n"
    264     "a=ssrc:5 mslabel:local_stream_2\r\n"
    265     "a=ssrc:5 label:video_track_id_3\r\n"
    266     "a=ssrc:6 cname:stream_2_cname\r\n"
    267     "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
    268     "a=ssrc:6 mslabel:local_stream_2\r\n"
    269     "a=ssrc:6 label:video_track_id_3\r\n";
    270 
    271 static const char kSdpRtpDataChannelString[] =
    272     "m=application 9 RTP/SAVPF 101\r\n"
    273     "c=IN IP4 0.0.0.0\r\n"
    274     "a=rtcp:9 IN IP4 0.0.0.0\r\n"
    275     "a=ice-ufrag:ufrag_data\r\n"
    276     "a=ice-pwd:pwd_data\r\n"
    277     "a=mid:data_content_name\r\n"
    278     "a=sendrecv\r\n"
    279     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
    280     "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5\r\n"
    281     "a=rtpmap:101 google-data/90000\r\n"
    282     "a=ssrc:10 cname:data_channel_cname\r\n"
    283     "a=ssrc:10 msid:data_channel data_channeld0\r\n"
    284     "a=ssrc:10 mslabel:data_channel\r\n"
    285     "a=ssrc:10 label:data_channeld0\r\n";
    286 
    287 static const char kSdpSctpDataChannelString[] =
    288     "m=application 9 DTLS/SCTP 5000\r\n"
    289     "c=IN IP4 0.0.0.0\r\n"
    290     "a=ice-ufrag:ufrag_data\r\n"
    291     "a=ice-pwd:pwd_data\r\n"
    292     "a=mid:data_content_name\r\n"
    293     "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
    294 
    295 // draft-ietf-mmusic-sctp-sdp-12
    296 static const char kSdpSctpDataChannelStringWithSctpPort[] =
    297     "m=application 9 DTLS/SCTP webrtc-datachannel\r\n"
    298     "a=max-message-size=100000\r\n"
    299     "a=sctp-port 5000\r\n"
    300     "c=IN IP4 0.0.0.0\r\n"
    301     "a=ice-ufrag:ufrag_data\r\n"
    302     "a=ice-pwd:pwd_data\r\n"
    303     "a=mid:data_content_name\r\n";
    304 
    305 static const char kSdpSctpDataChannelStringWithSctpColonPort[] =
    306     "m=application 9 DTLS/SCTP webrtc-datachannel\r\n"
    307     "a=max-message-size=100000\r\n"
    308     "a=sctp-port:5000\r\n"
    309     "c=IN IP4 0.0.0.0\r\n"
    310     "a=ice-ufrag:ufrag_data\r\n"
    311     "a=ice-pwd:pwd_data\r\n"
    312     "a=mid:data_content_name\r\n";
    313 
    314 static const char kSdpSctpDataChannelWithCandidatesString[] =
    315     "m=application 2345 DTLS/SCTP 5000\r\n"
    316     "c=IN IP4 74.125.127.126\r\n"
    317     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
    318     "generation 2\r\n"
    319     "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
    320     "generation 2\r\n"
    321     "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
    322     "raddr 192.168.1.5 rport 2346 "
    323     "generation 2\r\n"
    324     "a=ice-ufrag:ufrag_data\r\n"
    325     "a=ice-pwd:pwd_data\r\n"
    326     "a=mid:data_content_name\r\n"
    327     "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
    328 
    329 static const char kSdpConferenceString[] =
    330     "v=0\r\n"
    331     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
    332     "s=-\r\n"
    333     "t=0 0\r\n"
    334     "a=msid-semantic: WMS\r\n"
    335     "m=audio 9 RTP/SAVPF 111 103 104\r\n"
    336     "c=IN IP4 0.0.0.0\r\n"
    337     "a=x-google-flag:conference\r\n"
    338     "m=video 9 RTP/SAVPF 120\r\n"
    339     "c=IN IP4 0.0.0.0\r\n"
    340     "a=x-google-flag:conference\r\n";
    341 
    342 static const char kSdpSessionString[] =
    343     "v=0\r\n"
    344     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
    345     "s=-\r\n"
    346     "t=0 0\r\n"
    347     "a=msid-semantic: WMS local_stream\r\n";
    348 
    349 static const char kSdpAudioString[] =
    350     "m=audio 9 RTP/SAVPF 111\r\n"
    351     "c=IN IP4 0.0.0.0\r\n"
    352     "a=rtcp:9 IN IP4 0.0.0.0\r\n"
    353     "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
    354     "a=mid:audio_content_name\r\n"
    355     "a=sendrecv\r\n"
    356     "a=rtpmap:111 opus/48000/2\r\n"
    357     "a=ssrc:1 cname:stream_1_cname\r\n"
    358     "a=ssrc:1 msid:local_stream audio_track_id_1\r\n"
    359     "a=ssrc:1 mslabel:local_stream\r\n"
    360     "a=ssrc:1 label:audio_track_id_1\r\n";
    361 
    362 static const char kSdpVideoString[] =
    363     "m=video 9 RTP/SAVPF 120\r\n"
    364     "c=IN IP4 0.0.0.0\r\n"
    365     "a=rtcp:9 IN IP4 0.0.0.0\r\n"
    366     "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
    367     "a=mid:video_content_name\r\n"
    368     "a=sendrecv\r\n"
    369     "a=rtpmap:120 VP8/90000\r\n"
    370     "a=ssrc:2 cname:stream_1_cname\r\n"
    371     "a=ssrc:2 msid:local_stream video_track_id_1\r\n"
    372     "a=ssrc:2 mslabel:local_stream\r\n"
    373     "a=ssrc:2 label:video_track_id_1\r\n";
    374 
    375 
    376 // One candidate reference string as per W3c spec.
    377 // candidate:<blah> not a=candidate:<blah>CRLF
    378 static const char kRawCandidate[] =
    379     "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
    380 // One candidate reference string.
    381 static const char kSdpOneCandidate[] =
    382     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
    383     "generation 2\r\n";
    384 
    385 static const char kSdpTcpActiveCandidate[] =
    386     "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
    387     "tcptype active generation 2";
    388 static const char kSdpTcpPassiveCandidate[] =
    389     "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
    390     "tcptype passive generation 2";
    391 static const char kSdpTcpSOCandidate[] =
    392     "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
    393     "tcptype so generation 2";
    394 static const char kSdpTcpInvalidCandidate[] =
    395     "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
    396     "tcptype invalid generation 2";
    397 
    398 // One candidate reference string with IPV6 address.
    399 static const char kRawIPV6Candidate[] =
    400     "candidate:a0+B/1 1 udp 2130706432 "
    401     "abcd::abcd::abcd::abcd::abcd::abcd::abcd::abcd 1234 typ host generation 2";
    402 
    403 // One candidate reference string.
    404 static const char kSdpOneCandidateWithUfragPwd[] =
    405     "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
    406     " eth0 ufrag user_rtp pwd password_rtp generation 2\r\n";
    407 
    408 // Session id and version
    409 static const char kSessionId[] = "18446744069414584320";
    410 static const char kSessionVersion[] = "18446462598732840960";
    411 
    412 // Ice options
    413 static const char kIceOption1[] = "iceoption1";
    414 static const char kIceOption2[] = "iceoption2";
    415 static const char kIceOption3[] = "iceoption3";
    416 
    417 // Content name
    418 static const char kAudioContentName[] = "audio_content_name";
    419 static const char kVideoContentName[] = "video_content_name";
    420 static const char kDataContentName[] = "data_content_name";
    421 
    422 // MediaStream 1
    423 static const char kStreamLabel1[] = "local_stream_1";
    424 static const char kStream1Cname[] = "stream_1_cname";
    425 static const char kAudioTrackId1[] = "audio_track_id_1";
    426 static const uint32_t kAudioTrack1Ssrc = 1;
    427 static const char kVideoTrackId1[] = "video_track_id_1";
    428 static const uint32_t kVideoTrack1Ssrc = 2;
    429 static const char kVideoTrackId2[] = "video_track_id_2";
    430 static const uint32_t kVideoTrack2Ssrc = 3;
    431 
    432 // MediaStream 2
    433 static const char kStreamLabel2[] = "local_stream_2";
    434 static const char kStream2Cname[] = "stream_2_cname";
    435 static const char kAudioTrackId2[] = "audio_track_id_2";
    436 static const uint32_t kAudioTrack2Ssrc = 4;
    437 static const char kVideoTrackId3[] = "video_track_id_3";
    438 static const uint32_t kVideoTrack3Ssrc = 5;
    439 static const uint32_t kVideoTrack4Ssrc = 6;
    440 
    441 // DataChannel
    442 static const char kDataChannelLabel[] = "data_channel";
    443 static const char kDataChannelMsid[] = "data_channeld0";
    444 static const char kDataChannelCname[] = "data_channel_cname";
    445 static const uint32_t kDataChannelSsrc = 10;
    446 
    447 // Candidate
    448 static const char kDummyMid[] = "dummy_mid";
    449 static const int kDummyIndex = 123;
    450 
    451 // Misc
    452 static const char kDummyString[] = "dummy";
    453 
    454 // Helper functions
    455 
    456 static bool SdpDeserialize(const std::string& message,
    457                            JsepSessionDescription* jdesc) {
    458   return webrtc::SdpDeserialize(message, jdesc, NULL);
    459 }
    460 
    461 static bool SdpDeserializeCandidate(const std::string& message,
    462                                     JsepIceCandidate* candidate) {
    463   return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
    464 }
    465 
    466 // Add some extra |newlines| to the |message| after |line|.
    467 static void InjectAfter(const std::string& line,
    468                         const std::string& newlines,
    469                         std::string* message) {
    470   const std::string tmp = line + newlines;
    471   rtc::replace_substrs(line.c_str(), line.length(),
    472                              tmp.c_str(), tmp.length(), message);
    473 }
    474 
    475 static void Replace(const std::string& line,
    476                     const std::string& newlines,
    477                     std::string* message) {
    478   rtc::replace_substrs(line.c_str(), line.length(),
    479                              newlines.c_str(), newlines.length(), message);
    480 }
    481 
    482 // Expect fail to parase |bad_sdp| and expect |bad_part| be part of the error
    483 // message.
    484 static void ExpectParseFailure(const std::string& bad_sdp,
    485                                const std::string& bad_part) {
    486   JsepSessionDescription desc(kDummyString);
    487   SdpParseError error;
    488   bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
    489   EXPECT_FALSE(ret);
    490   EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()));
    491 }
    492 
    493 // Expect fail to parse kSdpFullString if replace |good_part| with |bad_part|.
    494 static void ExpectParseFailure(const char* good_part, const char* bad_part) {
    495   std::string bad_sdp = kSdpFullString;
    496   Replace(good_part, bad_part, &bad_sdp);
    497   ExpectParseFailure(bad_sdp, bad_part);
    498 }
    499 
    500 // Expect fail to parse kSdpFullString if add |newlines| after |injectpoint|.
    501 static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
    502                                            const std::string& newlines,
    503                                            const std::string& bad_part) {
    504   std::string bad_sdp = kSdpFullString;
    505   InjectAfter(injectpoint, newlines, &bad_sdp);
    506   ExpectParseFailure(bad_sdp, bad_part);
    507 }
    508 
    509 static void ReplaceDirection(cricket::MediaContentDirection direction,
    510                              std::string* message) {
    511   std::string new_direction;
    512   switch (direction) {
    513     case cricket::MD_INACTIVE:
    514       new_direction = "a=inactive";
    515       break;
    516     case cricket::MD_SENDONLY:
    517       new_direction = "a=sendonly";
    518       break;
    519     case cricket::MD_RECVONLY:
    520       new_direction = "a=recvonly";
    521       break;
    522     case cricket::MD_SENDRECV:
    523     default:
    524       new_direction = "a=sendrecv";
    525       break;
    526   }
    527   Replace("a=sendrecv", new_direction, message);
    528 }
    529 
    530 static void ReplaceRejected(bool audio_rejected, bool video_rejected,
    531                             std::string* message) {
    532   if (audio_rejected) {
    533     Replace("m=audio 9", "m=audio 0", message);
    534     Replace(kAttributeIceUfragVoice, "", message);
    535     Replace(kAttributeIcePwdVoice, "", message);
    536   }
    537   if (video_rejected) {
    538     Replace("m=video 9", "m=video 0", message);
    539     Replace(kAttributeIceUfragVideo, "", message);
    540     Replace(kAttributeIcePwdVideo, "", message);
    541   }
    542 }
    543 
    544 // WebRtcSdpTest
    545 
    546 class WebRtcSdpTest : public testing::Test {
    547  public:
    548   WebRtcSdpTest()
    549      : jdesc_(kDummyString) {
    550 #ifdef WEBRTC_ANDROID
    551     webrtc::InitializeAndroidObjects();
    552 #endif
    553     // AudioContentDescription
    554     audio_desc_ = CreateAudioContentDescription();
    555     AudioCodec opus(111, "opus", 48000, 0, 2, 3);
    556     audio_desc_->AddCodec(opus);
    557     audio_desc_->AddCodec(AudioCodec(103, "ISAC", 16000, 32000, 1, 2));
    558     audio_desc_->AddCodec(AudioCodec(104, "ISAC", 32000, 56000, 1, 1));
    559     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_desc_);
    560 
    561     // VideoContentDescription
    562     rtc::scoped_ptr<VideoContentDescription> video(
    563         new VideoContentDescription());
    564     video_desc_ = video.get();
    565     StreamParams video_stream1;
    566     video_stream1.id = kVideoTrackId1;
    567     video_stream1.cname = kStream1Cname;
    568     video_stream1.sync_label = kStreamLabel1;
    569     video_stream1.ssrcs.push_back(kVideoTrack1Ssrc);
    570     video->AddStream(video_stream1);
    571     StreamParams video_stream2;
    572     video_stream2.id = kVideoTrackId2;
    573     video_stream2.cname = kStream1Cname;
    574     video_stream2.sync_label = kStreamLabel1;
    575     video_stream2.ssrcs.push_back(kVideoTrack2Ssrc);
    576     video->AddStream(video_stream2);
    577     StreamParams video_stream3;
    578     video_stream3.id = kVideoTrackId3;
    579     video_stream3.cname = kStream2Cname;
    580     video_stream3.sync_label = kStreamLabel2;
    581     video_stream3.ssrcs.push_back(kVideoTrack3Ssrc);
    582     video_stream3.ssrcs.push_back(kVideoTrack4Ssrc);
    583     cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream3.ssrcs);
    584     video_stream3.ssrc_groups.push_back(ssrc_group);
    585     video->AddStream(video_stream3);
    586     video->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_80",
    587         "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
    588     video->set_protocol(cricket::kMediaProtocolSavpf);
    589     video->AddCodec(VideoCodec(
    590         120,
    591         JsepSessionDescription::kDefaultVideoCodecName,
    592         JsepSessionDescription::kMaxVideoCodecWidth,
    593         JsepSessionDescription::kMaxVideoCodecHeight,
    594         JsepSessionDescription::kDefaultVideoCodecFramerate,
    595         JsepSessionDescription::kDefaultVideoCodecPreference));
    596 
    597     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP,
    598                      video.release());
    599 
    600     // TransportInfo
    601     EXPECT_TRUE(desc_.AddTransportInfo(
    602         TransportInfo(kAudioContentName,
    603                       TransportDescription(kCandidateUfragVoice,
    604                                            kCandidatePwdVoice))));
    605     EXPECT_TRUE(desc_.AddTransportInfo(
    606         TransportInfo(kVideoContentName,
    607                       TransportDescription(kCandidateUfragVideo,
    608                                            kCandidatePwdVideo))));
    609 
    610     // v4 host
    611     int port = 1234;
    612     rtc::SocketAddress address("192.168.1.5", port++);
    613     Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
    614                          kCandidatePriority, "", "", LOCAL_PORT_TYPE,
    615                          kCandidateGeneration, kCandidateFoundation1);
    616     address.SetPort(port++);
    617     Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
    618                          kCandidatePriority, "", "", LOCAL_PORT_TYPE,
    619                          kCandidateGeneration, kCandidateFoundation1);
    620     address.SetPort(port++);
    621     Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
    622                          kCandidatePriority, "", "", LOCAL_PORT_TYPE,
    623                          kCandidateGeneration, kCandidateFoundation1);
    624     address.SetPort(port++);
    625     Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
    626                          kCandidatePriority, "", "", LOCAL_PORT_TYPE,
    627                          kCandidateGeneration, kCandidateFoundation1);
    628 
    629     // v6 host
    630     rtc::SocketAddress v6_address("::1", port++);
    631     cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
    632                                   v6_address, kCandidatePriority, "", "",
    633                                   cricket::LOCAL_PORT_TYPE,
    634                                   kCandidateGeneration, kCandidateFoundation2);
    635     v6_address.SetPort(port++);
    636     cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
    637                                   v6_address, kCandidatePriority, "", "",
    638                                   cricket::LOCAL_PORT_TYPE,
    639                                   kCandidateGeneration, kCandidateFoundation2);
    640     v6_address.SetPort(port++);
    641     cricket::Candidate candidate7(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
    642                                   v6_address, kCandidatePriority, "", "",
    643                                   cricket::LOCAL_PORT_TYPE,
    644                                   kCandidateGeneration, kCandidateFoundation2);
    645     v6_address.SetPort(port++);
    646     cricket::Candidate candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
    647                                   v6_address, kCandidatePriority, "", "",
    648                                   cricket::LOCAL_PORT_TYPE,
    649                                   kCandidateGeneration, kCandidateFoundation2);
    650 
    651     // stun
    652     int port_stun = 2345;
    653     rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
    654     rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
    655     cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
    656                                   address_stun, kCandidatePriority, "", "",
    657                                   STUN_PORT_TYPE, kCandidateGeneration,
    658                                   kCandidateFoundation3);
    659     candidate9.set_related_address(rel_address_stun);
    660 
    661     address_stun.SetPort(port_stun++);
    662     rel_address_stun.SetPort(port_stun++);
    663     cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
    664                                    address_stun, kCandidatePriority, "", "",
    665                                    STUN_PORT_TYPE, kCandidateGeneration,
    666                                    kCandidateFoundation3);
    667     candidate10.set_related_address(rel_address_stun);
    668 
    669     // relay
    670     int port_relay = 3456;
    671     rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
    672     cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
    673                                    address_relay, kCandidatePriority, "", "",
    674                                    cricket::RELAY_PORT_TYPE,
    675                                    kCandidateGeneration, kCandidateFoundation4);
    676     address_relay.SetPort(port_relay++);
    677     cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
    678                                    address_relay, kCandidatePriority, "", "",
    679                                    RELAY_PORT_TYPE, kCandidateGeneration,
    680                                    kCandidateFoundation4);
    681 
    682     // voice
    683     candidates_.push_back(candidate1);
    684     candidates_.push_back(candidate2);
    685     candidates_.push_back(candidate5);
    686     candidates_.push_back(candidate6);
    687     candidates_.push_back(candidate9);
    688     candidates_.push_back(candidate10);
    689 
    690     // video
    691     candidates_.push_back(candidate3);
    692     candidates_.push_back(candidate4);
    693     candidates_.push_back(candidate7);
    694     candidates_.push_back(candidate8);
    695     candidates_.push_back(candidate11);
    696     candidates_.push_back(candidate12);
    697 
    698     jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"),
    699                                            0, candidate1));
    700 
    701     // Set up JsepSessionDescription.
    702     jdesc_.Initialize(desc_.Copy(), kSessionId, kSessionVersion);
    703     std::string mline_id;
    704     int mline_index = 0;
    705     for (size_t i = 0; i< candidates_.size(); ++i) {
    706       // In this test, the audio m line index will be 0, and the video m line
    707       // will be 1.
    708       bool is_video = (i > 5);
    709       mline_id = is_video ? "video_content_name" : "audio_content_name";
    710       mline_index = is_video ? 1 : 0;
    711       JsepIceCandidate jice(mline_id,
    712                             mline_index,
    713                             candidates_.at(i));
    714       jdesc_.AddCandidate(&jice);
    715     }
    716   }
    717 
    718   AudioContentDescription* CreateAudioContentDescription() {
    719     AudioContentDescription* audio = new AudioContentDescription();
    720     audio->set_rtcp_mux(true);
    721     audio->set_rtcp_reduced_size(true);
    722     StreamParams audio_stream1;
    723     audio_stream1.id = kAudioTrackId1;
    724     audio_stream1.cname = kStream1Cname;
    725     audio_stream1.sync_label = kStreamLabel1;
    726     audio_stream1.ssrcs.push_back(kAudioTrack1Ssrc);
    727     audio->AddStream(audio_stream1);
    728     StreamParams audio_stream2;
    729     audio_stream2.id = kAudioTrackId2;
    730     audio_stream2.cname = kStream2Cname;
    731     audio_stream2.sync_label = kStreamLabel2;
    732     audio_stream2.ssrcs.push_back(kAudioTrack2Ssrc);
    733     audio->AddStream(audio_stream2);
    734     audio->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_32",
    735         "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
    736         "dummy_session_params"));
    737     audio->set_protocol(cricket::kMediaProtocolSavpf);
    738     return audio;
    739   }
    740 
    741   template <class MCD>
    742   void CompareMediaContentDescription(const MCD* cd1,
    743                                       const MCD* cd2) {
    744     // type
    745     EXPECT_EQ(cd1->type(), cd1->type());
    746 
    747     // content direction
    748     EXPECT_EQ(cd1->direction(), cd2->direction());
    749 
    750     // rtcp_mux
    751     EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
    752 
    753     // rtcp_reduced_size
    754     EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size());
    755 
    756     // cryptos
    757     EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
    758     if (cd1->cryptos().size() != cd2->cryptos().size()) {
    759       ADD_FAILURE();
    760       return;
    761     }
    762     for (size_t i = 0; i< cd1->cryptos().size(); ++i) {
    763       const CryptoParams c1 = cd1->cryptos().at(i);
    764       const CryptoParams c2 = cd2->cryptos().at(i);
    765       EXPECT_TRUE(c1.Matches(c2));
    766       EXPECT_EQ(c1.key_params, c2.key_params);
    767       EXPECT_EQ(c1.session_params, c2.session_params);
    768     }
    769 
    770     // protocol
    771     // Use an equivalence class here, for old and new versions of the
    772     // protocol description.
    773     if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp
    774         || cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp
    775         || cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
    776       const bool cd2_is_also_dtls_sctp =
    777         cd2->protocol() == cricket::kMediaProtocolDtlsSctp
    778         || cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp
    779         || cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
    780       EXPECT_TRUE(cd2_is_also_dtls_sctp);
    781     } else {
    782       EXPECT_EQ(cd1->protocol(), cd2->protocol());
    783     }
    784 
    785     // codecs
    786     EXPECT_EQ(cd1->codecs(), cd2->codecs());
    787 
    788     // bandwidth
    789     EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
    790 
    791     // streams
    792     EXPECT_EQ(cd1->streams(), cd2->streams());
    793 
    794     // extmap
    795     ASSERT_EQ(cd1->rtp_header_extensions().size(),
    796               cd2->rtp_header_extensions().size());
    797     for (size_t i = 0; i< cd1->rtp_header_extensions().size(); ++i) {
    798       const RtpHeaderExtension ext1 = cd1->rtp_header_extensions().at(i);
    799       const RtpHeaderExtension ext2 = cd2->rtp_header_extensions().at(i);
    800       EXPECT_EQ(ext1.uri, ext2.uri);
    801       EXPECT_EQ(ext1.id, ext2.id);
    802     }
    803   }
    804 
    805 
    806   void CompareSessionDescription(const SessionDescription& desc1,
    807                                  const SessionDescription& desc2) {
    808     // Compare content descriptions.
    809     if (desc1.contents().size() != desc2.contents().size()) {
    810       ADD_FAILURE();
    811       return;
    812     }
    813     for (size_t i = 0 ; i < desc1.contents().size(); ++i) {
    814       const cricket::ContentInfo& c1 = desc1.contents().at(i);
    815       const cricket::ContentInfo& c2 = desc2.contents().at(i);
    816       // content name
    817       EXPECT_EQ(c1.name, c2.name);
    818       // content type
    819       // Note, ASSERT will return from the function, but will not stop the test.
    820       ASSERT_EQ(c1.type, c2.type);
    821 
    822       ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
    823       if (IsAudioContent(&c1)) {
    824         const AudioContentDescription* acd1 =
    825             static_cast<const AudioContentDescription*>(c1.description);
    826         const AudioContentDescription* acd2 =
    827             static_cast<const AudioContentDescription*>(c2.description);
    828         CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
    829       }
    830 
    831       ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
    832       if (IsVideoContent(&c1)) {
    833         const VideoContentDescription* vcd1 =
    834             static_cast<const VideoContentDescription*>(c1.description);
    835         const VideoContentDescription* vcd2 =
    836             static_cast<const VideoContentDescription*>(c2.description);
    837         CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
    838       }
    839 
    840       ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
    841       if (IsDataContent(&c1)) {
    842         const DataContentDescription* dcd1 =
    843             static_cast<const DataContentDescription*>(c1.description);
    844         const DataContentDescription* dcd2 =
    845             static_cast<const DataContentDescription*>(c2.description);
    846         CompareMediaContentDescription<DataContentDescription>(dcd1, dcd2);
    847       }
    848     }
    849 
    850     // group
    851     const cricket::ContentGroups groups1 = desc1.groups();
    852     const cricket::ContentGroups groups2 = desc2.groups();
    853     EXPECT_EQ(groups1.size(), groups1.size());
    854     if (groups1.size() != groups2.size()) {
    855       ADD_FAILURE();
    856       return;
    857     }
    858     for (size_t i = 0; i < groups1.size(); ++i) {
    859       const cricket::ContentGroup group1 = groups1.at(i);
    860       const cricket::ContentGroup group2 = groups2.at(i);
    861       EXPECT_EQ(group1.semantics(), group2.semantics());
    862       const cricket::ContentNames names1 = group1.content_names();
    863       const cricket::ContentNames names2 = group2.content_names();
    864       EXPECT_EQ(names1.size(), names2.size());
    865       if (names1.size() != names2.size()) {
    866         ADD_FAILURE();
    867         return;
    868       }
    869       cricket::ContentNames::const_iterator iter1 = names1.begin();
    870       cricket::ContentNames::const_iterator iter2 = names2.begin();
    871       while (iter1 != names1.end()) {
    872         EXPECT_EQ(*iter1++, *iter2++);
    873       }
    874     }
    875 
    876     // transport info
    877     const cricket::TransportInfos transports1 = desc1.transport_infos();
    878     const cricket::TransportInfos transports2 = desc2.transport_infos();
    879     EXPECT_EQ(transports1.size(), transports2.size());
    880     if (transports1.size() != transports2.size()) {
    881       ADD_FAILURE();
    882       return;
    883     }
    884     for (size_t i = 0; i < transports1.size(); ++i) {
    885       const cricket::TransportInfo transport1 = transports1.at(i);
    886       const cricket::TransportInfo transport2 = transports2.at(i);
    887       EXPECT_EQ(transport1.content_name, transport2.content_name);
    888       EXPECT_EQ(transport1.description.ice_ufrag,
    889                 transport2.description.ice_ufrag);
    890       EXPECT_EQ(transport1.description.ice_pwd,
    891                 transport2.description.ice_pwd);
    892       if (transport1.description.identity_fingerprint) {
    893         EXPECT_EQ(*transport1.description.identity_fingerprint,
    894                   *transport2.description.identity_fingerprint);
    895       } else {
    896         EXPECT_EQ(transport1.description.identity_fingerprint.get(),
    897                   transport2.description.identity_fingerprint.get());
    898       }
    899       EXPECT_EQ(transport1.description.transport_options,
    900                 transport2.description.transport_options);
    901       EXPECT_TRUE(CompareCandidates(transport1.description.candidates,
    902                                     transport2.description.candidates));
    903     }
    904 
    905     // global attributes
    906     EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
    907   }
    908 
    909   bool CompareCandidates(const Candidates& cs1, const Candidates& cs2) {
    910     EXPECT_EQ(cs1.size(), cs2.size());
    911     if (cs1.size() != cs2.size())
    912       return false;
    913     for (size_t i = 0; i< cs1.size(); ++i) {
    914       const Candidate c1 = cs1.at(i);
    915       const Candidate c2 = cs2.at(i);
    916       EXPECT_TRUE(c1.IsEquivalent(c2));
    917     }
    918     return true;
    919   }
    920 
    921   bool CompareSessionDescription(
    922       const JsepSessionDescription& desc1,
    923       const JsepSessionDescription& desc2) {
    924     EXPECT_EQ(desc1.session_id(), desc2.session_id());
    925     EXPECT_EQ(desc1.session_version(), desc2.session_version());
    926     CompareSessionDescription(*desc1.description(), *desc2.description());
    927     if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
    928       return false;
    929     for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
    930       const IceCandidateCollection* cc1 = desc1.candidates(i);
    931       const IceCandidateCollection* cc2 = desc2.candidates(i);
    932       if (cc1->count() != cc2->count())
    933         return false;
    934       for (size_t j = 0; j < cc1->count(); ++j) {
    935         const IceCandidateInterface* c1 = cc1->at(j);
    936         const IceCandidateInterface* c2 = cc2->at(j);
    937         EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
    938         EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
    939         EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
    940       }
    941     }
    942     return true;
    943   }
    944 
    945   // Disable the ice-ufrag and ice-pwd in given |sdp| message by replacing
    946   // them with invalid keywords so that the parser will just ignore them.
    947   bool RemoveCandidateUfragPwd(std::string* sdp) {
    948     const char ice_ufrag[] = "a=ice-ufrag";
    949     const char ice_ufragx[] = "a=xice-ufrag";
    950     const char ice_pwd[] = "a=ice-pwd";
    951     const char ice_pwdx[] = "a=xice-pwd";
    952     rtc::replace_substrs(ice_ufrag, strlen(ice_ufrag),
    953         ice_ufragx, strlen(ice_ufragx), sdp);
    954     rtc::replace_substrs(ice_pwd, strlen(ice_pwd),
    955         ice_pwdx, strlen(ice_pwdx), sdp);
    956     return true;
    957   }
    958 
    959   // Update the candidates in |jdesc| to use the given |ufrag| and |pwd|.
    960   bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc, int mline_index,
    961       const std::string& ufrag, const std::string& pwd) {
    962     std::string content_name;
    963     if (mline_index == 0) {
    964       content_name = kAudioContentName;
    965     } else if (mline_index == 1) {
    966       content_name = kVideoContentName;
    967     } else {
    968       ASSERT(false);
    969     }
    970     TransportInfo transport_info(
    971         content_name, TransportDescription(ufrag, pwd));
    972     SessionDescription* desc =
    973         const_cast<SessionDescription*>(jdesc->description());
    974     desc->RemoveTransportInfoByName(content_name);
    975     EXPECT_TRUE(desc->AddTransportInfo(transport_info));
    976     for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
    977       const IceCandidateCollection* cc = jdesc_.candidates(i);
    978       for (size_t j = 0; j < cc->count(); ++j) {
    979         if (cc->at(j)->sdp_mline_index() == mline_index) {
    980           const_cast<Candidate&>(cc->at(j)->candidate()).set_username(
    981               ufrag);
    982           const_cast<Candidate&>(cc->at(j)->candidate()).set_password(
    983               pwd);
    984         }
    985       }
    986     }
    987     return true;
    988   }
    989 
    990   void AddIceOptions(const std::string& content_name,
    991                      const std::vector<std::string>& transport_options) {
    992     ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
    993     cricket::TransportInfo transport_info =
    994         *(desc_.GetTransportInfoByName(content_name));
    995     desc_.RemoveTransportInfoByName(content_name);
    996     transport_info.description.transport_options = transport_options;
    997     desc_.AddTransportInfo(transport_info);
    998   }
    999 
   1000   void SetIceUfragPwd(const std::string& content_name,
   1001                       const std::string& ice_ufrag,
   1002                       const std::string& ice_pwd) {
   1003     ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
   1004     cricket::TransportInfo transport_info =
   1005         *(desc_.GetTransportInfoByName(content_name));
   1006     desc_.RemoveTransportInfoByName(content_name);
   1007     transport_info.description.ice_ufrag = ice_ufrag;
   1008     transport_info.description.ice_pwd = ice_pwd;
   1009     desc_.AddTransportInfo(transport_info);
   1010   }
   1011 
   1012   void AddFingerprint() {
   1013     desc_.RemoveTransportInfoByName(kAudioContentName);
   1014     desc_.RemoveTransportInfoByName(kVideoContentName);
   1015     rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1,
   1016                                           kIdentityDigest,
   1017                                           sizeof(kIdentityDigest));
   1018     EXPECT_TRUE(desc_.AddTransportInfo(
   1019         TransportInfo(kAudioContentName,
   1020                       TransportDescription(std::vector<std::string>(),
   1021                                            kCandidateUfragVoice,
   1022                                            kCandidatePwdVoice,
   1023                                            cricket::ICEMODE_FULL,
   1024                                            cricket::CONNECTIONROLE_NONE,
   1025                                            &fingerprint, Candidates()))));
   1026     EXPECT_TRUE(desc_.AddTransportInfo(
   1027         TransportInfo(kVideoContentName,
   1028                       TransportDescription(std::vector<std::string>(),
   1029                                            kCandidateUfragVideo,
   1030                                            kCandidatePwdVideo,
   1031                                            cricket::ICEMODE_FULL,
   1032                                            cricket::CONNECTIONROLE_NONE,
   1033                                            &fingerprint, Candidates()))));
   1034   }
   1035 
   1036   void AddExtmap() {
   1037     audio_desc_ = static_cast<AudioContentDescription*>(
   1038         audio_desc_->Copy());
   1039     video_desc_ = static_cast<VideoContentDescription*>(
   1040         video_desc_->Copy());
   1041     audio_desc_->AddRtpHeaderExtension(
   1042         RtpHeaderExtension(kExtmapUri, kExtmapId));
   1043     video_desc_->AddRtpHeaderExtension(
   1044         RtpHeaderExtension(kExtmapUri, kExtmapId));
   1045     desc_.RemoveContentByName(kAudioContentName);
   1046     desc_.RemoveContentByName(kVideoContentName);
   1047     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_desc_);
   1048     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_desc_);
   1049   }
   1050 
   1051   void RemoveCryptos() {
   1052     audio_desc_->set_cryptos(std::vector<CryptoParams>());
   1053     video_desc_->set_cryptos(std::vector<CryptoParams>());
   1054   }
   1055 
   1056   bool TestSerializeDirection(cricket::MediaContentDirection direction) {
   1057     audio_desc_->set_direction(direction);
   1058     video_desc_->set_direction(direction);
   1059     std::string new_sdp = kSdpFullString;
   1060     ReplaceDirection(direction, &new_sdp);
   1061 
   1062     if (!jdesc_.Initialize(desc_.Copy(),
   1063                            jdesc_.session_id(),
   1064                            jdesc_.session_version())) {
   1065       return false;
   1066     }
   1067     std::string message = webrtc::SdpSerialize(jdesc_);
   1068     EXPECT_EQ(new_sdp, message);
   1069     return true;
   1070   }
   1071 
   1072   bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
   1073     audio_desc_ = static_cast<AudioContentDescription*>(
   1074         audio_desc_->Copy());
   1075     video_desc_ = static_cast<VideoContentDescription*>(
   1076         video_desc_->Copy());
   1077     desc_.RemoveContentByName(kAudioContentName);
   1078     desc_.RemoveContentByName(kVideoContentName);
   1079     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_rejected,
   1080                      audio_desc_);
   1081     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
   1082                      video_desc_);
   1083     SetIceUfragPwd(kAudioContentName,
   1084                    audio_rejected ? "" : kCandidateUfragVoice,
   1085                    audio_rejected ? "" : kCandidatePwdVoice);
   1086     SetIceUfragPwd(kVideoContentName,
   1087                    video_rejected ? "" : kCandidateUfragVideo,
   1088                    video_rejected ? "" : kCandidatePwdVideo);
   1089 
   1090     std::string new_sdp = kSdpString;
   1091     ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
   1092 
   1093     JsepSessionDescription jdesc_no_candidates(kDummyString);
   1094     if (!jdesc_no_candidates.Initialize(desc_.Copy(), kSessionId,
   1095                                         kSessionVersion)) {
   1096       return false;
   1097     }
   1098     std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
   1099     EXPECT_EQ(new_sdp, message);
   1100     return true;
   1101   }
   1102 
   1103   void AddSctpDataChannel() {
   1104     rtc::scoped_ptr<DataContentDescription> data(
   1105         new DataContentDescription());
   1106     data_desc_ = data.get();
   1107     data_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp);
   1108     DataCodec codec(cricket::kGoogleSctpDataCodecId,
   1109                     cricket::kGoogleSctpDataCodecName, 0);
   1110     codec.SetParam(cricket::kCodecParamPort, kDefaultSctpPort);
   1111     data_desc_->AddCodec(codec);
   1112     desc_.AddContent(kDataContentName, NS_JINGLE_DRAFT_SCTP, data.release());
   1113     EXPECT_TRUE(desc_.AddTransportInfo(
   1114            TransportInfo(kDataContentName,
   1115                          TransportDescription(kCandidateUfragData,
   1116                                               kCandidatePwdData))));
   1117   }
   1118 
   1119   void AddRtpDataChannel() {
   1120     rtc::scoped_ptr<DataContentDescription> data(
   1121         new DataContentDescription());
   1122     data_desc_ = data.get();
   1123 
   1124     data_desc_->AddCodec(DataCodec(101, "google-data", 1));
   1125     StreamParams data_stream;
   1126     data_stream.id = kDataChannelMsid;
   1127     data_stream.cname = kDataChannelCname;
   1128     data_stream.sync_label = kDataChannelLabel;
   1129     data_stream.ssrcs.push_back(kDataChannelSsrc);
   1130     data_desc_->AddStream(data_stream);
   1131     data_desc_->AddCrypto(CryptoParams(
   1132         1, "AES_CM_128_HMAC_SHA1_80",
   1133         "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5", ""));
   1134     data_desc_->set_protocol(cricket::kMediaProtocolSavpf);
   1135     desc_.AddContent(kDataContentName, NS_JINGLE_RTP, data.release());
   1136     EXPECT_TRUE(desc_.AddTransportInfo(
   1137            TransportInfo(kDataContentName,
   1138                          TransportDescription(kCandidateUfragData,
   1139                                               kCandidatePwdData))));
   1140   }
   1141 
   1142   bool TestDeserializeDirection(cricket::MediaContentDirection direction) {
   1143     std::string new_sdp = kSdpFullString;
   1144     ReplaceDirection(direction, &new_sdp);
   1145     JsepSessionDescription new_jdesc(kDummyString);
   1146 
   1147     EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
   1148 
   1149     audio_desc_->set_direction(direction);
   1150     video_desc_->set_direction(direction);
   1151     if (!jdesc_.Initialize(desc_.Copy(),
   1152                            jdesc_.session_id(),
   1153                            jdesc_.session_version())) {
   1154       return false;
   1155     }
   1156     EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
   1157     return true;
   1158   }
   1159 
   1160   bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
   1161     std::string new_sdp = kSdpString;
   1162     ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
   1163     JsepSessionDescription new_jdesc(JsepSessionDescription::kOffer);
   1164     EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
   1165 
   1166     audio_desc_ = static_cast<AudioContentDescription*>(
   1167         audio_desc_->Copy());
   1168     video_desc_ = static_cast<VideoContentDescription*>(
   1169         video_desc_->Copy());
   1170     desc_.RemoveContentByName(kAudioContentName);
   1171     desc_.RemoveContentByName(kVideoContentName);
   1172     desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_rejected,
   1173                      audio_desc_);
   1174     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
   1175                      video_desc_);
   1176     SetIceUfragPwd(kAudioContentName,
   1177                    audio_rejected ? "" : kCandidateUfragVoice,
   1178                    audio_rejected ? "" : kCandidatePwdVoice);
   1179     SetIceUfragPwd(kVideoContentName,
   1180                    video_rejected ? "" : kCandidateUfragVideo,
   1181                    video_rejected ? "" : kCandidatePwdVideo);
   1182     JsepSessionDescription jdesc_no_candidates(kDummyString);
   1183     if (!jdesc_no_candidates.Initialize(desc_.Copy(), jdesc_.session_id(),
   1184                                         jdesc_.session_version())) {
   1185       return false;
   1186     }
   1187     EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
   1188     return true;
   1189   }
   1190 
   1191   void TestDeserializeExtmap(bool session_level, bool media_level) {
   1192     AddExtmap();
   1193     JsepSessionDescription new_jdesc("dummy");
   1194     ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
   1195                                      jdesc_.session_id(),
   1196                                      jdesc_.session_version()));
   1197     JsepSessionDescription jdesc_with_extmap("dummy");
   1198     std::string sdp_with_extmap = kSdpString;
   1199     if (session_level) {
   1200       InjectAfter(kSessionTime, kExtmapWithDirectionAndAttribute,
   1201                   &sdp_with_extmap);
   1202     }
   1203     if (media_level) {
   1204       InjectAfter(kAttributeIcePwdVoice, kExtmapWithDirectionAndAttribute,
   1205                   &sdp_with_extmap);
   1206       InjectAfter(kAttributeIcePwdVideo, kExtmapWithDirectionAndAttribute,
   1207                   &sdp_with_extmap);
   1208     }
   1209     // The extmap can't be present at the same time in both session level and
   1210     // media level.
   1211     if (session_level && media_level) {
   1212       SdpParseError error;
   1213       EXPECT_FALSE(webrtc::SdpDeserialize(sdp_with_extmap,
   1214                    &jdesc_with_extmap, &error));
   1215       EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
   1216     } else {
   1217       EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
   1218       EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
   1219     }
   1220   }
   1221 
   1222   void VerifyCodecParameter(const cricket::CodecParameterMap& params,
   1223       const std::string& name, int expected_value) {
   1224     cricket::CodecParameterMap::const_iterator found = params.find(name);
   1225     ASSERT_TRUE(found != params.end());
   1226     EXPECT_EQ(found->second, rtc::ToString<int>(expected_value));
   1227   }
   1228 
   1229   void TestDeserializeCodecParams(const CodecParams& params,
   1230                                   JsepSessionDescription* jdesc_output) {
   1231     std::string sdp =
   1232         "v=0\r\n"
   1233         "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1234         "s=-\r\n"
   1235         "t=0 0\r\n"
   1236         // Include semantics for WebRTC Media Streams since it is supported by
   1237         // this parser, and will be added to the SDP when serializing a session
   1238         // description.
   1239         "a=msid-semantic: WMS\r\n"
   1240         // Pl type 111 preferred.
   1241         "m=audio 9 RTP/SAVPF 111 104 103\r\n"
   1242         // Pltype 111 listed before 103 and 104 in the map.
   1243         "a=rtpmap:111 opus/48000/2\r\n"
   1244         // Pltype 103 listed before 104.
   1245         "a=rtpmap:103 ISAC/16000\r\n"
   1246         "a=rtpmap:104 ISAC/32000\r\n"
   1247         "a=fmtp:111 0-15,66,70\r\n"
   1248         "a=fmtp:111 ";
   1249     std::ostringstream os;
   1250     os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
   1251        << "; sprop-stereo=" << params.sprop_stereo
   1252        << "; useinbandfec=" << params.useinband
   1253        << "; maxaveragebitrate=" << params.maxaveragebitrate << "\r\n"
   1254        << "a=ptime:" << params.ptime << "\r\n"
   1255        << "a=maxptime:" << params.max_ptime << "\r\n";
   1256     sdp += os.str();
   1257 
   1258     os.clear();
   1259     os.str("");
   1260     // Pl type 100 preferred.
   1261     os << "m=video 9 RTP/SAVPF 99 95\r\n"
   1262        << "a=rtpmap:99 VP8/90000\r\n"
   1263        << "a=rtpmap:95 RTX/90000\r\n"
   1264        << "a=fmtp:95 apt=99;\r\n";
   1265     sdp += os.str();
   1266 
   1267     // Deserialize
   1268     SdpParseError error;
   1269     EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
   1270 
   1271     const ContentInfo* ac = GetFirstAudioContent(jdesc_output->description());
   1272     ASSERT_TRUE(ac != NULL);
   1273     const AudioContentDescription* acd =
   1274         static_cast<const AudioContentDescription*>(ac->description);
   1275     ASSERT_FALSE(acd->codecs().empty());
   1276     cricket::AudioCodec opus = acd->codecs()[0];
   1277     EXPECT_EQ("opus", opus.name);
   1278     EXPECT_EQ(111, opus.id);
   1279     VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
   1280     VerifyCodecParameter(opus.params, "stereo", params.stereo);
   1281     VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
   1282     VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
   1283     VerifyCodecParameter(opus.params, "maxaveragebitrate",
   1284                          params.maxaveragebitrate);
   1285     for (size_t i = 0; i < acd->codecs().size(); ++i) {
   1286       cricket::AudioCodec codec = acd->codecs()[i];
   1287       VerifyCodecParameter(codec.params, "ptime", params.ptime);
   1288       VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
   1289       if (codec.name == "ISAC") {
   1290         if (codec.clockrate == 16000) {
   1291           EXPECT_EQ(32000, codec.bitrate);
   1292         } else {
   1293           EXPECT_EQ(56000, codec.bitrate);
   1294         }
   1295       }
   1296     }
   1297 
   1298     const ContentInfo* vc = GetFirstVideoContent(jdesc_output->description());
   1299     ASSERT_TRUE(vc != NULL);
   1300     const VideoContentDescription* vcd =
   1301         static_cast<const VideoContentDescription*>(vc->description);
   1302     ASSERT_FALSE(vcd->codecs().empty());
   1303     cricket::VideoCodec vp8 = vcd->codecs()[0];
   1304     EXPECT_EQ("VP8", vp8.name);
   1305     EXPECT_EQ(99, vp8.id);
   1306     cricket::VideoCodec rtx = vcd->codecs()[1];
   1307     EXPECT_EQ("RTX", rtx.name);
   1308     EXPECT_EQ(95, rtx.id);
   1309     VerifyCodecParameter(rtx.params, "apt", vp8.id);
   1310   }
   1311 
   1312   void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
   1313                              bool use_wildcard) {
   1314     std::string sdp_session_and_audio =
   1315         "v=0\r\n"
   1316         "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1317         "s=-\r\n"
   1318         "t=0 0\r\n"
   1319         // Include semantics for WebRTC Media Streams since it is supported by
   1320         // this parser, and will be added to the SDP when serializing a session
   1321         // description.
   1322         "a=msid-semantic: WMS\r\n"
   1323         "m=audio 9 RTP/SAVPF 111\r\n"
   1324         "a=rtpmap:111 opus/48000/2\r\n";
   1325     std::string sdp_video =
   1326         "m=video 3457 RTP/SAVPF 101\r\n"
   1327         "a=rtpmap:101 VP8/90000\r\n"
   1328         "a=rtcp-fb:101 nack\r\n"
   1329         "a=rtcp-fb:101 nack pli\r\n"
   1330         "a=rtcp-fb:101 goog-remb\r\n";
   1331     std::ostringstream os;
   1332     os << sdp_session_and_audio;
   1333     os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") <<  " nack\r\n";
   1334     os << sdp_video;
   1335     os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") <<  " ccm fir\r\n";
   1336     std::string sdp = os.str();
   1337     // Deserialize
   1338     SdpParseError error;
   1339     EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
   1340     const ContentInfo* ac = GetFirstAudioContent(jdesc_output->description());
   1341     ASSERT_TRUE(ac != NULL);
   1342     const AudioContentDescription* acd =
   1343         static_cast<const AudioContentDescription*>(ac->description);
   1344     ASSERT_FALSE(acd->codecs().empty());
   1345     cricket::AudioCodec opus = acd->codecs()[0];
   1346     EXPECT_EQ(111, opus.id);
   1347     EXPECT_TRUE(opus.HasFeedbackParam(
   1348         cricket::FeedbackParam(cricket::kRtcpFbParamNack,
   1349                                cricket::kParamValueEmpty)));
   1350 
   1351     const ContentInfo* vc = GetFirstVideoContent(jdesc_output->description());
   1352     ASSERT_TRUE(vc != NULL);
   1353     const VideoContentDescription* vcd =
   1354         static_cast<const VideoContentDescription*>(vc->description);
   1355     ASSERT_FALSE(vcd->codecs().empty());
   1356     cricket::VideoCodec vp8 = vcd->codecs()[0];
   1357     EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
   1358                  vp8.name.c_str());
   1359     EXPECT_EQ(101, vp8.id);
   1360     EXPECT_TRUE(vp8.HasFeedbackParam(
   1361         cricket::FeedbackParam(cricket::kRtcpFbParamNack,
   1362                                cricket::kParamValueEmpty)));
   1363     EXPECT_TRUE(vp8.HasFeedbackParam(
   1364         cricket::FeedbackParam(cricket::kRtcpFbParamNack,
   1365                                cricket::kRtcpFbNackParamPli)));
   1366     EXPECT_TRUE(vp8.HasFeedbackParam(
   1367         cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
   1368                                cricket::kParamValueEmpty)));
   1369     EXPECT_TRUE(vp8.HasFeedbackParam(
   1370         cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
   1371                                cricket::kRtcpFbCcmParamFir)));
   1372   }
   1373 
   1374   // Two SDP messages can mean the same thing but be different strings, e.g.
   1375   // some of the lines can be serialized in different order.
   1376   // However, a deserialized description can be compared field by field and has
   1377   // no order. If deserializer has already been tested, serializing then
   1378   // deserializing and comparing JsepSessionDescription will test
   1379   // the serializer sufficiently.
   1380   void TestSerialize(const JsepSessionDescription& jdesc) {
   1381     std::string message = webrtc::SdpSerialize(jdesc);
   1382     JsepSessionDescription jdesc_output_des(kDummyString);
   1383     SdpParseError error;
   1384     EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
   1385     EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
   1386   }
   1387 
   1388  protected:
   1389   SessionDescription desc_;
   1390   AudioContentDescription* audio_desc_;
   1391   VideoContentDescription* video_desc_;
   1392   DataContentDescription* data_desc_;
   1393   Candidates candidates_;
   1394   rtc::scoped_ptr<IceCandidateInterface> jcandidate_;
   1395   JsepSessionDescription jdesc_;
   1396 };
   1397 
   1398 void TestMismatch(const std::string& string1, const std::string& string2) {
   1399   int position = 0;
   1400   for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
   1401     if (string1.c_str()[i] != string2.c_str()[i]) {
   1402       position = static_cast<int>(i);
   1403       break;
   1404     }
   1405   }
   1406   EXPECT_EQ(0, position) << "Strings mismatch at the " << position
   1407                          << " character\n"
   1408                          << " 1: " << string1.substr(position, 20) << "\n"
   1409                          << " 2: " << string2.substr(position, 20) << "\n";
   1410 }
   1411 
   1412 TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
   1413   // SessionDescription with desc and candidates.
   1414   std::string message = webrtc::SdpSerialize(jdesc_);
   1415   TestMismatch(std::string(kSdpFullString), message);
   1416 }
   1417 
   1418 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
   1419   JsepSessionDescription jdesc_empty(kDummyString);
   1420   EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
   1421 }
   1422 
   1423 // This tests serialization of SDP with only IPv6 candidates and verifies that
   1424 // IPv6 is used as default address in c line according to preference.
   1425 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIPv6Only) {
   1426   // Only test 1 m line.
   1427   desc_.RemoveContentByName("video_content_name");
   1428   // Stun has a high preference than local host.
   1429   cricket::Candidate candidate1(
   1430       cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
   1431       rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
   1432       cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1433   cricket::Candidate candidate2(
   1434       cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
   1435       rtc::SocketAddress("::2", 1235), kCandidatePriority, "", "",
   1436       cricket::LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1437   JsepSessionDescription jdesc(kDummyString);
   1438   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1439 
   1440   // Only add the candidates to audio m line.
   1441   JsepIceCandidate jice1("audio_content_name", 0, candidate1);
   1442   JsepIceCandidate jice2("audio_content_name", 0, candidate2);
   1443   ASSERT_TRUE(jdesc.AddCandidate(&jice1));
   1444   ASSERT_TRUE(jdesc.AddCandidate(&jice2));
   1445   std::string message = webrtc::SdpSerialize(jdesc);
   1446 
   1447   // Audio line should have a c line like this one.
   1448   EXPECT_NE(message.find("c=IN IP6 ::1"), std::string::npos);
   1449   // Shouldn't have a IP4 c line.
   1450   EXPECT_EQ(message.find("c=IN IP4"), std::string::npos);
   1451 }
   1452 
   1453 // This tests serialization of SDP with both IPv4 and IPv6 candidates and
   1454 // verifies that IPv4 is used as default address in c line even if the
   1455 // preference of IPv4 is lower.
   1456 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBothIPFamilies) {
   1457   // Only test 1 m line.
   1458   desc_.RemoveContentByName("video_content_name");
   1459   cricket::Candidate candidate_v4(
   1460       cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
   1461       rtc::SocketAddress("192.168.1.5", 1234), kCandidatePriority, "", "",
   1462       cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1463   cricket::Candidate candidate_v6(
   1464       cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
   1465       rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
   1466       cricket::LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1467   JsepSessionDescription jdesc(kDummyString);
   1468   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1469 
   1470   // Only add the candidates to audio m line.
   1471   JsepIceCandidate jice_v4("audio_content_name", 0, candidate_v4);
   1472   JsepIceCandidate jice_v6("audio_content_name", 0, candidate_v6);
   1473   ASSERT_TRUE(jdesc.AddCandidate(&jice_v4));
   1474   ASSERT_TRUE(jdesc.AddCandidate(&jice_v6));
   1475   std::string message = webrtc::SdpSerialize(jdesc);
   1476 
   1477   // Audio line should have a c line like this one.
   1478   EXPECT_NE(message.find("c=IN IP4 192.168.1.5"), std::string::npos);
   1479   // Shouldn't have a IP6 c line.
   1480   EXPECT_EQ(message.find("c=IN IP6"), std::string::npos);
   1481 }
   1482 
   1483 // This tests serialization of SDP with both UDP and TCP candidates and
   1484 // verifies that UDP is used as default address in c line even if the
   1485 // preference of UDP is lower.
   1486 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBothProtocols) {
   1487   // Only test 1 m line.
   1488   desc_.RemoveContentByName("video_content_name");
   1489   // Stun has a high preference than local host.
   1490   cricket::Candidate candidate1(
   1491       cricket::ICE_CANDIDATE_COMPONENT_RTP, "tcp",
   1492       rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
   1493       cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1494   cricket::Candidate candidate2(
   1495       cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
   1496       rtc::SocketAddress("fe80::1234:5678:abcd:ef12", 1235), kCandidatePriority,
   1497       "", "", cricket::LOCAL_PORT_TYPE, kCandidateGeneration,
   1498       kCandidateFoundation1);
   1499   JsepSessionDescription jdesc(kDummyString);
   1500   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1501 
   1502   // Only add the candidates to audio m line.
   1503   JsepIceCandidate jice1("audio_content_name", 0, candidate1);
   1504   JsepIceCandidate jice2("audio_content_name", 0, candidate2);
   1505   ASSERT_TRUE(jdesc.AddCandidate(&jice1));
   1506   ASSERT_TRUE(jdesc.AddCandidate(&jice2));
   1507   std::string message = webrtc::SdpSerialize(jdesc);
   1508 
   1509   // Audio line should have a c line like this one.
   1510   EXPECT_NE(message.find("c=IN IP6 fe80::1234:5678:abcd:ef12"),
   1511             std::string::npos);
   1512   // Shouldn't have a IP4 c line.
   1513   EXPECT_EQ(message.find("c=IN IP4"), std::string::npos);
   1514 }
   1515 
   1516 // This tests serialization of SDP with only TCP candidates and verifies that
   1517 // null IPv4 is used as default address in c line.
   1518 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithTCPOnly) {
   1519   // Only test 1 m line.
   1520   desc_.RemoveContentByName("video_content_name");
   1521   // Stun has a high preference than local host.
   1522   cricket::Candidate candidate1(
   1523       cricket::ICE_CANDIDATE_COMPONENT_RTP, "tcp",
   1524       rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
   1525       cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1526   cricket::Candidate candidate2(
   1527       cricket::ICE_CANDIDATE_COMPONENT_RTP, "tcp",
   1528       rtc::SocketAddress("::2", 1235), kCandidatePriority, "", "",
   1529       cricket::LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
   1530   JsepSessionDescription jdesc(kDummyString);
   1531   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1532 
   1533   // Only add the candidates to audio m line.
   1534   JsepIceCandidate jice1("audio_content_name", 0, candidate1);
   1535   JsepIceCandidate jice2("audio_content_name", 0, candidate2);
   1536   ASSERT_TRUE(jdesc.AddCandidate(&jice1));
   1537   ASSERT_TRUE(jdesc.AddCandidate(&jice2));
   1538   std::string message = webrtc::SdpSerialize(jdesc);
   1539 
   1540   // Audio line should have a c line like this one when no any default exists.
   1541   EXPECT_NE(message.find("c=IN IP4 0.0.0.0"), std::string::npos);
   1542 }
   1543 
   1544 // This tests serialization of SDP with a=crypto and a=fingerprint, as would be
   1545 // the case in a DTLS offer.
   1546 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
   1547   AddFingerprint();
   1548   JsepSessionDescription jdesc_with_fingerprint(kDummyString);
   1549   ASSERT_TRUE(jdesc_with_fingerprint.Initialize(desc_.Copy(),
   1550                                                 kSessionId, kSessionVersion));
   1551   std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
   1552 
   1553   std::string sdp_with_fingerprint = kSdpString;
   1554   InjectAfter(kAttributeIcePwdVoice,
   1555               kFingerprint, &sdp_with_fingerprint);
   1556   InjectAfter(kAttributeIcePwdVideo,
   1557               kFingerprint, &sdp_with_fingerprint);
   1558 
   1559   EXPECT_EQ(sdp_with_fingerprint, message);
   1560 }
   1561 
   1562 // This tests serialization of SDP with a=fingerprint with no a=crypto, as would
   1563 // be the case in a DTLS answer.
   1564 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
   1565   AddFingerprint();
   1566   RemoveCryptos();
   1567   JsepSessionDescription jdesc_with_fingerprint(kDummyString);
   1568   ASSERT_TRUE(jdesc_with_fingerprint.Initialize(desc_.Copy(),
   1569                                                 kSessionId, kSessionVersion));
   1570   std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
   1571 
   1572   std::string sdp_with_fingerprint = kSdpString;
   1573   Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
   1574   Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
   1575   InjectAfter(kAttributeIcePwdVoice,
   1576               kFingerprint, &sdp_with_fingerprint);
   1577   InjectAfter(kAttributeIcePwdVideo,
   1578               kFingerprint, &sdp_with_fingerprint);
   1579 
   1580   EXPECT_EQ(sdp_with_fingerprint, message);
   1581 }
   1582 
   1583 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
   1584   // JsepSessionDescription with desc but without candidates.
   1585   JsepSessionDescription jdesc_no_candidates(kDummyString);
   1586   ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(), kSessionId,
   1587                                              kSessionVersion));
   1588   std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
   1589   EXPECT_EQ(std::string(kSdpString), message);
   1590 }
   1591 
   1592 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundle) {
   1593   ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
   1594   group.AddContentName(kAudioContentName);
   1595   group.AddContentName(kVideoContentName);
   1596   desc_.AddGroup(group);
   1597   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1598                                 jdesc_.session_id(),
   1599                                 jdesc_.session_version()));
   1600   std::string message = webrtc::SdpSerialize(jdesc_);
   1601   std::string sdp_with_bundle = kSdpFullString;
   1602   InjectAfter(kSessionTime,
   1603               "a=group:BUNDLE audio_content_name video_content_name\r\n",
   1604               &sdp_with_bundle);
   1605   EXPECT_EQ(sdp_with_bundle, message);
   1606 }
   1607 
   1608 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
   1609   VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
   1610       GetFirstVideoContent(&desc_)->description);
   1611   vcd->set_bandwidth(100 * 1000);
   1612   AudioContentDescription* acd = static_cast<AudioContentDescription*>(
   1613       GetFirstAudioContent(&desc_)->description);
   1614   acd->set_bandwidth(50 * 1000);
   1615   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1616                                 jdesc_.session_id(),
   1617                                 jdesc_.session_version()));
   1618   std::string message = webrtc::SdpSerialize(jdesc_);
   1619   std::string sdp_with_bandwidth = kSdpFullString;
   1620   InjectAfter("c=IN IP4 74.125.224.39\r\n",
   1621               "b=AS:100\r\n",
   1622               &sdp_with_bandwidth);
   1623   InjectAfter("c=IN IP4 74.125.127.126\r\n",
   1624               "b=AS:50\r\n",
   1625               &sdp_with_bandwidth);
   1626   EXPECT_EQ(sdp_with_bandwidth, message);
   1627 }
   1628 
   1629 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
   1630   std::vector<std::string> transport_options;
   1631   transport_options.push_back(kIceOption1);
   1632   transport_options.push_back(kIceOption3);
   1633   AddIceOptions(kAudioContentName, transport_options);
   1634   transport_options.clear();
   1635   transport_options.push_back(kIceOption2);
   1636   transport_options.push_back(kIceOption3);
   1637   AddIceOptions(kVideoContentName, transport_options);
   1638   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1639                                 jdesc_.session_id(),
   1640                                 jdesc_.session_version()));
   1641   std::string message = webrtc::SdpSerialize(jdesc_);
   1642   std::string sdp_with_ice_options = kSdpFullString;
   1643   InjectAfter(kAttributeIcePwdVoice,
   1644               "a=ice-options:iceoption1 iceoption3\r\n",
   1645               &sdp_with_ice_options);
   1646   InjectAfter(kAttributeIcePwdVideo,
   1647               "a=ice-options:iceoption2 iceoption3\r\n",
   1648               &sdp_with_ice_options);
   1649   EXPECT_EQ(sdp_with_ice_options, message);
   1650 }
   1651 
   1652 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
   1653   EXPECT_TRUE(TestSerializeDirection(cricket::MD_RECVONLY));
   1654 }
   1655 
   1656 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
   1657   EXPECT_TRUE(TestSerializeDirection(cricket::MD_SENDONLY));
   1658 }
   1659 
   1660 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
   1661   EXPECT_TRUE(TestSerializeDirection(cricket::MD_INACTIVE));
   1662 }
   1663 
   1664 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
   1665   EXPECT_TRUE(TestSerializeRejected(true, false));
   1666 }
   1667 
   1668 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
   1669   EXPECT_TRUE(TestSerializeRejected(false, true));
   1670 }
   1671 
   1672 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
   1673   EXPECT_TRUE(TestSerializeRejected(true, true));
   1674 }
   1675 
   1676 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRtpDataChannel) {
   1677   AddRtpDataChannel();
   1678   JsepSessionDescription jsep_desc(kDummyString);
   1679 
   1680   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1681   std::string message = webrtc::SdpSerialize(jsep_desc);
   1682 
   1683   std::string expected_sdp = kSdpString;
   1684   expected_sdp.append(kSdpRtpDataChannelString);
   1685   EXPECT_EQ(expected_sdp, message);
   1686 }
   1687 
   1688 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
   1689   AddSctpDataChannel();
   1690   JsepSessionDescription jsep_desc(kDummyString);
   1691 
   1692   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1693   std::string message = webrtc::SdpSerialize(jsep_desc);
   1694 
   1695   std::string expected_sdp = kSdpString;
   1696   expected_sdp.append(kSdpSctpDataChannelString);
   1697   EXPECT_EQ(message, expected_sdp);
   1698 }
   1699 
   1700 TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
   1701   AddSctpDataChannel();
   1702   JsepSessionDescription jsep_desc(kDummyString);
   1703 
   1704   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1705   DataContentDescription* dcdesc = static_cast<DataContentDescription*>(
   1706       jsep_desc.description()->GetContentDescriptionByName(kDataContentName));
   1707 
   1708   const int kNewPort = 1234;
   1709   cricket::DataCodec codec(
   1710         cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName, 0);
   1711   codec.SetParam(cricket::kCodecParamPort, kNewPort);
   1712   dcdesc->AddOrReplaceCodec(codec);
   1713 
   1714   std::string message = webrtc::SdpSerialize(jsep_desc);
   1715 
   1716   std::string expected_sdp = kSdpString;
   1717   expected_sdp.append(kSdpSctpDataChannelString);
   1718 
   1719   char default_portstr[16];
   1720   char new_portstr[16];
   1721   rtc::sprintfn(default_portstr, sizeof(default_portstr), "%d",
   1722                       kDefaultSctpPort);
   1723   rtc::sprintfn(new_portstr, sizeof(new_portstr), "%d", kNewPort);
   1724   rtc::replace_substrs(default_portstr, strlen(default_portstr),
   1725                              new_portstr, strlen(new_portstr),
   1726                              &expected_sdp);
   1727 
   1728   EXPECT_EQ(expected_sdp, message);
   1729 }
   1730 
   1731 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
   1732   AddRtpDataChannel();
   1733   data_desc_->set_bandwidth(100*1000);
   1734   JsepSessionDescription jsep_desc(kDummyString);
   1735 
   1736   ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   1737   std::string message = webrtc::SdpSerialize(jsep_desc);
   1738 
   1739   std::string expected_sdp = kSdpString;
   1740   expected_sdp.append(kSdpRtpDataChannelString);
   1741   // Serializing data content shouldn't ignore bandwidth settings.
   1742   InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\n",
   1743               "b=AS:100\r\n",
   1744               &expected_sdp);
   1745   EXPECT_EQ(expected_sdp, message);
   1746 }
   1747 
   1748 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
   1749   AddExtmap();
   1750   JsepSessionDescription desc_with_extmap("dummy");
   1751   ASSERT_TRUE(desc_with_extmap.Initialize(desc_.Copy(),
   1752                                           kSessionId, kSessionVersion));
   1753   std::string message = webrtc::SdpSerialize(desc_with_extmap);
   1754 
   1755   std::string sdp_with_extmap = kSdpString;
   1756   InjectAfter("a=mid:audio_content_name\r\n",
   1757               kExtmap, &sdp_with_extmap);
   1758   InjectAfter("a=mid:video_content_name\r\n",
   1759               kExtmap, &sdp_with_extmap);
   1760 
   1761   EXPECT_EQ(sdp_with_extmap, message);
   1762 }
   1763 
   1764 TEST_F(WebRtcSdpTest, SerializeCandidates) {
   1765   std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
   1766   EXPECT_EQ(std::string(kRawCandidate), message);
   1767 
   1768   Candidate candidate_with_ufrag(candidates_.front());
   1769   candidate_with_ufrag.set_username("ABC");
   1770   jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0,
   1771                                          candidate_with_ufrag));
   1772   message = webrtc::SdpSerializeCandidate(*jcandidate_);
   1773   EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
   1774 }
   1775 
   1776 // TODO(mallinath) : Enable this test once WebRTCSdp capable of parsing
   1777 // RFC 6544.
   1778 TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
   1779   Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
   1780                       rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
   1781                       "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
   1782                       kCandidateFoundation1);
   1783   candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
   1784   rtc::scoped_ptr<IceCandidateInterface> jcandidate(
   1785     new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
   1786 
   1787   std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
   1788   EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
   1789 }
   1790 
   1791 TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
   1792   JsepSessionDescription jdesc(kDummyString);
   1793   // Deserialize
   1794   EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
   1795   // Verify
   1796   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
   1797 }
   1798 
   1799 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
   1800   JsepSessionDescription jdesc(kDummyString);
   1801   const char kSdpWithoutMline[] =
   1802     "v=0\r\n"
   1803     "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   1804     "s=-\r\n"
   1805     "t=0 0\r\n"
   1806     "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
   1807   // Deserialize
   1808   EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
   1809   EXPECT_EQ(0u, jdesc.description()->contents().size());
   1810 }
   1811 
   1812 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
   1813   JsepSessionDescription jdesc(kDummyString);
   1814   std::string sdp_without_carriage_return = kSdpFullString;
   1815   Replace("\r\n", "\n", &sdp_without_carriage_return);
   1816   // Deserialize
   1817   EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
   1818   // Verify
   1819   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
   1820 }
   1821 
   1822 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
   1823   // SessionDescription with desc but without candidates.
   1824   JsepSessionDescription jdesc_no_candidates(kDummyString);
   1825   ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
   1826                                              kSessionId, kSessionVersion));
   1827   JsepSessionDescription new_jdesc(kDummyString);
   1828   EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
   1829   EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
   1830 }
   1831 
   1832 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
   1833   static const char kSdpNoRtpmapString[] =
   1834       "v=0\r\n"
   1835       "o=- 11 22 IN IP4 127.0.0.1\r\n"
   1836       "s=-\r\n"
   1837       "t=0 0\r\n"
   1838       "m=audio 49232 RTP/AVP 0 18 103\r\n"
   1839       // Codec that doesn't appear in the m= line will be ignored.
   1840       "a=rtpmap:104 ISAC/32000\r\n"
   1841       // The rtpmap line for static payload codec is optional.
   1842       "a=rtpmap:18 G729/16000\r\n"
   1843       "a=rtpmap:103 ISAC/16000\r\n";
   1844 
   1845   JsepSessionDescription jdesc(kDummyString);
   1846   EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
   1847   cricket::AudioContentDescription* audio =
   1848     static_cast<AudioContentDescription*>(
   1849         jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
   1850   AudioCodecs ref_codecs;
   1851   // The codecs in the AudioContentDescription will be sorted by preference.
   1852   ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1, 3));
   1853   ref_codecs.push_back(AudioCodec(18, "G729", 16000, 0, 1, 2));
   1854   ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 32000, 1, 1));
   1855   EXPECT_EQ(ref_codecs, audio->codecs());
   1856 }
   1857 
   1858 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
   1859   static const char kSdpNoRtpmapString[] =
   1860       "v=0\r\n"
   1861       "o=- 11 22 IN IP4 127.0.0.1\r\n"
   1862       "s=-\r\n"
   1863       "t=0 0\r\n"
   1864       "m=audio 49232 RTP/AVP 18 103\r\n"
   1865       "a=fmtp:18 annexb=yes\r\n"
   1866       "a=rtpmap:103 ISAC/16000\r\n";
   1867 
   1868   JsepSessionDescription jdesc(kDummyString);
   1869   EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
   1870   cricket::AudioContentDescription* audio =
   1871     static_cast<AudioContentDescription*>(
   1872         jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
   1873 
   1874   cricket::AudioCodec g729 = audio->codecs()[0];
   1875   EXPECT_EQ("G729", g729.name);
   1876   EXPECT_EQ(8000, g729.clockrate);
   1877   EXPECT_EQ(18, g729.id);
   1878   cricket::CodecParameterMap::iterator found =
   1879       g729.params.find("annexb");
   1880   ASSERT_TRUE(found != g729.params.end());
   1881   EXPECT_EQ(found->second, "yes");
   1882 
   1883   cricket::AudioCodec isac = audio->codecs()[1];
   1884   EXPECT_EQ("ISAC", isac.name);
   1885   EXPECT_EQ(103, isac.id);
   1886   EXPECT_EQ(16000, isac.clockrate);
   1887 }
   1888 
   1889 // Ensure that we can deserialize SDP with a=fingerprint properly.
   1890 TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
   1891   // Add a DTLS a=fingerprint attribute to our session description.
   1892   AddFingerprint();
   1893   JsepSessionDescription new_jdesc(kDummyString);
   1894   ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
   1895                                    jdesc_.session_id(),
   1896                                    jdesc_.session_version()));
   1897 
   1898   JsepSessionDescription jdesc_with_fingerprint(kDummyString);
   1899   std::string sdp_with_fingerprint = kSdpString;
   1900   InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
   1901   InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
   1902   EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
   1903   EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
   1904 }
   1905 
   1906 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
   1907   JsepSessionDescription jdesc_with_bundle(kDummyString);
   1908   std::string sdp_with_bundle = kSdpFullString;
   1909   InjectAfter(kSessionTime,
   1910               "a=group:BUNDLE audio_content_name video_content_name\r\n",
   1911               &sdp_with_bundle);
   1912   EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
   1913   ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
   1914   group.AddContentName(kAudioContentName);
   1915   group.AddContentName(kVideoContentName);
   1916   desc_.AddGroup(group);
   1917   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1918                                 jdesc_.session_id(),
   1919                                 jdesc_.session_version()));
   1920   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
   1921 }
   1922 
   1923 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
   1924   JsepSessionDescription jdesc_with_bandwidth(kDummyString);
   1925   std::string sdp_with_bandwidth = kSdpFullString;
   1926   InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
   1927               "b=AS:100\r\n",
   1928               &sdp_with_bandwidth);
   1929   InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
   1930               "b=AS:50\r\n",
   1931               &sdp_with_bandwidth);
   1932   EXPECT_TRUE(
   1933       SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
   1934   VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
   1935       GetFirstVideoContent(&desc_)->description);
   1936   vcd->set_bandwidth(100 * 1000);
   1937   AudioContentDescription* acd = static_cast<AudioContentDescription*>(
   1938       GetFirstAudioContent(&desc_)->description);
   1939   acd->set_bandwidth(50 * 1000);
   1940   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1941                                 jdesc_.session_id(),
   1942                                 jdesc_.session_version()));
   1943   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
   1944 }
   1945 
   1946 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
   1947   JsepSessionDescription jdesc_with_ice_options(kDummyString);
   1948   std::string sdp_with_ice_options = kSdpFullString;
   1949   InjectAfter(kSessionTime,
   1950               "a=ice-options:iceoption3\r\n",
   1951               &sdp_with_ice_options);
   1952   InjectAfter(kAttributeIcePwdVoice,
   1953               "a=ice-options:iceoption1\r\n",
   1954               &sdp_with_ice_options);
   1955   InjectAfter(kAttributeIcePwdVideo,
   1956               "a=ice-options:iceoption2\r\n",
   1957               &sdp_with_ice_options);
   1958   EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
   1959   std::vector<std::string> transport_options;
   1960   transport_options.push_back(kIceOption3);
   1961   transport_options.push_back(kIceOption1);
   1962   AddIceOptions(kAudioContentName, transport_options);
   1963   transport_options.clear();
   1964   transport_options.push_back(kIceOption3);
   1965   transport_options.push_back(kIceOption2);
   1966   AddIceOptions(kVideoContentName, transport_options);
   1967   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   1968                                 jdesc_.session_id(),
   1969                                 jdesc_.session_version()));
   1970   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
   1971 }
   1972 
   1973 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
   1974   // Remove the original ice-ufrag and ice-pwd
   1975   JsepSessionDescription jdesc_with_ufrag_pwd(kDummyString);
   1976   std::string sdp_with_ufrag_pwd = kSdpFullString;
   1977   EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
   1978   // Add session level ufrag and pwd
   1979   InjectAfter(kSessionTime,
   1980       "a=ice-pwd:session+level+icepwd\r\n"
   1981       "a=ice-ufrag:session+level+iceufrag\r\n",
   1982       &sdp_with_ufrag_pwd);
   1983   // Add media level ufrag and pwd for audio
   1984   InjectAfter("a=mid:audio_content_name\r\n",
   1985       "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
   1986       &sdp_with_ufrag_pwd);
   1987   // Update the candidate ufrag and pwd to the expected ones.
   1988   EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0,
   1989       "media+level+iceufrag", "media+level+icepwd"));
   1990   EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1,
   1991       "session+level+iceufrag", "session+level+icepwd"));
   1992   EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
   1993   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
   1994 }
   1995 
   1996 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
   1997   EXPECT_TRUE(TestDeserializeDirection(cricket::MD_RECVONLY));
   1998 }
   1999 
   2000 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
   2001   EXPECT_TRUE(TestDeserializeDirection(cricket::MD_SENDONLY));
   2002 }
   2003 
   2004 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
   2005   EXPECT_TRUE(TestDeserializeDirection(cricket::MD_INACTIVE));
   2006 }
   2007 
   2008 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
   2009   EXPECT_TRUE(TestDeserializeRejected(true, false));
   2010 }
   2011 
   2012 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
   2013   EXPECT_TRUE(TestDeserializeRejected(false, true));
   2014 }
   2015 
   2016 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
   2017   EXPECT_TRUE(TestDeserializeRejected(true, true));
   2018 }
   2019 
   2020 // Tests that we can still handle the sdp uses mslabel and label instead of
   2021 // msid for backward compatibility.
   2022 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMsid) {
   2023   jdesc_.description()->set_msid_supported(false);
   2024   JsepSessionDescription jdesc(kDummyString);
   2025   std::string sdp_without_msid = kSdpFullString;
   2026   Replace("msid", "xmsid", &sdp_without_msid);
   2027   // Deserialize
   2028   EXPECT_TRUE(SdpDeserialize(sdp_without_msid, &jdesc));
   2029   // Verify
   2030   EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
   2031 }
   2032 
   2033 TEST_F(WebRtcSdpTest, DeserializeCandidate) {
   2034   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   2035 
   2036   std::string sdp = kSdpOneCandidate;
   2037   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   2038   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   2039   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   2040   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   2041 
   2042   // Candidate line without generation extension.
   2043   sdp = kSdpOneCandidate;
   2044   Replace(" generation 2", "", &sdp);
   2045   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   2046   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   2047   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   2048   Candidate expected = jcandidate_->candidate();
   2049   expected.set_generation(0);
   2050   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
   2051 
   2052   sdp = kSdpTcpActiveCandidate;
   2053   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   2054   // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
   2055   Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
   2056                       rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
   2057                       "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
   2058                       kCandidateFoundation1);
   2059   rtc::scoped_ptr<IceCandidateInterface> jcandidate_template(
   2060     new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
   2061   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(
   2062                     jcandidate_template->candidate()));
   2063   sdp = kSdpTcpPassiveCandidate;
   2064   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   2065   sdp = kSdpTcpSOCandidate;
   2066   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   2067 }
   2068 
   2069 // This test verifies the deserialization of candidate-attribute
   2070 // as per RFC 5245. Candiate-attribute will be of the format
   2071 // candidate:<blah>. This format will be used when candidates
   2072 // are trickled.
   2073 TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
   2074   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   2075 
   2076   std::string candidate_attribute = kRawCandidate;
   2077   EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   2078   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   2079   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   2080   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   2081   EXPECT_EQ(2u, jcandidate.candidate().generation());
   2082 
   2083   // Candidate line without generation extension.
   2084   candidate_attribute = kRawCandidate;
   2085   Replace(" generation 2", "", &candidate_attribute);
   2086   EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   2087   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   2088   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   2089   Candidate expected = jcandidate_->candidate();
   2090   expected.set_generation(0);
   2091   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
   2092 
   2093   // Candidate line without candidate:
   2094   candidate_attribute = kRawCandidate;
   2095   Replace("candidate:", "", &candidate_attribute);
   2096   EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   2097 
   2098   // Candidate line with IPV6 address.
   2099   EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
   2100 }
   2101 
   2102 // This test verifies that the deserialization of an invalid candidate string
   2103 // fails.
   2104 TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
   2105     JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   2106 
   2107   std::string candidate_attribute = kRawCandidate;
   2108   candidate_attribute.replace(0, 1, "x");
   2109   EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   2110 
   2111   candidate_attribute = kSdpOneCandidate;
   2112   candidate_attribute.replace(0, 1, "x");
   2113   EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   2114 
   2115   candidate_attribute = kRawCandidate;
   2116   candidate_attribute.append("\r\n");
   2117   candidate_attribute.append(kRawCandidate);
   2118   EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
   2119 
   2120   EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
   2121 }
   2122 
   2123 TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannels) {
   2124   AddRtpDataChannel();
   2125   JsepSessionDescription jdesc(kDummyString);
   2126   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   2127 
   2128   std::string sdp_with_data = kSdpString;
   2129   sdp_with_data.append(kSdpRtpDataChannelString);
   2130   JsepSessionDescription jdesc_output(kDummyString);
   2131 
   2132   // Deserialize
   2133   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2134   // Verify
   2135   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2136 }
   2137 
   2138 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
   2139   AddSctpDataChannel();
   2140   JsepSessionDescription jdesc(kDummyString);
   2141   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   2142 
   2143   std::string sdp_with_data = kSdpString;
   2144   sdp_with_data.append(kSdpSctpDataChannelString);
   2145   JsepSessionDescription jdesc_output(kDummyString);
   2146 
   2147   // Verify with DTLS/SCTP (already in kSdpSctpDataChannelString).
   2148   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2149   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2150 
   2151   // Verify with UDP/DTLS/SCTP.
   2152   sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
   2153                         strlen(kDtlsSctp), kUdpDtlsSctp);
   2154   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2155   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2156 
   2157   // Verify with TCP/DTLS/SCTP.
   2158   sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
   2159                         strlen(kUdpDtlsSctp), kTcpDtlsSctp);
   2160   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2161   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2162 }
   2163 
   2164 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
   2165   AddSctpDataChannel();
   2166   JsepSessionDescription jdesc(kDummyString);
   2167   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   2168 
   2169   std::string sdp_with_data = kSdpString;
   2170   sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
   2171   JsepSessionDescription jdesc_output(kDummyString);
   2172 
   2173   // Verify with DTLS/SCTP (already in kSdpSctpDataChannelStringWithSctpPort).
   2174   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2175   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2176 
   2177   // Verify with UDP/DTLS/SCTP.
   2178   sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
   2179                         strlen(kDtlsSctp), kUdpDtlsSctp);
   2180   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2181   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2182 
   2183   // Verify with TCP/DTLS/SCTP.
   2184   sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
   2185                         strlen(kUdpDtlsSctp), kTcpDtlsSctp);
   2186   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2187   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2188 }
   2189 
   2190 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) {
   2191   AddSctpDataChannel();
   2192   JsepSessionDescription jdesc(kDummyString);
   2193   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   2194 
   2195   std::string sdp_with_data = kSdpString;
   2196   sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
   2197   JsepSessionDescription jdesc_output(kDummyString);
   2198 
   2199   // Verify with DTLS/SCTP.
   2200   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2201   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2202 
   2203   // Verify with UDP/DTLS/SCTP.
   2204   sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
   2205                         strlen(kDtlsSctp), kUdpDtlsSctp);
   2206   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2207   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2208 
   2209   // Verify with TCP/DTLS/SCTP.
   2210   sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
   2211                         strlen(kUdpDtlsSctp), kTcpDtlsSctp);
   2212   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2213   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2214 }
   2215 
   2216 // Test to check the behaviour if sctp-port is specified
   2217 // on the m= line and in a=sctp-port.
   2218 TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
   2219   AddSctpDataChannel();
   2220   JsepSessionDescription jdesc(kDummyString);
   2221   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   2222 
   2223   std::string sdp_with_data = kSdpString;
   2224   // Append m= attributes
   2225   sdp_with_data.append(kSdpSctpDataChannelString);
   2226   // Append a=sctp-port attribute
   2227   sdp_with_data.append("a=sctp-port 5000\r\n");
   2228   JsepSessionDescription jdesc_output(kDummyString);
   2229 
   2230   EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2231 }
   2232 
   2233 // For crbug/344475.
   2234 TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
   2235   std::string sdp_with_data = kSdpString;
   2236   sdp_with_data.append(kSdpSctpDataChannelString);
   2237   // Remove the "\n" at the end.
   2238   sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
   2239   JsepSessionDescription jdesc_output(kDummyString);
   2240 
   2241   EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2242   // No crash is a pass.
   2243 }
   2244 
   2245 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
   2246   AddSctpDataChannel();
   2247   const uint16_t kUnusualSctpPort = 9556;
   2248   char default_portstr[16];
   2249   char unusual_portstr[16];
   2250   rtc::sprintfn(default_portstr, sizeof(default_portstr), "%d",
   2251                       kDefaultSctpPort);
   2252   rtc::sprintfn(unusual_portstr, sizeof(unusual_portstr), "%d",
   2253                       kUnusualSctpPort);
   2254 
   2255   // First setup the expected JsepSessionDescription.
   2256   JsepSessionDescription jdesc(kDummyString);
   2257   // take our pre-built session description and change the SCTP port.
   2258   cricket::SessionDescription* mutant = desc_.Copy();
   2259   DataContentDescription* dcdesc = static_cast<DataContentDescription*>(
   2260       mutant->GetContentDescriptionByName(kDataContentName));
   2261   std::vector<cricket::DataCodec> codecs(dcdesc->codecs());
   2262   EXPECT_EQ(1U, codecs.size());
   2263   EXPECT_EQ(cricket::kGoogleSctpDataCodecId, codecs[0].id);
   2264   codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort);
   2265   dcdesc->set_codecs(codecs);
   2266 
   2267   // note: mutant's owned by jdesc now.
   2268   ASSERT_TRUE(jdesc.Initialize(mutant, kSessionId, kSessionVersion));
   2269   mutant = NULL;
   2270 
   2271   // Then get the deserialized JsepSessionDescription.
   2272   std::string sdp_with_data = kSdpString;
   2273   sdp_with_data.append(kSdpSctpDataChannelString);
   2274   rtc::replace_substrs(default_portstr, strlen(default_portstr),
   2275                              unusual_portstr, strlen(unusual_portstr),
   2276                              &sdp_with_data);
   2277   JsepSessionDescription jdesc_output(kDummyString);
   2278 
   2279   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2280   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2281 
   2282   // We need to test the deserialized JsepSessionDescription from
   2283   // kSdpSctpDataChannelStringWithSctpPort for
   2284   // draft-ietf-mmusic-sctp-sdp-07
   2285   // a=sctp-port
   2286   sdp_with_data = kSdpString;
   2287   sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
   2288   rtc::replace_substrs(default_portstr, strlen(default_portstr),
   2289                              unusual_portstr, strlen(unusual_portstr),
   2290                              &sdp_with_data);
   2291 
   2292   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2293   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
   2294 }
   2295 
   2296 TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
   2297   // We want to test that deserializing data content limits bandwidth
   2298   // settings (it should never be greater than the default).
   2299   // This should prevent someone from using unlimited data bandwidth through
   2300   // JS and "breaking the Internet".
   2301   // See: https://code.google.com/p/chromium/issues/detail?id=280726
   2302   std::string sdp_with_bandwidth = kSdpString;
   2303   sdp_with_bandwidth.append(kSdpRtpDataChannelString);
   2304   InjectAfter("a=mid:data_content_name\r\n",
   2305               "b=AS:100\r\n",
   2306               &sdp_with_bandwidth);
   2307   JsepSessionDescription jdesc_with_bandwidth(kDummyString);
   2308 
   2309   EXPECT_FALSE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
   2310 }
   2311 
   2312 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
   2313   AddSctpDataChannel();
   2314   JsepSessionDescription jdesc(kDummyString);
   2315   DataContentDescription* dcd = static_cast<DataContentDescription*>(
   2316      GetFirstDataContent(&desc_)->description);
   2317   dcd->set_bandwidth(100 * 1000);
   2318   ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
   2319 
   2320   std::string sdp_with_bandwidth = kSdpString;
   2321   sdp_with_bandwidth.append(kSdpSctpDataChannelString);
   2322   InjectAfter("a=mid:data_content_name\r\n",
   2323               "b=AS:100\r\n",
   2324               &sdp_with_bandwidth);
   2325   JsepSessionDescription jdesc_with_bandwidth(kDummyString);
   2326 
   2327   // SCTP has congestion control, so we shouldn't limit the bandwidth
   2328   // as we do for RTP.
   2329   EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
   2330   EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
   2331 }
   2332 
   2333 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSessionLevelExtmap) {
   2334   TestDeserializeExtmap(true, false);
   2335 }
   2336 
   2337 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
   2338   TestDeserializeExtmap(false, true);
   2339 }
   2340 
   2341 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInvalidExtmap) {
   2342   TestDeserializeExtmap(true, true);
   2343 }
   2344 
   2345 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
   2346   JsepSessionDescription jdesc(kDummyString);
   2347   std::string sdp = kSdpFullString;
   2348   sdp = sdp.substr(0, sdp.size() - 2);  // Remove \r\n at the end.
   2349   // Deserialize
   2350   SdpParseError error;
   2351   EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
   2352   const std::string lastline = "a=ssrc:6 label:video_track_id_3";
   2353   EXPECT_EQ(lastline, error.line);
   2354   EXPECT_EQ("Invalid SDP line.", error.description);
   2355 }
   2356 
   2357 TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
   2358   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   2359   std::string new_sdp = kSdpOneCandidate;
   2360   Replace("udp", "unsupported_transport", &new_sdp);
   2361   EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
   2362   new_sdp = kSdpOneCandidate;
   2363   Replace("udp", "uDP", &new_sdp);
   2364   EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
   2365   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   2366   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   2367   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
   2368 }
   2369 
   2370 TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) {
   2371   JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
   2372   EXPECT_TRUE(
   2373       SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate));
   2374   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   2375   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   2376   Candidate ref_candidate = jcandidate_->candidate();
   2377   ref_candidate.set_username("user_rtp");
   2378   ref_candidate.set_password("password_rtp");
   2379   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
   2380 }
   2381 
   2382 TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
   2383   JsepSessionDescription jdesc(kDummyString);
   2384 
   2385   // Deserialize
   2386   EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
   2387 
   2388   // Verify
   2389   cricket::AudioContentDescription* audio =
   2390     static_cast<AudioContentDescription*>(
   2391       jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
   2392   EXPECT_TRUE(audio->conference_mode());
   2393 
   2394   cricket::VideoContentDescription* video =
   2395     static_cast<VideoContentDescription*>(
   2396       jdesc.description()->GetContentDescriptionByName(cricket::CN_VIDEO));
   2397   EXPECT_TRUE(video->conference_mode());
   2398 }
   2399 
   2400 TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
   2401   const char kSdpDestroyer[] = "!@#$%^&";
   2402   const char kSdpEmptyType[] = " =candidate";
   2403   const char kSdpEqualAsPlus[] = "a+candidate";
   2404   const char kSdpSpaceAfterEqual[] = "a= candidate";
   2405   const char kSdpUpperType[] = "A=candidate";
   2406   const char kSdpEmptyLine[] = "";
   2407   const char kSdpMissingValue[] = "a=";
   2408 
   2409   const char kSdpBrokenFingerprint[] = "a=fingerprint:sha-1 "
   2410       "4AAD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
   2411   const char kSdpExtraField[] = "a=fingerprint:sha-1 "
   2412       "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB XXX";
   2413   const char kSdpMissingSpace[] = "a=fingerprint:sha-1"
   2414       "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
   2415   // MD5 is not allowed in fingerprints.
   2416   const char kSdpMd5[] = "a=fingerprint:md5 "
   2417       "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
   2418 
   2419   // Broken session description
   2420   ExpectParseFailure("v=", kSdpDestroyer);
   2421   ExpectParseFailure("o=", kSdpDestroyer);
   2422   ExpectParseFailure("s=-", kSdpDestroyer);
   2423   // Broken time description
   2424   ExpectParseFailure("t=", kSdpDestroyer);
   2425 
   2426   // Broken media description
   2427   ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
   2428   ExpectParseFailure("m=video", kSdpDestroyer);
   2429 
   2430   // Invalid lines
   2431   ExpectParseFailure("a=candidate", kSdpEmptyType);
   2432   ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
   2433   ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
   2434   ExpectParseFailure("a=candidate", kSdpUpperType);
   2435 
   2436   // Bogus fingerprint replacing a=sendrev. We selected this attribute
   2437   // because it's orthogonal to what we are replacing and hence
   2438   // safe.
   2439   ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
   2440   ExpectParseFailure("a=sendrecv", kSdpExtraField);
   2441   ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
   2442   ExpectParseFailure("a=sendrecv", kSdpMd5);
   2443 
   2444   // Empty Line
   2445   ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
   2446   ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
   2447 }
   2448 
   2449 TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
   2450   // ssrc
   2451   ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
   2452   ExpectParseFailure("a=ssrc-group:FEC 5 6", "a=ssrc-group:FEC badvalue 6");
   2453   // crypto
   2454   ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
   2455   // rtpmap
   2456   ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
   2457   ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
   2458   ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
   2459   // candidate
   2460   ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
   2461   ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
   2462   ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
   2463   ExpectParseFailure("rport 2346", "rport badvalue");
   2464   ExpectParseFailure("rport 2346 generation 2",
   2465                      "rport 2346 generation badvalue");
   2466   // m line
   2467   ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
   2468                      "m=audio 2345 RTP/SAVPF 111 badvalue 104");
   2469 
   2470   // bandwidth
   2471   ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
   2472                                  "b=AS:badvalue\r\n",
   2473                                  "b=AS:badvalue");
   2474   // rtcp-fb
   2475   ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
   2476                                  "a=rtcp-fb:badvalue nack\r\n",
   2477                                  "a=rtcp-fb:badvalue nack");
   2478   // extmap
   2479   ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
   2480                                  "a=extmap:badvalue http://example.com\r\n",
   2481                                  "a=extmap:badvalue http://example.com");
   2482 }
   2483 
   2484 TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
   2485   JsepSessionDescription jdesc_output(kDummyString);
   2486 
   2487   const char kSdpWithReorderedPlTypesString[] =
   2488       "v=0\r\n"
   2489       "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   2490       "s=-\r\n"
   2491       "t=0 0\r\n"
   2492       "m=audio 9 RTP/SAVPF 104 103\r\n"  // Pl type 104 preferred.
   2493       "a=rtpmap:111 opus/48000/2\r\n"  // Pltype 111 listed before 103 and 104
   2494                                        // in the map.
   2495       "a=rtpmap:103 ISAC/16000\r\n"  // Pltype 103 listed before 104 in the map.
   2496       "a=rtpmap:104 ISAC/32000\r\n";
   2497 
   2498   // Deserialize
   2499   EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
   2500 
   2501   const ContentInfo* ac = GetFirstAudioContent(jdesc_output.description());
   2502   ASSERT_TRUE(ac != NULL);
   2503   const AudioContentDescription* acd =
   2504       static_cast<const AudioContentDescription*>(ac->description);
   2505   ASSERT_FALSE(acd->codecs().empty());
   2506   EXPECT_EQ("ISAC", acd->codecs()[0].name);
   2507   EXPECT_EQ(32000, acd->codecs()[0].clockrate);
   2508   EXPECT_EQ(104, acd->codecs()[0].id);
   2509 }
   2510 
   2511 TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
   2512   JsepSessionDescription jdesc_output(kDummyString);
   2513   CodecParams params;
   2514   params.max_ptime = 40;
   2515   params.ptime = 30;
   2516   params.min_ptime = 10;
   2517   params.sprop_stereo = 1;
   2518   params.stereo = 1;
   2519   params.useinband = 1;
   2520   params.maxaveragebitrate = 128000;
   2521   TestDeserializeCodecParams(params, &jdesc_output);
   2522   TestSerialize(jdesc_output);
   2523 }
   2524 
   2525 TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
   2526   const bool kUseWildcard = false;
   2527   JsepSessionDescription jdesc_output(kDummyString);
   2528   TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
   2529   TestSerialize(jdesc_output);
   2530 }
   2531 
   2532 TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
   2533   const bool kUseWildcard = true;
   2534   JsepSessionDescription jdesc_output(kDummyString);
   2535   TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
   2536   TestSerialize(jdesc_output);
   2537 }
   2538 
   2539 TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
   2540   JsepSessionDescription jdesc_output(kDummyString);
   2541 
   2542   const char kSdpWithFmtpString[] =
   2543       "v=0\r\n"
   2544       "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   2545       "s=-\r\n"
   2546       "t=0 0\r\n"
   2547       "m=video 3457 RTP/SAVPF 120\r\n"
   2548       "a=rtpmap:120 VP8/90000\r\n"
   2549       "a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
   2550 
   2551   // Deserialize
   2552   SdpParseError error;
   2553   EXPECT_TRUE(
   2554       webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
   2555 
   2556   const ContentInfo* vc = GetFirstVideoContent(jdesc_output.description());
   2557   ASSERT_TRUE(vc != NULL);
   2558   const VideoContentDescription* vcd =
   2559       static_cast<const VideoContentDescription*>(vc->description);
   2560   ASSERT_FALSE(vcd->codecs().empty());
   2561   cricket::VideoCodec vp8 = vcd->codecs()[0];
   2562   EXPECT_EQ("VP8", vp8.name);
   2563   EXPECT_EQ(120, vp8.id);
   2564   cricket::CodecParameterMap::iterator found =
   2565       vp8.params.find("x-google-min-bitrate");
   2566   ASSERT_TRUE(found != vp8.params.end());
   2567   EXPECT_EQ(found->second, "10");
   2568   found = vp8.params.find("x-google-max-quantization");
   2569   ASSERT_TRUE(found != vp8.params.end());
   2570   EXPECT_EQ(found->second, "40");
   2571 }
   2572 
   2573 TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
   2574   JsepSessionDescription jdesc_output(kDummyString);
   2575 
   2576   const char kSdpWithFmtpString[] =
   2577       "v=0\r\n"
   2578       "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
   2579       "s=-\r\n"
   2580       "t=0 0\r\n"
   2581       "m=video 3457 RTP/SAVPF 120\r\n"
   2582       "a=rtpmap:120 VP8/90000\r\n"
   2583       "a=fmtp:120   x-google-min-bitrate=10;  x-google-max-quantization=40\r\n";
   2584 
   2585   // Deserialize
   2586   SdpParseError error;
   2587   EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output,
   2588                                      &error));
   2589 
   2590   const ContentInfo* vc = GetFirstVideoContent(jdesc_output.description());
   2591   ASSERT_TRUE(vc != NULL);
   2592   const VideoContentDescription* vcd =
   2593       static_cast<const VideoContentDescription*>(vc->description);
   2594   ASSERT_FALSE(vcd->codecs().empty());
   2595   cricket::VideoCodec vp8 = vcd->codecs()[0];
   2596   EXPECT_EQ("VP8", vp8.name);
   2597   EXPECT_EQ(120, vp8.id);
   2598   cricket::CodecParameterMap::iterator found =
   2599       vp8.params.find("x-google-min-bitrate");
   2600   ASSERT_TRUE(found != vp8.params.end());
   2601   EXPECT_EQ(found->second, "10");
   2602   found = vp8.params.find("x-google-max-quantization");
   2603   ASSERT_TRUE(found != vp8.params.end());
   2604   EXPECT_EQ(found->second, "40");
   2605 }
   2606 
   2607 TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
   2608   VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
   2609       GetFirstVideoContent(&desc_)->description);
   2610 
   2611   cricket::VideoCodecs codecs = vcd->codecs();
   2612   codecs[0].params["x-google-min-bitrate"] = "10";
   2613   vcd->set_codecs(codecs);
   2614 
   2615   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   2616                                 jdesc_.session_id(),
   2617                                 jdesc_.session_version()));
   2618   std::string message = webrtc::SdpSerialize(jdesc_);
   2619   std::string sdp_with_fmtp = kSdpFullString;
   2620   InjectAfter("a=rtpmap:120 VP8/90000\r\n",
   2621               "a=fmtp:120 x-google-min-bitrate=10\r\n",
   2622               &sdp_with_fmtp);
   2623   EXPECT_EQ(sdp_with_fmtp, message);
   2624 }
   2625 
   2626 TEST_F(WebRtcSdpTest, DeserializeSdpWithIceLite) {
   2627   JsepSessionDescription jdesc_with_icelite(kDummyString);
   2628   std::string sdp_with_icelite = kSdpFullString;
   2629   EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
   2630   cricket::SessionDescription* desc = jdesc_with_icelite.description();
   2631   const cricket::TransportInfo* tinfo1 =
   2632       desc->GetTransportInfoByName("audio_content_name");
   2633   EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
   2634   const cricket::TransportInfo* tinfo2 =
   2635       desc->GetTransportInfoByName("video_content_name");
   2636   EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
   2637   InjectAfter(kSessionTime,
   2638               "a=ice-lite\r\n",
   2639               &sdp_with_icelite);
   2640   EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
   2641   desc = jdesc_with_icelite.description();
   2642   const cricket::TransportInfo* atinfo =
   2643       desc->GetTransportInfoByName("audio_content_name");
   2644   EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
   2645   const cricket::TransportInfo* vtinfo =
   2646         desc->GetTransportInfoByName("video_content_name");
   2647   EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
   2648 }
   2649 
   2650 // Verifies that the candidates in the input SDP are parsed and serialized
   2651 // correctly in the output SDP.
   2652 TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
   2653   std::string sdp_with_data = kSdpString;
   2654   sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
   2655   JsepSessionDescription jdesc_output(kDummyString);
   2656 
   2657   EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
   2658   EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
   2659 }
   2660 
   2661 TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
   2662   AddFingerprint();
   2663   TransportInfo audio_transport_info =
   2664       *(desc_.GetTransportInfoByName(kAudioContentName));
   2665   EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
   2666             audio_transport_info.description.connection_role);
   2667   audio_transport_info.description.connection_role =
   2668         cricket::CONNECTIONROLE_ACTIVE;
   2669 
   2670   TransportInfo video_transport_info =
   2671       *(desc_.GetTransportInfoByName(kVideoContentName));
   2672   EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
   2673             video_transport_info.description.connection_role);
   2674   video_transport_info.description.connection_role =
   2675         cricket::CONNECTIONROLE_ACTIVE;
   2676 
   2677   desc_.RemoveTransportInfoByName(kAudioContentName);
   2678   desc_.RemoveTransportInfoByName(kVideoContentName);
   2679 
   2680   desc_.AddTransportInfo(audio_transport_info);
   2681   desc_.AddTransportInfo(video_transport_info);
   2682 
   2683   ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
   2684                                 jdesc_.session_id(),
   2685                                 jdesc_.session_version()));
   2686   std::string message = webrtc::SdpSerialize(jdesc_);
   2687   std::string sdp_with_dtlssetup = kSdpFullString;
   2688 
   2689   // Fingerprint attribute is necessary to add DTLS setup attribute.
   2690   InjectAfter(kAttributeIcePwdVoice,
   2691               kFingerprint, &sdp_with_dtlssetup);
   2692   InjectAfter(kAttributeIcePwdVideo,
   2693               kFingerprint, &sdp_with_dtlssetup);
   2694   // Now adding |setup| attribute.
   2695   InjectAfter(kFingerprint,
   2696               "a=setup:active\r\n", &sdp_with_dtlssetup);
   2697   EXPECT_EQ(sdp_with_dtlssetup, message);
   2698 }
   2699 
   2700 TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttribute) {
   2701   JsepSessionDescription jdesc_with_dtlssetup(kDummyString);
   2702   std::string sdp_with_dtlssetup = kSdpFullString;
   2703   InjectAfter(kSessionTime,
   2704               "a=setup:actpass\r\n",
   2705               &sdp_with_dtlssetup);
   2706   EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
   2707   cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
   2708   const cricket::TransportInfo* atinfo =
   2709       desc->GetTransportInfoByName("audio_content_name");
   2710   EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
   2711             atinfo->description.connection_role);
   2712   const cricket::TransportInfo* vtinfo =
   2713         desc->GetTransportInfoByName("video_content_name");
   2714   EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
   2715             vtinfo->description.connection_role);
   2716 }
   2717 
   2718 // Verifies that the order of the serialized m-lines follows the order of the
   2719 // ContentInfo in SessionDescription, and vise versa for deserialization.
   2720 TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
   2721   JsepSessionDescription jdesc(kDummyString);
   2722   const std::string media_content_sdps[3] = {
   2723     kSdpAudioString,
   2724     kSdpVideoString,
   2725     kSdpSctpDataChannelString
   2726   };
   2727   const cricket::MediaType media_types[3] = {
   2728     cricket::MEDIA_TYPE_AUDIO,
   2729     cricket::MEDIA_TYPE_VIDEO,
   2730     cricket::MEDIA_TYPE_DATA
   2731   };
   2732 
   2733   // Verifies all 6 permutations.
   2734   for (size_t i = 0; i < 6; ++i) {
   2735     size_t media_content_in_sdp[3];
   2736     // The index of the first media content.
   2737     media_content_in_sdp[0] = i / 2;
   2738     // The index of the second media content.
   2739     media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
   2740     // The index of the third media content.
   2741     media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
   2742 
   2743     std::string sdp_string = kSdpSessionString;
   2744     for (size_t i = 0; i < 3; ++i)
   2745       sdp_string += media_content_sdps[media_content_in_sdp[i]];
   2746 
   2747     EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
   2748     cricket::SessionDescription* desc = jdesc.description();
   2749     EXPECT_EQ(3u, desc->contents().size());
   2750 
   2751     for (size_t i = 0; i < 3; ++i) {
   2752       const cricket::MediaContentDescription* mdesc =
   2753           static_cast<const cricket::MediaContentDescription*>(
   2754               desc->contents()[i].description);
   2755       EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
   2756     }
   2757 
   2758     std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
   2759     EXPECT_EQ(sdp_string, serialized_sdp);
   2760   }
   2761 }
   2762