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