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