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