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