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