blob: 9d6cfa300563a45e84e2e85b27adb60c68f23fa7 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2011 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwibergd1fe2812016-04-27 06:47:29 -070011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <set>
13#include <string>
14#include <vector>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "api/jsepsessiondescription.h"
17#include "media/base/mediaconstants.h"
18#include "media/engine/webrtcvideoengine.h"
Patrik Höglundaba85d12017-11-28 15:46:08 +010019#include "p2p/base/port.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "p2p/base/p2pconstants.h"
21#include "pc/mediasession.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/gunit.h"
24#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/stringencode.h"
26#include "rtc_base/stringutils.h"
Patrik Höglund563934e2017-09-15 09:04:28 +020027
ossu7bb87ee2017-01-23 04:56:25 -080028#ifdef WEBRTC_ANDROID
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "pc/test/androidtestinitializer.h"
ossu7bb87ee2017-01-23 04:56:25 -080030#endif
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "pc/webrtcsdp.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
33using cricket::AudioCodec;
34using cricket::AudioContentDescription;
35using cricket::Candidate;
36using cricket::ContentInfo;
37using cricket::CryptoParams;
38using cricket::ContentGroup;
39using cricket::DataCodec;
40using cricket::DataContentDescription;
41using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
42using cricket::ICE_CANDIDATE_COMPONENT_RTP;
43using cricket::kFecSsrcGroupSemantics;
44using cricket::LOCAL_PORT_TYPE;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045using cricket::RELAY_PORT_TYPE;
46using cricket::SessionDescription;
Steve Anton5adfafd2017-12-20 16:34:00 -080047using cricket::MediaProtocolType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048using cricket::StreamParams;
49using cricket::STUN_PORT_TYPE;
50using cricket::TransportDescription;
51using cricket::TransportInfo;
52using cricket::VideoCodec;
53using cricket::VideoContentDescription;
54using webrtc::IceCandidateCollection;
55using webrtc::IceCandidateInterface;
56using webrtc::JsepIceCandidate;
57using webrtc::JsepSessionDescription;
isheriff6f8d6862016-05-26 11:24:55 -070058using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080059using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using webrtc::SdpParseError;
Steve Antona3a92c22017-12-07 10:27:41 -080061using webrtc::SdpType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using webrtc::SessionDescriptionInterface;
63
64typedef std::vector<AudioCodec> AudioCodecs;
65typedef std::vector<Candidate> Candidates;
66
Peter Boström0c4e06b2015-10-07 12:23:21 +020067static const uint32_t kDefaultSctpPort = 5000;
zstein4b2e0822017-02-17 19:48:38 -080068static const char kDefaultSctpPortStr[] = "5000";
69static const uint16_t kUnusualSctpPort = 9556;
70static const char kUnusualSctpPortStr[] = "9556";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071static const char kSessionTime[] = "t=0 0\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020072static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0
deadbeef3f7219b2015-12-28 15:17:14 -080073static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
deadbeef3f7219b2015-12-28 15:17:14 -080075static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020077static const uint32_t kCandidateGeneration = 2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078static const char kCandidateFoundation1[] = "a0+B/1";
79static const char kCandidateFoundation2[] = "a0+B/2";
80static const char kCandidateFoundation3[] = "a0+B/3";
81static const char kCandidateFoundation4[] = "a0+B/4";
82static const char kAttributeCryptoVoice[] =
83 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
84 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
85 "dummy_session_params\r\n";
86static const char kAttributeCryptoVideo[] =
87 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
88 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
89static const char kFingerprint[] = "a=fingerprint:sha-1 "
90 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n";
91static const int kExtmapId = 1;
92static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
93static const char kExtmap[] =
94 "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
95static const char kExtmapWithDirectionAndAttribute[] =
96 "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
jbauch5869f502017-06-29 12:31:36 -070097static const char kExtmapWithDirectionAndAttributeEncrypted[] =
98 "a=extmap:1/sendrecv urn:ietf:params:rtp-hdrext:encrypt "
99 "http://example.com/082005/ext.htm#ttime a1 a2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100
Peter Boström0c4e06b2015-10-07 12:23:21 +0200101static const uint8_t kIdentityDigest[] = {
102 0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
103 0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104
lally@webrtc.org34807282015-02-24 20:19:39 +0000105static const char kDtlsSctp[] = "DTLS/SCTP";
106static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
107static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
lally@webrtc.org36300852015-02-24 20:19:35 +0000108
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109struct CodecParams {
110 int max_ptime;
111 int ptime;
112 int min_ptime;
113 int sprop_stereo;
114 int stereo;
115 int useinband;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000116 int maxaveragebitrate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117};
118
deadbeef9d3584c2016-02-16 17:54:10 -0800119// TODO(deadbeef): In these reference strings, use "a=fingerprint" by default
120// instead of "a=crypto", and have an explicit test for adding "a=crypto".
121// Currently it's the other way around.
122
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123// Reference sdp string
124static const char kSdpFullString[] =
125 "v=0\r\n"
126 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
127 "s=-\r\n"
128 "t=0 0\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800129 "a=msid-semantic: WMS local_stream_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
131 "c=IN IP4 74.125.127.126\r\n"
132 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
133 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
134 "generation 2\r\n"
135 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
136 "generation 2\r\n"
137 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
138 "generation 2\r\n"
139 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
140 "generation 2\r\n"
141 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
142 "raddr 192.168.1.5 rport 2346 "
143 "generation 2\r\n"
144 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
145 "raddr 192.168.1.5 rport 2348 "
146 "generation 2\r\n"
147 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
148 "a=mid:audio_content_name\r\n"
149 "a=sendrecv\r\n"
150 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 12:37:51 -0800151 "a=rtcp-rsize\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000152 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
153 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
154 "dummy_session_params\r\n"
155 "a=rtpmap:111 opus/48000/2\r\n"
156 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000157 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158 "a=ssrc:1 cname:stream_1_cname\r\n"
159 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
160 "a=ssrc:1 mslabel:local_stream_1\r\n"
161 "a=ssrc:1 label:audio_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162 "m=video 3457 RTP/SAVPF 120\r\n"
163 "c=IN IP4 74.125.224.39\r\n"
164 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
165 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
166 "generation 2\r\n"
167 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
168 "generation 2\r\n"
169 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
170 "generation 2\r\n"
171 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
172 "generation 2\r\n"
173 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
174 "generation 2\r\n"
175 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
176 "generation 2\r\n"
177 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
178 "a=mid:video_content_name\r\n"
179 "a=sendrecv\r\n"
180 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
181 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
182 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800183 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184 "a=ssrc:2 cname:stream_1_cname\r\n"
185 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
186 "a=ssrc:2 mslabel:local_stream_1\r\n"
187 "a=ssrc:2 label:video_track_id_1\r\n"
188 "a=ssrc:3 cname:stream_1_cname\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800189 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190 "a=ssrc:3 mslabel:local_stream_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800191 "a=ssrc:3 label:video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192
193// SDP reference string without the candidates.
194static const char kSdpString[] =
195 "v=0\r\n"
196 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
197 "s=-\r\n"
198 "t=0 0\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800199 "a=msid-semantic: WMS local_stream_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000200 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000201 "c=IN IP4 0.0.0.0\r\n"
202 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
204 "a=mid:audio_content_name\r\n"
205 "a=sendrecv\r\n"
206 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 12:37:51 -0800207 "a=rtcp-rsize\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
209 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
210 "dummy_session_params\r\n"
211 "a=rtpmap:111 opus/48000/2\r\n"
212 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000213 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214 "a=ssrc:1 cname:stream_1_cname\r\n"
215 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
216 "a=ssrc:1 mslabel:local_stream_1\r\n"
217 "a=ssrc:1 label:audio_track_id_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000218 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000219 "c=IN IP4 0.0.0.0\r\n"
220 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
222 "a=mid:video_content_name\r\n"
223 "a=sendrecv\r\n"
224 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
225 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
226 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800227 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228 "a=ssrc:2 cname:stream_1_cname\r\n"
229 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
230 "a=ssrc:2 mslabel:local_stream_1\r\n"
231 "a=ssrc:2 label:video_track_id_1\r\n"
232 "a=ssrc:3 cname:stream_1_cname\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800233 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234 "a=ssrc:3 mslabel:local_stream_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800235 "a=ssrc:3 label:video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236
237static const char kSdpRtpDataChannelString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000238 "m=application 9 RTP/SAVPF 101\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000239 "c=IN IP4 0.0.0.0\r\n"
240 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241 "a=ice-ufrag:ufrag_data\r\n"
242 "a=ice-pwd:pwd_data\r\n"
243 "a=mid:data_content_name\r\n"
244 "a=sendrecv\r\n"
245 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
246 "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5\r\n"
247 "a=rtpmap:101 google-data/90000\r\n"
248 "a=ssrc:10 cname:data_channel_cname\r\n"
249 "a=ssrc:10 msid:data_channel data_channeld0\r\n"
250 "a=ssrc:10 mslabel:data_channel\r\n"
251 "a=ssrc:10 label:data_channeld0\r\n";
252
253static const char kSdpSctpDataChannelString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000254 "m=application 9 DTLS/SCTP 5000\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000255 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256 "a=ice-ufrag:ufrag_data\r\n"
257 "a=ice-pwd:pwd_data\r\n"
258 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000259 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260
lally@webrtc.orgec97c652015-02-24 20:18:48 +0000261// draft-ietf-mmusic-sctp-sdp-12
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +0000262static const char kSdpSctpDataChannelStringWithSctpPort[] =
lally@webrtc.orgc7848b72015-02-24 20:19:26 +0000263 "m=application 9 DTLS/SCTP webrtc-datachannel\r\n"
264 "a=max-message-size=100000\r\n"
265 "a=sctp-port 5000\r\n"
266 "c=IN IP4 0.0.0.0\r\n"
267 "a=ice-ufrag:ufrag_data\r\n"
268 "a=ice-pwd:pwd_data\r\n"
269 "a=mid:data_content_name\r\n";
270
lally69f57602015-10-08 10:15:04 -0700271static const char kSdpSctpDataChannelStringWithSctpColonPort[] =
272 "m=application 9 DTLS/SCTP webrtc-datachannel\r\n"
273 "a=max-message-size=100000\r\n"
274 "a=sctp-port:5000\r\n"
275 "c=IN IP4 0.0.0.0\r\n"
276 "a=ice-ufrag:ufrag_data\r\n"
277 "a=ice-pwd:pwd_data\r\n"
278 "a=mid:data_content_name\r\n";
279
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280static const char kSdpSctpDataChannelWithCandidatesString[] =
281 "m=application 2345 DTLS/SCTP 5000\r\n"
282 "c=IN IP4 74.125.127.126\r\n"
283 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
284 "generation 2\r\n"
285 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
286 "generation 2\r\n"
287 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
288 "raddr 192.168.1.5 rport 2346 "
289 "generation 2\r\n"
290 "a=ice-ufrag:ufrag_data\r\n"
291 "a=ice-pwd:pwd_data\r\n"
292 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000293 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000295static const char kSdpConferenceString[] =
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000296 "v=0\r\n"
297 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
298 "s=-\r\n"
299 "t=0 0\r\n"
300 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000301 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000302 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000303 "a=x-google-flag:conference\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000304 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000305 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000306 "a=x-google-flag:conference\r\n";
307
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000308static const char kSdpSessionString[] =
309 "v=0\r\n"
310 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
311 "s=-\r\n"
312 "t=0 0\r\n"
313 "a=msid-semantic: WMS local_stream\r\n";
314
315static const char kSdpAudioString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000316 "m=audio 9 RTP/SAVPF 111\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000317 "c=IN IP4 0.0.0.0\r\n"
318 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000319 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
320 "a=mid:audio_content_name\r\n"
321 "a=sendrecv\r\n"
322 "a=rtpmap:111 opus/48000/2\r\n"
323 "a=ssrc:1 cname:stream_1_cname\r\n"
324 "a=ssrc:1 msid:local_stream audio_track_id_1\r\n"
325 "a=ssrc:1 mslabel:local_stream\r\n"
326 "a=ssrc:1 label:audio_track_id_1\r\n";
327
328static const char kSdpVideoString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000329 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000330 "c=IN IP4 0.0.0.0\r\n"
331 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000332 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
333 "a=mid:video_content_name\r\n"
334 "a=sendrecv\r\n"
335 "a=rtpmap:120 VP8/90000\r\n"
336 "a=ssrc:2 cname:stream_1_cname\r\n"
337 "a=ssrc:2 msid:local_stream video_track_id_1\r\n"
338 "a=ssrc:2 mslabel:local_stream\r\n"
339 "a=ssrc:2 label:video_track_id_1\r\n";
340
deadbeef25ed4352016-12-12 18:37:36 -0800341// Reference sdp string using bundle-only.
342static const char kBundleOnlySdpFullString[] =
343 "v=0\r\n"
344 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
345 "s=-\r\n"
346 "t=0 0\r\n"
347 "a=group:BUNDLE audio_content_name video_content_name\r\n"
348 "a=msid-semantic: WMS local_stream_1\r\n"
349 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
350 "c=IN IP4 74.125.127.126\r\n"
351 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
352 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
353 "generation 2\r\n"
354 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
355 "generation 2\r\n"
356 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
357 "generation 2\r\n"
358 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
359 "generation 2\r\n"
360 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
361 "raddr 192.168.1.5 rport 2346 "
362 "generation 2\r\n"
363 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
364 "raddr 192.168.1.5 rport 2348 "
365 "generation 2\r\n"
366 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
367 "a=mid:audio_content_name\r\n"
368 "a=sendrecv\r\n"
369 "a=rtcp-mux\r\n"
370 "a=rtcp-rsize\r\n"
371 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
372 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
373 "dummy_session_params\r\n"
374 "a=rtpmap:111 opus/48000/2\r\n"
375 "a=rtpmap:103 ISAC/16000\r\n"
376 "a=rtpmap:104 ISAC/32000\r\n"
377 "a=ssrc:1 cname:stream_1_cname\r\n"
378 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
379 "a=ssrc:1 mslabel:local_stream_1\r\n"
380 "a=ssrc:1 label:audio_track_id_1\r\n"
381 "m=video 0 RTP/SAVPF 120\r\n"
382 "c=IN IP4 0.0.0.0\r\n"
383 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
384 "a=bundle-only\r\n"
385 "a=mid:video_content_name\r\n"
386 "a=sendrecv\r\n"
387 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
388 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
389 "a=rtpmap:120 VP8/90000\r\n"
390 "a=ssrc-group:FEC 2 3\r\n"
391 "a=ssrc:2 cname:stream_1_cname\r\n"
392 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
393 "a=ssrc:2 mslabel:local_stream_1\r\n"
394 "a=ssrc:2 label:video_track_id_1\r\n"
395 "a=ssrc:3 cname:stream_1_cname\r\n"
396 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
397 "a=ssrc:3 mslabel:local_stream_1\r\n"
398 "a=ssrc:3 label:video_track_id_1\r\n";
399
deadbeef9d3584c2016-02-16 17:54:10 -0800400// Plan B SDP reference string, with 2 streams, 2 audio tracks and 3 video
401// tracks.
402static const char kPlanBSdpFullString[] =
403 "v=0\r\n"
404 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
405 "s=-\r\n"
406 "t=0 0\r\n"
407 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
408 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
409 "c=IN IP4 74.125.127.126\r\n"
410 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
411 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
412 "generation 2\r\n"
413 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
414 "generation 2\r\n"
415 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
416 "generation 2\r\n"
417 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
418 "generation 2\r\n"
419 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
420 "raddr 192.168.1.5 rport 2346 "
421 "generation 2\r\n"
422 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
423 "raddr 192.168.1.5 rport 2348 "
424 "generation 2\r\n"
425 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
426 "a=mid:audio_content_name\r\n"
427 "a=sendrecv\r\n"
428 "a=rtcp-mux\r\n"
429 "a=rtcp-rsize\r\n"
430 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
431 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
432 "dummy_session_params\r\n"
433 "a=rtpmap:111 opus/48000/2\r\n"
434 "a=rtpmap:103 ISAC/16000\r\n"
435 "a=rtpmap:104 ISAC/32000\r\n"
436 "a=ssrc:1 cname:stream_1_cname\r\n"
437 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
438 "a=ssrc:1 mslabel:local_stream_1\r\n"
439 "a=ssrc:1 label:audio_track_id_1\r\n"
440 "a=ssrc:4 cname:stream_2_cname\r\n"
441 "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
442 "a=ssrc:4 mslabel:local_stream_2\r\n"
443 "a=ssrc:4 label:audio_track_id_2\r\n"
444 "m=video 3457 RTP/SAVPF 120\r\n"
445 "c=IN IP4 74.125.224.39\r\n"
446 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
447 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
448 "generation 2\r\n"
449 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
450 "generation 2\r\n"
451 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
452 "generation 2\r\n"
453 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
454 "generation 2\r\n"
455 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
456 "generation 2\r\n"
457 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
458 "generation 2\r\n"
459 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
460 "a=mid:video_content_name\r\n"
461 "a=sendrecv\r\n"
462 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
463 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
464 "a=rtpmap:120 VP8/90000\r\n"
465 "a=ssrc-group:FEC 2 3\r\n"
466 "a=ssrc:2 cname:stream_1_cname\r\n"
467 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
468 "a=ssrc:2 mslabel:local_stream_1\r\n"
469 "a=ssrc:2 label:video_track_id_1\r\n"
470 "a=ssrc:3 cname:stream_1_cname\r\n"
471 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
472 "a=ssrc:3 mslabel:local_stream_1\r\n"
473 "a=ssrc:3 label:video_track_id_1\r\n"
474 "a=ssrc:5 cname:stream_2_cname\r\n"
475 "a=ssrc:5 msid:local_stream_2 video_track_id_2\r\n"
476 "a=ssrc:5 mslabel:local_stream_2\r\n"
477 "a=ssrc:5 label:video_track_id_2\r\n"
478 "a=ssrc:6 cname:stream_2_cname\r\n"
479 "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
480 "a=ssrc:6 mslabel:local_stream_2\r\n"
481 "a=ssrc:6 label:video_track_id_3\r\n";
482
483// Unified Plan SDP reference string, with 2 streams, 2 audio tracks and 3 video
484// tracks.
485static const char kUnifiedPlanSdpFullString[] =
486 "v=0\r\n"
487 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
488 "s=-\r\n"
489 "t=0 0\r\n"
490 "a=msid-semantic: WMS local_stream_1\r\n"
491 // Audio track 1, stream 1 (with candidates).
492 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
493 "c=IN IP4 74.125.127.126\r\n"
494 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
495 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
496 "generation 2\r\n"
497 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
498 "generation 2\r\n"
499 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
500 "generation 2\r\n"
501 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
502 "generation 2\r\n"
503 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
504 "raddr 192.168.1.5 rport 2346 "
505 "generation 2\r\n"
506 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
507 "raddr 192.168.1.5 rport 2348 "
508 "generation 2\r\n"
509 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
510 "a=mid:audio_content_name\r\n"
511 "a=msid:local_stream_1 audio_track_id_1\r\n"
512 "a=sendrecv\r\n"
513 "a=rtcp-mux\r\n"
514 "a=rtcp-rsize\r\n"
515 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
516 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
517 "dummy_session_params\r\n"
518 "a=rtpmap:111 opus/48000/2\r\n"
519 "a=rtpmap:103 ISAC/16000\r\n"
520 "a=rtpmap:104 ISAC/32000\r\n"
521 "a=ssrc:1 cname:stream_1_cname\r\n"
522 // Video track 1, stream 1 (with candidates).
523 "m=video 3457 RTP/SAVPF 120\r\n"
524 "c=IN IP4 74.125.224.39\r\n"
525 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
526 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
527 "generation 2\r\n"
528 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
529 "generation 2\r\n"
530 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
531 "generation 2\r\n"
532 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
533 "generation 2\r\n"
534 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
535 "generation 2\r\n"
536 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
537 "generation 2\r\n"
538 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
539 "a=mid:video_content_name\r\n"
540 "a=msid:local_stream_1 video_track_id_1\r\n"
541 "a=sendrecv\r\n"
542 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
543 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
544 "a=rtpmap:120 VP8/90000\r\n"
545 "a=ssrc-group:FEC 2 3\r\n"
546 "a=ssrc:2 cname:stream_1_cname\r\n"
547 "a=ssrc:3 cname:stream_1_cname\r\n"
548 // Audio track 2, stream 2.
549 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
550 "c=IN IP4 0.0.0.0\r\n"
551 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
552 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
553 "a=mid:audio_content_name_2\r\n"
554 "a=msid:local_stream_2 audio_track_id_2\r\n"
555 "a=sendrecv\r\n"
556 "a=rtcp-mux\r\n"
557 "a=rtcp-rsize\r\n"
558 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
559 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
560 "dummy_session_params\r\n"
561 "a=rtpmap:111 opus/48000/2\r\n"
562 "a=rtpmap:103 ISAC/16000\r\n"
563 "a=rtpmap:104 ISAC/32000\r\n"
564 "a=ssrc:4 cname:stream_2_cname\r\n"
565 // Video track 2, stream 2.
566 "m=video 9 RTP/SAVPF 120\r\n"
567 "c=IN IP4 0.0.0.0\r\n"
568 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
569 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
570 "a=mid:video_content_name_2\r\n"
571 "a=msid:local_stream_2 video_track_id_2\r\n"
572 "a=sendrecv\r\n"
573 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
574 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
575 "a=rtpmap:120 VP8/90000\r\n"
576 "a=ssrc:5 cname:stream_2_cname\r\n"
577 // Video track 3, stream 2.
578 "m=video 9 RTP/SAVPF 120\r\n"
579 "c=IN IP4 0.0.0.0\r\n"
580 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
581 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
582 "a=mid:video_content_name_3\r\n"
583 "a=msid:local_stream_2 video_track_id_3\r\n"
584 "a=sendrecv\r\n"
585 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
586 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
587 "a=rtpmap:120 VP8/90000\r\n"
588 "a=ssrc:6 cname:stream_2_cname\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589
Seth Hampson5b4f0752018-04-02 16:31:36 -0700590// Unified Plan SDP reference string:
591// - audio track 1 has 1 a=msid lines
592// - audio track 2 has 2 a=msid lines
593// - audio track 3 has 1 a=msid line with the special "-" marker signifying that
594// there are 0 media stream ids.
595// This Unified Plan SDP represents a SDP that signals the msid using both
596// a=msid and a=ssrc msid semantics.
597static const char kUnifiedPlanSdpFullStringWithSpecialMsid[] =
598 "v=0\r\n"
599 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
600 "s=-\r\n"
601 "t=0 0\r\n"
602 "a=msid-semantic: WMS local_stream_1\r\n"
603 // Audio track 1, with 1 stream id.
604 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
605 "c=IN IP4 74.125.127.126\r\n"
606 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
607 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
608 "generation 2\r\n"
609 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
610 "generation 2\r\n"
611 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
612 "generation 2\r\n"
613 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
614 "generation 2\r\n"
615 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
616 "raddr 192.168.1.5 rport 2346 "
617 "generation 2\r\n"
618 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
619 "raddr 192.168.1.5 rport 2348 "
620 "generation 2\r\n"
621 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
622 "a=mid:audio_content_name\r\n"
623 "a=msid:local_stream_1 audio_track_id_1\r\n"
624 "a=sendrecv\r\n"
625 "a=rtcp-mux\r\n"
626 "a=rtcp-rsize\r\n"
627 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
628 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
629 "dummy_session_params\r\n"
630 "a=rtpmap:111 opus/48000/2\r\n"
631 "a=rtpmap:103 ISAC/16000\r\n"
632 "a=rtpmap:104 ISAC/32000\r\n"
633 "a=ssrc:1 cname:stream_1_cname\r\n"
634 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
635 "a=ssrc:1 mslabel:local_stream_1\r\n"
636 "a=ssrc:1 label:audio_track_id_1\r\n"
637 // Audio track 2, with two stream ids.
638 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
639 "c=IN IP4 0.0.0.0\r\n"
640 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
641 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
642 "a=mid:audio_content_name_2\r\n"
643 "a=msid:local_stream_1 audio_track_id_2\r\n"
644 "a=msid:local_stream_2 audio_track_id_2\r\n"
645 "a=sendrecv\r\n"
646 "a=rtcp-mux\r\n"
647 "a=rtcp-rsize\r\n"
648 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
649 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
650 "dummy_session_params\r\n"
651 "a=rtpmap:111 opus/48000/2\r\n"
652 "a=rtpmap:103 ISAC/16000\r\n"
653 "a=rtpmap:104 ISAC/32000\r\n"
654 "a=ssrc:4 cname:stream_1_cname\r\n"
655 // The support for Plan B msid signaling only includes the
656 // first media stream id "local_stream_1."
657 "a=ssrc:4 msid:local_stream_1 audio_track_id_2\r\n"
658 "a=ssrc:4 mslabel:local_stream_1\r\n"
659 "a=ssrc:4 label:audio_track_id_2\r\n"
660 // Audio track 3, with no stream ids.
661 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
662 "c=IN IP4 0.0.0.0\r\n"
663 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
664 "a=ice-ufrag:ufrag_voice_3\r\na=ice-pwd:pwd_voice_3\r\n"
665 "a=mid:audio_content_name_3\r\n"
666 "a=msid:- audio_track_id_3\r\n"
667 "a=sendrecv\r\n"
668 "a=rtcp-mux\r\n"
669 "a=rtcp-rsize\r\n"
670 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
671 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
672 "dummy_session_params\r\n"
673 "a=rtpmap:111 opus/48000/2\r\n"
674 "a=rtpmap:103 ISAC/16000\r\n"
675 "a=rtpmap:104 ISAC/32000\r\n"
676 "a=ssrc:7 cname:stream_2_cname\r\n";
677
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678// One candidate reference string as per W3c spec.
679// candidate:<blah> not a=candidate:<blah>CRLF
680static const char kRawCandidate[] =
681 "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
682// One candidate reference string.
683static const char kSdpOneCandidate[] =
684 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
685 "generation 2\r\n";
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000686
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +0000687static const char kSdpTcpActiveCandidate[] =
688 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
689 "tcptype active generation 2";
690static const char kSdpTcpPassiveCandidate[] =
691 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
692 "tcptype passive generation 2";
693static const char kSdpTcpSOCandidate[] =
694 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
695 "tcptype so generation 2";
696static const char kSdpTcpInvalidCandidate[] =
697 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
698 "tcptype invalid generation 2";
699
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000700// One candidate reference string with IPV6 address.
701static const char kRawIPV6Candidate[] =
702 "candidate:a0+B/1 1 udp 2130706432 "
ehmaldonado121cabb2017-05-05 12:04:36 -0700703 "abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd 1234 typ host generation 2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704
705// One candidate reference string.
honghaiza54a0802015-12-16 18:37:23 -0800706static const char kSdpOneCandidateWithUfragPwd[] =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
honghaiza54a0802015-12-16 18:37:23 -0800708 " eth0 ufrag user_rtp pwd password_rtp generation 2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709
710// Session id and version
711static const char kSessionId[] = "18446744069414584320";
712static const char kSessionVersion[] = "18446462598732840960";
713
deadbeef9d3584c2016-02-16 17:54:10 -0800714// ICE options.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000715static const char kIceOption1[] = "iceoption1";
716static const char kIceOption2[] = "iceoption2";
717static const char kIceOption3[] = "iceoption3";
718
deadbeef9d3584c2016-02-16 17:54:10 -0800719// ICE ufrags/passwords.
720static const char kUfragVoice[] = "ufrag_voice";
721static const char kPwdVoice[] = "pwd_voice";
722static const char kUfragVideo[] = "ufrag_video";
723static const char kPwdVideo[] = "pwd_video";
724static const char kUfragData[] = "ufrag_data";
725static const char kPwdData[] = "pwd_data";
726
727// Extra ufrags/passwords for extra unified plan m= sections.
728static const char kUfragVoice2[] = "ufrag_voice_2";
729static const char kPwdVoice2[] = "pwd_voice_2";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700730static const char kUfragVoice3[] = "ufrag_voice_3";
731static const char kPwdVoice3[] = "pwd_voice_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800732static const char kUfragVideo2[] = "ufrag_video_2";
733static const char kPwdVideo2[] = "pwd_video_2";
734static const char kUfragVideo3[] = "ufrag_video_3";
735static const char kPwdVideo3[] = "pwd_video_3";
736
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737// Content name
738static const char kAudioContentName[] = "audio_content_name";
739static const char kVideoContentName[] = "video_content_name";
740static const char kDataContentName[] = "data_content_name";
741
deadbeef9d3584c2016-02-16 17:54:10 -0800742// Extra content names for extra unified plan m= sections.
743static const char kAudioContentName2[] = "audio_content_name_2";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700744static const char kAudioContentName3[] = "audio_content_name_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800745static const char kVideoContentName2[] = "video_content_name_2";
746static const char kVideoContentName3[] = "video_content_name_3";
747
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748// MediaStream 1
Seth Hampson845e8782018-03-02 11:34:10 -0800749static const char kStreamId1[] = "local_stream_1";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750static const char kStream1Cname[] = "stream_1_cname";
751static const char kAudioTrackId1[] = "audio_track_id_1";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200752static const uint32_t kAudioTrack1Ssrc = 1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753static const char kVideoTrackId1[] = "video_track_id_1";
deadbeef9d3584c2016-02-16 17:54:10 -0800754static const uint32_t kVideoTrack1Ssrc1 = 2;
755static const uint32_t kVideoTrack1Ssrc2 = 3;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756
757// MediaStream 2
Seth Hampson845e8782018-03-02 11:34:10 -0800758static const char kStreamId2[] = "local_stream_2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759static const char kStream2Cname[] = "stream_2_cname";
760static const char kAudioTrackId2[] = "audio_track_id_2";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200761static const uint32_t kAudioTrack2Ssrc = 4;
deadbeef9d3584c2016-02-16 17:54:10 -0800762static const char kVideoTrackId2[] = "video_track_id_2";
763static const uint32_t kVideoTrack2Ssrc = 5;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764static const char kVideoTrackId3[] = "video_track_id_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800765static const uint32_t kVideoTrack3Ssrc = 6;
Seth Hampson5b4f0752018-04-02 16:31:36 -0700766static const char kAudioTrackId3[] = "audio_track_id_3";
767static const uint32_t kAudioTrack3Ssrc = 7;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768
769// DataChannel
770static const char kDataChannelLabel[] = "data_channel";
771static const char kDataChannelMsid[] = "data_channeld0";
772static const char kDataChannelCname[] = "data_channel_cname";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200773static const uint32_t kDataChannelSsrc = 10;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774
775// Candidate
776static const char kDummyMid[] = "dummy_mid";
777static const int kDummyIndex = 123;
778
779// Misc
Steve Antona3a92c22017-12-07 10:27:41 -0800780static SdpType kDummyType = SdpType::kOffer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781
782// Helper functions
783
784static bool SdpDeserialize(const std::string& message,
785 JsepSessionDescription* jdesc) {
786 return webrtc::SdpDeserialize(message, jdesc, NULL);
787}
788
789static bool SdpDeserializeCandidate(const std::string& message,
790 JsepIceCandidate* candidate) {
791 return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
792}
793
794// Add some extra |newlines| to the |message| after |line|.
795static void InjectAfter(const std::string& line,
796 const std::string& newlines,
797 std::string* message) {
798 const std::string tmp = line + newlines;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000799 rtc::replace_substrs(line.c_str(), line.length(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 tmp.c_str(), tmp.length(), message);
801}
802
803static void Replace(const std::string& line,
804 const std::string& newlines,
805 std::string* message) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000806 rtc::replace_substrs(line.c_str(), line.length(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 newlines.c_str(), newlines.length(), message);
808}
809
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000810// Expect fail to parase |bad_sdp| and expect |bad_part| be part of the error
811// message.
812static void ExpectParseFailure(const std::string& bad_sdp,
813 const std::string& bad_part) {
Steve Antona3a92c22017-12-07 10:27:41 -0800814 JsepSessionDescription desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 SdpParseError error;
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000816 bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817 EXPECT_FALSE(ret);
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000818 EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()));
819}
820
821// Expect fail to parse kSdpFullString if replace |good_part| with |bad_part|.
822static void ExpectParseFailure(const char* good_part, const char* bad_part) {
823 std::string bad_sdp = kSdpFullString;
824 Replace(good_part, bad_part, &bad_sdp);
825 ExpectParseFailure(bad_sdp, bad_part);
826}
827
828// Expect fail to parse kSdpFullString if add |newlines| after |injectpoint|.
829static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
830 const std::string& newlines,
831 const std::string& bad_part) {
832 std::string bad_sdp = kSdpFullString;
833 InjectAfter(injectpoint, newlines, &bad_sdp);
834 ExpectParseFailure(bad_sdp, bad_part);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835}
836
Steve Anton4e70a722017-11-28 14:57:10 -0800837static void ReplaceDirection(RtpTransceiverDirection direction,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 std::string* message) {
839 std::string new_direction;
840 switch (direction) {
Steve Anton4e70a722017-11-28 14:57:10 -0800841 case RtpTransceiverDirection::kInactive:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 new_direction = "a=inactive";
843 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800844 case RtpTransceiverDirection::kSendOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 new_direction = "a=sendonly";
846 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800847 case RtpTransceiverDirection::kRecvOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 new_direction = "a=recvonly";
849 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800850 case RtpTransceiverDirection::kSendRecv:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 default:
852 new_direction = "a=sendrecv";
853 break;
854 }
855 Replace("a=sendrecv", new_direction, message);
856}
857
858static void ReplaceRejected(bool audio_rejected, bool video_rejected,
859 std::string* message) {
860 if (audio_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -0800861 Replace("m=audio 9", "m=audio 0", message);
862 Replace(kAttributeIceUfragVoice, "", message);
863 Replace(kAttributeIcePwdVoice, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 }
865 if (video_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -0800866 Replace("m=video 9", "m=video 0", message);
867 Replace(kAttributeIceUfragVideo, "", message);
868 Replace(kAttributeIcePwdVideo, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869 }
870}
871
872// WebRtcSdpTest
873
874class WebRtcSdpTest : public testing::Test {
875 public:
Steve Antona3a92c22017-12-07 10:27:41 -0800876 WebRtcSdpTest() : jdesc_(kDummyType) {
phoglund37ebcf02016-01-08 05:04:57 -0800877#ifdef WEBRTC_ANDROID
878 webrtc::InitializeAndroidObjects();
879#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 // AudioContentDescription
881 audio_desc_ = CreateAudioContentDescription();
deadbeef9d3584c2016-02-16 17:54:10 -0800882 StreamParams audio_stream;
883 audio_stream.id = kAudioTrackId1;
884 audio_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800885 audio_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-16 17:54:10 -0800886 audio_stream.ssrcs.push_back(kAudioTrack1Ssrc);
887 audio_desc_->AddStream(audio_stream);
zhihuang38989e52017-03-21 11:04:53 -0700888 rtc::SocketAddress audio_addr("74.125.127.126", 2345);
889 audio_desc_->set_connection_address(audio_addr);
Steve Anton5adfafd2017-12-20 16:34:00 -0800890 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891
892 // VideoContentDescription
deadbeef9d3584c2016-02-16 17:54:10 -0800893 video_desc_ = CreateVideoContentDescription();
894 StreamParams video_stream;
895 video_stream.id = kVideoTrackId1;
896 video_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800897 video_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-16 17:54:10 -0800898 video_stream.ssrcs.push_back(kVideoTrack1Ssrc1);
899 video_stream.ssrcs.push_back(kVideoTrack1Ssrc2);
900 cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream.ssrcs);
901 video_stream.ssrc_groups.push_back(ssrc_group);
902 video_desc_->AddStream(video_stream);
zhihuang38989e52017-03-21 11:04:53 -0700903 rtc::SocketAddress video_addr("74.125.224.39", 3457);
904 video_desc_->set_connection_address(video_addr);
Steve Anton5adfafd2017-12-20 16:34:00 -0800905 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000906
907 // TransportInfo
deadbeef9d3584c2016-02-16 17:54:10 -0800908 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
909 kAudioContentName, TransportDescription(kUfragVoice, kPwdVoice))));
910 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
911 kVideoContentName, TransportDescription(kUfragVideo, kPwdVideo))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000912
913 // v4 host
914 int port = 1234;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000915 rtc::SocketAddress address("192.168.1.5", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000916 Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000917 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
918 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000920 Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000921 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
922 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000924 Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000925 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
926 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000927 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000928 Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000929 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
930 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931
932 // v6 host
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000933 rtc::SocketAddress v6_address("::1", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000934 cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
935 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000936 cricket::LOCAL_PORT_TYPE,
937 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000939 cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
940 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000941 cricket::LOCAL_PORT_TYPE,
942 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000943 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000944 cricket::Candidate candidate7(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
945 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000946 cricket::LOCAL_PORT_TYPE,
947 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000949 cricket::Candidate candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
950 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000951 cricket::LOCAL_PORT_TYPE,
952 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000953
954 // stun
955 int port_stun = 2345;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000956 rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
957 rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000958 cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
959 address_stun, kCandidatePriority, "", "",
960 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000961 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000962 candidate9.set_related_address(rel_address_stun);
963
964 address_stun.SetPort(port_stun++);
965 rel_address_stun.SetPort(port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000966 cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
967 address_stun, kCandidatePriority, "", "",
968 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000969 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000970 candidate10.set_related_address(rel_address_stun);
971
972 // relay
973 int port_relay = 3456;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000974 rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000975 cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
976 address_relay, kCandidatePriority, "", "",
977 cricket::RELAY_PORT_TYPE,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000978 kCandidateGeneration, kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979 address_relay.SetPort(port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000980 cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
981 address_relay, kCandidatePriority, "", "",
982 RELAY_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000983 kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984
985 // voice
986 candidates_.push_back(candidate1);
987 candidates_.push_back(candidate2);
988 candidates_.push_back(candidate5);
989 candidates_.push_back(candidate6);
990 candidates_.push_back(candidate9);
991 candidates_.push_back(candidate10);
992
993 // video
994 candidates_.push_back(candidate3);
995 candidates_.push_back(candidate4);
996 candidates_.push_back(candidate7);
997 candidates_.push_back(candidate8);
998 candidates_.push_back(candidate11);
999 candidates_.push_back(candidate12);
1000
1001 jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"),
1002 0, candidate1));
1003
1004 // Set up JsepSessionDescription.
1005 jdesc_.Initialize(desc_.Copy(), kSessionId, kSessionVersion);
1006 std::string mline_id;
1007 int mline_index = 0;
1008 for (size_t i = 0; i< candidates_.size(); ++i) {
1009 // In this test, the audio m line index will be 0, and the video m line
1010 // will be 1.
1011 bool is_video = (i > 5);
1012 mline_id = is_video ? "video_content_name" : "audio_content_name";
1013 mline_index = is_video ? 1 : 0;
1014 JsepIceCandidate jice(mline_id,
1015 mline_index,
1016 candidates_.at(i));
1017 jdesc_.AddCandidate(&jice);
1018 }
1019 }
1020
Seth Hampson5b4f0752018-04-02 16:31:36 -07001021 void RemoveVideoCandidates() {
deadbeef25ed4352016-12-12 18:37:36 -08001022 const IceCandidateCollection* video_candidates_collection =
1023 jdesc_.candidates(1);
1024 ASSERT_NE(nullptr, video_candidates_collection);
1025 std::vector<cricket::Candidate> video_candidates;
1026 for (size_t i = 0; i < video_candidates_collection->count(); ++i) {
1027 cricket::Candidate c = video_candidates_collection->at(i)->candidate();
1028 c.set_transport_name("video_content_name");
1029 video_candidates.push_back(c);
1030 }
1031 jdesc_.RemoveCandidates(video_candidates);
Seth Hampson5b4f0752018-04-02 16:31:36 -07001032 }
1033
1034 // Turns the existing reference description into a description using
1035 // a=bundle-only. This means no transport attributes and a 0 port value on
1036 // the m= sections not associated with the BUNDLE-tag.
1037 void MakeBundleOnlyDescription() {
1038 RemoveVideoCandidates();
deadbeef25ed4352016-12-12 18:37:36 -08001039
1040 // And the rest of the transport attributes.
1041 desc_.transport_infos()[1].description.ice_ufrag.clear();
1042 desc_.transport_infos()[1].description.ice_pwd.clear();
1043 desc_.transport_infos()[1].description.connection_role =
1044 cricket::CONNECTIONROLE_NONE;
1045
1046 // Set bundle-only flag.
1047 desc_.contents()[1].bundle_only = true;
1048
1049 // Add BUNDLE group.
1050 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1051 group.AddContentName(kAudioContentName);
1052 group.AddContentName(kVideoContentName);
1053 desc_.AddGroup(group);
1054
1055 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(), jdesc_.session_id(),
1056 jdesc_.session_version()));
1057 }
1058
deadbeef9d3584c2016-02-16 17:54:10 -08001059 // Turns the existing reference description into a plan B description,
1060 // with 2 audio tracks and 3 video tracks.
1061 void MakePlanBDescription() {
Steve Antonb1c1de12017-12-21 15:14:30 -08001062 audio_desc_ = audio_desc_->Copy();
1063 video_desc_ = video_desc_->Copy();
deadbeef9d3584c2016-02-16 17:54:10 -08001064
1065 StreamParams audio_track_2;
1066 audio_track_2.id = kAudioTrackId2;
1067 audio_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001068 audio_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001069 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1070 audio_desc_->AddStream(audio_track_2);
1071
1072 StreamParams video_track_2;
1073 video_track_2.id = kVideoTrackId2;
1074 video_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001075 video_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001076 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1077 video_desc_->AddStream(video_track_2);
1078
1079 StreamParams video_track_3;
1080 video_track_3.id = kVideoTrackId3;
1081 video_track_3.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001082 video_track_3.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001083 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1084 video_desc_->AddStream(video_track_3);
1085
1086 desc_.RemoveContentByName(kAudioContentName);
1087 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001088 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_desc_);
1089 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_desc_);
deadbeef9d3584c2016-02-16 17:54:10 -08001090
1091 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(), jdesc_.session_id(),
1092 jdesc_.session_version()));
1093 }
1094
1095 // Turns the existing reference description into a unified plan description,
1096 // with 2 audio tracks and 3 video tracks.
1097 void MakeUnifiedPlanDescription() {
1098 // Audio track 2.
1099 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1100 StreamParams audio_track_2;
1101 audio_track_2.id = kAudioTrackId2;
1102 audio_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001103 audio_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001104 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1105 audio_desc_2->AddStream(audio_track_2);
Steve Anton5adfafd2017-12-20 16:34:00 -08001106 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp, audio_desc_2);
deadbeef9d3584c2016-02-16 17:54:10 -08001107 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1108 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2))));
deadbeef9d3584c2016-02-16 17:54:10 -08001109 // Video track 2, in stream 2.
1110 VideoContentDescription* video_desc_2 = CreateVideoContentDescription();
1111 StreamParams video_track_2;
1112 video_track_2.id = kVideoTrackId2;
1113 video_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001114 video_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001115 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1116 video_desc_2->AddStream(video_track_2);
Steve Anton5adfafd2017-12-20 16:34:00 -08001117 desc_.AddContent(kVideoContentName2, MediaProtocolType::kRtp, video_desc_2);
deadbeef9d3584c2016-02-16 17:54:10 -08001118 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1119 kVideoContentName2, TransportDescription(kUfragVideo2, kPwdVideo2))));
1120
1121 // Video track 3, in stream 2.
1122 VideoContentDescription* video_desc_3 = CreateVideoContentDescription();
1123 StreamParams video_track_3;
1124 video_track_3.id = kVideoTrackId3;
1125 video_track_3.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001126 video_track_3.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001127 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1128 video_desc_3->AddStream(video_track_3);
Steve Anton5adfafd2017-12-20 16:34:00 -08001129 desc_.AddContent(kVideoContentName3, MediaProtocolType::kRtp, video_desc_3);
deadbeef9d3584c2016-02-16 17:54:10 -08001130 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1131 kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3))));
Steve Antone831b8c2018-02-01 12:22:16 -08001132 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
deadbeef9d3584c2016-02-16 17:54:10 -08001133
1134 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(), jdesc_.session_id(),
1135 jdesc_.session_version()));
1136 }
1137
1138 // Creates an audio content description with no streams, and some default
1139 // configuration.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140 AudioContentDescription* CreateAudioContentDescription() {
1141 AudioContentDescription* audio = new AudioContentDescription();
1142 audio->set_rtcp_mux(true);
deadbeef13871492015-12-09 12:37:51 -08001143 audio->set_rtcp_reduced_size(true);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 audio->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_32",
1145 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
1146 "dummy_session_params"));
1147 audio->set_protocol(cricket::kMediaProtocolSavpf);
deadbeef67cf2c12016-04-13 10:07:16 -07001148 AudioCodec opus(111, "opus", 48000, 0, 2);
deadbeef9d3584c2016-02-16 17:54:10 -08001149 audio->AddCodec(opus);
ossue1405ad2017-01-23 08:55:48 -08001150 audio->AddCodec(AudioCodec(103, "ISAC", 16000, 0, 1));
1151 audio->AddCodec(AudioCodec(104, "ISAC", 32000, 0, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 return audio;
1153 }
1154
Seth Hampson5b4f0752018-04-02 16:31:36 -07001155 // Turns the existing reference description into a unified plan description,
1156 // with 3 audio MediaContentDescriptions with special StreamParams that
1157 // contain 0 or multiple stream ids: - audio track 1 has 1 media stream id -
1158 // audio track 2 has 2 media stream ids - audio track 3 has 0 media stream ids
1159 void MakeUnifiedPlanDescriptionMultipleStreamIds() {
1160 desc_.RemoveContentByName(kVideoContentName);
1161 desc_.RemoveTransportInfoByName(kVideoContentName);
1162 RemoveVideoCandidates();
1163
1164 // Audio track 2 has 2 media stream ids.
1165 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1166 StreamParams audio_track_2;
1167 audio_track_2.id = kAudioTrackId2;
1168 audio_track_2.cname = kStream1Cname;
1169 audio_track_2.set_stream_ids({kStreamId1, kStreamId2});
1170 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1171 audio_desc_2->AddStream(audio_track_2);
1172 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp, audio_desc_2);
1173 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1174 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2))));
1175
1176 // Audio track 3 has no stream ids.
1177 AudioContentDescription* audio_desc_3 = CreateAudioContentDescription();
1178 StreamParams audio_track_3;
1179 audio_track_3.id = kAudioTrackId3;
1180 audio_track_3.cname = kStream2Cname;
1181 audio_track_3.set_stream_ids({});
1182 audio_track_3.ssrcs.push_back(kAudioTrack3Ssrc);
1183 audio_desc_3->AddStream(audio_track_3);
1184 desc_.AddContent(kAudioContentName3, MediaProtocolType::kRtp, audio_desc_3);
1185 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1186 kAudioContentName3, TransportDescription(kUfragVoice3, kPwdVoice3))));
1187 // Make sure to create both a=msid lines.
1188 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection |
1189 cricket::kMsidSignalingSsrcAttribute);
1190 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(), jdesc_.session_id(),
1191 jdesc_.session_version()));
1192 }
1193
deadbeef9d3584c2016-02-16 17:54:10 -08001194 // Creates a video content description with no streams, and some default
1195 // configuration.
1196 VideoContentDescription* CreateVideoContentDescription() {
1197 VideoContentDescription* video = new VideoContentDescription();
1198 video->AddCrypto(CryptoParams(
1199 1, "AES_CM_128_HMAC_SHA1_80",
1200 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
1201 video->set_protocol(cricket::kMediaProtocolSavpf);
1202 video->AddCodec(
perkj26752742016-10-24 01:21:16 -07001203 VideoCodec(120, JsepSessionDescription::kDefaultVideoCodecName));
deadbeef9d3584c2016-02-16 17:54:10 -08001204 return video;
1205 }
1206
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207 template <class MCD>
1208 void CompareMediaContentDescription(const MCD* cd1,
1209 const MCD* cd2) {
1210 // type
1211 EXPECT_EQ(cd1->type(), cd1->type());
1212
1213 // content direction
1214 EXPECT_EQ(cd1->direction(), cd2->direction());
1215
1216 // rtcp_mux
1217 EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
1218
deadbeef13871492015-12-09 12:37:51 -08001219 // rtcp_reduced_size
1220 EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size());
1221
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 // cryptos
1223 EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
1224 if (cd1->cryptos().size() != cd2->cryptos().size()) {
1225 ADD_FAILURE();
1226 return;
1227 }
1228 for (size_t i = 0; i< cd1->cryptos().size(); ++i) {
1229 const CryptoParams c1 = cd1->cryptos().at(i);
1230 const CryptoParams c2 = cd2->cryptos().at(i);
1231 EXPECT_TRUE(c1.Matches(c2));
1232 EXPECT_EQ(c1.key_params, c2.key_params);
1233 EXPECT_EQ(c1.session_params, c2.session_params);
1234 }
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001235
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001236 // protocol
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001237 // Use an equivalence class here, for old and new versions of the
1238 // protocol description.
1239 if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp
lally@webrtc.org36300852015-02-24 20:19:35 +00001240 || cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp
1241 || cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
1242 const bool cd2_is_also_dtls_sctp =
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001243 cd2->protocol() == cricket::kMediaProtocolDtlsSctp
lally@webrtc.org36300852015-02-24 20:19:35 +00001244 || cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp
1245 || cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
1246 EXPECT_TRUE(cd2_is_also_dtls_sctp);
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001247 } else {
1248 EXPECT_EQ(cd1->protocol(), cd2->protocol());
1249 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250
1251 // codecs
1252 EXPECT_EQ(cd1->codecs(), cd2->codecs());
1253
1254 // bandwidth
1255 EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
1256
1257 // streams
1258 EXPECT_EQ(cd1->streams(), cd2->streams());
1259
1260 // extmap
1261 ASSERT_EQ(cd1->rtp_header_extensions().size(),
1262 cd2->rtp_header_extensions().size());
1263 for (size_t i = 0; i< cd1->rtp_header_extensions().size(); ++i) {
isheriff6f8d6862016-05-26 11:24:55 -07001264 const RtpExtension ext1 = cd1->rtp_header_extensions().at(i);
1265 const RtpExtension ext2 = cd2->rtp_header_extensions().at(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 EXPECT_EQ(ext1.uri, ext2.uri);
1267 EXPECT_EQ(ext1.id, ext2.id);
jbauch5869f502017-06-29 12:31:36 -07001268 EXPECT_EQ(ext1.encrypt, ext2.encrypt);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 }
1271
zstein4b2e0822017-02-17 19:48:38 -08001272 void CompareDataContentDescription(const DataContentDescription* dcd1,
1273 const DataContentDescription* dcd2) {
1274 EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap());
1275 CompareMediaContentDescription<DataContentDescription>(dcd1, dcd2);
1276 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277
1278 void CompareSessionDescription(const SessionDescription& desc1,
1279 const SessionDescription& desc2) {
1280 // Compare content descriptions.
1281 if (desc1.contents().size() != desc2.contents().size()) {
1282 ADD_FAILURE();
1283 return;
1284 }
1285 for (size_t i = 0 ; i < desc1.contents().size(); ++i) {
1286 const cricket::ContentInfo& c1 = desc1.contents().at(i);
1287 const cricket::ContentInfo& c2 = desc2.contents().at(i);
deadbeef25ed4352016-12-12 18:37:36 -08001288 // ContentInfo properties.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289 EXPECT_EQ(c1.name, c2.name);
deadbeef25ed4352016-12-12 18:37:36 -08001290 EXPECT_EQ(c1.type, c2.type);
1291 EXPECT_EQ(c1.rejected, c2.rejected);
1292 EXPECT_EQ(c1.bundle_only, c2.bundle_only);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293
1294 ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
1295 if (IsAudioContent(&c1)) {
1296 const AudioContentDescription* acd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001297 c1.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 const AudioContentDescription* acd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001299 c2.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
1301 }
1302
1303 ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
1304 if (IsVideoContent(&c1)) {
1305 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001306 c1.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001308 c2.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
1310 }
1311
1312 ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
1313 if (IsDataContent(&c1)) {
Steve Antonb1c1de12017-12-21 15:14:30 -08001314 const DataContentDescription* dcd1 = c1.media_description()->as_data();
1315 const DataContentDescription* dcd2 = c2.media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001316 CompareDataContentDescription(dcd1, dcd2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317 }
1318 }
1319
1320 // group
1321 const cricket::ContentGroups groups1 = desc1.groups();
1322 const cricket::ContentGroups groups2 = desc2.groups();
1323 EXPECT_EQ(groups1.size(), groups1.size());
1324 if (groups1.size() != groups2.size()) {
1325 ADD_FAILURE();
1326 return;
1327 }
1328 for (size_t i = 0; i < groups1.size(); ++i) {
1329 const cricket::ContentGroup group1 = groups1.at(i);
1330 const cricket::ContentGroup group2 = groups2.at(i);
1331 EXPECT_EQ(group1.semantics(), group2.semantics());
1332 const cricket::ContentNames names1 = group1.content_names();
1333 const cricket::ContentNames names2 = group2.content_names();
1334 EXPECT_EQ(names1.size(), names2.size());
1335 if (names1.size() != names2.size()) {
1336 ADD_FAILURE();
1337 return;
1338 }
1339 cricket::ContentNames::const_iterator iter1 = names1.begin();
1340 cricket::ContentNames::const_iterator iter2 = names2.begin();
1341 while (iter1 != names1.end()) {
1342 EXPECT_EQ(*iter1++, *iter2++);
1343 }
1344 }
1345
1346 // transport info
1347 const cricket::TransportInfos transports1 = desc1.transport_infos();
1348 const cricket::TransportInfos transports2 = desc2.transport_infos();
1349 EXPECT_EQ(transports1.size(), transports2.size());
1350 if (transports1.size() != transports2.size()) {
1351 ADD_FAILURE();
1352 return;
1353 }
1354 for (size_t i = 0; i < transports1.size(); ++i) {
1355 const cricket::TransportInfo transport1 = transports1.at(i);
1356 const cricket::TransportInfo transport2 = transports2.at(i);
1357 EXPECT_EQ(transport1.content_name, transport2.content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001358 EXPECT_EQ(transport1.description.ice_ufrag,
1359 transport2.description.ice_ufrag);
1360 EXPECT_EQ(transport1.description.ice_pwd,
1361 transport2.description.ice_pwd);
1362 if (transport1.description.identity_fingerprint) {
1363 EXPECT_EQ(*transport1.description.identity_fingerprint,
1364 *transport2.description.identity_fingerprint);
1365 } else {
1366 EXPECT_EQ(transport1.description.identity_fingerprint.get(),
1367 transport2.description.identity_fingerprint.get());
1368 }
1369 EXPECT_EQ(transport1.description.transport_options,
1370 transport2.description.transport_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001371 }
deadbeefc80741f2015-10-22 13:14:45 -07001372
1373 // global attributes
1374 EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001375 }
1376
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001377 bool CompareSessionDescription(
1378 const JsepSessionDescription& desc1,
1379 const JsepSessionDescription& desc2) {
1380 EXPECT_EQ(desc1.session_id(), desc2.session_id());
1381 EXPECT_EQ(desc1.session_version(), desc2.session_version());
1382 CompareSessionDescription(*desc1.description(), *desc2.description());
1383 if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
1384 return false;
1385 for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
1386 const IceCandidateCollection* cc1 = desc1.candidates(i);
1387 const IceCandidateCollection* cc2 = desc2.candidates(i);
deadbeef25ed4352016-12-12 18:37:36 -08001388 if (cc1->count() != cc2->count()) {
1389 ADD_FAILURE();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001390 return false;
deadbeef25ed4352016-12-12 18:37:36 -08001391 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001392 for (size_t j = 0; j < cc1->count(); ++j) {
1393 const IceCandidateInterface* c1 = cc1->at(j);
1394 const IceCandidateInterface* c2 = cc2->at(j);
1395 EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
1396 EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
1397 EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
1398 }
1399 }
1400 return true;
1401 }
1402
1403 // Disable the ice-ufrag and ice-pwd in given |sdp| message by replacing
1404 // them with invalid keywords so that the parser will just ignore them.
1405 bool RemoveCandidateUfragPwd(std::string* sdp) {
1406 const char ice_ufrag[] = "a=ice-ufrag";
1407 const char ice_ufragx[] = "a=xice-ufrag";
1408 const char ice_pwd[] = "a=ice-pwd";
1409 const char ice_pwdx[] = "a=xice-pwd";
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001410 rtc::replace_substrs(ice_ufrag, strlen(ice_ufrag),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001411 ice_ufragx, strlen(ice_ufragx), sdp);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001412 rtc::replace_substrs(ice_pwd, strlen(ice_pwd),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001413 ice_pwdx, strlen(ice_pwdx), sdp);
1414 return true;
1415 }
1416
1417 // Update the candidates in |jdesc| to use the given |ufrag| and |pwd|.
1418 bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc, int mline_index,
1419 const std::string& ufrag, const std::string& pwd) {
1420 std::string content_name;
1421 if (mline_index == 0) {
1422 content_name = kAudioContentName;
1423 } else if (mline_index == 1) {
1424 content_name = kVideoContentName;
1425 } else {
nissec80e7412017-01-11 05:56:46 -08001426 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001427 }
1428 TransportInfo transport_info(
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001429 content_name, TransportDescription(ufrag, pwd));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001430 SessionDescription* desc =
1431 const_cast<SessionDescription*>(jdesc->description());
1432 desc->RemoveTransportInfoByName(content_name);
1433 EXPECT_TRUE(desc->AddTransportInfo(transport_info));
1434 for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
1435 const IceCandidateCollection* cc = jdesc_.candidates(i);
1436 for (size_t j = 0; j < cc->count(); ++j) {
1437 if (cc->at(j)->sdp_mline_index() == mline_index) {
1438 const_cast<Candidate&>(cc->at(j)->candidate()).set_username(
1439 ufrag);
1440 const_cast<Candidate&>(cc->at(j)->candidate()).set_password(
1441 pwd);
1442 }
1443 }
1444 }
1445 return true;
1446 }
1447
1448 void AddIceOptions(const std::string& content_name,
1449 const std::vector<std::string>& transport_options) {
1450 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1451 cricket::TransportInfo transport_info =
1452 *(desc_.GetTransportInfoByName(content_name));
1453 desc_.RemoveTransportInfoByName(content_name);
1454 transport_info.description.transport_options = transport_options;
1455 desc_.AddTransportInfo(transport_info);
1456 }
1457
deadbeef3f7219b2015-12-28 15:17:14 -08001458 void SetIceUfragPwd(const std::string& content_name,
1459 const std::string& ice_ufrag,
1460 const std::string& ice_pwd) {
1461 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1462 cricket::TransportInfo transport_info =
1463 *(desc_.GetTransportInfoByName(content_name));
1464 desc_.RemoveTransportInfoByName(content_name);
1465 transport_info.description.ice_ufrag = ice_ufrag;
1466 transport_info.description.ice_pwd = ice_pwd;
1467 desc_.AddTransportInfo(transport_info);
1468 }
1469
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001470 void AddFingerprint() {
1471 desc_.RemoveTransportInfoByName(kAudioContentName);
1472 desc_.RemoveTransportInfoByName(kVideoContentName);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001473 rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001474 kIdentityDigest,
1475 sizeof(kIdentityDigest));
deadbeef46eed762016-01-28 13:24:37 -08001476 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1477 kAudioContentName,
deadbeef9d3584c2016-02-16 17:54:10 -08001478 TransportDescription(std::vector<std::string>(), kUfragVoice, kPwdVoice,
1479 cricket::ICEMODE_FULL,
deadbeef46eed762016-01-28 13:24:37 -08001480 cricket::CONNECTIONROLE_NONE, &fingerprint))));
1481 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1482 kVideoContentName,
deadbeef9d3584c2016-02-16 17:54:10 -08001483 TransportDescription(std::vector<std::string>(), kUfragVideo, kPwdVideo,
1484 cricket::ICEMODE_FULL,
deadbeef46eed762016-01-28 13:24:37 -08001485 cricket::CONNECTIONROLE_NONE, &fingerprint))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001486 }
1487
jbauch5869f502017-06-29 12:31:36 -07001488 void AddExtmap(bool encrypted) {
Steve Antonb1c1de12017-12-21 15:14:30 -08001489 audio_desc_ = audio_desc_->Copy();
1490 video_desc_ = video_desc_->Copy();
jbauch5869f502017-06-29 12:31:36 -07001491 audio_desc_->AddRtpHeaderExtension(
1492 RtpExtension(kExtmapUri, kExtmapId, encrypted));
1493 video_desc_->AddRtpHeaderExtension(
1494 RtpExtension(kExtmapUri, kExtmapId, encrypted));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495 desc_.RemoveContentByName(kAudioContentName);
1496 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001497 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_desc_);
1498 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001499 }
1500
1501 void RemoveCryptos() {
1502 audio_desc_->set_cryptos(std::vector<CryptoParams>());
1503 video_desc_->set_cryptos(std::vector<CryptoParams>());
1504 }
1505
Steve Anton4e70a722017-11-28 14:57:10 -08001506 bool TestSerializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 audio_desc_->set_direction(direction);
1508 video_desc_->set_direction(direction);
1509 std::string new_sdp = kSdpFullString;
1510 ReplaceDirection(direction, &new_sdp);
1511
1512 if (!jdesc_.Initialize(desc_.Copy(),
1513 jdesc_.session_id(),
1514 jdesc_.session_version())) {
1515 return false;
1516 }
Steve Antone831b8c2018-02-01 12:22:16 -08001517 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518 EXPECT_EQ(new_sdp, message);
1519 return true;
1520 }
1521
1522 bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
Steve Antonb1c1de12017-12-21 15:14:30 -08001523 audio_desc_ = audio_desc_->Copy();
1524 video_desc_ = video_desc_->Copy();
zhihuang38989e52017-03-21 11:04:53 -07001525
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 desc_.RemoveContentByName(kAudioContentName);
1527 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001528 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001529 audio_desc_);
Steve Anton5adfafd2017-12-20 16:34:00 -08001530 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001531 video_desc_);
deadbeef9d3584c2016-02-16 17:54:10 -08001532 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1533 audio_rejected ? "" : kPwdVoice);
1534 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1535 video_rejected ? "" : kPwdVideo);
deadbeef3f7219b2015-12-28 15:17:14 -08001536
1537 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
1539
Steve Antona3a92c22017-12-07 10:27:41 -08001540 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07001541 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 12:22:16 -08001542 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 EXPECT_EQ(new_sdp, message);
1544 return true;
1545 }
1546
zstein4b2e0822017-02-17 19:48:38 -08001547 void AddSctpDataChannel(bool use_sctpmap) {
kwibergd1fe2812016-04-27 06:47:29 -07001548 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 data_desc_ = data.get();
zstein4b2e0822017-02-17 19:48:38 -08001550 data_desc_->set_use_sctpmap(use_sctpmap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001551 data_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp);
solenberg9fa49752016-10-08 13:02:44 -07001552 DataCodec codec(cricket::kGoogleSctpDataCodecPlType,
deadbeef67cf2c12016-04-13 10:07:16 -07001553 cricket::kGoogleSctpDataCodecName);
wu@webrtc.org78187522013-10-07 23:32:02 +00001554 codec.SetParam(cricket::kCodecParamPort, kDefaultSctpPort);
1555 data_desc_->AddCodec(codec);
Steve Anton5adfafd2017-12-20 16:34:00 -08001556 desc_.AddContent(kDataContentName, MediaProtocolType::kSctp,
1557 data.release());
deadbeef9d3584c2016-02-16 17:54:10 -08001558 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1559 kDataContentName, TransportDescription(kUfragData, kPwdData))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 }
1561
1562 void AddRtpDataChannel() {
kwibergd1fe2812016-04-27 06:47:29 -07001563 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564 data_desc_ = data.get();
1565
deadbeef67cf2c12016-04-13 10:07:16 -07001566 data_desc_->AddCodec(DataCodec(101, "google-data"));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567 StreamParams data_stream;
1568 data_stream.id = kDataChannelMsid;
1569 data_stream.cname = kDataChannelCname;
Seth Hampson845e8782018-03-02 11:34:10 -08001570 data_stream.set_stream_ids({kDataChannelLabel});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001571 data_stream.ssrcs.push_back(kDataChannelSsrc);
1572 data_desc_->AddStream(data_stream);
1573 data_desc_->AddCrypto(CryptoParams(
1574 1, "AES_CM_128_HMAC_SHA1_80",
1575 "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5", ""));
1576 data_desc_->set_protocol(cricket::kMediaProtocolSavpf);
Steve Anton5adfafd2017-12-20 16:34:00 -08001577 desc_.AddContent(kDataContentName, MediaProtocolType::kRtp, data.release());
deadbeef9d3584c2016-02-16 17:54:10 -08001578 EXPECT_TRUE(desc_.AddTransportInfo(TransportInfo(
1579 kDataContentName, TransportDescription(kUfragData, kPwdData))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001580 }
1581
Steve Anton4e70a722017-11-28 14:57:10 -08001582 bool TestDeserializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001583 std::string new_sdp = kSdpFullString;
1584 ReplaceDirection(direction, &new_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08001585 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001586
1587 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
1588
1589 audio_desc_->set_direction(direction);
1590 video_desc_->set_direction(direction);
1591 if (!jdesc_.Initialize(desc_.Copy(),
1592 jdesc_.session_id(),
1593 jdesc_.session_version())) {
1594 return false;
1595 }
1596 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
1597 return true;
1598 }
1599
1600 bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -08001601 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08001603 JsepSessionDescription new_jdesc(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
deadbeef3f7219b2015-12-28 15:17:14 -08001605
Steve Antonb1c1de12017-12-21 15:14:30 -08001606 audio_desc_ = audio_desc_->Copy();
1607 video_desc_ = video_desc_->Copy();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001608 desc_.RemoveContentByName(kAudioContentName);
1609 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001610 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611 audio_desc_);
Steve Anton5adfafd2017-12-20 16:34:00 -08001612 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001613 video_desc_);
deadbeef9d3584c2016-02-16 17:54:10 -08001614 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1615 audio_rejected ? "" : kPwdVoice);
1616 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1617 video_rejected ? "" : kPwdVideo);
Steve Antona3a92c22017-12-07 10:27:41 -08001618 JsepSessionDescription jdesc_no_candidates(kDummyType);
deadbeef3f7219b2015-12-28 15:17:14 -08001619 if (!jdesc_no_candidates.Initialize(desc_.Copy(), jdesc_.session_id(),
1620 jdesc_.session_version())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001621 return false;
1622 }
deadbeef3f7219b2015-12-28 15:17:14 -08001623 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001624 return true;
1625 }
1626
jbauch5869f502017-06-29 12:31:36 -07001627 void TestDeserializeExtmap(bool session_level, bool media_level,
1628 bool encrypted) {
1629 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08001630 JsepSessionDescription new_jdesc(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
1632 jdesc_.session_id(),
1633 jdesc_.session_version()));
Steve Antona3a92c22017-12-07 10:27:41 -08001634 JsepSessionDescription jdesc_with_extmap(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 std::string sdp_with_extmap = kSdpString;
1636 if (session_level) {
jbauch5869f502017-06-29 12:31:36 -07001637 InjectAfter(kSessionTime,
1638 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1639 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640 &sdp_with_extmap);
1641 }
1642 if (media_level) {
jbauch5869f502017-06-29 12:31:36 -07001643 InjectAfter(kAttributeIcePwdVoice,
1644 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1645 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646 &sdp_with_extmap);
jbauch5869f502017-06-29 12:31:36 -07001647 InjectAfter(kAttributeIcePwdVideo,
1648 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1649 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 &sdp_with_extmap);
1651 }
1652 // The extmap can't be present at the same time in both session level and
1653 // media level.
1654 if (session_level && media_level) {
1655 SdpParseError error;
1656 EXPECT_FALSE(webrtc::SdpDeserialize(sdp_with_extmap,
1657 &jdesc_with_extmap, &error));
1658 EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
1659 } else {
1660 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
1661 EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
1662 }
1663 }
1664
1665 void VerifyCodecParameter(const cricket::CodecParameterMap& params,
1666 const std::string& name, int expected_value) {
1667 cricket::CodecParameterMap::const_iterator found = params.find(name);
1668 ASSERT_TRUE(found != params.end());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001669 EXPECT_EQ(found->second, rtc::ToString<int>(expected_value));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001670 }
1671
1672 void TestDeserializeCodecParams(const CodecParams& params,
1673 JsepSessionDescription* jdesc_output) {
1674 std::string sdp =
1675 "v=0\r\n"
1676 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1677 "s=-\r\n"
1678 "t=0 0\r\n"
1679 // Include semantics for WebRTC Media Streams since it is supported by
1680 // this parser, and will be added to the SDP when serializing a session
1681 // description.
1682 "a=msid-semantic: WMS\r\n"
1683 // Pl type 111 preferred.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001684 "m=audio 9 RTP/SAVPF 111 104 103\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001685 // Pltype 111 listed before 103 and 104 in the map.
1686 "a=rtpmap:111 opus/48000/2\r\n"
1687 // Pltype 103 listed before 104.
1688 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001689 "a=rtpmap:104 ISAC/32000\r\n"
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001690 "a=fmtp:111 0-15,66,70\r\n"
1691 "a=fmtp:111 ";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001692 std::ostringstream os;
Donald Curtis144d0182015-05-15 13:14:24 -07001693 os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001694 << "; sprop-stereo=" << params.sprop_stereo
1695 << "; useinbandfec=" << params.useinband
Donald Curtis0e07f922015-05-15 09:21:23 -07001696 << "; maxaveragebitrate=" << params.maxaveragebitrate << "\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001697 << "a=ptime:" << params.ptime << "\r\n"
1698 << "a=maxptime:" << params.max_ptime << "\r\n";
1699 sdp += os.str();
1700
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001701 os.clear();
1702 os.str("");
1703 // Pl type 100 preferred.
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00001704 os << "m=video 9 RTP/SAVPF 99 95\r\n"
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001705 << "a=rtpmap:99 VP8/90000\r\n"
1706 << "a=rtpmap:95 RTX/90000\r\n"
Donald Curtis0e07f922015-05-15 09:21:23 -07001707 << "a=fmtp:95 apt=99;\r\n";
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001708 sdp += os.str();
1709
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001710 // Deserialize
1711 SdpParseError error;
1712 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
1713
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001714 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001715 GetFirstAudioContentDescription(jdesc_output->description());
1716 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717 ASSERT_FALSE(acd->codecs().empty());
1718 cricket::AudioCodec opus = acd->codecs()[0];
1719 EXPECT_EQ("opus", opus.name);
1720 EXPECT_EQ(111, opus.id);
1721 VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
1722 VerifyCodecParameter(opus.params, "stereo", params.stereo);
1723 VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
1724 VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001725 VerifyCodecParameter(opus.params, "maxaveragebitrate",
1726 params.maxaveragebitrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 for (size_t i = 0; i < acd->codecs().size(); ++i) {
1728 cricket::AudioCodec codec = acd->codecs()[i];
1729 VerifyCodecParameter(codec.params, "ptime", params.ptime);
1730 VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 }
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001732
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001733 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001734 GetFirstVideoContentDescription(jdesc_output->description());
1735 ASSERT_TRUE(vcd);
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001736 ASSERT_FALSE(vcd->codecs().empty());
1737 cricket::VideoCodec vp8 = vcd->codecs()[0];
1738 EXPECT_EQ("VP8", vp8.name);
1739 EXPECT_EQ(99, vp8.id);
1740 cricket::VideoCodec rtx = vcd->codecs()[1];
1741 EXPECT_EQ("RTX", rtx.name);
1742 EXPECT_EQ(95, rtx.id);
1743 VerifyCodecParameter(rtx.params, "apt", vp8.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744 }
1745
1746 void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
1747 bool use_wildcard) {
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001748 std::string sdp_session_and_audio =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001749 "v=0\r\n"
1750 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1751 "s=-\r\n"
1752 "t=0 0\r\n"
1753 // Include semantics for WebRTC Media Streams since it is supported by
1754 // this parser, and will be added to the SDP when serializing a session
1755 // description.
1756 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00001757 "m=audio 9 RTP/SAVPF 111\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001758 "a=rtpmap:111 opus/48000/2\r\n";
1759 std::string sdp_video =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001760 "m=video 3457 RTP/SAVPF 101\r\n"
1761 "a=rtpmap:101 VP8/90000\r\n"
1762 "a=rtcp-fb:101 nack\r\n"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001763 "a=rtcp-fb:101 nack pli\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001764 "a=rtcp-fb:101 goog-remb\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001765 std::ostringstream os;
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001766 os << sdp_session_and_audio;
1767 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") << " nack\r\n";
1768 os << sdp_video;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001769 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") << " ccm fir\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001770 std::string sdp = os.str();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001771 // Deserialize
1772 SdpParseError error;
1773 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001775 GetFirstAudioContentDescription(jdesc_output->description());
1776 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 ASSERT_FALSE(acd->codecs().empty());
1778 cricket::AudioCodec opus = acd->codecs()[0];
1779 EXPECT_EQ(111, opus.id);
1780 EXPECT_TRUE(opus.HasFeedbackParam(
1781 cricket::FeedbackParam(cricket::kRtcpFbParamNack,
1782 cricket::kParamValueEmpty)));
1783
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001785 GetFirstVideoContentDescription(jdesc_output->description());
1786 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787 ASSERT_FALSE(vcd->codecs().empty());
1788 cricket::VideoCodec vp8 = vcd->codecs()[0];
1789 EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
1790 vp8.name.c_str());
1791 EXPECT_EQ(101, vp8.id);
1792 EXPECT_TRUE(vp8.HasFeedbackParam(
1793 cricket::FeedbackParam(cricket::kRtcpFbParamNack,
1794 cricket::kParamValueEmpty)));
1795 EXPECT_TRUE(vp8.HasFeedbackParam(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001796 cricket::FeedbackParam(cricket::kRtcpFbParamNack,
1797 cricket::kRtcpFbNackParamPli)));
1798 EXPECT_TRUE(vp8.HasFeedbackParam(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001799 cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
1800 cricket::kParamValueEmpty)));
1801 EXPECT_TRUE(vp8.HasFeedbackParam(
1802 cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
1803 cricket::kRtcpFbCcmParamFir)));
1804 }
1805
1806 // Two SDP messages can mean the same thing but be different strings, e.g.
1807 // some of the lines can be serialized in different order.
1808 // However, a deserialized description can be compared field by field and has
1809 // no order. If deserializer has already been tested, serializing then
1810 // deserializing and comparing JsepSessionDescription will test
1811 // the serializer sufficiently.
Steve Antone831b8c2018-02-01 12:22:16 -08001812 void TestSerialize(const JsepSessionDescription& jdesc) {
1813 std::string message = webrtc::SdpSerialize(jdesc);
Steve Antona3a92c22017-12-07 10:27:41 -08001814 JsepSessionDescription jdesc_output_des(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001815 SdpParseError error;
1816 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
1817 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
1818 }
1819
zhihuang38989e52017-03-21 11:04:53 -07001820 // Calling 'Initialize' with a copy of the inner SessionDescription will
1821 // create a copy of the JsepSessionDescription without candidates. The
1822 // 'connection address' field, previously set from the candidates, must also
1823 // be reset.
1824 void MakeDescriptionWithoutCandidates(JsepSessionDescription* jdesc) {
1825 rtc::SocketAddress audio_addr("0.0.0.0", 9);
1826 rtc::SocketAddress video_addr("0.0.0.0", 9);
1827 audio_desc_->set_connection_address(audio_addr);
1828 video_desc_->set_connection_address(video_addr);
1829 ASSERT_TRUE(jdesc->Initialize(desc_.Copy(), kSessionId, kSessionVersion));
1830 }
1831
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001832 protected:
1833 SessionDescription desc_;
1834 AudioContentDescription* audio_desc_;
1835 VideoContentDescription* video_desc_;
1836 DataContentDescription* data_desc_;
1837 Candidates candidates_;
kwibergd1fe2812016-04-27 06:47:29 -07001838 std::unique_ptr<IceCandidateInterface> jcandidate_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001839 JsepSessionDescription jdesc_;
1840};
1841
1842void TestMismatch(const std::string& string1, const std::string& string2) {
1843 int position = 0;
1844 for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
1845 if (string1.c_str()[i] != string2.c_str()[i]) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001846 position = static_cast<int>(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 break;
1848 }
1849 }
1850 EXPECT_EQ(0, position) << "Strings mismatch at the " << position
1851 << " character\n"
1852 << " 1: " << string1.substr(position, 20) << "\n"
1853 << " 2: " << string2.substr(position, 20) << "\n";
1854}
1855
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001856TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
1857 // SessionDescription with desc and candidates.
Steve Antone831b8c2018-02-01 12:22:16 -08001858 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001859 TestMismatch(std::string(kSdpFullString), message);
1860}
1861
1862TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
Steve Antona3a92c22017-12-07 10:27:41 -08001863 JsepSessionDescription jdesc_empty(kDummyType);
Steve Antone831b8c2018-02-01 12:22:16 -08001864 EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865}
1866
1867// This tests serialization of SDP with a=crypto and a=fingerprint, as would be
1868// the case in a DTLS offer.
1869TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
1870 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08001871 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07001872 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 12:22:16 -08001873 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001874
1875 std::string sdp_with_fingerprint = kSdpString;
1876 InjectAfter(kAttributeIcePwdVoice,
1877 kFingerprint, &sdp_with_fingerprint);
1878 InjectAfter(kAttributeIcePwdVideo,
1879 kFingerprint, &sdp_with_fingerprint);
1880
1881 EXPECT_EQ(sdp_with_fingerprint, message);
1882}
1883
1884// This tests serialization of SDP with a=fingerprint with no a=crypto, as would
1885// be the case in a DTLS answer.
1886TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
1887 AddFingerprint();
1888 RemoveCryptos();
Steve Antona3a92c22017-12-07 10:27:41 -08001889 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07001890 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 12:22:16 -08001891 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001892
1893 std::string sdp_with_fingerprint = kSdpString;
1894 Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
1895 Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
1896 InjectAfter(kAttributeIcePwdVoice,
1897 kFingerprint, &sdp_with_fingerprint);
1898 InjectAfter(kAttributeIcePwdVideo,
1899 kFingerprint, &sdp_with_fingerprint);
1900
1901 EXPECT_EQ(sdp_with_fingerprint, message);
1902}
1903
1904TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
1905 // JsepSessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 10:27:41 -08001906 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07001907 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 12:22:16 -08001908 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001909 EXPECT_EQ(std::string(kSdpString), message);
1910}
1911
1912TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundle) {
1913 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1914 group.AddContentName(kAudioContentName);
1915 group.AddContentName(kVideoContentName);
1916 desc_.AddGroup(group);
1917 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1918 jdesc_.session_id(),
1919 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08001920 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001921 std::string sdp_with_bundle = kSdpFullString;
1922 InjectAfter(kSessionTime,
1923 "a=group:BUNDLE audio_content_name video_content_name\r\n",
1924 &sdp_with_bundle);
1925 EXPECT_EQ(sdp_with_bundle, message);
1926}
1927
1928TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
Steve Antonb1c1de12017-12-21 15:14:30 -08001929 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001930 vcd->set_bandwidth(100 * 1000);
Steve Antonb1c1de12017-12-21 15:14:30 -08001931 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001932 acd->set_bandwidth(50 * 1000);
1933 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1934 jdesc_.session_id(),
1935 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08001936 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937 std::string sdp_with_bandwidth = kSdpFullString;
wu@webrtc.org4c3e9912014-07-16 21:03:13 +00001938 InjectAfter("c=IN IP4 74.125.224.39\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939 "b=AS:100\r\n",
1940 &sdp_with_bandwidth);
wu@webrtc.org4c3e9912014-07-16 21:03:13 +00001941 InjectAfter("c=IN IP4 74.125.127.126\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 "b=AS:50\r\n",
1943 &sdp_with_bandwidth);
1944 EXPECT_EQ(sdp_with_bandwidth, message);
1945}
1946
1947TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
1948 std::vector<std::string> transport_options;
1949 transport_options.push_back(kIceOption1);
1950 transport_options.push_back(kIceOption3);
1951 AddIceOptions(kAudioContentName, transport_options);
1952 transport_options.clear();
1953 transport_options.push_back(kIceOption2);
1954 transport_options.push_back(kIceOption3);
1955 AddIceOptions(kVideoContentName, transport_options);
1956 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
1957 jdesc_.session_id(),
1958 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08001959 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001960 std::string sdp_with_ice_options = kSdpFullString;
1961 InjectAfter(kAttributeIcePwdVoice,
1962 "a=ice-options:iceoption1 iceoption3\r\n",
1963 &sdp_with_ice_options);
1964 InjectAfter(kAttributeIcePwdVideo,
1965 "a=ice-options:iceoption2 iceoption3\r\n",
1966 &sdp_with_ice_options);
1967 EXPECT_EQ(sdp_with_ice_options, message);
1968}
1969
1970TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08001971 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001972}
1973
1974TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08001975 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976}
1977
1978TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08001979 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001980}
1981
1982TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
1983 EXPECT_TRUE(TestSerializeRejected(true, false));
1984}
1985
1986TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
1987 EXPECT_TRUE(TestSerializeRejected(false, true));
1988}
1989
1990TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
1991 EXPECT_TRUE(TestSerializeRejected(true, true));
1992}
1993
1994TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRtpDataChannel) {
1995 AddRtpDataChannel();
Steve Antona3a92c22017-12-07 10:27:41 -08001996 JsepSessionDescription jsep_desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997
zhihuang38989e52017-03-21 11:04:53 -07001998 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08001999 std::string message = webrtc::SdpSerialize(jsep_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002000
2001 std::string expected_sdp = kSdpString;
2002 expected_sdp.append(kSdpRtpDataChannelString);
2003 EXPECT_EQ(expected_sdp, message);
2004}
2005
2006TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
zstein4b2e0822017-02-17 19:48:38 -08002007 bool use_sctpmap = true;
2008 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002009 JsepSessionDescription jsep_desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010
zhihuang38989e52017-03-21 11:04:53 -07002011 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08002012 std::string message = webrtc::SdpSerialize(jsep_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002013
2014 std::string expected_sdp = kSdpString;
2015 expected_sdp.append(kSdpSctpDataChannelString);
2016 EXPECT_EQ(message, expected_sdp);
2017}
2018
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002019TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
zstein4b2e0822017-02-17 19:48:38 -08002020 bool use_sctpmap = true;
2021 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002022 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002023 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antonb1c1de12017-12-21 15:14:30 -08002024 DataContentDescription* dcdesc =
2025 jsep_desc.description()
2026 ->GetContentDescriptionByName(kDataContentName)
2027 ->as_data();
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002028
2029 const int kNewPort = 1234;
solenberg9fa49752016-10-08 13:02:44 -07002030 cricket::DataCodec codec(cricket::kGoogleSctpDataCodecPlType,
deadbeef67cf2c12016-04-13 10:07:16 -07002031 cricket::kGoogleSctpDataCodecName);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002032 codec.SetParam(cricket::kCodecParamPort, kNewPort);
2033 dcdesc->AddOrReplaceCodec(codec);
2034
Steve Antone831b8c2018-02-01 12:22:16 -08002035 std::string message = webrtc::SdpSerialize(jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002036
2037 std::string expected_sdp = kSdpString;
2038 expected_sdp.append(kSdpSctpDataChannelString);
2039
2040 char default_portstr[16];
2041 char new_portstr[16];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002042 rtc::sprintfn(default_portstr, sizeof(default_portstr), "%d",
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002043 kDefaultSctpPort);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002044 rtc::sprintfn(new_portstr, sizeof(new_portstr), "%d", kNewPort);
2045 rtc::replace_substrs(default_portstr, strlen(default_portstr),
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002046 new_portstr, strlen(new_portstr),
2047 &expected_sdp);
2048
2049 EXPECT_EQ(expected_sdp, message);
2050}
2051
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002052TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
Steve Antona3a92c22017-12-07 10:27:41 -08002053 JsepSessionDescription jsep_desc(kDummyType);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002054 AddRtpDataChannel();
2055 data_desc_->set_bandwidth(100*1000);
zhihuang38989e52017-03-21 11:04:53 -07002056 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08002057 std::string message = webrtc::SdpSerialize(jsep_desc);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002058
2059 std::string expected_sdp = kSdpString;
2060 expected_sdp.append(kSdpRtpDataChannelString);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002061 // Serializing data content shouldn't ignore bandwidth settings.
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +00002062 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 +00002063 "b=AS:100\r\n",
2064 &expected_sdp);
2065 EXPECT_EQ(expected_sdp, message);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002066}
2067
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002068TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
jbauch5869f502017-06-29 12:31:36 -07002069 bool encrypted = false;
2070 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08002071 JsepSessionDescription desc_with_extmap(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002072 MakeDescriptionWithoutCandidates(&desc_with_extmap);
Steve Antone831b8c2018-02-01 12:22:16 -08002073 std::string message = webrtc::SdpSerialize(desc_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002074
2075 std::string sdp_with_extmap = kSdpString;
2076 InjectAfter("a=mid:audio_content_name\r\n",
2077 kExtmap, &sdp_with_extmap);
2078 InjectAfter("a=mid:video_content_name\r\n",
2079 kExtmap, &sdp_with_extmap);
2080
2081 EXPECT_EQ(sdp_with_extmap, message);
2082}
2083
jbauch5869f502017-06-29 12:31:36 -07002084TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapEncrypted) {
2085 bool encrypted = true;
2086 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08002087 JsepSessionDescription desc_with_extmap(kDummyType);
jbauch5869f502017-06-29 12:31:36 -07002088 ASSERT_TRUE(desc_with_extmap.Initialize(desc_.Copy(),
2089 kSessionId, kSessionVersion));
Steve Antone831b8c2018-02-01 12:22:16 -08002090 TestSerialize(desc_with_extmap);
jbauch5869f502017-06-29 12:31:36 -07002091}
2092
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093TEST_F(WebRtcSdpTest, SerializeCandidates) {
2094 std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
wu@webrtc.orgec9f5fb2014-06-24 17:05:10 +00002095 EXPECT_EQ(std::string(kRawCandidate), message);
honghaiza54a0802015-12-16 18:37:23 -08002096
2097 Candidate candidate_with_ufrag(candidates_.front());
2098 candidate_with_ufrag.set_username("ABC");
2099 jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0,
2100 candidate_with_ufrag));
2101 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2102 EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
honghaiza0c44ea2016-03-23 16:07:48 -07002103
2104 Candidate candidate_with_network_info(candidates_.front());
2105 candidate_with_network_info.set_network_id(1);
2106 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2107 candidate_with_network_info));
2108 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2109 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
2110 candidate_with_network_info.set_network_cost(999);
2111 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2112 candidate_with_network_info));
2113 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2114 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
2115 message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116}
2117
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002118// TODO(mallinath) : Enable this test once WebRTCSdp capable of parsing
2119// RFC 6544.
mallinath@webrtc.orge999bd02014-08-13 06:05:55 +00002120TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00002121 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00002122 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2123 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2124 kCandidateFoundation1);
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002125 candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
kwibergd1fe2812016-04-27 06:47:29 -07002126 std::unique_ptr<IceCandidateInterface> jcandidate(
2127 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002128
2129 std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
2130 EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
2131}
2132
htaa6b99442016-04-12 10:29:17 -07002133TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithH264) {
magjed509e4fe2016-11-18 01:34:11 -08002134 cricket::VideoCodec h264_codec("H264");
2135 h264_codec.SetParam("profile-level-id", "42e01f");
2136 h264_codec.SetParam("level-asymmetry-allowed", "1");
2137 h264_codec.SetParam("packetization-mode", "1");
2138 video_desc_->AddCodec(h264_codec);
2139
htaa6b99442016-04-12 10:29:17 -07002140 jdesc_.Initialize(desc_.Copy(), kSessionId, kSessionVersion);
2141
Steve Antone831b8c2018-02-01 12:22:16 -08002142 std::string message = webrtc::SdpSerialize(jdesc_);
htaa6b99442016-04-12 10:29:17 -07002143 size_t after_pt = message.find(" H264/90000");
2144 ASSERT_NE(after_pt, std::string::npos);
2145 size_t before_pt = message.rfind("a=rtpmap:", after_pt);
2146 ASSERT_NE(before_pt, std::string::npos);
2147 before_pt += strlen("a=rtpmap:");
2148 std::string pt = message.substr(before_pt, after_pt - before_pt);
2149 // TODO(hta): Check if payload type |pt| occurs in the m=video line.
2150 std::string to_find = "a=fmtp:" + pt + " ";
2151 size_t fmtp_pos = message.find(to_find);
2152 ASSERT_NE(std::string::npos, fmtp_pos) << "Failed to find " << to_find;
2153 size_t fmtp_endpos = message.find("\n", fmtp_pos);
2154 ASSERT_NE(std::string::npos, fmtp_endpos);
2155 std::string fmtp_value = message.substr(fmtp_pos, fmtp_endpos);
2156 EXPECT_NE(std::string::npos, fmtp_value.find("level-asymmetry-allowed=1"));
2157 EXPECT_NE(std::string::npos, fmtp_value.find("packetization-mode=1"));
2158 EXPECT_NE(std::string::npos, fmtp_value.find("profile-level-id=42e01f"));
hta62a216e2016-04-15 11:02:14 -07002159 // Check that there are no spaces after semicolons.
2160 // https://bugs.webrtc.org/5793
2161 EXPECT_EQ(std::string::npos, fmtp_value.find("; "));
htaa6b99442016-04-12 10:29:17 -07002162}
2163
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
Steve Antona3a92c22017-12-07 10:27:41 -08002165 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002166 // Deserialize
2167 EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
2168 // Verify
2169 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2170}
2171
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002172TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
Steve Antona3a92c22017-12-07 10:27:41 -08002173 JsepSessionDescription jdesc(kDummyType);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002174 const char kSdpWithoutMline[] =
2175 "v=0\r\n"
2176 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2177 "s=-\r\n"
2178 "t=0 0\r\n"
2179 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
2180 // Deserialize
2181 EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
2182 EXPECT_EQ(0u, jdesc.description()->contents().size());
2183}
2184
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
Steve Antona3a92c22017-12-07 10:27:41 -08002186 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 std::string sdp_without_carriage_return = kSdpFullString;
2188 Replace("\r\n", "\n", &sdp_without_carriage_return);
2189 // Deserialize
2190 EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
2191 // Verify
2192 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2193}
2194
2195TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
2196 // SessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 10:27:41 -08002197 JsepSessionDescription jdesc_no_candidates(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002198 ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
2199 kSessionId, kSessionVersion));
Steve Antona3a92c22017-12-07 10:27:41 -08002200 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002201 EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
2202 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
2203}
2204
2205TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
2206 static const char kSdpNoRtpmapString[] =
2207 "v=0\r\n"
2208 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2209 "s=-\r\n"
2210 "t=0 0\r\n"
2211 "m=audio 49232 RTP/AVP 0 18 103\r\n"
2212 // Codec that doesn't appear in the m= line will be ignored.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002213 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 // The rtpmap line for static payload codec is optional.
2215 "a=rtpmap:18 G729/16000\r\n"
2216 "a=rtpmap:103 ISAC/16000\r\n";
2217
Steve Antona3a92c22017-12-07 10:27:41 -08002218 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002219 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2220 cricket::AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08002221 jdesc.description()
2222 ->GetContentDescriptionByName(cricket::CN_AUDIO)
2223 ->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002224 AudioCodecs ref_codecs;
deadbeef67cf2c12016-04-13 10:07:16 -07002225 // The codecs in the AudioContentDescription should be in the same order as
2226 // the payload types (<fmt>s) on the m= line.
2227 ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1));
2228 ref_codecs.push_back(AudioCodec(18, "G729", 16000, 0, 1));
ossue1405ad2017-01-23 08:55:48 -08002229 ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 0, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230 EXPECT_EQ(ref_codecs, audio->codecs());
2231}
2232
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002233TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
2234 static const char kSdpNoRtpmapString[] =
2235 "v=0\r\n"
2236 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2237 "s=-\r\n"
2238 "t=0 0\r\n"
2239 "m=audio 49232 RTP/AVP 18 103\r\n"
2240 "a=fmtp:18 annexb=yes\r\n"
2241 "a=rtpmap:103 ISAC/16000\r\n";
2242
Steve Antona3a92c22017-12-07 10:27:41 -08002243 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002244 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2245 cricket::AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08002246 jdesc.description()
2247 ->GetContentDescriptionByName(cricket::CN_AUDIO)
2248 ->as_audio();
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002249
2250 cricket::AudioCodec g729 = audio->codecs()[0];
2251 EXPECT_EQ("G729", g729.name);
2252 EXPECT_EQ(8000, g729.clockrate);
2253 EXPECT_EQ(18, g729.id);
2254 cricket::CodecParameterMap::iterator found =
2255 g729.params.find("annexb");
2256 ASSERT_TRUE(found != g729.params.end());
2257 EXPECT_EQ(found->second, "yes");
2258
2259 cricket::AudioCodec isac = audio->codecs()[1];
2260 EXPECT_EQ("ISAC", isac.name);
2261 EXPECT_EQ(103, isac.id);
2262 EXPECT_EQ(16000, isac.clockrate);
2263}
2264
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265// Ensure that we can deserialize SDP with a=fingerprint properly.
2266TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
2267 // Add a DTLS a=fingerprint attribute to our session description.
2268 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08002269 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002270 ASSERT_TRUE(new_jdesc.Initialize(desc_.Copy(),
2271 jdesc_.session_id(),
2272 jdesc_.session_version()));
2273
Steve Antona3a92c22017-12-07 10:27:41 -08002274 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002275 std::string sdp_with_fingerprint = kSdpString;
2276 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2277 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
2278 EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
2279 EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
2280}
2281
2282TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
Steve Antona3a92c22017-12-07 10:27:41 -08002283 JsepSessionDescription jdesc_with_bundle(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002284 std::string sdp_with_bundle = kSdpFullString;
2285 InjectAfter(kSessionTime,
2286 "a=group:BUNDLE audio_content_name video_content_name\r\n",
2287 &sdp_with_bundle);
2288 EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
2289 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
2290 group.AddContentName(kAudioContentName);
2291 group.AddContentName(kVideoContentName);
2292 desc_.AddGroup(group);
2293 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
2294 jdesc_.session_id(),
2295 jdesc_.session_version()));
2296 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
2297}
2298
2299TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
Steve Antona3a92c22017-12-07 10:27:41 -08002300 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002301 std::string sdp_with_bandwidth = kSdpFullString;
2302 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
2303 "b=AS:100\r\n",
2304 &sdp_with_bandwidth);
2305 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
2306 "b=AS:50\r\n",
2307 &sdp_with_bandwidth);
2308 EXPECT_TRUE(
2309 SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
Steve Antonb1c1de12017-12-21 15:14:30 -08002310 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002311 vcd->set_bandwidth(100 * 1000);
Steve Antonb1c1de12017-12-21 15:14:30 -08002312 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002313 acd->set_bandwidth(50 * 1000);
2314 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
2315 jdesc_.session_id(),
2316 jdesc_.session_version()));
2317 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2318}
2319
2320TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
Steve Antona3a92c22017-12-07 10:27:41 -08002321 JsepSessionDescription jdesc_with_ice_options(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002322 std::string sdp_with_ice_options = kSdpFullString;
2323 InjectAfter(kSessionTime,
2324 "a=ice-options:iceoption3\r\n",
2325 &sdp_with_ice_options);
2326 InjectAfter(kAttributeIcePwdVoice,
2327 "a=ice-options:iceoption1\r\n",
2328 &sdp_with_ice_options);
2329 InjectAfter(kAttributeIcePwdVideo,
2330 "a=ice-options:iceoption2\r\n",
2331 &sdp_with_ice_options);
2332 EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
2333 std::vector<std::string> transport_options;
2334 transport_options.push_back(kIceOption3);
2335 transport_options.push_back(kIceOption1);
2336 AddIceOptions(kAudioContentName, transport_options);
2337 transport_options.clear();
2338 transport_options.push_back(kIceOption3);
2339 transport_options.push_back(kIceOption2);
2340 AddIceOptions(kVideoContentName, transport_options);
2341 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
2342 jdesc_.session_id(),
2343 jdesc_.session_version()));
2344 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
2345}
2346
2347TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
2348 // Remove the original ice-ufrag and ice-pwd
Steve Antona3a92c22017-12-07 10:27:41 -08002349 JsepSessionDescription jdesc_with_ufrag_pwd(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002350 std::string sdp_with_ufrag_pwd = kSdpFullString;
2351 EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
2352 // Add session level ufrag and pwd
2353 InjectAfter(kSessionTime,
2354 "a=ice-pwd:session+level+icepwd\r\n"
2355 "a=ice-ufrag:session+level+iceufrag\r\n",
2356 &sdp_with_ufrag_pwd);
2357 // Add media level ufrag and pwd for audio
2358 InjectAfter("a=mid:audio_content_name\r\n",
2359 "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
2360 &sdp_with_ufrag_pwd);
2361 // Update the candidate ufrag and pwd to the expected ones.
2362 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0,
2363 "media+level+iceufrag", "media+level+icepwd"));
2364 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1,
2365 "session+level+iceufrag", "session+level+icepwd"));
2366 EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
2367 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
2368}
2369
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002371 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002372}
2373
2374TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002375 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002376}
2377
2378TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002379 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380}
2381
2382TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
2383 EXPECT_TRUE(TestDeserializeRejected(true, false));
2384}
2385
2386TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
2387 EXPECT_TRUE(TestDeserializeRejected(false, true));
2388}
2389
2390TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
2391 EXPECT_TRUE(TestDeserializeRejected(true, true));
2392}
2393
2394// Tests that we can still handle the sdp uses mslabel and label instead of
2395// msid for backward compatibility.
2396TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMsid) {
deadbeefc80741f2015-10-22 13:14:45 -07002397 jdesc_.description()->set_msid_supported(false);
Steve Antona3a92c22017-12-07 10:27:41 -08002398 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002399 std::string sdp_without_msid = kSdpFullString;
2400 Replace("msid", "xmsid", &sdp_without_msid);
2401 // Deserialize
2402 EXPECT_TRUE(SdpDeserialize(sdp_without_msid, &jdesc));
2403 // Verify
2404 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2405}
2406
2407TEST_F(WebRtcSdpTest, DeserializeCandidate) {
2408 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2409
2410 std::string sdp = kSdpOneCandidate;
2411 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2412 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2413 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2414 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
honghaiza0c44ea2016-03-23 16:07:48 -07002415 EXPECT_EQ(0, jcandidate.candidate().network_cost());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002416
2417 // Candidate line without generation extension.
2418 sdp = kSdpOneCandidate;
2419 Replace(" generation 2", "", &sdp);
2420 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2421 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2422 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2423 Candidate expected = jcandidate_->candidate();
2424 expected.set_generation(0);
2425 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2426
honghaiza0c44ea2016-03-23 16:07:48 -07002427 // Candidate with network id and/or cost.
2428 sdp = kSdpOneCandidate;
2429 Replace(" generation 2", " generation 2 network-id 2", &sdp);
2430 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2431 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2432 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2433 expected = jcandidate_->candidate();
2434 expected.set_network_id(2);
2435 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2436 EXPECT_EQ(0, jcandidate.candidate().network_cost());
2437 // Add network cost
2438 Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
2439 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2440 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2441 EXPECT_EQ(9, jcandidate.candidate().network_cost());
2442
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002443 sdp = kSdpTcpActiveCandidate;
2444 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2445 // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00002446 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00002447 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2448 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2449 kCandidateFoundation1);
kwibergd1fe2812016-04-27 06:47:29 -07002450 std::unique_ptr<IceCandidateInterface> jcandidate_template(
2451 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002452 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(
2453 jcandidate_template->candidate()));
2454 sdp = kSdpTcpPassiveCandidate;
2455 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2456 sdp = kSdpTcpSOCandidate;
2457 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002458}
2459
2460// This test verifies the deserialization of candidate-attribute
2461// as per RFC 5245. Candiate-attribute will be of the format
2462// candidate:<blah>. This format will be used when candidates
2463// are trickled.
2464TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
2465 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2466
2467 std::string candidate_attribute = kRawCandidate;
2468 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2469 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2470 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2471 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2472 EXPECT_EQ(2u, jcandidate.candidate().generation());
2473
2474 // Candidate line without generation extension.
2475 candidate_attribute = kRawCandidate;
2476 Replace(" generation 2", "", &candidate_attribute);
2477 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2478 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2479 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2480 Candidate expected = jcandidate_->candidate();
2481 expected.set_generation(0);
2482 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2483
2484 // Candidate line without candidate:
2485 candidate_attribute = kRawCandidate;
2486 Replace("candidate:", "", &candidate_attribute);
2487 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2488
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002489 // Candidate line with IPV6 address.
2490 EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
2491}
2492
2493// This test verifies that the deserialization of an invalid candidate string
2494// fails.
2495TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
2496 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2497
2498 std::string candidate_attribute = kRawCandidate;
2499 candidate_attribute.replace(0, 1, "x");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002500 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002501
2502 candidate_attribute = kSdpOneCandidate;
2503 candidate_attribute.replace(0, 1, "x");
2504 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2505
2506 candidate_attribute = kRawCandidate;
2507 candidate_attribute.append("\r\n");
2508 candidate_attribute.append(kRawCandidate);
2509 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2510
2511 EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512}
2513
2514TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannels) {
2515 AddRtpDataChannel();
Steve Antona3a92c22017-12-07 10:27:41 -08002516 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2518
2519 std::string sdp_with_data = kSdpString;
2520 sdp_with_data.append(kSdpRtpDataChannelString);
Steve Antona3a92c22017-12-07 10:27:41 -08002521 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002522
2523 // Deserialize
2524 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2525 // Verify
2526 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2527}
2528
2529TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
zstein4b2e0822017-02-17 19:48:38 -08002530 bool use_sctpmap = true;
2531 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002532 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002533 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2534
2535 std::string sdp_with_data = kSdpString;
2536 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Antona3a92c22017-12-07 10:27:41 -08002537 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002538
lally@webrtc.org36300852015-02-24 20:19:35 +00002539 // Verify with DTLS/SCTP (already in kSdpSctpDataChannelString).
2540 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2541 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2542
2543 // Verify with UDP/DTLS/SCTP.
2544 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
2545 strlen(kDtlsSctp), kUdpDtlsSctp);
2546 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2547 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2548
2549 // Verify with TCP/DTLS/SCTP.
2550 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
2551 strlen(kUdpDtlsSctp), kTcpDtlsSctp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002552 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2553 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2554}
2555
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002556TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
zstein4b2e0822017-02-17 19:48:38 -08002557 bool use_sctpmap = false;
2558 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002559 JsepSessionDescription jdesc(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002560 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2561
2562 std::string sdp_with_data = kSdpString;
2563 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Antona3a92c22017-12-07 10:27:41 -08002564 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002565
lally@webrtc.org36300852015-02-24 20:19:35 +00002566 // Verify with DTLS/SCTP (already in kSdpSctpDataChannelStringWithSctpPort).
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002567 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2568 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002569
lally@webrtc.org36300852015-02-24 20:19:35 +00002570 // Verify with UDP/DTLS/SCTP.
2571 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
2572 strlen(kDtlsSctp), kUdpDtlsSctp);
2573 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2574 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
lally@webrtc.orgc7848b72015-02-24 20:19:26 +00002575
lally@webrtc.org36300852015-02-24 20:19:35 +00002576 // Verify with TCP/DTLS/SCTP.
2577 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
2578 strlen(kUdpDtlsSctp), kTcpDtlsSctp);
lally@webrtc.orgc7848b72015-02-24 20:19:26 +00002579 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2580 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2581}
2582
lally69f57602015-10-08 10:15:04 -07002583TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) {
zstein4b2e0822017-02-17 19:48:38 -08002584 bool use_sctpmap = false;
2585 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002586 JsepSessionDescription jdesc(kDummyType);
lally69f57602015-10-08 10:15:04 -07002587 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2588
2589 std::string sdp_with_data = kSdpString;
2590 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
Steve Antona3a92c22017-12-07 10:27:41 -08002591 JsepSessionDescription jdesc_output(kDummyType);
lally69f57602015-10-08 10:15:04 -07002592
2593 // Verify with DTLS/SCTP.
2594 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2595 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2596
2597 // Verify with UDP/DTLS/SCTP.
2598 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp),
2599 strlen(kDtlsSctp), kUdpDtlsSctp);
2600 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2601 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2602
2603 // Verify with TCP/DTLS/SCTP.
2604 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp),
2605 strlen(kUdpDtlsSctp), kTcpDtlsSctp);
2606 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2607 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2608}
2609
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002610// Test to check the behaviour if sctp-port is specified
2611// on the m= line and in a=sctp-port.
2612TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
zstein4b2e0822017-02-17 19:48:38 -08002613 bool use_sctpmap = true;
2614 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002615 JsepSessionDescription jdesc(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002616 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2617
2618 std::string sdp_with_data = kSdpString;
2619 // Append m= attributes
2620 sdp_with_data.append(kSdpSctpDataChannelString);
2621 // Append a=sctp-port attribute
2622 sdp_with_data.append("a=sctp-port 5000\r\n");
Steve Antona3a92c22017-12-07 10:27:41 -08002623 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002624
2625 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2626}
2627
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00002628// For crbug/344475.
2629TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
2630 std::string sdp_with_data = kSdpString;
2631 sdp_with_data.append(kSdpSctpDataChannelString);
2632 // Remove the "\n" at the end.
2633 sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
Steve Antona3a92c22017-12-07 10:27:41 -08002634 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00002635
2636 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2637 // No crash is a pass.
2638}
2639
Steve Anton36b29d12017-10-30 09:57:42 -07002640void MutateJsepSctpPort(JsepSessionDescription* jdesc,
zstein4b2e0822017-02-17 19:48:38 -08002641 const SessionDescription& desc) {
wu@webrtc.org78187522013-10-07 23:32:02 +00002642 // take our pre-built session description and change the SCTP port.
zstein4b2e0822017-02-17 19:48:38 -08002643 cricket::SessionDescription* mutant = desc.Copy();
Steve Antonb1c1de12017-12-21 15:14:30 -08002644 DataContentDescription* dcdesc =
2645 mutant->GetContentDescriptionByName(kDataContentName)->as_data();
wu@webrtc.org78187522013-10-07 23:32:02 +00002646 std::vector<cricket::DataCodec> codecs(dcdesc->codecs());
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00002647 EXPECT_EQ(1U, codecs.size());
solenberg9fa49752016-10-08 13:02:44 -07002648 EXPECT_EQ(cricket::kGoogleSctpDataCodecPlType, codecs[0].id);
wu@webrtc.org78187522013-10-07 23:32:02 +00002649 codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002650 dcdesc->set_codecs(codecs);
wu@webrtc.org78187522013-10-07 23:32:02 +00002651
2652 // note: mutant's owned by jdesc now.
Steve Anton36b29d12017-10-30 09:57:42 -07002653 ASSERT_TRUE(jdesc->Initialize(mutant, kSessionId, kSessionVersion));
wu@webrtc.org78187522013-10-07 23:32:02 +00002654 mutant = NULL;
zstein4b2e0822017-02-17 19:48:38 -08002655}
2656
2657TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) {
2658 bool use_sctpmap = true;
2659 AddSctpDataChannel(use_sctpmap);
2660
2661 // First setup the expected JsepSessionDescription.
Steve Antona3a92c22017-12-07 10:27:41 -08002662 JsepSessionDescription jdesc(kDummyType);
Steve Anton36b29d12017-10-30 09:57:42 -07002663 MutateJsepSctpPort(&jdesc, desc_);
wu@webrtc.org78187522013-10-07 23:32:02 +00002664
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002665 // Then get the deserialized JsepSessionDescription.
wu@webrtc.org78187522013-10-07 23:32:02 +00002666 std::string sdp_with_data = kSdpString;
2667 sdp_with_data.append(kSdpSctpDataChannelString);
zstein4b2e0822017-02-17 19:48:38 -08002668 rtc::replace_substrs(kDefaultSctpPortStr, strlen(kDefaultSctpPortStr),
2669 kUnusualSctpPortStr, strlen(kUnusualSctpPortStr),
2670 &sdp_with_data);
Steve Antona3a92c22017-12-07 10:27:41 -08002671 JsepSessionDescription jdesc_output(kDummyType);
wu@webrtc.org78187522013-10-07 23:32:02 +00002672
2673 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2674 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
zstein4b2e0822017-02-17 19:48:38 -08002675}
2676
2677TEST_F(WebRtcSdpTest,
2678 DeserializeSdpWithSctpDataChannelAndUnusualPortInAttribute) {
2679 bool use_sctpmap = false;
2680 AddSctpDataChannel(use_sctpmap);
2681
Steve Antona3a92c22017-12-07 10:27:41 -08002682 JsepSessionDescription jdesc(kDummyType);
Steve Anton36b29d12017-10-30 09:57:42 -07002683 MutateJsepSctpPort(&jdesc, desc_);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002684
2685 // We need to test the deserialized JsepSessionDescription from
2686 // kSdpSctpDataChannelStringWithSctpPort for
2687 // draft-ietf-mmusic-sctp-sdp-07
2688 // a=sctp-port
zstein4b2e0822017-02-17 19:48:38 -08002689 std::string sdp_with_data = kSdpString;
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002690 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
zstein4b2e0822017-02-17 19:48:38 -08002691 rtc::replace_substrs(kDefaultSctpPortStr, strlen(kDefaultSctpPortStr),
2692 kUnusualSctpPortStr, strlen(kUnusualSctpPortStr),
2693 &sdp_with_data);
Steve Antona3a92c22017-12-07 10:27:41 -08002694 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002695
2696 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2697 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
wu@webrtc.org78187522013-10-07 23:32:02 +00002698}
2699
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002700TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002701 // We want to test that deserializing data content limits bandwidth
2702 // settings (it should never be greater than the default).
2703 // This should prevent someone from using unlimited data bandwidth through
2704 // JS and "breaking the Internet".
2705 // See: https://code.google.com/p/chromium/issues/detail?id=280726
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002706 std::string sdp_with_bandwidth = kSdpString;
2707 sdp_with_bandwidth.append(kSdpRtpDataChannelString);
2708 InjectAfter("a=mid:data_content_name\r\n",
2709 "b=AS:100\r\n",
2710 &sdp_with_bandwidth);
Steve Antona3a92c22017-12-07 10:27:41 -08002711 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002712
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002713 EXPECT_FALSE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2714}
2715
2716TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
zstein4b2e0822017-02-17 19:48:38 -08002717 bool use_sctpmap = true;
2718 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002719 JsepSessionDescription jdesc(kDummyType);
Steve Antonb1c1de12017-12-21 15:14:30 -08002720 DataContentDescription* dcd = GetFirstDataContentDescription(&desc_);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002721 dcd->set_bandwidth(100 * 1000);
2722 ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
2723
2724 std::string sdp_with_bandwidth = kSdpString;
2725 sdp_with_bandwidth.append(kSdpSctpDataChannelString);
2726 InjectAfter("a=mid:data_content_name\r\n",
2727 "b=AS:100\r\n",
2728 &sdp_with_bandwidth);
Steve Antona3a92c22017-12-07 10:27:41 -08002729 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002730
2731 // SCTP has congestion control, so we shouldn't limit the bandwidth
2732 // as we do for RTP.
2733 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002734 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
2735}
2736
jbauch5869f502017-06-29 12:31:36 -07002737class WebRtcSdpExtmapTest
2738 : public WebRtcSdpTest, public testing::WithParamInterface<bool> {
2739};
2740
2741TEST_P(WebRtcSdpExtmapTest,
2742 DeserializeSessionDescriptionWithSessionLevelExtmap) {
2743 bool encrypted = GetParam();
2744 TestDeserializeExtmap(true, false, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745}
2746
jbauch5869f502017-06-29 12:31:36 -07002747TEST_P(WebRtcSdpExtmapTest,
2748 DeserializeSessionDescriptionWithMediaLevelExtmap) {
2749 bool encrypted = GetParam();
2750 TestDeserializeExtmap(false, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002751}
2752
jbauch5869f502017-06-29 12:31:36 -07002753TEST_P(WebRtcSdpExtmapTest,
2754 DeserializeSessionDescriptionWithInvalidExtmap) {
2755 bool encrypted = GetParam();
2756 TestDeserializeExtmap(true, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002757}
2758
jbauch5869f502017-06-29 12:31:36 -07002759INSTANTIATE_TEST_CASE_P(Encrypted,
2760 WebRtcSdpExtmapTest,
2761 ::testing::Values(false, true));
2762
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00002763TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
Steve Antona3a92c22017-12-07 10:27:41 -08002764 JsepSessionDescription jdesc(kDummyType);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00002765 std::string sdp = kSdpFullString;
2766 sdp = sdp.substr(0, sdp.size() - 2); // Remove \r\n at the end.
2767 // Deserialize
2768 SdpParseError error;
2769 EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
deadbeef9d3584c2016-02-16 17:54:10 -08002770 const std::string lastline = "a=ssrc:3 label:video_track_id_1";
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00002771 EXPECT_EQ(lastline, error.line);
2772 EXPECT_EQ("Invalid SDP line.", error.description);
2773}
2774
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002775TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
2776 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2777 std::string new_sdp = kSdpOneCandidate;
2778 Replace("udp", "unsupported_transport", &new_sdp);
2779 EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
2780 new_sdp = kSdpOneCandidate;
2781 Replace("udp", "uDP", &new_sdp);
2782 EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
2783 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2784 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2785 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2786}
2787
honghaiza54a0802015-12-16 18:37:23 -08002788TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
honghaiza54a0802015-12-16 18:37:23 -08002790 EXPECT_TRUE(
2791 SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002792 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2793 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2794 Candidate ref_candidate = jcandidate_->candidate();
2795 ref_candidate.set_username("user_rtp");
2796 ref_candidate.set_password("password_rtp");
2797 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
2798}
2799
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002800TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 10:27:41 -08002801 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002802
2803 // Deserialize
2804 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
2805
2806 // Verify
2807 cricket::AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08002808 jdesc.description()
2809 ->GetContentDescriptionByName(cricket::CN_AUDIO)
2810 ->as_audio();
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002811 EXPECT_TRUE(audio->conference_mode());
2812
2813 cricket::VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08002814 jdesc.description()
2815 ->GetContentDescriptionByName(cricket::CN_VIDEO)
2816 ->as_video();
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002817 EXPECT_TRUE(video->conference_mode());
2818}
2819
deadbeefd45aea82017-09-16 01:24:29 -07002820TEST_F(WebRtcSdpTest, SerializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 10:27:41 -08002821 JsepSessionDescription jdesc(kDummyType);
deadbeefd45aea82017-09-16 01:24:29 -07002822
2823 // We tested deserialization already above, so just test that if we serialize
2824 // and deserialize the flag doesn't disappear.
2825 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
Steve Antone831b8c2018-02-01 12:22:16 -08002826 std::string reserialized = webrtc::SdpSerialize(jdesc);
deadbeefd45aea82017-09-16 01:24:29 -07002827 EXPECT_TRUE(SdpDeserialize(reserialized, &jdesc));
2828
2829 // Verify.
2830 cricket::AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08002831 jdesc.description()
2832 ->GetContentDescriptionByName(cricket::CN_AUDIO)
2833 ->as_audio();
deadbeefd45aea82017-09-16 01:24:29 -07002834 EXPECT_TRUE(audio->conference_mode());
2835
2836 cricket::VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08002837 jdesc.description()
2838 ->GetContentDescriptionByName(cricket::CN_VIDEO)
2839 ->as_video();
deadbeefd45aea82017-09-16 01:24:29 -07002840 EXPECT_TRUE(video->conference_mode());
2841}
2842
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002843TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
2844 const char kSdpDestroyer[] = "!@#$%^&";
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002845 const char kSdpEmptyType[] = " =candidate";
2846 const char kSdpEqualAsPlus[] = "a+candidate";
2847 const char kSdpSpaceAfterEqual[] = "a= candidate";
2848 const char kSdpUpperType[] = "A=candidate";
2849 const char kSdpEmptyLine[] = "";
2850 const char kSdpMissingValue[] = "a=";
2851
2852 const char kSdpBrokenFingerprint[] = "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002853 "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 +00002854 const char kSdpExtraField[] = "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002855 "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 +00002856 const char kSdpMissingSpace[] = "a=fingerprint:sha-1"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002857 "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 +00002858 // MD5 is not allowed in fingerprints.
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002859 const char kSdpMd5[] = "a=fingerprint:md5 "
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00002860 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861
2862 // Broken session description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002863 ExpectParseFailure("v=", kSdpDestroyer);
2864 ExpectParseFailure("o=", kSdpDestroyer);
2865 ExpectParseFailure("s=-", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002866 // Broken time description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002867 ExpectParseFailure("t=", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002868
2869 // Broken media description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002870 ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
2871 ExpectParseFailure("m=video", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002872
2873 // Invalid lines
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002874 ExpectParseFailure("a=candidate", kSdpEmptyType);
2875 ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
2876 ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
2877 ExpectParseFailure("a=candidate", kSdpUpperType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002878
2879 // Bogus fingerprint replacing a=sendrev. We selected this attribute
2880 // because it's orthogonal to what we are replacing and hence
2881 // safe.
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00002882 ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
2883 ExpectParseFailure("a=sendrecv", kSdpExtraField);
2884 ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
2885 ExpectParseFailure("a=sendrecv", kSdpMd5);
2886
2887 // Empty Line
2888 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
2889 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002890}
2891
2892TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
2893 // ssrc
2894 ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
deadbeef9d3584c2016-02-16 17:54:10 -08002895 ExpectParseFailure("a=ssrc-group:FEC 2 3", "a=ssrc-group:FEC badvalue 3");
wu@webrtc.org5e760e72014-04-02 23:19:09 +00002896 // crypto
2897 ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
2898 // rtpmap
2899 ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
2900 ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
2901 ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
2902 // candidate
2903 ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
2904 ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
2905 ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
2906 ExpectParseFailure("rport 2346", "rport badvalue");
2907 ExpectParseFailure("rport 2346 generation 2",
2908 "rport 2346 generation badvalue");
2909 // m line
2910 ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
2911 "m=audio 2345 RTP/SAVPF 111 badvalue 104");
2912
2913 // bandwidth
2914 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
2915 "b=AS:badvalue\r\n",
2916 "b=AS:badvalue");
2917 // rtcp-fb
2918 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
2919 "a=rtcp-fb:badvalue nack\r\n",
2920 "a=rtcp-fb:badvalue nack");
2921 // extmap
2922 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
2923 "a=extmap:badvalue http://example.com\r\n",
2924 "a=extmap:badvalue http://example.com");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002925}
2926
2927TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
Steve Antona3a92c22017-12-07 10:27:41 -08002928 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002929
2930 const char kSdpWithReorderedPlTypesString[] =
2931 "v=0\r\n"
2932 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2933 "s=-\r\n"
2934 "t=0 0\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00002935 "m=audio 9 RTP/SAVPF 104 103\r\n" // Pl type 104 preferred.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002936 "a=rtpmap:111 opus/48000/2\r\n" // Pltype 111 listed before 103 and 104
2937 // in the map.
2938 "a=rtpmap:103 ISAC/16000\r\n" // Pltype 103 listed before 104 in the map.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002939 "a=rtpmap:104 ISAC/32000\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002940
2941 // Deserialize
2942 EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
2943
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002944 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002945 GetFirstAudioContentDescription(jdesc_output.description());
2946 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002947 ASSERT_FALSE(acd->codecs().empty());
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002948 EXPECT_EQ("ISAC", acd->codecs()[0].name);
2949 EXPECT_EQ(32000, acd->codecs()[0].clockrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002950 EXPECT_EQ(104, acd->codecs()[0].id);
2951}
2952
2953TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
Steve Antona3a92c22017-12-07 10:27:41 -08002954 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002955 CodecParams params;
2956 params.max_ptime = 40;
2957 params.ptime = 30;
2958 params.min_ptime = 10;
2959 params.sprop_stereo = 1;
2960 params.stereo = 1;
2961 params.useinband = 1;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002962 params.maxaveragebitrate = 128000;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963 TestDeserializeCodecParams(params, &jdesc_output);
Steve Antone831b8c2018-02-01 12:22:16 -08002964 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002965}
2966
2967TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
2968 const bool kUseWildcard = false;
Steve Antona3a92c22017-12-07 10:27:41 -08002969 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002970 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 12:22:16 -08002971 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002972}
2973
2974TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
2975 const bool kUseWildcard = true;
Steve Antona3a92c22017-12-07 10:27:41 -08002976 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 12:22:16 -08002978 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979}
2980
2981TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
Steve Antona3a92c22017-12-07 10:27:41 -08002982 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002983
2984 const char kSdpWithFmtpString[] =
2985 "v=0\r\n"
2986 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2987 "s=-\r\n"
2988 "t=0 0\r\n"
2989 "m=video 3457 RTP/SAVPF 120\r\n"
2990 "a=rtpmap:120 VP8/90000\r\n"
Donald Curtis0e07f922015-05-15 09:21:23 -07002991 "a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
2992
2993 // Deserialize
2994 SdpParseError error;
Donald Curtis144d0182015-05-15 13:14:24 -07002995 EXPECT_TRUE(
2996 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
Donald Curtis0e07f922015-05-15 09:21:23 -07002997
Donald Curtis0e07f922015-05-15 09:21:23 -07002998 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002999 GetFirstVideoContentDescription(jdesc_output.description());
3000 ASSERT_TRUE(vcd);
Donald Curtis0e07f922015-05-15 09:21:23 -07003001 ASSERT_FALSE(vcd->codecs().empty());
3002 cricket::VideoCodec vp8 = vcd->codecs()[0];
3003 EXPECT_EQ("VP8", vp8.name);
3004 EXPECT_EQ(120, vp8.id);
3005 cricket::CodecParameterMap::iterator found =
3006 vp8.params.find("x-google-min-bitrate");
3007 ASSERT_TRUE(found != vp8.params.end());
3008 EXPECT_EQ(found->second, "10");
3009 found = vp8.params.find("x-google-max-quantization");
3010 ASSERT_TRUE(found != vp8.params.end());
3011 EXPECT_EQ(found->second, "40");
3012}
3013
johan2d8d23e2016-06-03 01:22:42 -07003014TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSprops) {
Steve Antona3a92c22017-12-07 10:27:41 -08003015 JsepSessionDescription jdesc_output(kDummyType);
johan2d8d23e2016-06-03 01:22:42 -07003016
3017 const char kSdpWithFmtpString[] =
3018 "v=0\r\n"
3019 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3020 "s=-\r\n"
3021 "t=0 0\r\n"
3022 "m=video 49170 RTP/AVP 98\r\n"
3023 "a=rtpmap:98 H264/90000\r\n"
3024 "a=fmtp:98 profile-level-id=42A01E; "
3025 "sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==\r\n";
3026
3027 // Deserialize.
3028 SdpParseError error;
3029 EXPECT_TRUE(
3030 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
3031
johan2d8d23e2016-06-03 01:22:42 -07003032 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003033 GetFirstVideoContentDescription(jdesc_output.description());
3034 ASSERT_TRUE(vcd);
johan2d8d23e2016-06-03 01:22:42 -07003035 ASSERT_FALSE(vcd->codecs().empty());
3036 cricket::VideoCodec h264 = vcd->codecs()[0];
3037 EXPECT_EQ("H264", h264.name);
3038 EXPECT_EQ(98, h264.id);
3039 cricket::CodecParameterMap::const_iterator found =
3040 h264.params.find("profile-level-id");
3041 ASSERT_TRUE(found != h264.params.end());
3042 EXPECT_EQ(found->second, "42A01E");
3043 found = h264.params.find("sprop-parameter-sets");
3044 ASSERT_TRUE(found != h264.params.end());
3045 EXPECT_EQ(found->second, "Z0IACpZTBYmI,aMljiA==");
3046}
3047
Donald Curtis0e07f922015-05-15 09:21:23 -07003048TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
Steve Antona3a92c22017-12-07 10:27:41 -08003049 JsepSessionDescription jdesc_output(kDummyType);
Donald Curtis0e07f922015-05-15 09:21:23 -07003050
3051 const char kSdpWithFmtpString[] =
3052 "v=0\r\n"
3053 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3054 "s=-\r\n"
3055 "t=0 0\r\n"
3056 "m=video 3457 RTP/SAVPF 120\r\n"
3057 "a=rtpmap:120 VP8/90000\r\n"
3058 "a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003059
3060 // Deserialize
3061 SdpParseError error;
3062 EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output,
3063 &error));
3064
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003065 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003066 GetFirstVideoContentDescription(jdesc_output.description());
3067 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003068 ASSERT_FALSE(vcd->codecs().empty());
3069 cricket::VideoCodec vp8 = vcd->codecs()[0];
3070 EXPECT_EQ("VP8", vp8.name);
3071 EXPECT_EQ(120, vp8.id);
3072 cricket::CodecParameterMap::iterator found =
3073 vp8.params.find("x-google-min-bitrate");
3074 ASSERT_TRUE(found != vp8.params.end());
3075 EXPECT_EQ(found->second, "10");
3076 found = vp8.params.find("x-google-max-quantization");
3077 ASSERT_TRUE(found != vp8.params.end());
3078 EXPECT_EQ(found->second, "40");
3079}
3080
ossuaa4b0772017-01-30 07:41:18 -08003081TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithUnknownParameter) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003082 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003083
3084 cricket::AudioCodecs codecs = acd->codecs();
3085 codecs[0].params["unknown-future-parameter"] = "SomeFutureValue";
3086 acd->set_codecs(codecs);
3087
3088 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
3089 jdesc_.session_id(),
3090 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003091 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003092 std::string sdp_with_fmtp = kSdpFullString;
3093 InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
3094 "a=fmtp:111 unknown-future-parameter=SomeFutureValue\r\n",
3095 &sdp_with_fmtp);
3096 EXPECT_EQ(sdp_with_fmtp, message);
3097}
3098
3099TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithKnownFmtpParameter) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003100 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003101
3102 cricket::AudioCodecs codecs = acd->codecs();
3103 codecs[0].params["stereo"] = "1";
3104 acd->set_codecs(codecs);
3105
3106 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
3107 jdesc_.session_id(),
3108 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003109 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003110 std::string sdp_with_fmtp = kSdpFullString;
3111 InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
3112 "a=fmtp:111 stereo=1\r\n",
3113 &sdp_with_fmtp);
3114 EXPECT_EQ(sdp_with_fmtp, message);
3115}
3116
3117TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithPTimeAndMaxPTime) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003118 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003119
3120 cricket::AudioCodecs codecs = acd->codecs();
3121 codecs[0].params["ptime"] = "20";
3122 codecs[0].params["maxptime"] = "120";
3123 acd->set_codecs(codecs);
3124
3125 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
3126 jdesc_.session_id(),
3127 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003128 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003129 std::string sdp_with_fmtp = kSdpFullString;
3130 InjectAfter("a=rtpmap:104 ISAC/32000\r\n",
3131 "a=maxptime:120\r\n" // No comma here. String merging!
3132 "a=ptime:20\r\n",
3133 &sdp_with_fmtp);
3134 EXPECT_EQ(sdp_with_fmtp, message);
3135}
3136
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003137TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003138 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003139
3140 cricket::VideoCodecs codecs = vcd->codecs();
3141 codecs[0].params["x-google-min-bitrate"] = "10";
3142 vcd->set_codecs(codecs);
3143
3144 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
3145 jdesc_.session_id(),
3146 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003147 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148 std::string sdp_with_fmtp = kSdpFullString;
3149 InjectAfter("a=rtpmap:120 VP8/90000\r\n",
3150 "a=fmtp:120 x-google-min-bitrate=10\r\n",
3151 &sdp_with_fmtp);
3152 EXPECT_EQ(sdp_with_fmtp, message);
3153}
3154
3155TEST_F(WebRtcSdpTest, DeserializeSdpWithIceLite) {
Steve Antona3a92c22017-12-07 10:27:41 -08003156 JsepSessionDescription jdesc_with_icelite(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003157 std::string sdp_with_icelite = kSdpFullString;
3158 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3159 cricket::SessionDescription* desc = jdesc_with_icelite.description();
3160 const cricket::TransportInfo* tinfo1 =
3161 desc->GetTransportInfoByName("audio_content_name");
3162 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
3163 const cricket::TransportInfo* tinfo2 =
3164 desc->GetTransportInfoByName("video_content_name");
3165 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
3166 InjectAfter(kSessionTime,
3167 "a=ice-lite\r\n",
3168 &sdp_with_icelite);
3169 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3170 desc = jdesc_with_icelite.description();
3171 const cricket::TransportInfo* atinfo =
3172 desc->GetTransportInfoByName("audio_content_name");
3173 EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
3174 const cricket::TransportInfo* vtinfo =
3175 desc->GetTransportInfoByName("video_content_name");
3176 EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
3177}
3178
3179// Verifies that the candidates in the input SDP are parsed and serialized
3180// correctly in the output SDP.
3181TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
3182 std::string sdp_with_data = kSdpString;
3183 sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
Steve Antona3a92c22017-12-07 10:27:41 -08003184 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003185
3186 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
Steve Antone831b8c2018-02-01 12:22:16 -08003187 EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003188}
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003189
3190TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
3191 AddFingerprint();
3192 TransportInfo audio_transport_info =
3193 *(desc_.GetTransportInfoByName(kAudioContentName));
3194 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3195 audio_transport_info.description.connection_role);
3196 audio_transport_info.description.connection_role =
3197 cricket::CONNECTIONROLE_ACTIVE;
3198
3199 TransportInfo video_transport_info =
3200 *(desc_.GetTransportInfoByName(kVideoContentName));
3201 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3202 video_transport_info.description.connection_role);
3203 video_transport_info.description.connection_role =
3204 cricket::CONNECTIONROLE_ACTIVE;
3205
3206 desc_.RemoveTransportInfoByName(kAudioContentName);
3207 desc_.RemoveTransportInfoByName(kVideoContentName);
3208
3209 desc_.AddTransportInfo(audio_transport_info);
3210 desc_.AddTransportInfo(video_transport_info);
3211
3212 ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
3213 jdesc_.session_id(),
3214 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003215 std::string message = webrtc::SdpSerialize(jdesc_);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003216 std::string sdp_with_dtlssetup = kSdpFullString;
3217
3218 // Fingerprint attribute is necessary to add DTLS setup attribute.
3219 InjectAfter(kAttributeIcePwdVoice,
3220 kFingerprint, &sdp_with_dtlssetup);
3221 InjectAfter(kAttributeIcePwdVideo,
3222 kFingerprint, &sdp_with_dtlssetup);
3223 // Now adding |setup| attribute.
3224 InjectAfter(kFingerprint,
3225 "a=setup:active\r\n", &sdp_with_dtlssetup);
3226 EXPECT_EQ(sdp_with_dtlssetup, message);
3227}
3228
3229TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttribute) {
Steve Antona3a92c22017-12-07 10:27:41 -08003230 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003231 std::string sdp_with_dtlssetup = kSdpFullString;
3232 InjectAfter(kSessionTime,
3233 "a=setup:actpass\r\n",
3234 &sdp_with_dtlssetup);
3235 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3236 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3237 const cricket::TransportInfo* atinfo =
3238 desc->GetTransportInfoByName("audio_content_name");
3239 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3240 atinfo->description.connection_role);
3241 const cricket::TransportInfo* vtinfo =
3242 desc->GetTransportInfoByName("video_content_name");
3243 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3244 vtinfo->description.connection_role);
3245}
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003246
3247// Verifies that the order of the serialized m-lines follows the order of the
3248// ContentInfo in SessionDescription, and vise versa for deserialization.
3249TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
Steve Antona3a92c22017-12-07 10:27:41 -08003250 JsepSessionDescription jdesc(kDummyType);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003251 const std::string media_content_sdps[3] = {
3252 kSdpAudioString,
3253 kSdpVideoString,
3254 kSdpSctpDataChannelString
3255 };
3256 const cricket::MediaType media_types[3] = {
3257 cricket::MEDIA_TYPE_AUDIO,
3258 cricket::MEDIA_TYPE_VIDEO,
3259 cricket::MEDIA_TYPE_DATA
3260 };
3261
3262 // Verifies all 6 permutations.
3263 for (size_t i = 0; i < 6; ++i) {
3264 size_t media_content_in_sdp[3];
3265 // The index of the first media content.
3266 media_content_in_sdp[0] = i / 2;
3267 // The index of the second media content.
3268 media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
3269 // The index of the third media content.
3270 media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
3271
3272 std::string sdp_string = kSdpSessionString;
3273 for (size_t i = 0; i < 3; ++i)
3274 sdp_string += media_content_sdps[media_content_in_sdp[i]];
3275
3276 EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
3277 cricket::SessionDescription* desc = jdesc.description();
3278 EXPECT_EQ(3u, desc->contents().size());
3279
3280 for (size_t i = 0; i < 3; ++i) {
3281 const cricket::MediaContentDescription* mdesc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003282 desc->contents()[i].media_description();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003283 EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
3284 }
3285
Steve Antone831b8c2018-02-01 12:22:16 -08003286 std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003287 EXPECT_EQ(sdp_string, serialized_sdp);
3288 }
3289}
deadbeef9d3584c2016-02-16 17:54:10 -08003290
deadbeef25ed4352016-12-12 18:37:36 -08003291TEST_F(WebRtcSdpTest, DeserializeBundleOnlyAttribute) {
3292 MakeBundleOnlyDescription();
Steve Antona3a92c22017-12-07 10:27:41 -08003293 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 13:53:47 -08003294 ASSERT_TRUE(
deadbeef25ed4352016-12-12 18:37:36 -08003295 SdpDeserialize(kBundleOnlySdpFullString, &deserialized_description));
3296 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3297}
3298
deadbeef12771a12017-01-03 13:53:47 -08003299// The semantics of "a=bundle-only" are only defined when it's used in
3300// combination with a 0 port on the m= line. We should ignore it if used with a
3301// nonzero port.
3302TEST_F(WebRtcSdpTest, IgnoreBundleOnlyWithNonzeroPort) {
3303 // Make the base bundle-only description but unset the bundle-only flag.
3304 MakeBundleOnlyDescription();
3305 jdesc_.description()->contents()[1].bundle_only = false;
3306
3307 std::string modified_sdp = kBundleOnlySdpFullString;
3308 Replace("m=video 0", "m=video 9", &modified_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08003309 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 13:53:47 -08003310 ASSERT_TRUE(SdpDeserialize(modified_sdp, &deserialized_description));
3311 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
deadbeef25ed4352016-12-12 18:37:36 -08003312}
3313
3314TEST_F(WebRtcSdpTest, SerializeBundleOnlyAttribute) {
3315 MakeBundleOnlyDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003316 TestSerialize(jdesc_);
deadbeef25ed4352016-12-12 18:37:36 -08003317}
3318
deadbeef9d3584c2016-02-16 17:54:10 -08003319TEST_F(WebRtcSdpTest, DeserializePlanBSessionDescription) {
3320 MakePlanBDescription();
3321
Steve Antona3a92c22017-12-07 10:27:41 -08003322 JsepSessionDescription deserialized_description(kDummyType);
deadbeef9d3584c2016-02-16 17:54:10 -08003323 EXPECT_TRUE(SdpDeserialize(kPlanBSdpFullString, &deserialized_description));
3324
3325 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3326}
3327
3328TEST_F(WebRtcSdpTest, SerializePlanBSessionDescription) {
3329 MakePlanBDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003330 TestSerialize(jdesc_);
deadbeef9d3584c2016-02-16 17:54:10 -08003331}
3332
3333TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescription) {
3334 MakeUnifiedPlanDescription();
3335
Steve Antona3a92c22017-12-07 10:27:41 -08003336 JsepSessionDescription deserialized_description(kDummyType);
deadbeef9d3584c2016-02-16 17:54:10 -08003337 EXPECT_TRUE(
3338 SdpDeserialize(kUnifiedPlanSdpFullString, &deserialized_description));
3339
3340 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3341}
3342
3343TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescription) {
3344 MakeUnifiedPlanDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003345 TestSerialize(jdesc_);
3346}
3347
Seth Hampson5b4f0752018-04-02 16:31:36 -07003348// This tests deserializing a Unified Plan SDP that is compatible with both
3349// Unified Plan and Plan B style SDP. It tests the case for audio/video tracks
3350// with no stream ids and multiple stream ids. For parsing this, the Unified
3351// Plan a=msid lines should take priority, because the Plan B style a=ssrc msid
3352// lines do not support multiple stream ids and no stream ids.
3353TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescriptionSpecialMsid) {
3354 MakeUnifiedPlanDescriptionMultipleStreamIds();
3355
3356 JsepSessionDescription deserialized_description(kDummyType);
3357 EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
3358 &deserialized_description));
3359
3360 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3361}
3362
3363TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescriptionSpecialMsid) {
3364 MakeUnifiedPlanDescriptionMultipleStreamIds();
3365 TestSerialize(jdesc_);
3366}
3367
Steve Antone831b8c2018-02-01 12:22:16 -08003368TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
3369 JsepSessionDescription jsep_desc(kDummyType);
3370 ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
3371 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
3372}
3373
3374TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
3375 JsepSessionDescription jsep_desc(kDummyType);
3376 std::string sdp = kSdpSessionString;
3377 sdp += kSdpSctpDataChannelString;
3378 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3379 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
3380}
3381
3382TEST_F(WebRtcSdpTest, PlanBHasSsrcAttributeMsidSignaling) {
3383 JsepSessionDescription jsep_desc(kDummyType);
3384 ASSERT_TRUE(SdpDeserialize(kPlanBSdpFullString, &jsep_desc));
3385 EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
3386 jsep_desc.description()->msid_signaling());
3387}
3388
3389TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
3390 JsepSessionDescription jsep_desc(kDummyType);
3391 ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
3392 EXPECT_EQ(cricket::kMsidSignalingMediaSection,
3393 jsep_desc.description()->msid_signaling());
3394}
3395
3396const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";
3397const char kSsrcAttributeMsidLine[] =
3398 "a=ssrc:1 msid:local_stream_1 audio_track_id_1";
3399
3400TEST_F(WebRtcSdpTest, SerializeOnlyMediaSectionMsid) {
3401 jdesc_.description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
3402 std::string sdp = webrtc::SdpSerialize(jdesc_);
3403
3404 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
3405 EXPECT_EQ(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
3406}
3407
3408TEST_F(WebRtcSdpTest, SerializeOnlySsrcAttributeMsid) {
3409 jdesc_.description()->set_msid_signaling(
3410 cricket::kMsidSignalingSsrcAttribute);
3411 std::string sdp = webrtc::SdpSerialize(jdesc_);
3412
3413 EXPECT_EQ(std::string::npos, sdp.find(kMediaSectionMsidLine));
3414 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
3415}
3416
3417TEST_F(WebRtcSdpTest, SerializeBothMediaSectionAndSsrcAttributeMsid) {
3418 jdesc_.description()->set_msid_signaling(
3419 cricket::kMsidSignalingMediaSection |
3420 cricket::kMsidSignalingSsrcAttribute);
3421 std::string sdp = webrtc::SdpSerialize(jdesc_);
3422
3423 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
3424 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
deadbeef9d3584c2016-02-16 17:54:10 -08003425}
deadbeef7e146cb2016-09-28 10:04:34 -07003426
3427// Regression test for heap overflow bug:
3428// https://bugs.chromium.org/p/chromium/issues/detail?id=647916
3429TEST_F(WebRtcSdpTest, DeserializeSctpPortInVideoDescription) {
deadbeef7e146cb2016-09-28 10:04:34 -07003430 // The issue occurs when the sctp-port attribute is found in a video
3431 // description. The actual heap overflow occurs when parsing the fmtp line.
deadbeef7bcdb692017-01-20 12:43:58 -08003432 static const char kSdpWithSctpPortInVideoDescription[] =
deadbeef7e146cb2016-09-28 10:04:34 -07003433 "v=0\r\n"
3434 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3435 "s=-\r\n"
3436 "t=0 0\r\n"
3437 "m=video 9 UDP/DTLS/SCTP 120\r\n"
3438 "a=sctp-port 5000\r\n"
3439 "a=fmtp:108 foo=10\r\n";
3440
3441 ExpectParseFailure(std::string(kSdpWithSctpPortInVideoDescription),
3442 "sctp-port");
3443}
deadbeefb2362572016-12-13 16:37:06 -08003444
3445// Regression test for integer overflow bug:
3446// https://bugs.chromium.org/p/chromium/issues/detail?id=648071
3447TEST_F(WebRtcSdpTest, DeserializeLargeBandwidthLimit) {
deadbeefb2362572016-12-13 16:37:06 -08003448 // Bandwidth attribute is the max signed 32-bit int, which will get
3449 // multiplied by 1000 and cause int overflow if not careful.
deadbeef7bcdb692017-01-20 12:43:58 -08003450 static const char kSdpWithLargeBandwidth[] =
deadbeefb2362572016-12-13 16:37:06 -08003451 "v=0\r\n"
3452 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3453 "s=-\r\n"
3454 "t=0 0\r\n"
3455 "m=video 3457 RTP/SAVPF 120\r\n"
3456 "b=AS:2147483647\r\n"
3457 "foo=fail\r\n";
3458
3459 ExpectParseFailure(std::string(kSdpWithLargeBandwidth), "foo=fail");
3460}
deadbeef7bcdb692017-01-20 12:43:58 -08003461
deadbeefbc88c6b2017-08-02 11:26:34 -07003462// Similar to the above, except that negative values are illegal, not just
3463// error-prone as large values are.
3464// https://bugs.chromium.org/p/chromium/issues/detail?id=675361
3465TEST_F(WebRtcSdpTest, DeserializingNegativeBandwidthLimitFails) {
3466 static const char kSdpWithNegativeBandwidth[] =
3467 "v=0\r\n"
3468 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3469 "s=-\r\n"
3470 "t=0 0\r\n"
3471 "m=video 3457 RTP/SAVPF 120\r\n"
3472 "b=AS:-1000\r\n";
3473
3474 ExpectParseFailure(std::string(kSdpWithNegativeBandwidth), "b=AS:-1000");
3475}
3476
deadbeef3e8016e2017-08-03 17:49:30 -07003477// An exception to the above rule: a value of -1 for b=AS should just be
3478// ignored, resulting in "kAutoBandwidth" in the deserialized object.
3479// Applications historically may be using "b=AS:-1" to mean "no bandwidth
3480// limit", but this is now what ommitting the attribute entirely will do, so
3481// ignoring it will have the intended effect.
3482TEST_F(WebRtcSdpTest, BandwidthLimitOfNegativeOneIgnored) {
3483 static const char kSdpWithBandwidthOfNegativeOne[] =
3484 "v=0\r\n"
3485 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3486 "s=-\r\n"
3487 "t=0 0\r\n"
3488 "m=video 3457 RTP/SAVPF 120\r\n"
3489 "b=AS:-1\r\n";
3490
Steve Antona3a92c22017-12-07 10:27:41 -08003491 JsepSessionDescription jdesc_output(kDummyType);
deadbeef3e8016e2017-08-03 17:49:30 -07003492 EXPECT_TRUE(SdpDeserialize(kSdpWithBandwidthOfNegativeOne, &jdesc_output));
deadbeef3e8016e2017-08-03 17:49:30 -07003493 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003494 GetFirstVideoContentDescription(jdesc_output.description());
3495 ASSERT_TRUE(vcd);
deadbeef3e8016e2017-08-03 17:49:30 -07003496 EXPECT_EQ(cricket::kAutoBandwidth, vcd->bandwidth());
3497}
3498
deadbeef7bcdb692017-01-20 12:43:58 -08003499// Test that "ufrag"/"pwd" in the candidate line itself are ignored, and only
3500// the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
3501// Regression test for:
3502// https://bugs.chromium.org/p/chromium/issues/detail?id=681286
3503TEST_F(WebRtcSdpTest, IceCredentialsInCandidateStringIgnored) {
3504 // Important piece is "ufrag foo pwd bar".
3505 static const char kSdpWithIceCredentialsInCandidateString[] =
3506 "v=0\r\n"
3507 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3508 "s=-\r\n"
3509 "t=0 0\r\n"
3510 "m=audio 9 RTP/SAVPF 111\r\n"
3511 "c=IN IP4 0.0.0.0\r\n"
3512 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
3513 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
3514 "a=rtpmap:111 opus/48000/2\r\n"
3515 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
3516 "generation 2 ufrag foo pwd bar\r\n";
3517
Steve Antona3a92c22017-12-07 10:27:41 -08003518 JsepSessionDescription jdesc_output(kDummyType);
deadbeef7bcdb692017-01-20 12:43:58 -08003519 EXPECT_TRUE(
3520 SdpDeserialize(kSdpWithIceCredentialsInCandidateString, &jdesc_output));
3521 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
3522 ASSERT_NE(nullptr, candidates);
3523 ASSERT_EQ(1, candidates->count());
3524 cricket::Candidate c = candidates->at(0)->candidate();
3525 EXPECT_EQ("ufrag_voice", c.username());
3526 EXPECT_EQ("pwd_voice", c.password());
3527}
deadbeef90f1e1e2017-02-10 12:35:05 -08003528
3529// Test that SDP with an invalid port number in "a=candidate" lines is
3530// rejected, without crashing.
3531// Regression test for:
3532// https://bugs.chromium.org/p/chromium/issues/detail?id=677029
3533TEST_F(WebRtcSdpTest, DeserializeInvalidPortInCandidateAttribute) {
3534 static const char kSdpWithInvalidCandidatePort[] =
3535 "v=0\r\n"
3536 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3537 "s=-\r\n"
3538 "t=0 0\r\n"
3539 "m=audio 9 RTP/SAVPF 111\r\n"
3540 "c=IN IP4 0.0.0.0\r\n"
3541 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
3542 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
3543 "a=rtpmap:111 opus/48000/2\r\n"
3544 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 12345678 typ host "
3545 "generation 2 raddr 192.168.1.1 rport 87654321\r\n";
3546
Steve Antona3a92c22017-12-07 10:27:41 -08003547 JsepSessionDescription jdesc_output(kDummyType);
deadbeef90f1e1e2017-02-10 12:35:05 -08003548 EXPECT_FALSE(SdpDeserialize(kSdpWithInvalidCandidatePort, &jdesc_output));
3549}
deadbeefa4549d62017-02-10 17:26:22 -08003550
3551// Test that "a=msid" with a missing track ID is rejected and doesn't crash.
3552// Regression test for:
3553// https://bugs.chromium.org/p/chromium/issues/detail?id=686405
3554TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingTrackId) {
3555 static const char kSdpWithMissingTrackId[] =
3556 "v=0\r\n"
3557 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3558 "s=-\r\n"
3559 "t=0 0\r\n"
3560 "m=audio 9 RTP/SAVPF 111\r\n"
3561 "c=IN IP4 0.0.0.0\r\n"
3562 "a=rtpmap:111 opus/48000/2\r\n"
3563 "a=msid:stream_id \r\n";
3564
Steve Antona3a92c22017-12-07 10:27:41 -08003565 JsepSessionDescription jdesc_output(kDummyType);
deadbeefa4549d62017-02-10 17:26:22 -08003566 EXPECT_FALSE(SdpDeserialize(kSdpWithMissingTrackId, &jdesc_output));
3567}
3568
3569TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingStreamId) {
3570 static const char kSdpWithMissingStreamId[] =
3571 "v=0\r\n"
3572 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3573 "s=-\r\n"
3574 "t=0 0\r\n"
3575 "m=audio 9 RTP/SAVPF 111\r\n"
3576 "c=IN IP4 0.0.0.0\r\n"
3577 "a=rtpmap:111 opus/48000/2\r\n"
3578 "a=msid: track_id\r\n";
3579
Steve Antona3a92c22017-12-07 10:27:41 -08003580 JsepSessionDescription jdesc_output(kDummyType);
deadbeefa4549d62017-02-10 17:26:22 -08003581 EXPECT_FALSE(SdpDeserialize(kSdpWithMissingStreamId, &jdesc_output));
3582}
zhihuang38989e52017-03-21 11:04:53 -07003583
3584// Tests that if both session-level address and media-level address exist, use
3585// the media-level address.
3586TEST_F(WebRtcSdpTest, ParseConnectionData) {
Steve Antona3a92c22017-12-07 10:27:41 -08003587 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07003588
3589 // Sesssion-level address.
3590 std::string sdp = kSdpFullString;
3591 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
3592 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3593
3594 const auto& content1 = jsep_desc.description()->contents()[0];
3595 EXPECT_EQ("74.125.127.126:2345",
Steve Antonb1c1de12017-12-21 15:14:30 -08003596 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07003597 const auto& content2 = jsep_desc.description()->contents()[1];
3598 EXPECT_EQ("74.125.224.39:3457",
Steve Antonb1c1de12017-12-21 15:14:30 -08003599 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07003600}
3601
3602// Tests that the session-level connection address will be used if the media
3603// level-addresses are not specified.
3604TEST_F(WebRtcSdpTest, ParseConnectionDataSessionLevelOnly) {
Steve Antona3a92c22017-12-07 10:27:41 -08003605 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07003606
3607 // Sesssion-level address.
3608 std::string sdp = kSdpString;
3609 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
3610 // Remove the media level addresses.
3611 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
3612 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
3613 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3614
3615 const auto& content1 = jsep_desc.description()->contents()[0];
3616 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08003617 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07003618 const auto& content2 = jsep_desc.description()->contents()[1];
3619 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08003620 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07003621}
3622
3623TEST_F(WebRtcSdpTest, ParseConnectionDataIPv6) {
Steve Antona3a92c22017-12-07 10:27:41 -08003624 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07003625
3626 std::string sdp = kSdpString;
3627 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3628 Replace("m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP4 0.0.0.0\r\n",
3629 "m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP6 "
3630 "2001:0db8:85a3:0000:0000:8a2e:0370:7335\r\n",
3631 &sdp);
3632 Replace("m=video 9 RTP/SAVPF 120\r\nc=IN IP4 0.0.0.0\r\n",
3633 "m=video 9 RTP/SAVPF 120\r\nc=IN IP6 "
3634 "2001:0db8:85a3:0000:0000:8a2e:0370:7336\r\n",
3635 &sdp);
3636 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3637 const auto& content1 = jsep_desc.description()->contents()[0];
3638 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7335]:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08003639 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07003640 const auto& content2 = jsep_desc.description()->contents()[1];
3641 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7336]:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08003642 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07003643}
3644
3645// Test that the invalid or unsupprted connection data cannot be parsed.
3646TEST_F(WebRtcSdpTest, ParseConnectionDataFailure) {
Steve Antona3a92c22017-12-07 10:27:41 -08003647 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07003648 std::string sdp = kSdpString;
3649 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3650
3651 // Unsupported multicast IPv4 address.
3652 sdp = kSdpFullString;
3653 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP4 74.125.224.39/127\r\n", &sdp);
3654 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
3655
3656 // Unsupported multicast IPv6 address.
3657 sdp = kSdpFullString;
3658 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 ::1/3\r\n", &sdp);
3659 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
3660
3661 // Mismatched address type.
3662 sdp = kSdpFullString;
3663 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 74.125.224.39\r\n", &sdp);
3664 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
3665
3666 sdp = kSdpFullString;
3667 Replace("c=IN IP4 74.125.224.39\r\n",
3668 "c=IN IP4 2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n", &sdp);
3669 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
3670}
3671
3672TEST_F(WebRtcSdpTest, SerializeAndDeserializeWithConnectionAddress) {
Steve Antona3a92c22017-12-07 10:27:41 -08003673 JsepSessionDescription expected_jsep(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07003674 MakeDescriptionWithoutCandidates(&expected_jsep);
3675 // Serialization.
Steve Antone831b8c2018-02-01 12:22:16 -08003676 std::string message = webrtc::SdpSerialize(expected_jsep);
zhihuang38989e52017-03-21 11:04:53 -07003677 // Deserialization.
Steve Antona3a92c22017-12-07 10:27:41 -08003678 JsepSessionDescription jdesc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07003679 EXPECT_TRUE(SdpDeserialize(message, &jdesc));
Steve Antonb1c1de12017-12-21 15:14:30 -08003680 auto audio_desc = jdesc.description()
3681 ->GetContentByName(kAudioContentName)
3682 ->media_description();
3683 auto video_desc = jdesc.description()
3684 ->GetContentByName(kVideoContentName)
3685 ->media_description();
zhihuang38989e52017-03-21 11:04:53 -07003686 EXPECT_EQ(audio_desc_->connection_address().ToString(),
3687 audio_desc->connection_address().ToString());
3688 EXPECT_EQ(video_desc_->connection_address().ToString(),
3689 video_desc->connection_address().ToString());
3690}