blob: a972daa62d82b58c985892c7810241922d71370a [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;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::NS_JINGLE_RTP;
59using cricket::RtpHeaderExtension;
60using cricket::RELAY_PORT_TYPE;
61using cricket::SessionDescription;
62using cricket::StreamParams;
63using cricket::STUN_PORT_TYPE;
64using cricket::TransportDescription;
65using cricket::TransportInfo;
66using cricket::VideoCodec;
67using cricket::VideoContentDescription;
68using webrtc::IceCandidateCollection;
69using webrtc::IceCandidateInterface;
70using webrtc::JsepIceCandidate;
71using webrtc::JsepSessionDescription;
72using webrtc::SdpParseError;
73using webrtc::SessionDescriptionInterface;
74
75typedef std::vector<AudioCodec> AudioCodecs;
76typedef std::vector<Candidate> Candidates;
77
Peter Boström0c4e06b2015-10-07 12:23:21 +020078static const uint32_t kDefaultSctpPort = 5000;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079static const char kSessionTime[] = "t=0 0\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020080static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081static const char kCandidateUfragVoice[] = "ufrag_voice";
82static const char kCandidatePwdVoice[] = "pwd_voice";
83static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
84static const char kCandidateUfragVideo[] = "ufrag_video";
85static const char kCandidatePwdVideo[] = "pwd_video";
86static const char kCandidateUfragData[] = "ufrag_data";
87static const char kCandidatePwdData[] = "pwd_data";
88static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020089static const uint32_t kCandidateGeneration = 2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090static const char kCandidateFoundation1[] = "a0+B/1";
91static const char kCandidateFoundation2[] = "a0+B/2";
92static const char kCandidateFoundation3[] = "a0+B/3";
93static const char kCandidateFoundation4[] = "a0+B/4";
94static const char kAttributeCryptoVoice[] =
95 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
96 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
97 "dummy_session_params\r\n";
98static const char kAttributeCryptoVideo[] =
99 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
100 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
101static const char kFingerprint[] = "a=fingerprint:sha-1 "
102 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n";
103static const int kExtmapId = 1;
104static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
105static const char kExtmap[] =
106 "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
107static const char kExtmapWithDirectionAndAttribute[] =
108 "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
109
Peter Boström0c4e06b2015-10-07 12:23:21 +0200110static const uint8_t kIdentityDigest[] = {
111 0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
112 0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113
lally@webrtc.org34807282015-02-24 20:19:39 +0000114static const char kDtlsSctp[] = "DTLS/SCTP";
115static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
116static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
lally@webrtc.org36300852015-02-24 20:19:35 +0000117
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118struct CodecParams {
119 int max_ptime;
120 int ptime;
121 int min_ptime;
122 int sprop_stereo;
123 int stereo;
124 int useinband;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000125 int maxaveragebitrate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126};
127
128// Reference sdp string
129static const char kSdpFullString[] =
130 "v=0\r\n"
131 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
132 "s=-\r\n"
133 "t=0 0\r\n"
134 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
135 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
136 "c=IN IP4 74.125.127.126\r\n"
137 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
138 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
139 "generation 2\r\n"
140 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
141 "generation 2\r\n"
142 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
143 "generation 2\r\n"
144 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
145 "generation 2\r\n"
146 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
147 "raddr 192.168.1.5 rport 2346 "
148 "generation 2\r\n"
149 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
150 "raddr 192.168.1.5 rport 2348 "
151 "generation 2\r\n"
152 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
153 "a=mid:audio_content_name\r\n"
154 "a=sendrecv\r\n"
155 "a=rtcp-mux\r\n"
156 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
157 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
158 "dummy_session_params\r\n"
159 "a=rtpmap:111 opus/48000/2\r\n"
160 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000161 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162 "a=ssrc:1 cname:stream_1_cname\r\n"
163 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
164 "a=ssrc:1 mslabel:local_stream_1\r\n"
165 "a=ssrc:1 label:audio_track_id_1\r\n"
166 "a=ssrc:4 cname:stream_2_cname\r\n"
167 "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
168 "a=ssrc:4 mslabel:local_stream_2\r\n"
169 "a=ssrc:4 label:audio_track_id_2\r\n"
170 "m=video 3457 RTP/SAVPF 120\r\n"
171 "c=IN IP4 74.125.224.39\r\n"
172 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
173 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
174 "generation 2\r\n"
175 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
176 "generation 2\r\n"
177 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
178 "generation 2\r\n"
179 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
180 "generation 2\r\n"
181 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
182 "generation 2\r\n"
183 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
184 "generation 2\r\n"
185 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
186 "a=mid:video_content_name\r\n"
187 "a=sendrecv\r\n"
188 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
189 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
190 "a=rtpmap:120 VP8/90000\r\n"
191 "a=ssrc:2 cname:stream_1_cname\r\n"
192 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
193 "a=ssrc:2 mslabel:local_stream_1\r\n"
194 "a=ssrc:2 label:video_track_id_1\r\n"
195 "a=ssrc:3 cname:stream_1_cname\r\n"
196 "a=ssrc:3 msid:local_stream_1 video_track_id_2\r\n"
197 "a=ssrc:3 mslabel:local_stream_1\r\n"
198 "a=ssrc:3 label:video_track_id_2\r\n"
199 "a=ssrc-group:FEC 5 6\r\n"
200 "a=ssrc:5 cname:stream_2_cname\r\n"
201 "a=ssrc:5 msid:local_stream_2 video_track_id_3\r\n"
202 "a=ssrc:5 mslabel:local_stream_2\r\n"
203 "a=ssrc:5 label:video_track_id_3\r\n"
204 "a=ssrc:6 cname:stream_2_cname\r\n"
205 "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
206 "a=ssrc:6 mslabel:local_stream_2\r\n"
207 "a=ssrc:6 label:video_track_id_3\r\n";
208
209// SDP reference string without the candidates.
210static const char kSdpString[] =
211 "v=0\r\n"
212 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
213 "s=-\r\n"
214 "t=0 0\r\n"
215 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000216 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000217 "c=IN IP4 0.0.0.0\r\n"
218 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
220 "a=mid:audio_content_name\r\n"
221 "a=sendrecv\r\n"
222 "a=rtcp-mux\r\n"
223 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
224 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
225 "dummy_session_params\r\n"
226 "a=rtpmap:111 opus/48000/2\r\n"
227 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000228 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 "a=ssrc:1 cname:stream_1_cname\r\n"
230 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
231 "a=ssrc:1 mslabel:local_stream_1\r\n"
232 "a=ssrc:1 label:audio_track_id_1\r\n"
233 "a=ssrc:4 cname:stream_2_cname\r\n"
234 "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
235 "a=ssrc:4 mslabel:local_stream_2\r\n"
236 "a=ssrc:4 label:audio_track_id_2\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000237 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000238 "c=IN IP4 0.0.0.0\r\n"
239 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
241 "a=mid:video_content_name\r\n"
242 "a=sendrecv\r\n"
243 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
244 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
245 "a=rtpmap:120 VP8/90000\r\n"
246 "a=ssrc:2 cname:stream_1_cname\r\n"
247 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
248 "a=ssrc:2 mslabel:local_stream_1\r\n"
249 "a=ssrc:2 label:video_track_id_1\r\n"
250 "a=ssrc:3 cname:stream_1_cname\r\n"
251 "a=ssrc:3 msid:local_stream_1 video_track_id_2\r\n"
252 "a=ssrc:3 mslabel:local_stream_1\r\n"
253 "a=ssrc:3 label:video_track_id_2\r\n"
254 "a=ssrc-group:FEC 5 6\r\n"
255 "a=ssrc:5 cname:stream_2_cname\r\n"
256 "a=ssrc:5 msid:local_stream_2 video_track_id_3\r\n"
257 "a=ssrc:5 mslabel:local_stream_2\r\n"
258 "a=ssrc:5 label:video_track_id_3\r\n"
259 "a=ssrc:6 cname:stream_2_cname\r\n"
260 "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
261 "a=ssrc:6 mslabel:local_stream_2\r\n"
262 "a=ssrc:6 label:video_track_id_3\r\n";
263
264static const char kSdpRtpDataChannelString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000265 "m=application 9 RTP/SAVPF 101\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000266 "c=IN IP4 0.0.0.0\r\n"
267 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268 "a=ice-ufrag:ufrag_data\r\n"
269 "a=ice-pwd:pwd_data\r\n"
270 "a=mid:data_content_name\r\n"
271 "a=sendrecv\r\n"
272 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
273 "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5\r\n"
274 "a=rtpmap:101 google-data/90000\r\n"
275 "a=ssrc:10 cname:data_channel_cname\r\n"
276 "a=ssrc:10 msid:data_channel data_channeld0\r\n"
277 "a=ssrc:10 mslabel:data_channel\r\n"
278 "a=ssrc:10 label:data_channeld0\r\n";
279
280static const char kSdpSctpDataChannelString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000281 "m=application 9 DTLS/SCTP 5000\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000282 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 "a=ice-ufrag:ufrag_data\r\n"
284 "a=ice-pwd:pwd_data\r\n"
285 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000286 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287
lally@webrtc.orgec97c652015-02-24 20:18:48 +0000288// draft-ietf-mmusic-sctp-sdp-12
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +0000289static const char kSdpSctpDataChannelStringWithSctpPort[] =
lally@webrtc.orgc7848b72015-02-24 20:19:26 +0000290 "m=application 9 DTLS/SCTP webrtc-datachannel\r\n"
291 "a=max-message-size=100000\r\n"
292 "a=sctp-port 5000\r\n"
293 "c=IN IP4 0.0.0.0\r\n"
294 "a=ice-ufrag:ufrag_data\r\n"
295 "a=ice-pwd:pwd_data\r\n"
296 "a=mid:data_content_name\r\n";
297
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298static const char kSdpSctpDataChannelWithCandidatesString[] =
299 "m=application 2345 DTLS/SCTP 5000\r\n"
300 "c=IN IP4 74.125.127.126\r\n"
301 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
302 "generation 2\r\n"
303 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
304 "generation 2\r\n"
305 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
306 "raddr 192.168.1.5 rport 2346 "
307 "generation 2\r\n"
308 "a=ice-ufrag:ufrag_data\r\n"
309 "a=ice-pwd:pwd_data\r\n"
310 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000311 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000313static const char kSdpConferenceString[] =
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000314 "v=0\r\n"
315 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
316 "s=-\r\n"
317 "t=0 0\r\n"
318 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000319 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000320 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000321 "a=x-google-flag:conference\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000322 "m=video 9 RTP/SAVPF 120\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";
325
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000326static const char kSdpSessionString[] =
327 "v=0\r\n"
328 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
329 "s=-\r\n"
330 "t=0 0\r\n"
331 "a=msid-semantic: WMS local_stream\r\n";
332
333static const char kSdpAudioString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000334 "m=audio 9 RTP/SAVPF 111\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000335 "c=IN IP4 0.0.0.0\r\n"
336 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000337 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
338 "a=mid:audio_content_name\r\n"
339 "a=sendrecv\r\n"
340 "a=rtpmap:111 opus/48000/2\r\n"
341 "a=ssrc:1 cname:stream_1_cname\r\n"
342 "a=ssrc:1 msid:local_stream audio_track_id_1\r\n"
343 "a=ssrc:1 mslabel:local_stream\r\n"
344 "a=ssrc:1 label:audio_track_id_1\r\n";
345
346static const char kSdpVideoString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000347 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000348 "c=IN IP4 0.0.0.0\r\n"
349 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000350 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
351 "a=mid:video_content_name\r\n"
352 "a=sendrecv\r\n"
353 "a=rtpmap:120 VP8/90000\r\n"
354 "a=ssrc:2 cname:stream_1_cname\r\n"
355 "a=ssrc:2 msid:local_stream video_track_id_1\r\n"
356 "a=ssrc:2 mslabel:local_stream\r\n"
357 "a=ssrc:2 label:video_track_id_1\r\n";
358
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359
360// One candidate reference string as per W3c spec.
361// candidate:<blah> not a=candidate:<blah>CRLF
362static const char kRawCandidate[] =
363 "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
364// One candidate reference string.
365static const char kSdpOneCandidate[] =
366 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
367 "generation 2\r\n";
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000368
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +0000369static const char kSdpTcpActiveCandidate[] =
370 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
371 "tcptype active generation 2";
372static const char kSdpTcpPassiveCandidate[] =
373 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
374 "tcptype passive generation 2";
375static const char kSdpTcpSOCandidate[] =
376 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
377 "tcptype so generation 2";
378static const char kSdpTcpInvalidCandidate[] =
379 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
380 "tcptype invalid generation 2";
381
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000382// One candidate reference string with IPV6 address.
383static const char kRawIPV6Candidate[] =
384 "candidate:a0+B/1 1 udp 2130706432 "
385 "abcd::abcd::abcd::abcd::abcd::abcd::abcd::abcd 1234 typ host generation 2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386
387// One candidate reference string.
388static const char kSdpOneCandidateOldFormat[] =
389 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
390 " eth0 username user_rtp password password_rtp generation 2\r\n";
391
392// Session id and version
393static const char kSessionId[] = "18446744069414584320";
394static const char kSessionVersion[] = "18446462598732840960";
395
396// Ice options
397static const char kIceOption1[] = "iceoption1";
398static const char kIceOption2[] = "iceoption2";
399static const char kIceOption3[] = "iceoption3";
400
401// Content name
402static const char kAudioContentName[] = "audio_content_name";
403static const char kVideoContentName[] = "video_content_name";
404static const char kDataContentName[] = "data_content_name";
405
406// MediaStream 1
407static const char kStreamLabel1[] = "local_stream_1";
408static const char kStream1Cname[] = "stream_1_cname";
409static const char kAudioTrackId1[] = "audio_track_id_1";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200410static const uint32_t kAudioTrack1Ssrc = 1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411static const char kVideoTrackId1[] = "video_track_id_1";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200412static const uint32_t kVideoTrack1Ssrc = 2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413static const char kVideoTrackId2[] = "video_track_id_2";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200414static const uint32_t kVideoTrack2Ssrc = 3;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415
416// MediaStream 2
417static const char kStreamLabel2[] = "local_stream_2";
418static const char kStream2Cname[] = "stream_2_cname";
419static const char kAudioTrackId2[] = "audio_track_id_2";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200420static const uint32_t kAudioTrack2Ssrc = 4;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421static const char kVideoTrackId3[] = "video_track_id_3";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200422static const uint32_t kVideoTrack3Ssrc = 5;
423static const uint32_t kVideoTrack4Ssrc = 6;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424
425// DataChannel
426static const char kDataChannelLabel[] = "data_channel";
427static const char kDataChannelMsid[] = "data_channeld0";
428static const char kDataChannelCname[] = "data_channel_cname";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200429static const uint32_t kDataChannelSsrc = 10;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430
431// Candidate
432static const char kDummyMid[] = "dummy_mid";
433static const int kDummyIndex = 123;
434
435// Misc
436static const char kDummyString[] = "dummy";
437
438// Helper functions
439
440static bool SdpDeserialize(const std::string& message,
441 JsepSessionDescription* jdesc) {
442 return webrtc::SdpDeserialize(message, jdesc, NULL);
443}
444
445static bool SdpDeserializeCandidate(const std::string& message,
446 JsepIceCandidate* candidate) {
447 return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
448}
449
450// Add some extra |newlines| to the |message| after |line|.
451static void InjectAfter(const std::string& line,
452 const std::string& newlines,
453 std::string* message) {
454 const std::string tmp = line + newlines;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000455 rtc::replace_substrs(line.c_str(), line.length(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456 tmp.c_str(), tmp.length(), message);
457}
458
459static void Replace(const std::string& line,
460 const std::string& newlines,
461 std::string* message) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000462 rtc::replace_substrs(line.c_str(), line.length(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463 newlines.c_str(), newlines.length(), message);
464}
465
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000466// Expect fail to parase |bad_sdp| and expect |bad_part| be part of the error
467// message.
468static void ExpectParseFailure(const std::string& bad_sdp,
469 const std::string& bad_part) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 JsepSessionDescription desc(kDummyString);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 SdpParseError error;
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000472 bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 EXPECT_FALSE(ret);
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000474 EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()));
475}
476
477// Expect fail to parse kSdpFullString if replace |good_part| with |bad_part|.
478static void ExpectParseFailure(const char* good_part, const char* bad_part) {
479 std::string bad_sdp = kSdpFullString;
480 Replace(good_part, bad_part, &bad_sdp);
481 ExpectParseFailure(bad_sdp, bad_part);
482}
483
484// Expect fail to parse kSdpFullString if add |newlines| after |injectpoint|.
485static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
486 const std::string& newlines,
487 const std::string& bad_part) {
488 std::string bad_sdp = kSdpFullString;
489 InjectAfter(injectpoint, newlines, &bad_sdp);
490 ExpectParseFailure(bad_sdp, bad_part);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000491}
492
493static void ReplaceDirection(cricket::MediaContentDirection direction,
494 std::string* message) {
495 std::string new_direction;
496 switch (direction) {
497 case cricket::MD_INACTIVE:
498 new_direction = "a=inactive";
499 break;
500 case cricket::MD_SENDONLY:
501 new_direction = "a=sendonly";
502 break;
503 case cricket::MD_RECVONLY:
504 new_direction = "a=recvonly";
505 break;
506 case cricket::MD_SENDRECV:
507 default:
508 new_direction = "a=sendrecv";
509 break;
510 }
511 Replace("a=sendrecv", new_direction, message);
512}
513
514static void ReplaceRejected(bool audio_rejected, bool video_rejected,
515 std::string* message) {
516 if (audio_rejected) {
517 Replace("m=audio 2345", "m=audio 0", message);
518 }
519 if (video_rejected) {
520 Replace("m=video 3457", "m=video 0", message);
521 }
522}
523
524// WebRtcSdpTest
525
526class WebRtcSdpTest : public testing::Test {
527 public:
528 WebRtcSdpTest()
529 : jdesc_(kDummyString) {
530 // AudioContentDescription
531 audio_desc_ = CreateAudioContentDescription();
532 AudioCodec opus(111, "opus", 48000, 0, 2, 3);
533 audio_desc_->AddCodec(opus);
534 audio_desc_->AddCodec(AudioCodec(103, "ISAC", 16000, 32000, 1, 2));
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000535 audio_desc_->AddCodec(AudioCodec(104, "ISAC", 32000, 56000, 1, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_desc_);
537
538 // VideoContentDescription
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000539 rtc::scoped_ptr<VideoContentDescription> video(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 new VideoContentDescription());
541 video_desc_ = video.get();
542 StreamParams video_stream1;
543 video_stream1.id = kVideoTrackId1;
544 video_stream1.cname = kStream1Cname;
545 video_stream1.sync_label = kStreamLabel1;
546 video_stream1.ssrcs.push_back(kVideoTrack1Ssrc);
547 video->AddStream(video_stream1);
548 StreamParams video_stream2;
549 video_stream2.id = kVideoTrackId2;
550 video_stream2.cname = kStream1Cname;
551 video_stream2.sync_label = kStreamLabel1;
552 video_stream2.ssrcs.push_back(kVideoTrack2Ssrc);
553 video->AddStream(video_stream2);
554 StreamParams video_stream3;
555 video_stream3.id = kVideoTrackId3;
556 video_stream3.cname = kStream2Cname;
557 video_stream3.sync_label = kStreamLabel2;
558 video_stream3.ssrcs.push_back(kVideoTrack3Ssrc);
559 video_stream3.ssrcs.push_back(kVideoTrack4Ssrc);
560 cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream3.ssrcs);
561 video_stream3.ssrc_groups.push_back(ssrc_group);
562 video->AddStream(video_stream3);
563 video->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_80",
564 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
565 video->set_protocol(cricket::kMediaProtocolSavpf);
566 video->AddCodec(VideoCodec(
567 120,
568 JsepSessionDescription::kDefaultVideoCodecName,
569 JsepSessionDescription::kMaxVideoCodecWidth,
570 JsepSessionDescription::kMaxVideoCodecHeight,
571 JsepSessionDescription::kDefaultVideoCodecFramerate,
572 JsepSessionDescription::kDefaultVideoCodecPreference));
573
574 desc_.AddContent(kVideoContentName, NS_JINGLE_RTP,
575 video.release());
576
577 // TransportInfo
578 EXPECT_TRUE(desc_.AddTransportInfo(
579 TransportInfo(kAudioContentName,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700580 TransportDescription(kCandidateUfragVoice,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000581 kCandidatePwdVoice))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 EXPECT_TRUE(desc_.AddTransportInfo(
583 TransportInfo(kVideoContentName,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700584 TransportDescription(kCandidateUfragVideo,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000585 kCandidatePwdVideo))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586
587 // v4 host
588 int port = 1234;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000589 rtc::SocketAddress address("192.168.1.5", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000590 Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000591 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
592 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000594 Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000595 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
596 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000598 Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000599 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
600 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000602 Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000603 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
604 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605
606 // v6 host
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000607 rtc::SocketAddress v6_address("::1", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000608 cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
609 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000610 cricket::LOCAL_PORT_TYPE,
611 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000613 cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "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 candidate7(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 candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "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
628 // stun
629 int port_stun = 2345;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000630 rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
631 rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000632 cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
633 address_stun, kCandidatePriority, "", "",
634 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000635 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 candidate9.set_related_address(rel_address_stun);
637
638 address_stun.SetPort(port_stun++);
639 rel_address_stun.SetPort(port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000640 cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
641 address_stun, kCandidatePriority, "", "",
642 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000643 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 candidate10.set_related_address(rel_address_stun);
645
646 // relay
647 int port_relay = 3456;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000648 rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000649 cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
650 address_relay, kCandidatePriority, "", "",
651 cricket::RELAY_PORT_TYPE,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000652 kCandidateGeneration, kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 address_relay.SetPort(port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000654 cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
655 address_relay, kCandidatePriority, "", "",
656 RELAY_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000657 kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658
659 // voice
660 candidates_.push_back(candidate1);
661 candidates_.push_back(candidate2);
662 candidates_.push_back(candidate5);
663 candidates_.push_back(candidate6);
664 candidates_.push_back(candidate9);
665 candidates_.push_back(candidate10);
666
667 // video
668 candidates_.push_back(candidate3);
669 candidates_.push_back(candidate4);
670 candidates_.push_back(candidate7);
671 candidates_.push_back(candidate8);
672 candidates_.push_back(candidate11);
673 candidates_.push_back(candidate12);
674
675 jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"),
676 0, candidate1));
677
678 // Set up JsepSessionDescription.
679 jdesc_.Initialize(desc_.Copy(), kSessionId, kSessionVersion);
680 std::string mline_id;
681 int mline_index = 0;
682 for (size_t i = 0; i< candidates_.size(); ++i) {
683 // In this test, the audio m line index will be 0, and the video m line
684 // will be 1.
685 bool is_video = (i > 5);
686 mline_id = is_video ? "video_content_name" : "audio_content_name";
687 mline_index = is_video ? 1 : 0;
688 JsepIceCandidate jice(mline_id,
689 mline_index,
690 candidates_.at(i));
691 jdesc_.AddCandidate(&jice);
692 }
693 }
694
695 AudioContentDescription* CreateAudioContentDescription() {
696 AudioContentDescription* audio = new AudioContentDescription();
697 audio->set_rtcp_mux(true);
698 StreamParams audio_stream1;
699 audio_stream1.id = kAudioTrackId1;
700 audio_stream1.cname = kStream1Cname;
701 audio_stream1.sync_label = kStreamLabel1;
702 audio_stream1.ssrcs.push_back(kAudioTrack1Ssrc);
703 audio->AddStream(audio_stream1);
704 StreamParams audio_stream2;
705 audio_stream2.id = kAudioTrackId2;
706 audio_stream2.cname = kStream2Cname;
707 audio_stream2.sync_label = kStreamLabel2;
708 audio_stream2.ssrcs.push_back(kAudioTrack2Ssrc);
709 audio->AddStream(audio_stream2);
710 audio->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_32",
711 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
712 "dummy_session_params"));
713 audio->set_protocol(cricket::kMediaProtocolSavpf);
714 return audio;
715 }
716
717 template <class MCD>
718 void CompareMediaContentDescription(const MCD* cd1,
719 const MCD* cd2) {
720 // type
721 EXPECT_EQ(cd1->type(), cd1->type());
722
723 // content direction
724 EXPECT_EQ(cd1->direction(), cd2->direction());
725
726 // rtcp_mux
727 EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
728
729 // cryptos
730 EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
731 if (cd1->cryptos().size() != cd2->cryptos().size()) {
732 ADD_FAILURE();
733 return;
734 }
735 for (size_t i = 0; i< cd1->cryptos().size(); ++i) {
736 const CryptoParams c1 = cd1->cryptos().at(i);
737 const CryptoParams c2 = cd2->cryptos().at(i);
738 EXPECT_TRUE(c1.Matches(c2));
739 EXPECT_EQ(c1.key_params, c2.key_params);
740 EXPECT_EQ(c1.session_params, c2.session_params);
741 }
lally@webrtc.orgd7b61652015-02-24 20:18:55 +0000742
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 // protocol
lally@webrtc.orgd7b61652015-02-24 20:18:55 +0000744 // Use an equivalence class here, for old and new versions of the
745 // protocol description.
746 if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp
lally@webrtc.org36300852015-02-24 20:19:35 +0000747 || cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp
748 || cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
749 const bool cd2_is_also_dtls_sctp =
lally@webrtc.orgd7b61652015-02-24 20:18:55 +0000750 cd2->protocol() == cricket::kMediaProtocolDtlsSctp
lally@webrtc.org36300852015-02-24 20:19:35 +0000751 || cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp
752 || cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
753 EXPECT_TRUE(cd2_is_also_dtls_sctp);
lally@webrtc.orgd7b61652015-02-24 20:18:55 +0000754 } else {
755 EXPECT_EQ(cd1->protocol(), cd2->protocol());
756 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757
758 // codecs
759 EXPECT_EQ(cd1->codecs(), cd2->codecs());
760
761 // bandwidth
762 EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
763
764 // streams
765 EXPECT_EQ(cd1->streams(), cd2->streams());
766
767 // extmap
768 ASSERT_EQ(cd1->rtp_header_extensions().size(),
769 cd2->rtp_header_extensions().size());
770 for (size_t i = 0; i< cd1->rtp_header_extensions().size(); ++i) {
771 const RtpHeaderExtension ext1 = cd1->rtp_header_extensions().at(i);
772 const RtpHeaderExtension ext2 = cd2->rtp_header_extensions().at(i);
773 EXPECT_EQ(ext1.uri, ext2.uri);
774 EXPECT_EQ(ext1.id, ext2.id);
775 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000776 }
777
778
779 void CompareSessionDescription(const SessionDescription& desc1,
780 const SessionDescription& desc2) {
781 // Compare content descriptions.
782 if (desc1.contents().size() != desc2.contents().size()) {
783 ADD_FAILURE();
784 return;
785 }
786 for (size_t i = 0 ; i < desc1.contents().size(); ++i) {
787 const cricket::ContentInfo& c1 = desc1.contents().at(i);
788 const cricket::ContentInfo& c2 = desc2.contents().at(i);
789 // content name
790 EXPECT_EQ(c1.name, c2.name);
791 // content type
792 // Note, ASSERT will return from the function, but will not stop the test.
793 ASSERT_EQ(c1.type, c2.type);
794
795 ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
796 if (IsAudioContent(&c1)) {
797 const AudioContentDescription* acd1 =
798 static_cast<const AudioContentDescription*>(c1.description);
799 const AudioContentDescription* acd2 =
800 static_cast<const AudioContentDescription*>(c2.description);
801 CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
802 }
803
804 ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
805 if (IsVideoContent(&c1)) {
806 const VideoContentDescription* vcd1 =
807 static_cast<const VideoContentDescription*>(c1.description);
808 const VideoContentDescription* vcd2 =
809 static_cast<const VideoContentDescription*>(c2.description);
810 CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
811 }
812
813 ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
814 if (IsDataContent(&c1)) {
815 const DataContentDescription* dcd1 =
816 static_cast<const DataContentDescription*>(c1.description);
817 const DataContentDescription* dcd2 =
818 static_cast<const DataContentDescription*>(c2.description);
819 CompareMediaContentDescription<DataContentDescription>(dcd1, dcd2);
820 }
821 }
822
823 // group
824 const cricket::ContentGroups groups1 = desc1.groups();
825 const cricket::ContentGroups groups2 = desc2.groups();
826 EXPECT_EQ(groups1.size(), groups1.size());
827 if (groups1.size() != groups2.size()) {
828 ADD_FAILURE();
829 return;
830 }
831 for (size_t i = 0; i < groups1.size(); ++i) {
832 const cricket::ContentGroup group1 = groups1.at(i);
833 const cricket::ContentGroup group2 = groups2.at(i);
834 EXPECT_EQ(group1.semantics(), group2.semantics());
835 const cricket::ContentNames names1 = group1.content_names();
836 const cricket::ContentNames names2 = group2.content_names();
837 EXPECT_EQ(names1.size(), names2.size());
838 if (names1.size() != names2.size()) {
839 ADD_FAILURE();
840 return;
841 }
842 cricket::ContentNames::const_iterator iter1 = names1.begin();
843 cricket::ContentNames::const_iterator iter2 = names2.begin();
844 while (iter1 != names1.end()) {
845 EXPECT_EQ(*iter1++, *iter2++);
846 }
847 }
848
849 // transport info
850 const cricket::TransportInfos transports1 = desc1.transport_infos();
851 const cricket::TransportInfos transports2 = desc2.transport_infos();
852 EXPECT_EQ(transports1.size(), transports2.size());
853 if (transports1.size() != transports2.size()) {
854 ADD_FAILURE();
855 return;
856 }
857 for (size_t i = 0; i < transports1.size(); ++i) {
858 const cricket::TransportInfo transport1 = transports1.at(i);
859 const cricket::TransportInfo transport2 = transports2.at(i);
860 EXPECT_EQ(transport1.content_name, transport2.content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861 EXPECT_EQ(transport1.description.ice_ufrag,
862 transport2.description.ice_ufrag);
863 EXPECT_EQ(transport1.description.ice_pwd,
864 transport2.description.ice_pwd);
865 if (transport1.description.identity_fingerprint) {
866 EXPECT_EQ(*transport1.description.identity_fingerprint,
867 *transport2.description.identity_fingerprint);
868 } else {
869 EXPECT_EQ(transport1.description.identity_fingerprint.get(),
870 transport2.description.identity_fingerprint.get());
871 }
872 EXPECT_EQ(transport1.description.transport_options,
873 transport2.description.transport_options);
874 EXPECT_TRUE(CompareCandidates(transport1.description.candidates,
875 transport2.description.candidates));
876 }
877 }
878
879 bool CompareCandidates(const Candidates& cs1, const Candidates& cs2) {
880 EXPECT_EQ(cs1.size(), cs2.size());
881 if (cs1.size() != cs2.size())
882 return false;
883 for (size_t i = 0; i< cs1.size(); ++i) {
884 const Candidate c1 = cs1.at(i);
885 const Candidate c2 = cs2.at(i);
886 EXPECT_TRUE(c1.IsEquivalent(c2));
887 }
888 return true;
889 }
890
891 bool CompareSessionDescription(
892 const JsepSessionDescription& desc1,
893 const JsepSessionDescription& desc2) {
894 EXPECT_EQ(desc1.session_id(), desc2.session_id());
895 EXPECT_EQ(desc1.session_version(), desc2.session_version());
896 CompareSessionDescription(*desc1.description(), *desc2.description());
897 if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
898 return false;
899 for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
900 const IceCandidateCollection* cc1 = desc1.candidates(i);
901 const IceCandidateCollection* cc2 = desc2.candidates(i);
902 if (cc1->count() != cc2->count())
903 return false;
904 for (size_t j = 0; j < cc1->count(); ++j) {
905 const IceCandidateInterface* c1 = cc1->at(j);
906 const IceCandidateInterface* c2 = cc2->at(j);
907 EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
908 EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
909 EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
910 }
911 }
912 return true;
913 }
914
915 // Disable the ice-ufrag and ice-pwd in given |sdp| message by replacing
916 // them with invalid keywords so that the parser will just ignore them.
917 bool RemoveCandidateUfragPwd(std::string* sdp) {
918 const char ice_ufrag[] = "a=ice-ufrag";
919 const char ice_ufragx[] = "a=xice-ufrag";
920 const char ice_pwd[] = "a=ice-pwd";
921 const char ice_pwdx[] = "a=xice-pwd";
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000922 rtc::replace_substrs(ice_ufrag, strlen(ice_ufrag),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 ice_ufragx, strlen(ice_ufragx), sdp);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000924 rtc::replace_substrs(ice_pwd, strlen(ice_pwd),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000925 ice_pwdx, strlen(ice_pwdx), sdp);
926 return true;
927 }
928
929 // Update the candidates in |jdesc| to use the given |ufrag| and |pwd|.
930 bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc, int mline_index,
931 const std::string& ufrag, const std::string& pwd) {
932 std::string content_name;
933 if (mline_index == 0) {
934 content_name = kAudioContentName;
935 } else if (mline_index == 1) {
936 content_name = kVideoContentName;
937 } else {
938 ASSERT(false);
939 }
940 TransportInfo transport_info(
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700941 content_name, TransportDescription(ufrag, pwd));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942 SessionDescription* desc =
943 const_cast<SessionDescription*>(jdesc->description());
944 desc->RemoveTransportInfoByName(content_name);
945 EXPECT_TRUE(desc->AddTransportInfo(transport_info));
946 for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
947 const IceCandidateCollection* cc = jdesc_.candidates(i);
948 for (size_t j = 0; j < cc->count(); ++j) {
949 if (cc->at(j)->sdp_mline_index() == mline_index) {
950 const_cast<Candidate&>(cc->at(j)->candidate()).set_username(
951 ufrag);
952 const_cast<Candidate&>(cc->at(j)->candidate()).set_password(
953 pwd);
954 }
955 }
956 }
957 return true;
958 }
959
960 void AddIceOptions(const std::string& content_name,
961 const std::vector<std::string>& transport_options) {
962 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
963 cricket::TransportInfo transport_info =
964 *(desc_.GetTransportInfoByName(content_name));
965 desc_.RemoveTransportInfoByName(content_name);
966 transport_info.description.transport_options = transport_options;
967 desc_.AddTransportInfo(transport_info);
968 }
969
970 void AddFingerprint() {
971 desc_.RemoveTransportInfoByName(kAudioContentName);
972 desc_.RemoveTransportInfoByName(kVideoContentName);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000973 rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000974 kIdentityDigest,
975 sizeof(kIdentityDigest));
976 EXPECT_TRUE(desc_.AddTransportInfo(
977 TransportInfo(kAudioContentName,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700978 TransportDescription(std::vector<std::string>(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979 kCandidateUfragVoice,
980 kCandidatePwdVoice,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000981 cricket::ICEMODE_FULL,
982 cricket::CONNECTIONROLE_NONE,
983 &fingerprint, Candidates()))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984 EXPECT_TRUE(desc_.AddTransportInfo(
985 TransportInfo(kVideoContentName,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700986 TransportDescription(std::vector<std::string>(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 kCandidateUfragVideo,
988 kCandidatePwdVideo,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000989 cricket::ICEMODE_FULL,
990 cricket::CONNECTIONROLE_NONE,
991 &fingerprint, Candidates()))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000992 }
993
994 void AddExtmap() {
995 audio_desc_ = static_cast<AudioContentDescription*>(
996 audio_desc_->Copy());
997 video_desc_ = static_cast<VideoContentDescription*>(
998 video_desc_->Copy());
999 audio_desc_->AddRtpHeaderExtension(
1000 RtpHeaderExtension(kExtmapUri, kExtmapId));
1001 video_desc_->AddRtpHeaderExtension(
1002 RtpHeaderExtension(kExtmapUri, kExtmapId));
1003 desc_.RemoveContentByName(kAudioContentName);
1004 desc_.RemoveContentByName(kVideoContentName);
1005 desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_desc_);
1006 desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_desc_);
1007 }
1008
1009 void RemoveCryptos() {
1010 audio_desc_->set_cryptos(std::vector<CryptoParams>());
1011 video_desc_->set_cryptos(std::vector<CryptoParams>());
1012 }
1013
1014 bool TestSerializeDirection(cricket::MediaContentDirection direction) {
1015 audio_desc_->set_direction(direction);
1016 video_desc_->set_direction(direction);
1017 std::string new_sdp = kSdpFullString;
1018 ReplaceDirection(direction, &new_sdp);
1019
1020 if (!jdesc_.Initialize(desc_.Copy(),
1021 jdesc_.session_id(),
1022 jdesc_.session_version())) {
1023 return false;
1024 }
1025 std::string message = webrtc::SdpSerialize(jdesc_);
1026 EXPECT_EQ(new_sdp, message);
1027 return true;
1028 }
1029
1030 bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
1031 audio_desc_ = static_cast<AudioContentDescription*>(
1032 audio_desc_->Copy());
1033 video_desc_ = static_cast<VideoContentDescription*>(
1034 video_desc_->Copy());
1035 desc_.RemoveContentByName(kAudioContentName);
1036 desc_.RemoveContentByName(kVideoContentName);
1037 desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_rejected,
1038 audio_desc_);
1039 desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
1040 video_desc_);
1041 std::string new_sdp = kSdpFullString;
1042 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
1043
1044 if (!jdesc_.Initialize(desc_.Copy(),
1045 jdesc_.session_id(),
1046 jdesc_.session_version())) {
1047 return false;
1048 }
1049 std::string message = webrtc::SdpSerialize(jdesc_);
1050 EXPECT_EQ(new_sdp, message);
1051 return true;
1052 }
1053
1054 void AddSctpDataChannel() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001055 rtc::scoped_ptr<DataContentDescription> data(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001056 new DataContentDescription());
1057 data_desc_ = data.get();
1058 data_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp);
wu@webrtc.org78187522013-10-07 23:32:02 +00001059 DataCodec codec(cricket::kGoogleSctpDataCodecId,
1060 cricket::kGoogleSctpDataCodecName, 0);
1061 codec.SetParam(cricket::kCodecParamPort, kDefaultSctpPort);
1062 data_desc_->AddCodec(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001063 desc_.AddContent(kDataContentName, NS_JINGLE_DRAFT_SCTP, data.release());
1064 EXPECT_TRUE(desc_.AddTransportInfo(
1065 TransportInfo(kDataContentName,
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001066 TransportDescription(kCandidateUfragData,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001067 kCandidatePwdData))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 }
1069
1070 void AddRtpDataChannel() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001071 rtc::scoped_ptr<DataContentDescription> data(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 new DataContentDescription());
1073 data_desc_ = data.get();
1074
1075 data_desc_->AddCodec(DataCodec(101, "google-data", 1));
1076 StreamParams data_stream;
1077 data_stream.id = kDataChannelMsid;
1078 data_stream.cname = kDataChannelCname;
1079 data_stream.sync_label = kDataChannelLabel;
1080 data_stream.ssrcs.push_back(kDataChannelSsrc);
1081 data_desc_->AddStream(data_stream);
1082 data_desc_->AddCrypto(CryptoParams(
1083 1, "AES_CM_128_HMAC_SHA1_80",
1084 "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5", ""));
1085 data_desc_->set_protocol(cricket::kMediaProtocolSavpf);
1086 desc_.AddContent(kDataContentName, NS_JINGLE_RTP, data.release());
1087 EXPECT_TRUE(desc_.AddTransportInfo(
1088 TransportInfo(kDataContentName,
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001089 TransportDescription(kCandidateUfragData,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001090 kCandidatePwdData))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001091 }
1092
1093 bool TestDeserializeDirection(cricket::MediaContentDirection direction) {
1094 std::string new_sdp = kSdpFullString;
1095 ReplaceDirection(direction, &new_sdp);
1096 JsepSessionDescription new_jdesc(kDummyString);
1097
1098 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
1099
1100 audio_desc_->set_direction(direction);
1101 video_desc_->set_direction(direction);
1102 if (!jdesc_.Initialize(desc_.Copy(),
1103 jdesc_.session_id(),
1104 jdesc_.session_version())) {
1105 return false;
1106 }
1107 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
1108 return true;
1109 }
1110
1111 bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
1112 std::string new_sdp = kSdpFullString;
1113 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
1114 JsepSessionDescription new_jdesc(JsepSessionDescription::kOffer);
1115
1116 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
1117 audio_desc_ = static_cast<AudioContentDescription*>(
1118 audio_desc_->Copy());
1119 video_desc_ = static_cast<VideoContentDescription*>(
1120 video_desc_->Copy());
1121 desc_.RemoveContentByName(kAudioContentName);
1122 desc_.RemoveContentByName(kVideoContentName);
1123 desc_.AddContent(kAudioContentName, NS_JINGLE_RTP, audio_rejected,
1124 audio_desc_);
1125 desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
1126 video_desc_);
1127 if (!jdesc_.Initialize(desc_.Copy(),
1128 jdesc_.session_id(),
1129 jdesc_.session_version())) {
1130 return false;
1131 }
1132 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
1133 return true;
1134 }
1135
1136 void TestDeserializeExtmap(bool session_level, bool media_level) {
1137 AddExtmap();
1138 JsepSessionDescription new_jdesc("dummy");
1139 ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
1140 jdesc_.session_id(),
1141 jdesc_.session_version()));
1142 JsepSessionDescription jdesc_with_extmap("dummy");
1143 std::string sdp_with_extmap = kSdpString;
1144 if (session_level) {
1145 InjectAfter(kSessionTime, kExtmapWithDirectionAndAttribute,
1146 &sdp_with_extmap);
1147 }
1148 if (media_level) {
1149 InjectAfter(kAttributeIcePwdVoice, kExtmapWithDirectionAndAttribute,
1150 &sdp_with_extmap);
1151 InjectAfter(kAttributeIcePwdVideo, kExtmapWithDirectionAndAttribute,
1152 &sdp_with_extmap);
1153 }
1154 // The extmap can't be present at the same time in both session level and
1155 // media level.
1156 if (session_level && media_level) {
1157 SdpParseError error;
1158 EXPECT_FALSE(webrtc::SdpDeserialize(sdp_with_extmap,
1159 &jdesc_with_extmap, &error));
1160 EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
1161 } else {
1162 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
1163 EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
1164 }
1165 }
1166
1167 void VerifyCodecParameter(const cricket::CodecParameterMap& params,
1168 const std::string& name, int expected_value) {
1169 cricket::CodecParameterMap::const_iterator found = params.find(name);
1170 ASSERT_TRUE(found != params.end());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001171 EXPECT_EQ(found->second, rtc::ToString<int>(expected_value));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001172 }
1173
1174 void TestDeserializeCodecParams(const CodecParams& params,
1175 JsepSessionDescription* jdesc_output) {
1176 std::string sdp =
1177 "v=0\r\n"
1178 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1179 "s=-\r\n"
1180 "t=0 0\r\n"
1181 // Include semantics for WebRTC Media Streams since it is supported by
1182 // this parser, and will be added to the SDP when serializing a session
1183 // description.
1184 "a=msid-semantic: WMS\r\n"
1185 // Pl type 111 preferred.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001186 "m=audio 9 RTP/SAVPF 111 104 103\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 // Pltype 111 listed before 103 and 104 in the map.
1188 "a=rtpmap:111 opus/48000/2\r\n"
1189 // Pltype 103 listed before 104.
1190 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001191 "a=rtpmap:104 ISAC/32000\r\n"
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001192 "a=fmtp:111 0-15,66,70\r\n"
1193 "a=fmtp:111 ";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 std::ostringstream os;
Donald Curtis144d0182015-05-15 13:14:24 -07001195 os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001196 << "; sprop-stereo=" << params.sprop_stereo
1197 << "; useinbandfec=" << params.useinband
Donald Curtis0e07f922015-05-15 09:21:23 -07001198 << "; maxaveragebitrate=" << params.maxaveragebitrate << "\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001199 << "a=ptime:" << params.ptime << "\r\n"
1200 << "a=maxptime:" << params.max_ptime << "\r\n";
1201 sdp += os.str();
1202
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001203 os.clear();
1204 os.str("");
1205 // Pl type 100 preferred.
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00001206 os << "m=video 9 RTP/SAVPF 99 95\r\n"
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001207 << "a=rtpmap:99 VP8/90000\r\n"
1208 << "a=rtpmap:95 RTX/90000\r\n"
Donald Curtis0e07f922015-05-15 09:21:23 -07001209 << "a=fmtp:95 apt=99;\r\n";
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001210 sdp += os.str();
1211
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 // Deserialize
1213 SdpParseError error;
1214 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
1215
1216 const ContentInfo* ac = GetFirstAudioContent(jdesc_output->description());
1217 ASSERT_TRUE(ac != NULL);
1218 const AudioContentDescription* acd =
1219 static_cast<const AudioContentDescription*>(ac->description);
1220 ASSERT_FALSE(acd->codecs().empty());
1221 cricket::AudioCodec opus = acd->codecs()[0];
1222 EXPECT_EQ("opus", opus.name);
1223 EXPECT_EQ(111, opus.id);
1224 VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
1225 VerifyCodecParameter(opus.params, "stereo", params.stereo);
1226 VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
1227 VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001228 VerifyCodecParameter(opus.params, "maxaveragebitrate",
1229 params.maxaveragebitrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230 for (size_t i = 0; i < acd->codecs().size(); ++i) {
1231 cricket::AudioCodec codec = acd->codecs()[i];
1232 VerifyCodecParameter(codec.params, "ptime", params.ptime);
1233 VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
1234 if (codec.name == "ISAC") {
1235 if (codec.clockrate == 16000) {
1236 EXPECT_EQ(32000, codec.bitrate);
1237 } else {
1238 EXPECT_EQ(56000, codec.bitrate);
1239 }
1240 }
1241 }
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001242
1243 const ContentInfo* vc = GetFirstVideoContent(jdesc_output->description());
1244 ASSERT_TRUE(vc != NULL);
1245 const VideoContentDescription* vcd =
1246 static_cast<const VideoContentDescription*>(vc->description);
1247 ASSERT_FALSE(vcd->codecs().empty());
1248 cricket::VideoCodec vp8 = vcd->codecs()[0];
1249 EXPECT_EQ("VP8", vp8.name);
1250 EXPECT_EQ(99, vp8.id);
1251 cricket::VideoCodec rtx = vcd->codecs()[1];
1252 EXPECT_EQ("RTX", rtx.name);
1253 EXPECT_EQ(95, rtx.id);
1254 VerifyCodecParameter(rtx.params, "apt", vp8.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255 }
1256
1257 void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
1258 bool use_wildcard) {
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001259 std::string sdp_session_and_audio =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 "v=0\r\n"
1261 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1262 "s=-\r\n"
1263 "t=0 0\r\n"
1264 // Include semantics for WebRTC Media Streams since it is supported by
1265 // this parser, and will be added to the SDP when serializing a session
1266 // description.
1267 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00001268 "m=audio 9 RTP/SAVPF 111\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001269 "a=rtpmap:111 opus/48000/2\r\n";
1270 std::string sdp_video =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 "m=video 3457 RTP/SAVPF 101\r\n"
1272 "a=rtpmap:101 VP8/90000\r\n"
1273 "a=rtcp-fb:101 nack\r\n"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001274 "a=rtcp-fb:101 nack pli\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001275 "a=rtcp-fb:101 goog-remb\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 std::ostringstream os;
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001277 os << sdp_session_and_audio;
1278 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") << " nack\r\n";
1279 os << sdp_video;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") << " ccm fir\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001281 std::string sdp = os.str();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282 // Deserialize
1283 SdpParseError error;
1284 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
1285 const ContentInfo* ac = GetFirstAudioContent(jdesc_output->description());
1286 ASSERT_TRUE(ac != NULL);
1287 const AudioContentDescription* acd =
1288 static_cast<const AudioContentDescription*>(ac->description);
1289 ASSERT_FALSE(acd->codecs().empty());
1290 cricket::AudioCodec opus = acd->codecs()[0];
1291 EXPECT_EQ(111, opus.id);
1292 EXPECT_TRUE(opus.HasFeedbackParam(
1293 cricket::FeedbackParam(cricket::kRtcpFbParamNack,
1294 cricket::kParamValueEmpty)));
1295
1296 const ContentInfo* vc = GetFirstVideoContent(jdesc_output->description());
1297 ASSERT_TRUE(vc != NULL);
1298 const VideoContentDescription* vcd =
1299 static_cast<const VideoContentDescription*>(vc->description);
1300 ASSERT_FALSE(vcd->codecs().empty());
1301 cricket::VideoCodec vp8 = vcd->codecs()[0];
1302 EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
1303 vp8.name.c_str());
1304 EXPECT_EQ(101, vp8.id);
1305 EXPECT_TRUE(vp8.HasFeedbackParam(
1306 cricket::FeedbackParam(cricket::kRtcpFbParamNack,
1307 cricket::kParamValueEmpty)));
1308 EXPECT_TRUE(vp8.HasFeedbackParam(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001309 cricket::FeedbackParam(cricket::kRtcpFbParamNack,
1310 cricket::kRtcpFbNackParamPli)));
1311 EXPECT_TRUE(vp8.HasFeedbackParam(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
1313 cricket::kParamValueEmpty)));
1314 EXPECT_TRUE(vp8.HasFeedbackParam(
1315 cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
1316 cricket::kRtcpFbCcmParamFir)));
1317 }
1318
1319 // Two SDP messages can mean the same thing but be different strings, e.g.
1320 // some of the lines can be serialized in different order.
1321 // However, a deserialized description can be compared field by field and has
1322 // no order. If deserializer has already been tested, serializing then
1323 // deserializing and comparing JsepSessionDescription will test
1324 // the serializer sufficiently.
1325 void TestSerialize(const JsepSessionDescription& jdesc) {
1326 std::string message = webrtc::SdpSerialize(jdesc);
1327 JsepSessionDescription jdesc_output_des(kDummyString);
1328 SdpParseError error;
1329 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
1330 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
1331 }
1332
1333 protected:
1334 SessionDescription desc_;
1335 AudioContentDescription* audio_desc_;
1336 VideoContentDescription* video_desc_;
1337 DataContentDescription* data_desc_;
1338 Candidates candidates_;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001339 rtc::scoped_ptr<IceCandidateInterface> jcandidate_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001340 JsepSessionDescription jdesc_;
1341};
1342
1343void TestMismatch(const std::string& string1, const std::string& string2) {
1344 int position = 0;
1345 for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
1346 if (string1.c_str()[i] != string2.c_str()[i]) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001347 position = static_cast<int>(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001348 break;
1349 }
1350 }
1351 EXPECT_EQ(0, position) << "Strings mismatch at the " << position
1352 << " character\n"
1353 << " 1: " << string1.substr(position, 20) << "\n"
1354 << " 2: " << string2.substr(position, 20) << "\n";
1355}
1356
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001357TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
1358 // SessionDescription with desc and candidates.
1359 std::string message = webrtc::SdpSerialize(jdesc_);
1360 TestMismatch(std::string(kSdpFullString), message);
1361}
1362
1363TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
1364 JsepSessionDescription jdesc_empty(kDummyString);
1365 EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
1366}
1367
guoweis@webrtc.org57ac2c82015-02-06 00:45:13 +00001368// This tests serialization of SDP with only IPv6 candidates and verifies that
1369// IPv6 is used as default address in c line according to preference.
1370TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIPv6Only) {
1371 // Only test 1 m line.
1372 desc_.RemoveContentByName("video_content_name");
1373 // Stun has a high preference than local host.
1374 cricket::Candidate candidate1(
1375 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1376 rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
1377 cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1378 cricket::Candidate candidate2(
1379 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1380 rtc::SocketAddress("::2", 1235), kCandidatePriority, "", "",
1381 cricket::LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1382 JsepSessionDescription jdesc(kDummyString);
1383 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1384
1385 // Only add the candidates to audio m line.
1386 JsepIceCandidate jice1("audio_content_name", 0, candidate1);
1387 JsepIceCandidate jice2("audio_content_name", 0, candidate2);
1388 ASSERT_TRUE(jdesc.AddCandidate(&jice1));
1389 ASSERT_TRUE(jdesc.AddCandidate(&jice2));
1390 std::string message = webrtc::SdpSerialize(jdesc);
1391
1392 // Audio line should have a c line like this one.
1393 EXPECT_NE(message.find("c=IN IP6 ::1"), std::string::npos);
1394 // Shouldn't have a IP4 c line.
1395 EXPECT_EQ(message.find("c=IN IP4"), std::string::npos);
1396}
1397
1398// This tests serialization of SDP with both IPv4 and IPv6 candidates and
1399// verifies that IPv4 is used as default address in c line even if the
1400// preference of IPv4 is lower.
1401TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBothIPFamilies) {
1402 // Only test 1 m line.
1403 desc_.RemoveContentByName("video_content_name");
1404 cricket::Candidate candidate_v4(
1405 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1406 rtc::SocketAddress("192.168.1.5", 1234), kCandidatePriority, "", "",
1407 cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1408 cricket::Candidate candidate_v6(
1409 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1410 rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
1411 cricket::LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1412 JsepSessionDescription jdesc(kDummyString);
1413 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1414
1415 // Only add the candidates to audio m line.
1416 JsepIceCandidate jice_v4("audio_content_name", 0, candidate_v4);
1417 JsepIceCandidate jice_v6("audio_content_name", 0, candidate_v6);
1418 ASSERT_TRUE(jdesc.AddCandidate(&jice_v4));
1419 ASSERT_TRUE(jdesc.AddCandidate(&jice_v6));
1420 std::string message = webrtc::SdpSerialize(jdesc);
1421
1422 // Audio line should have a c line like this one.
1423 EXPECT_NE(message.find("c=IN IP4 192.168.1.5"), std::string::npos);
1424 // Shouldn't have a IP6 c line.
1425 EXPECT_EQ(message.find("c=IN IP6"), std::string::npos);
1426}
1427
1428// This tests serialization of SDP with both UDP and TCP candidates and
1429// verifies that UDP is used as default address in c line even if the
1430// preference of UDP is lower.
1431TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBothProtocols) {
1432 // Only test 1 m line.
1433 desc_.RemoveContentByName("video_content_name");
1434 // Stun has a high preference than local host.
1435 cricket::Candidate candidate1(
1436 cricket::ICE_CANDIDATE_COMPONENT_RTP, "tcp",
1437 rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
1438 cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1439 cricket::Candidate candidate2(
1440 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1441 rtc::SocketAddress("fe80::1234:5678:abcd:ef12", 1235), kCandidatePriority,
1442 "", "", cricket::LOCAL_PORT_TYPE, kCandidateGeneration,
1443 kCandidateFoundation1);
1444 JsepSessionDescription jdesc(kDummyString);
1445 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1446
1447 // Only add the candidates to audio m line.
1448 JsepIceCandidate jice1("audio_content_name", 0, candidate1);
1449 JsepIceCandidate jice2("audio_content_name", 0, candidate2);
1450 ASSERT_TRUE(jdesc.AddCandidate(&jice1));
1451 ASSERT_TRUE(jdesc.AddCandidate(&jice2));
1452 std::string message = webrtc::SdpSerialize(jdesc);
1453
1454 // Audio line should have a c line like this one.
1455 EXPECT_NE(message.find("c=IN IP6 fe80::1234:5678:abcd:ef12"),
1456 std::string::npos);
1457 // Shouldn't have a IP4 c line.
1458 EXPECT_EQ(message.find("c=IN IP4"), std::string::npos);
1459}
1460
1461// This tests serialization of SDP with only TCP candidates and verifies that
1462// null IPv4 is used as default address in c line.
1463TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithTCPOnly) {
1464 // Only test 1 m line.
1465 desc_.RemoveContentByName("video_content_name");
1466 // Stun has a high preference than local host.
1467 cricket::Candidate candidate1(
1468 cricket::ICE_CANDIDATE_COMPONENT_RTP, "tcp",
1469 rtc::SocketAddress("::1", 1234), kCandidatePriority, "", "",
1470 cricket::STUN_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1471 cricket::Candidate candidate2(
1472 cricket::ICE_CANDIDATE_COMPONENT_RTP, "tcp",
1473 rtc::SocketAddress("::2", 1235), kCandidatePriority, "", "",
1474 cricket::LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
1475 JsepSessionDescription jdesc(kDummyString);
1476 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1477
1478 // Only add the candidates to audio m line.
1479 JsepIceCandidate jice1("audio_content_name", 0, candidate1);
1480 JsepIceCandidate jice2("audio_content_name", 0, candidate2);
1481 ASSERT_TRUE(jdesc.AddCandidate(&jice1));
1482 ASSERT_TRUE(jdesc.AddCandidate(&jice2));
1483 std::string message = webrtc::SdpSerialize(jdesc);
1484
1485 // Audio line should have a c line like this one when no any default exists.
1486 EXPECT_NE(message.find("c=IN IP4 0.0.0.0"), std::string::npos);
1487}
1488
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001489// This tests serialization of SDP with a=crypto and a=fingerprint, as would be
1490// the case in a DTLS offer.
1491TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
1492 AddFingerprint();
1493 JsepSessionDescription jdesc_with_fingerprint(kDummyString);
1494 ASSERT_TRUE(jdesc_with_fingerprint.Initialize(desc_.Copy(),
1495 kSessionId, kSessionVersion));
1496 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
1497
1498 std::string sdp_with_fingerprint = kSdpString;
1499 InjectAfter(kAttributeIcePwdVoice,
1500 kFingerprint, &sdp_with_fingerprint);
1501 InjectAfter(kAttributeIcePwdVideo,
1502 kFingerprint, &sdp_with_fingerprint);
1503
1504 EXPECT_EQ(sdp_with_fingerprint, message);
1505}
1506
1507// This tests serialization of SDP with a=fingerprint with no a=crypto, as would
1508// be the case in a DTLS answer.
1509TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
1510 AddFingerprint();
1511 RemoveCryptos();
1512 JsepSessionDescription jdesc_with_fingerprint(kDummyString);
1513 ASSERT_TRUE(jdesc_with_fingerprint.Initialize(desc_.Copy(),
1514 kSessionId, kSessionVersion));
1515 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
1516
1517 std::string sdp_with_fingerprint = kSdpString;
1518 Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
1519 Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
1520 InjectAfter(kAttributeIcePwdVoice,
1521 kFingerprint, &sdp_with_fingerprint);
1522 InjectAfter(kAttributeIcePwdVideo,
1523 kFingerprint, &sdp_with_fingerprint);
1524
1525 EXPECT_EQ(sdp_with_fingerprint, message);
1526}
1527
1528TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
1529 // JsepSessionDescription with desc but without candidates.
1530 JsepSessionDescription jdesc_no_candidates(kDummyString);
1531 ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
1532 kSessionId, kSessionVersion));
1533 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
1534 EXPECT_EQ(std::string(kSdpString), message);
1535}
1536
1537TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundle) {
1538 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1539 group.AddContentName(kAudioContentName);
1540 group.AddContentName(kVideoContentName);
1541 desc_.AddGroup(group);
1542 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1543 jdesc_.session_id(),
1544 jdesc_.session_version()));
1545 std::string message = webrtc::SdpSerialize(jdesc_);
1546 std::string sdp_with_bundle = kSdpFullString;
1547 InjectAfter(kSessionTime,
1548 "a=group:BUNDLE audio_content_name video_content_name\r\n",
1549 &sdp_with_bundle);
1550 EXPECT_EQ(sdp_with_bundle, message);
1551}
1552
1553TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
1554 VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
1555 GetFirstVideoContent(&desc_)->description);
1556 vcd->set_bandwidth(100 * 1000);
1557 AudioContentDescription* acd = static_cast<AudioContentDescription*>(
1558 GetFirstAudioContent(&desc_)->description);
1559 acd->set_bandwidth(50 * 1000);
1560 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1561 jdesc_.session_id(),
1562 jdesc_.session_version()));
1563 std::string message = webrtc::SdpSerialize(jdesc_);
1564 std::string sdp_with_bandwidth = kSdpFullString;
wu@webrtc.org4c3e9912014-07-16 21:03:13 +00001565 InjectAfter("c=IN IP4 74.125.224.39\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001566 "b=AS:100\r\n",
1567 &sdp_with_bandwidth);
wu@webrtc.org4c3e9912014-07-16 21:03:13 +00001568 InjectAfter("c=IN IP4 74.125.127.126\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001569 "b=AS:50\r\n",
1570 &sdp_with_bandwidth);
1571 EXPECT_EQ(sdp_with_bandwidth, message);
1572}
1573
1574TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
1575 std::vector<std::string> transport_options;
1576 transport_options.push_back(kIceOption1);
1577 transport_options.push_back(kIceOption3);
1578 AddIceOptions(kAudioContentName, transport_options);
1579 transport_options.clear();
1580 transport_options.push_back(kIceOption2);
1581 transport_options.push_back(kIceOption3);
1582 AddIceOptions(kVideoContentName, transport_options);
1583 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1584 jdesc_.session_id(),
1585 jdesc_.session_version()));
1586 std::string message = webrtc::SdpSerialize(jdesc_);
1587 std::string sdp_with_ice_options = kSdpFullString;
1588 InjectAfter(kAttributeIcePwdVoice,
1589 "a=ice-options:iceoption1 iceoption3\r\n",
1590 &sdp_with_ice_options);
1591 InjectAfter(kAttributeIcePwdVideo,
1592 "a=ice-options:iceoption2 iceoption3\r\n",
1593 &sdp_with_ice_options);
1594 EXPECT_EQ(sdp_with_ice_options, message);
1595}
1596
1597TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
1598 EXPECT_TRUE(TestSerializeDirection(cricket::MD_RECVONLY));
1599}
1600
1601TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
1602 EXPECT_TRUE(TestSerializeDirection(cricket::MD_SENDONLY));
1603}
1604
1605TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
1606 EXPECT_TRUE(TestSerializeDirection(cricket::MD_INACTIVE));
1607}
1608
1609TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
1610 EXPECT_TRUE(TestSerializeRejected(true, false));
1611}
1612
1613TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
1614 EXPECT_TRUE(TestSerializeRejected(false, true));
1615}
1616
1617TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
1618 EXPECT_TRUE(TestSerializeRejected(true, true));
1619}
1620
1621TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRtpDataChannel) {
1622 AddRtpDataChannel();
1623 JsepSessionDescription jsep_desc(kDummyString);
1624
1625 ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1626 std::string message = webrtc::SdpSerialize(jsep_desc);
1627
1628 std::string expected_sdp = kSdpString;
1629 expected_sdp.append(kSdpRtpDataChannelString);
1630 EXPECT_EQ(expected_sdp, message);
1631}
1632
1633TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
1634 AddSctpDataChannel();
1635 JsepSessionDescription jsep_desc(kDummyString);
1636
1637 ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1638 std::string message = webrtc::SdpSerialize(jsep_desc);
1639
1640 std::string expected_sdp = kSdpString;
1641 expected_sdp.append(kSdpSctpDataChannelString);
1642 EXPECT_EQ(message, expected_sdp);
1643}
1644
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00001645TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
1646 AddSctpDataChannel();
1647 JsepSessionDescription jsep_desc(kDummyString);
1648
1649 ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1650 DataContentDescription* dcdesc = static_cast<DataContentDescription*>(
1651 jsep_desc.description()->GetContentDescriptionByName(kDataContentName));
1652
1653 const int kNewPort = 1234;
1654 cricket::DataCodec codec(
1655 cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName, 0);
1656 codec.SetParam(cricket::kCodecParamPort, kNewPort);
1657 dcdesc->AddOrReplaceCodec(codec);
1658
1659 std::string message = webrtc::SdpSerialize(jsep_desc);
1660
1661 std::string expected_sdp = kSdpString;
1662 expected_sdp.append(kSdpSctpDataChannelString);
1663
1664 char default_portstr[16];
1665 char new_portstr[16];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001666 rtc::sprintfn(default_portstr, sizeof(default_portstr), "%d",
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00001667 kDefaultSctpPort);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001668 rtc::sprintfn(new_portstr, sizeof(new_portstr), "%d", kNewPort);
1669 rtc::replace_substrs(default_portstr, strlen(default_portstr),
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00001670 new_portstr, strlen(new_portstr),
1671 &expected_sdp);
1672
1673 EXPECT_EQ(expected_sdp, message);
1674}
1675
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001676TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
1677 AddRtpDataChannel();
1678 data_desc_->set_bandwidth(100*1000);
1679 JsepSessionDescription jsep_desc(kDummyString);
1680
1681 ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1682 std::string message = webrtc::SdpSerialize(jsep_desc);
1683
1684 std::string expected_sdp = kSdpString;
1685 expected_sdp.append(kSdpRtpDataChannelString);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07001686 // Serializing data content shouldn't ignore bandwidth settings.
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +00001687 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 +00001688 "b=AS:100\r\n",
1689 &expected_sdp);
1690 EXPECT_EQ(expected_sdp, message);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001691}
1692
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001693TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
1694 AddExtmap();
1695 JsepSessionDescription desc_with_extmap("dummy");
1696 ASSERT_TRUE(desc_with_extmap.Initialize(desc_.Copy(),
1697 kSessionId, kSessionVersion));
1698 std::string message = webrtc::SdpSerialize(desc_with_extmap);
1699
1700 std::string sdp_with_extmap = kSdpString;
1701 InjectAfter("a=mid:audio_content_name\r\n",
1702 kExtmap, &sdp_with_extmap);
1703 InjectAfter("a=mid:video_content_name\r\n",
1704 kExtmap, &sdp_with_extmap);
1705
1706 EXPECT_EQ(sdp_with_extmap, message);
1707}
1708
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001709TEST_F(WebRtcSdpTest, SerializeCandidates) {
1710 std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
wu@webrtc.orgec9f5fb2014-06-24 17:05:10 +00001711 EXPECT_EQ(std::string(kRawCandidate), message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712}
1713
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00001714// TODO(mallinath) : Enable this test once WebRTCSdp capable of parsing
1715// RFC 6544.
mallinath@webrtc.orge999bd02014-08-13 06:05:55 +00001716TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001717 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001718 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
1719 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
1720 kCandidateFoundation1);
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00001721 candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
1722 rtc::scoped_ptr<IceCandidateInterface> jcandidate(
1723 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
1724
1725 std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
1726 EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
1727}
1728
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001729TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
1730 JsepSessionDescription jdesc(kDummyString);
1731 // Deserialize
1732 EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
1733 // Verify
1734 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
1735}
1736
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001737TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
1738 JsepSessionDescription jdesc(kDummyString);
1739 const char kSdpWithoutMline[] =
1740 "v=0\r\n"
1741 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1742 "s=-\r\n"
1743 "t=0 0\r\n"
1744 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
1745 // Deserialize
1746 EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
1747 EXPECT_EQ(0u, jdesc.description()->contents().size());
1748}
1749
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001750TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
1751 JsepSessionDescription jdesc(kDummyString);
1752 std::string sdp_without_carriage_return = kSdpFullString;
1753 Replace("\r\n", "\n", &sdp_without_carriage_return);
1754 // Deserialize
1755 EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
1756 // Verify
1757 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
1758}
1759
1760TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
1761 // SessionDescription with desc but without candidates.
1762 JsepSessionDescription jdesc_no_candidates(kDummyString);
1763 ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
1764 kSessionId, kSessionVersion));
1765 JsepSessionDescription new_jdesc(kDummyString);
1766 EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
1767 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
1768}
1769
1770TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
1771 static const char kSdpNoRtpmapString[] =
1772 "v=0\r\n"
1773 "o=- 11 22 IN IP4 127.0.0.1\r\n"
1774 "s=-\r\n"
1775 "t=0 0\r\n"
1776 "m=audio 49232 RTP/AVP 0 18 103\r\n"
1777 // Codec that doesn't appear in the m= line will be ignored.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001778 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001779 // The rtpmap line for static payload codec is optional.
1780 "a=rtpmap:18 G729/16000\r\n"
1781 "a=rtpmap:103 ISAC/16000\r\n";
1782
1783 JsepSessionDescription jdesc(kDummyString);
1784 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
1785 cricket::AudioContentDescription* audio =
1786 static_cast<AudioContentDescription*>(
1787 jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
1788 AudioCodecs ref_codecs;
1789 // The codecs in the AudioContentDescription will be sorted by preference.
1790 ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1, 3));
1791 ref_codecs.push_back(AudioCodec(18, "G729", 16000, 0, 1, 2));
1792 ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 32000, 1, 1));
1793 EXPECT_EQ(ref_codecs, audio->codecs());
1794}
1795
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001796TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
1797 static const char kSdpNoRtpmapString[] =
1798 "v=0\r\n"
1799 "o=- 11 22 IN IP4 127.0.0.1\r\n"
1800 "s=-\r\n"
1801 "t=0 0\r\n"
1802 "m=audio 49232 RTP/AVP 18 103\r\n"
1803 "a=fmtp:18 annexb=yes\r\n"
1804 "a=rtpmap:103 ISAC/16000\r\n";
1805
1806 JsepSessionDescription jdesc(kDummyString);
1807 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
1808 cricket::AudioContentDescription* audio =
1809 static_cast<AudioContentDescription*>(
1810 jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
1811
1812 cricket::AudioCodec g729 = audio->codecs()[0];
1813 EXPECT_EQ("G729", g729.name);
1814 EXPECT_EQ(8000, g729.clockrate);
1815 EXPECT_EQ(18, g729.id);
1816 cricket::CodecParameterMap::iterator found =
1817 g729.params.find("annexb");
1818 ASSERT_TRUE(found != g729.params.end());
1819 EXPECT_EQ(found->second, "yes");
1820
1821 cricket::AudioCodec isac = audio->codecs()[1];
1822 EXPECT_EQ("ISAC", isac.name);
1823 EXPECT_EQ(103, isac.id);
1824 EXPECT_EQ(16000, isac.clockrate);
1825}
1826
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001827// Ensure that we can deserialize SDP with a=fingerprint properly.
1828TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
1829 // Add a DTLS a=fingerprint attribute to our session description.
1830 AddFingerprint();
1831 JsepSessionDescription new_jdesc(kDummyString);
1832 ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
1833 jdesc_.session_id(),
1834 jdesc_.session_version()));
1835
1836 JsepSessionDescription jdesc_with_fingerprint(kDummyString);
1837 std::string sdp_with_fingerprint = kSdpString;
1838 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
1839 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
1840 EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
1841 EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
1842}
1843
1844TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
1845 JsepSessionDescription jdesc_with_bundle(kDummyString);
1846 std::string sdp_with_bundle = kSdpFullString;
1847 InjectAfter(kSessionTime,
1848 "a=group:BUNDLE audio_content_name video_content_name\r\n",
1849 &sdp_with_bundle);
1850 EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
1851 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1852 group.AddContentName(kAudioContentName);
1853 group.AddContentName(kVideoContentName);
1854 desc_.AddGroup(group);
1855 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1856 jdesc_.session_id(),
1857 jdesc_.session_version()));
1858 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
1859}
1860
1861TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
1862 JsepSessionDescription jdesc_with_bandwidth(kDummyString);
1863 std::string sdp_with_bandwidth = kSdpFullString;
1864 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
1865 "b=AS:100\r\n",
1866 &sdp_with_bandwidth);
1867 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
1868 "b=AS:50\r\n",
1869 &sdp_with_bandwidth);
1870 EXPECT_TRUE(
1871 SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
1872 VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
1873 GetFirstVideoContent(&desc_)->description);
1874 vcd->set_bandwidth(100 * 1000);
1875 AudioContentDescription* acd = static_cast<AudioContentDescription*>(
1876 GetFirstAudioContent(&desc_)->description);
1877 acd->set_bandwidth(50 * 1000);
1878 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1879 jdesc_.session_id(),
1880 jdesc_.session_version()));
1881 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
1882}
1883
1884TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
1885 JsepSessionDescription jdesc_with_ice_options(kDummyString);
1886 std::string sdp_with_ice_options = kSdpFullString;
1887 InjectAfter(kSessionTime,
1888 "a=ice-options:iceoption3\r\n",
1889 &sdp_with_ice_options);
1890 InjectAfter(kAttributeIcePwdVoice,
1891 "a=ice-options:iceoption1\r\n",
1892 &sdp_with_ice_options);
1893 InjectAfter(kAttributeIcePwdVideo,
1894 "a=ice-options:iceoption2\r\n",
1895 &sdp_with_ice_options);
1896 EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
1897 std::vector<std::string> transport_options;
1898 transport_options.push_back(kIceOption3);
1899 transport_options.push_back(kIceOption1);
1900 AddIceOptions(kAudioContentName, transport_options);
1901 transport_options.clear();
1902 transport_options.push_back(kIceOption3);
1903 transport_options.push_back(kIceOption2);
1904 AddIceOptions(kVideoContentName, transport_options);
1905 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1906 jdesc_.session_id(),
1907 jdesc_.session_version()));
1908 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
1909}
1910
1911TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
1912 // Remove the original ice-ufrag and ice-pwd
1913 JsepSessionDescription jdesc_with_ufrag_pwd(kDummyString);
1914 std::string sdp_with_ufrag_pwd = kSdpFullString;
1915 EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
1916 // Add session level ufrag and pwd
1917 InjectAfter(kSessionTime,
1918 "a=ice-pwd:session+level+icepwd\r\n"
1919 "a=ice-ufrag:session+level+iceufrag\r\n",
1920 &sdp_with_ufrag_pwd);
1921 // Add media level ufrag and pwd for audio
1922 InjectAfter("a=mid:audio_content_name\r\n",
1923 "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
1924 &sdp_with_ufrag_pwd);
1925 // Update the candidate ufrag and pwd to the expected ones.
1926 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0,
1927 "media+level+iceufrag", "media+level+icepwd"));
1928 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1,
1929 "session+level+iceufrag", "session+level+icepwd"));
1930 EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
1931 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
1932}
1933
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001934TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
1935 EXPECT_TRUE(TestDeserializeDirection(cricket::MD_RECVONLY));
1936}
1937
1938TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
1939 EXPECT_TRUE(TestDeserializeDirection(cricket::MD_SENDONLY));
1940}
1941
1942TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
1943 EXPECT_TRUE(TestDeserializeDirection(cricket::MD_INACTIVE));
1944}
1945
1946TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
1947 EXPECT_TRUE(TestDeserializeRejected(true, false));
1948}
1949
1950TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
1951 EXPECT_TRUE(TestDeserializeRejected(false, true));
1952}
1953
1954TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
1955 EXPECT_TRUE(TestDeserializeRejected(true, true));
1956}
1957
1958// Tests that we can still handle the sdp uses mslabel and label instead of
1959// msid for backward compatibility.
1960TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMsid) {
1961 JsepSessionDescription jdesc(kDummyString);
1962 std::string sdp_without_msid = kSdpFullString;
1963 Replace("msid", "xmsid", &sdp_without_msid);
1964 // Deserialize
1965 EXPECT_TRUE(SdpDeserialize(sdp_without_msid, &jdesc));
1966 // Verify
1967 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
1968}
1969
1970TEST_F(WebRtcSdpTest, DeserializeCandidate) {
1971 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
1972
1973 std::string sdp = kSdpOneCandidate;
1974 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
1975 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
1976 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
1977 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
1978
1979 // Candidate line without generation extension.
1980 sdp = kSdpOneCandidate;
1981 Replace(" generation 2", "", &sdp);
1982 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
1983 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
1984 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
1985 Candidate expected = jcandidate_->candidate();
1986 expected.set_generation(0);
1987 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
1988
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00001989 sdp = kSdpTcpActiveCandidate;
1990 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
1991 // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001992 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001993 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
1994 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
1995 kCandidateFoundation1);
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00001996 rtc::scoped_ptr<IceCandidateInterface> jcandidate_template(
1997 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
1998 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(
1999 jcandidate_template->candidate()));
2000 sdp = kSdpTcpPassiveCandidate;
2001 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2002 sdp = kSdpTcpSOCandidate;
2003 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004}
2005
2006// This test verifies the deserialization of candidate-attribute
2007// as per RFC 5245. Candiate-attribute will be of the format
2008// candidate:<blah>. This format will be used when candidates
2009// are trickled.
2010TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
2011 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2012
2013 std::string candidate_attribute = kRawCandidate;
2014 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2015 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2016 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2017 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2018 EXPECT_EQ(2u, jcandidate.candidate().generation());
2019
2020 // Candidate line without generation extension.
2021 candidate_attribute = kRawCandidate;
2022 Replace(" generation 2", "", &candidate_attribute);
2023 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2024 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2025 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2026 Candidate expected = jcandidate_->candidate();
2027 expected.set_generation(0);
2028 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2029
2030 // Candidate line without candidate:
2031 candidate_attribute = kRawCandidate;
2032 Replace("candidate:", "", &candidate_attribute);
2033 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2034
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002035 // Candidate line with IPV6 address.
2036 EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
2037}
2038
2039// This test verifies that the deserialization of an invalid candidate string
2040// fails.
2041TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
2042 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2043
2044 std::string candidate_attribute = kRawCandidate;
2045 candidate_attribute.replace(0, 1, "x");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002046 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002047
2048 candidate_attribute = kSdpOneCandidate;
2049 candidate_attribute.replace(0, 1, "x");
2050 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2051
2052 candidate_attribute = kRawCandidate;
2053 candidate_attribute.append("\r\n");
2054 candidate_attribute.append(kRawCandidate);
2055 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2056
2057 EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058}
2059
2060TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannels) {
2061 AddRtpDataChannel();
2062 JsepSessionDescription jdesc(kDummyString);
2063 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2064
2065 std::string sdp_with_data = kSdpString;
2066 sdp_with_data.append(kSdpRtpDataChannelString);
2067 JsepSessionDescription jdesc_output(kDummyString);
2068
2069 // Deserialize
2070 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2071 // Verify
2072 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2073}
2074
2075TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
2076 AddSctpDataChannel();
2077 JsepSessionDescription jdesc(kDummyString);
2078 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2079
2080 std::string sdp_with_data = kSdpString;
2081 sdp_with_data.append(kSdpSctpDataChannelString);
2082 JsepSessionDescription jdesc_output(kDummyString);
2083
lally@webrtc.org36300852015-02-24 20:19:35 +00002084 // Verify with DTLS/SCTP (already in kSdpSctpDataChannelString).
2085 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2086 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2087
2088 // Verify with UDP/DTLS/SCTP.
2089 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
2090 strlen(kDtlsSctp), kUdpDtlsSctp);
2091 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2092 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2093
2094 // Verify with TCP/DTLS/SCTP.
2095 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
2096 strlen(kUdpDtlsSctp), kTcpDtlsSctp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002097 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2098 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2099}
2100
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002101TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
2102 AddSctpDataChannel();
2103 JsepSessionDescription jdesc(kDummyString);
2104 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2105
2106 std::string sdp_with_data = kSdpString;
2107 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
2108 JsepSessionDescription jdesc_output(kDummyString);
2109
lally@webrtc.org36300852015-02-24 20:19:35 +00002110 // Verify with DTLS/SCTP (already in kSdpSctpDataChannelStringWithSctpPort).
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002111 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2112 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002113
lally@webrtc.org36300852015-02-24 20:19:35 +00002114 // Verify with UDP/DTLS/SCTP.
2115 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
2116 strlen(kDtlsSctp), kUdpDtlsSctp);
2117 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2118 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
lally@webrtc.orgc7848b72015-02-24 20:19:26 +00002119
lally@webrtc.org36300852015-02-24 20:19:35 +00002120 // Verify with TCP/DTLS/SCTP.
2121 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
2122 strlen(kUdpDtlsSctp), kTcpDtlsSctp);
lally@webrtc.orgc7848b72015-02-24 20:19:26 +00002123 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2124 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2125}
2126
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002127// Test to check the behaviour if sctp-port is specified
2128// on the m= line and in a=sctp-port.
2129TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
2130 AddSctpDataChannel();
2131 JsepSessionDescription jdesc(kDummyString);
2132 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2133
2134 std::string sdp_with_data = kSdpString;
2135 // Append m= attributes
2136 sdp_with_data.append(kSdpSctpDataChannelString);
2137 // Append a=sctp-port attribute
2138 sdp_with_data.append("a=sctp-port 5000\r\n");
2139 JsepSessionDescription jdesc_output(kDummyString);
2140
2141 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2142}
2143
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00002144// For crbug/344475.
2145TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
2146 std::string sdp_with_data = kSdpString;
2147 sdp_with_data.append(kSdpSctpDataChannelString);
2148 // Remove the "\n" at the end.
2149 sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
2150 JsepSessionDescription jdesc_output(kDummyString);
2151
2152 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2153 // No crash is a pass.
2154}
2155
wu@webrtc.org78187522013-10-07 23:32:02 +00002156TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
2157 AddSctpDataChannel();
Peter Boström0c4e06b2015-10-07 12:23:21 +02002158 const uint16_t kUnusualSctpPort = 9556;
wu@webrtc.org78187522013-10-07 23:32:02 +00002159 char default_portstr[16];
2160 char unusual_portstr[16];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002161 rtc::sprintfn(default_portstr, sizeof(default_portstr), "%d",
wu@webrtc.org78187522013-10-07 23:32:02 +00002162 kDefaultSctpPort);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002163 rtc::sprintfn(unusual_portstr, sizeof(unusual_portstr), "%d",
wu@webrtc.org78187522013-10-07 23:32:02 +00002164 kUnusualSctpPort);
2165
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002166 // First setup the expected JsepSessionDescription.
wu@webrtc.org78187522013-10-07 23:32:02 +00002167 JsepSessionDescription jdesc(kDummyString);
2168 // take our pre-built session description and change the SCTP port.
2169 cricket::SessionDescription* mutant = desc_.Copy();
2170 DataContentDescription* dcdesc = static_cast<DataContentDescription*>(
2171 mutant->GetContentDescriptionByName(kDataContentName));
2172 std::vector<cricket::DataCodec> codecs(dcdesc->codecs());
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00002173 EXPECT_EQ(1U, codecs.size());
2174 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, codecs[0].id);
wu@webrtc.org78187522013-10-07 23:32:02 +00002175 codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002176 dcdesc->set_codecs(codecs);
wu@webrtc.org78187522013-10-07 23:32:02 +00002177
2178 // note: mutant's owned by jdesc now.
2179 ASSERT_TRUE(jdesc.Initialize(mutant, kSessionId, kSessionVersion));
2180 mutant = NULL;
2181
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002182 // Then get the deserialized JsepSessionDescription.
wu@webrtc.org78187522013-10-07 23:32:02 +00002183 std::string sdp_with_data = kSdpString;
2184 sdp_with_data.append(kSdpSctpDataChannelString);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002185 rtc::replace_substrs(default_portstr, strlen(default_portstr),
wu@webrtc.org78187522013-10-07 23:32:02 +00002186 unusual_portstr, strlen(unusual_portstr),
2187 &sdp_with_data);
2188 JsepSessionDescription jdesc_output(kDummyString);
2189
2190 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2191 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002192
2193 // We need to test the deserialized JsepSessionDescription from
2194 // kSdpSctpDataChannelStringWithSctpPort for
2195 // draft-ietf-mmusic-sctp-sdp-07
2196 // a=sctp-port
2197 sdp_with_data = kSdpString;
2198 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
2199 rtc::replace_substrs(default_portstr, strlen(default_portstr),
2200 unusual_portstr, strlen(unusual_portstr),
2201 &sdp_with_data);
2202
2203 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2204 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
wu@webrtc.org78187522013-10-07 23:32:02 +00002205}
2206
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002207TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002208 // We want to test that deserializing data content limits bandwidth
2209 // settings (it should never be greater than the default).
2210 // This should prevent someone from using unlimited data bandwidth through
2211 // JS and "breaking the Internet".
2212 // See: https://code.google.com/p/chromium/issues/detail?id=280726
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002213 std::string sdp_with_bandwidth = kSdpString;
2214 sdp_with_bandwidth.append(kSdpRtpDataChannelString);
2215 InjectAfter("a=mid:data_content_name\r\n",
2216 "b=AS:100\r\n",
2217 &sdp_with_bandwidth);
2218 JsepSessionDescription jdesc_with_bandwidth(kDummyString);
2219
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002220 EXPECT_FALSE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2221}
2222
2223TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
2224 AddSctpDataChannel();
2225 JsepSessionDescription jdesc(kDummyString);
2226 DataContentDescription* dcd = static_cast<DataContentDescription*>(
2227 GetFirstDataContent(&desc_)->description);
2228 dcd->set_bandwidth(100 * 1000);
2229 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2230
2231 std::string sdp_with_bandwidth = kSdpString;
2232 sdp_with_bandwidth.append(kSdpSctpDataChannelString);
2233 InjectAfter("a=mid:data_content_name\r\n",
2234 "b=AS:100\r\n",
2235 &sdp_with_bandwidth);
2236 JsepSessionDescription jdesc_with_bandwidth(kDummyString);
2237
2238 // SCTP has congestion control, so we shouldn't limit the bandwidth
2239 // as we do for RTP.
2240 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002241 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
2242}
2243
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSessionLevelExtmap) {
2245 TestDeserializeExtmap(true, false);
2246}
2247
2248TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
2249 TestDeserializeExtmap(false, true);
2250}
2251
2252TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInvalidExtmap) {
2253 TestDeserializeExtmap(true, true);
2254}
2255
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00002256TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
2257 JsepSessionDescription jdesc(kDummyString);
2258 std::string sdp = kSdpFullString;
2259 sdp = sdp.substr(0, sdp.size() - 2); // Remove \r\n at the end.
2260 // Deserialize
2261 SdpParseError error;
2262 EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
2263 const std::string lastline = "a=ssrc:6 label:video_track_id_3";
2264 EXPECT_EQ(lastline, error.line);
2265 EXPECT_EQ("Invalid SDP line.", error.description);
2266}
2267
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
2269 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2270 std::string new_sdp = kSdpOneCandidate;
2271 Replace("udp", "unsupported_transport", &new_sdp);
2272 EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
2273 new_sdp = kSdpOneCandidate;
2274 Replace("udp", "uDP", &new_sdp);
2275 EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
2276 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2277 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2278 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2279}
2280
2281TEST_F(WebRtcSdpTest, DeserializeCandidateOldFormat) {
2282 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2283 EXPECT_TRUE(SdpDeserializeCandidate(kSdpOneCandidateOldFormat,&jcandidate));
2284 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2285 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2286 Candidate ref_candidate = jcandidate_->candidate();
2287 ref_candidate.set_username("user_rtp");
2288 ref_candidate.set_password("password_rtp");
2289 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
2290}
2291
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002292TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
2293 JsepSessionDescription jdesc(kDummyString);
2294
2295 // Deserialize
2296 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
2297
2298 // Verify
2299 cricket::AudioContentDescription* audio =
2300 static_cast<AudioContentDescription*>(
2301 jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
2302 EXPECT_TRUE(audio->conference_mode());
2303
2304 cricket::VideoContentDescription* video =
2305 static_cast<VideoContentDescription*>(
2306 jdesc.description()->GetContentDescriptionByName(cricket::CN_VIDEO));
2307 EXPECT_TRUE(video->conference_mode());
2308}
2309
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
2311 const char kSdpDestroyer[] = "!@#$%^&";
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002312 const char kSdpEmptyType[] = " =candidate";
2313 const char kSdpEqualAsPlus[] = "a+candidate";
2314 const char kSdpSpaceAfterEqual[] = "a= candidate";
2315 const char kSdpUpperType[] = "A=candidate";
2316 const char kSdpEmptyLine[] = "";
2317 const char kSdpMissingValue[] = "a=";
2318
2319 const char kSdpBrokenFingerprint[] = "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002320 "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 +00002321 const char kSdpExtraField[] = "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002322 "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 +00002323 const char kSdpMissingSpace[] = "a=fingerprint:sha-1"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002324 "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 +00002325 // MD5 is not allowed in fingerprints.
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002326 const char kSdpMd5[] = "a=fingerprint:md5 "
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00002327 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328
2329 // Broken session description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002330 ExpectParseFailure("v=", kSdpDestroyer);
2331 ExpectParseFailure("o=", kSdpDestroyer);
2332 ExpectParseFailure("s=-", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002333 // Broken time description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002334 ExpectParseFailure("t=", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335
2336 // Broken media description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002337 ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
2338 ExpectParseFailure("m=video", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339
2340 // Invalid lines
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002341 ExpectParseFailure("a=candidate", kSdpEmptyType);
2342 ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
2343 ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
2344 ExpectParseFailure("a=candidate", kSdpUpperType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002345
2346 // Bogus fingerprint replacing a=sendrev. We selected this attribute
2347 // because it's orthogonal to what we are replacing and hence
2348 // safe.
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002349 ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
2350 ExpectParseFailure("a=sendrecv", kSdpExtraField);
2351 ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
2352 ExpectParseFailure("a=sendrecv", kSdpMd5);
2353
2354 // Empty Line
2355 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
2356 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002357}
2358
2359TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
2360 // ssrc
2361 ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
2362 ExpectParseFailure("a=ssrc-group:FEC 5 6", "a=ssrc-group:FEC badvalue 6");
2363 // crypto
2364 ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
2365 // rtpmap
2366 ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
2367 ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
2368 ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
2369 // candidate
2370 ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
2371 ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
2372 ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
2373 ExpectParseFailure("rport 2346", "rport badvalue");
2374 ExpectParseFailure("rport 2346 generation 2",
2375 "rport 2346 generation badvalue");
2376 // m line
2377 ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
2378 "m=audio 2345 RTP/SAVPF 111 badvalue 104");
2379
2380 // bandwidth
2381 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
2382 "b=AS:badvalue\r\n",
2383 "b=AS:badvalue");
2384 // rtcp-fb
2385 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
2386 "a=rtcp-fb:badvalue nack\r\n",
2387 "a=rtcp-fb:badvalue nack");
2388 // extmap
2389 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
2390 "a=extmap:badvalue http://example.com\r\n",
2391 "a=extmap:badvalue http://example.com");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002392}
2393
2394TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
2395 JsepSessionDescription jdesc_output(kDummyString);
2396
2397 const char kSdpWithReorderedPlTypesString[] =
2398 "v=0\r\n"
2399 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2400 "s=-\r\n"
2401 "t=0 0\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00002402 "m=audio 9 RTP/SAVPF 104 103\r\n" // Pl type 104 preferred.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002403 "a=rtpmap:111 opus/48000/2\r\n" // Pltype 111 listed before 103 and 104
2404 // in the map.
2405 "a=rtpmap:103 ISAC/16000\r\n" // Pltype 103 listed before 104 in the map.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002406 "a=rtpmap:104 ISAC/32000\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002407
2408 // Deserialize
2409 EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
2410
2411 const ContentInfo* ac = GetFirstAudioContent(jdesc_output.description());
2412 ASSERT_TRUE(ac != NULL);
2413 const AudioContentDescription* acd =
2414 static_cast<const AudioContentDescription*>(ac->description);
2415 ASSERT_FALSE(acd->codecs().empty());
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002416 EXPECT_EQ("ISAC", acd->codecs()[0].name);
2417 EXPECT_EQ(32000, acd->codecs()[0].clockrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002418 EXPECT_EQ(104, acd->codecs()[0].id);
2419}
2420
2421TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
2422 JsepSessionDescription jdesc_output(kDummyString);
2423 CodecParams params;
2424 params.max_ptime = 40;
2425 params.ptime = 30;
2426 params.min_ptime = 10;
2427 params.sprop_stereo = 1;
2428 params.stereo = 1;
2429 params.useinband = 1;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002430 params.maxaveragebitrate = 128000;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002431 TestDeserializeCodecParams(params, &jdesc_output);
2432 TestSerialize(jdesc_output);
2433}
2434
2435TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
2436 const bool kUseWildcard = false;
2437 JsepSessionDescription jdesc_output(kDummyString);
2438 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
2439 TestSerialize(jdesc_output);
2440}
2441
2442TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
2443 const bool kUseWildcard = true;
2444 JsepSessionDescription jdesc_output(kDummyString);
2445 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
2446 TestSerialize(jdesc_output);
2447}
2448
2449TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
2450 JsepSessionDescription jdesc_output(kDummyString);
2451
2452 const char kSdpWithFmtpString[] =
2453 "v=0\r\n"
2454 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2455 "s=-\r\n"
2456 "t=0 0\r\n"
2457 "m=video 3457 RTP/SAVPF 120\r\n"
2458 "a=rtpmap:120 VP8/90000\r\n"
Donald Curtis0e07f922015-05-15 09:21:23 -07002459 "a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
2460
2461 // Deserialize
2462 SdpParseError error;
Donald Curtis144d0182015-05-15 13:14:24 -07002463 EXPECT_TRUE(
2464 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
Donald Curtis0e07f922015-05-15 09:21:23 -07002465
2466 const ContentInfo* vc = GetFirstVideoContent(jdesc_output.description());
2467 ASSERT_TRUE(vc != NULL);
2468 const VideoContentDescription* vcd =
2469 static_cast<const VideoContentDescription*>(vc->description);
2470 ASSERT_FALSE(vcd->codecs().empty());
2471 cricket::VideoCodec vp8 = vcd->codecs()[0];
2472 EXPECT_EQ("VP8", vp8.name);
2473 EXPECT_EQ(120, vp8.id);
2474 cricket::CodecParameterMap::iterator found =
2475 vp8.params.find("x-google-min-bitrate");
2476 ASSERT_TRUE(found != vp8.params.end());
2477 EXPECT_EQ(found->second, "10");
2478 found = vp8.params.find("x-google-max-quantization");
2479 ASSERT_TRUE(found != vp8.params.end());
2480 EXPECT_EQ(found->second, "40");
2481}
2482
2483TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
2484 JsepSessionDescription jdesc_output(kDummyString);
2485
2486 const char kSdpWithFmtpString[] =
2487 "v=0\r\n"
2488 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2489 "s=-\r\n"
2490 "t=0 0\r\n"
2491 "m=video 3457 RTP/SAVPF 120\r\n"
2492 "a=rtpmap:120 VP8/90000\r\n"
2493 "a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002494
2495 // Deserialize
2496 SdpParseError error;
2497 EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output,
2498 &error));
2499
2500 const ContentInfo* vc = GetFirstVideoContent(jdesc_output.description());
2501 ASSERT_TRUE(vc != NULL);
2502 const VideoContentDescription* vcd =
2503 static_cast<const VideoContentDescription*>(vc->description);
2504 ASSERT_FALSE(vcd->codecs().empty());
2505 cricket::VideoCodec vp8 = vcd->codecs()[0];
2506 EXPECT_EQ("VP8", vp8.name);
2507 EXPECT_EQ(120, vp8.id);
2508 cricket::CodecParameterMap::iterator found =
2509 vp8.params.find("x-google-min-bitrate");
2510 ASSERT_TRUE(found != vp8.params.end());
2511 EXPECT_EQ(found->second, "10");
2512 found = vp8.params.find("x-google-max-quantization");
2513 ASSERT_TRUE(found != vp8.params.end());
2514 EXPECT_EQ(found->second, "40");
2515}
2516
2517TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
2518 VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
2519 GetFirstVideoContent(&desc_)->description);
2520
2521 cricket::VideoCodecs codecs = vcd->codecs();
2522 codecs[0].params["x-google-min-bitrate"] = "10";
2523 vcd->set_codecs(codecs);
2524
2525 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
2526 jdesc_.session_id(),
2527 jdesc_.session_version()));
2528 std::string message = webrtc::SdpSerialize(jdesc_);
2529 std::string sdp_with_fmtp = kSdpFullString;
2530 InjectAfter("a=rtpmap:120 VP8/90000\r\n",
2531 "a=fmtp:120 x-google-min-bitrate=10\r\n",
2532 &sdp_with_fmtp);
2533 EXPECT_EQ(sdp_with_fmtp, message);
2534}
2535
2536TEST_F(WebRtcSdpTest, DeserializeSdpWithIceLite) {
2537 JsepSessionDescription jdesc_with_icelite(kDummyString);
2538 std::string sdp_with_icelite = kSdpFullString;
2539 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
2540 cricket::SessionDescription* desc = jdesc_with_icelite.description();
2541 const cricket::TransportInfo* tinfo1 =
2542 desc->GetTransportInfoByName("audio_content_name");
2543 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
2544 const cricket::TransportInfo* tinfo2 =
2545 desc->GetTransportInfoByName("video_content_name");
2546 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
2547 InjectAfter(kSessionTime,
2548 "a=ice-lite\r\n",
2549 &sdp_with_icelite);
2550 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
2551 desc = jdesc_with_icelite.description();
2552 const cricket::TransportInfo* atinfo =
2553 desc->GetTransportInfoByName("audio_content_name");
2554 EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
2555 const cricket::TransportInfo* vtinfo =
2556 desc->GetTransportInfoByName("video_content_name");
2557 EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
2558}
2559
2560// Verifies that the candidates in the input SDP are parsed and serialized
2561// correctly in the output SDP.
2562TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
2563 std::string sdp_with_data = kSdpString;
2564 sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
2565 JsepSessionDescription jdesc_output(kDummyString);
2566
2567 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2568 EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
2569}
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00002570
2571TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
2572 AddFingerprint();
2573 TransportInfo audio_transport_info =
2574 *(desc_.GetTransportInfoByName(kAudioContentName));
2575 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
2576 audio_transport_info.description.connection_role);
2577 audio_transport_info.description.connection_role =
2578 cricket::CONNECTIONROLE_ACTIVE;
2579
2580 TransportInfo video_transport_info =
2581 *(desc_.GetTransportInfoByName(kVideoContentName));
2582 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
2583 video_transport_info.description.connection_role);
2584 video_transport_info.description.connection_role =
2585 cricket::CONNECTIONROLE_ACTIVE;
2586
2587 desc_.RemoveTransportInfoByName(kAudioContentName);
2588 desc_.RemoveTransportInfoByName(kVideoContentName);
2589
2590 desc_.AddTransportInfo(audio_transport_info);
2591 desc_.AddTransportInfo(video_transport_info);
2592
2593 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
2594 jdesc_.session_id(),
2595 jdesc_.session_version()));
2596 std::string message = webrtc::SdpSerialize(jdesc_);
2597 std::string sdp_with_dtlssetup = kSdpFullString;
2598
2599 // Fingerprint attribute is necessary to add DTLS setup attribute.
2600 InjectAfter(kAttributeIcePwdVoice,
2601 kFingerprint, &sdp_with_dtlssetup);
2602 InjectAfter(kAttributeIcePwdVideo,
2603 kFingerprint, &sdp_with_dtlssetup);
2604 // Now adding |setup| attribute.
2605 InjectAfter(kFingerprint,
2606 "a=setup:active\r\n", &sdp_with_dtlssetup);
2607 EXPECT_EQ(sdp_with_dtlssetup, message);
2608}
2609
2610TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttribute) {
2611 JsepSessionDescription jdesc_with_dtlssetup(kDummyString);
2612 std::string sdp_with_dtlssetup = kSdpFullString;
2613 InjectAfter(kSessionTime,
2614 "a=setup:actpass\r\n",
2615 &sdp_with_dtlssetup);
2616 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
2617 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
2618 const cricket::TransportInfo* atinfo =
2619 desc->GetTransportInfoByName("audio_content_name");
2620 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
2621 atinfo->description.connection_role);
2622 const cricket::TransportInfo* vtinfo =
2623 desc->GetTransportInfoByName("video_content_name");
2624 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
2625 vtinfo->description.connection_role);
2626}
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002627
2628// Verifies that the order of the serialized m-lines follows the order of the
2629// ContentInfo in SessionDescription, and vise versa for deserialization.
2630TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
2631 JsepSessionDescription jdesc(kDummyString);
2632 const std::string media_content_sdps[3] = {
2633 kSdpAudioString,
2634 kSdpVideoString,
2635 kSdpSctpDataChannelString
2636 };
2637 const cricket::MediaType media_types[3] = {
2638 cricket::MEDIA_TYPE_AUDIO,
2639 cricket::MEDIA_TYPE_VIDEO,
2640 cricket::MEDIA_TYPE_DATA
2641 };
2642
2643 // Verifies all 6 permutations.
2644 for (size_t i = 0; i < 6; ++i) {
2645 size_t media_content_in_sdp[3];
2646 // The index of the first media content.
2647 media_content_in_sdp[0] = i / 2;
2648 // The index of the second media content.
2649 media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
2650 // The index of the third media content.
2651 media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
2652
2653 std::string sdp_string = kSdpSessionString;
2654 for (size_t i = 0; i < 3; ++i)
2655 sdp_string += media_content_sdps[media_content_in_sdp[i]];
2656
2657 EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
2658 cricket::SessionDescription* desc = jdesc.description();
2659 EXPECT_EQ(3u, desc->contents().size());
2660
2661 for (size_t i = 0; i < 3; ++i) {
2662 const cricket::MediaContentDescription* mdesc =
2663 static_cast<const cricket::MediaContentDescription*>(
2664 desc->contents()[i].description);
2665 EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
2666 }
2667
2668 std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
2669 EXPECT_EQ(sdp_string, serialized_sdp);
2670 }
2671}