blob: 5e7c225aa1f4b694d2df09ef4c504a23e8634fe1 [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
Yves Gerey3e707812018-11-28 16:47:49 +010011#include <stdio.h>
12#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020013
Harald Alvestrand4d7160e2019-04-12 07:01:29 +020014#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010015#include <cstdint>
16#include <map>
kwibergd1fe2812016-04-27 06:47:29 -070017#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000018#include <string>
Yves Gerey3e707812018-11-28 16:47:49 +010019#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000020#include <vector>
21
Steve Anton64b626b2019-01-28 17:25:26 -080022#include "absl/algorithm/container.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -080023#include "absl/memory/memory.h"
Steve Anton1c9c9fc2019-02-14 15:13:09 -080024#include "absl/strings/str_replace.h"
Yves Gerey3e707812018-11-28 16:47:49 +010025#include "api/array_view.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "api/crypto_params.h"
27#include "api/jsep_session_description.h"
28#include "api/media_types.h"
29#include "api/rtp_parameters.h"
30#include "api/rtp_transceiver_interface.h"
Yves Gerey3e707812018-11-28 16:47:49 +010031#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "media/base/media_constants.h"
33#include "media/base/stream_params.h"
34#include "p2p/base/p2p_constants.h"
Yves Gerey665174f2018-06-19 15:03:05 +020035#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "p2p/base/transport_description.h"
37#include "p2p/base/transport_info.h"
38#include "pc/media_session.h"
39#include "pc/session_description.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080041#include "rtc_base/message_digest.h"
42#include "rtc_base/socket_address.h"
43#include "rtc_base/ssl_fingerprint.h"
44#include "rtc_base/string_encode.h"
Steve Anton06817cd2018-12-18 15:55:30 -080045#include "test/gmock.h"
Yves Gerey3e707812018-11-28 16:47:49 +010046#include "test/gtest.h"
Patrik Höglund563934e2017-09-15 09:04:28 +020047
ossu7bb87ee2017-01-23 04:56:25 -080048#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080049#include "pc/test/android_test_initializer.h"
ossu7bb87ee2017-01-23 04:56:25 -080050#endif
Steve Anton10542f22019-01-11 09:11:00 -080051#include "pc/webrtc_sdp.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052
53using cricket::AudioCodec;
54using cricket::AudioContentDescription;
55using cricket::Candidate;
Steve Anton06817cd2018-12-18 15:55:30 -080056using cricket::ContentGroup;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057using cricket::ContentInfo;
58using cricket::CryptoParams;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::DataCodec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
61using cricket::ICE_CANDIDATE_COMPONENT_RTP;
62using cricket::kFecSsrcGroupSemantics;
63using cricket::LOCAL_PORT_TYPE;
Steve Anton5adfafd2017-12-20 16:34:00 -080064using cricket::MediaProtocolType;
Steve Anton06817cd2018-12-18 15:55:30 -080065using cricket::RELAY_PORT_TYPE;
Amit Hilbuchc57d5732018-12-11 15:30:11 -080066using cricket::RidDescription;
67using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020068using cricket::RtpDataContentDescription;
69using cricket::SctpDataContentDescription;
Steve Anton06817cd2018-12-18 15:55:30 -080070using cricket::SessionDescription;
Amit Hilbucha2012042018-12-03 11:35:05 -080071using cricket::SimulcastDescription;
72using cricket::SimulcastLayer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::StreamParams;
74using cricket::STUN_PORT_TYPE;
75using cricket::TransportDescription;
76using cricket::TransportInfo;
77using cricket::VideoCodec;
78using cricket::VideoContentDescription;
Steve Anton06817cd2018-12-18 15:55:30 -080079using ::testing::ElementsAre;
80using ::testing::Field;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081using webrtc::IceCandidateCollection;
82using webrtc::IceCandidateInterface;
83using webrtc::JsepIceCandidate;
84using webrtc::JsepSessionDescription;
isheriff6f8d6862016-05-26 11:24:55 -070085using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080086using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087using webrtc::SdpParseError;
Steve Antona3a92c22017-12-07 10:27:41 -080088using webrtc::SdpType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089using webrtc::SessionDescriptionInterface;
90
91typedef std::vector<AudioCodec> AudioCodecs;
92typedef std::vector<Candidate> Candidates;
93
Peter Boström0c4e06b2015-10-07 12:23:21 +020094static const uint32_t kDefaultSctpPort = 5000;
zstein4b2e0822017-02-17 19:48:38 -080095static const uint16_t kUnusualSctpPort = 9556;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096static const char kSessionTime[] = "t=0 0\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020097static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0
deadbeef3f7219b2015-12-28 15:17:14 -080098static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
deadbeef3f7219b2015-12-28 15:17:14 -0800100static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200102static const uint32_t kCandidateGeneration = 2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103static const char kCandidateFoundation1[] = "a0+B/1";
104static const char kCandidateFoundation2[] = "a0+B/2";
105static const char kCandidateFoundation3[] = "a0+B/3";
106static const char kCandidateFoundation4[] = "a0+B/4";
107static const char kAttributeCryptoVoice[] =
108 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
109 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
110 "dummy_session_params\r\n";
111static const char kAttributeCryptoVideo[] =
112 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
113 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
Yves Gerey665174f2018-06-19 15:03:05 +0200114static const char kFingerprint[] =
115 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n";
Johannes Kron0854eb62018-10-10 22:33:20 +0200117static const char kExtmapAllowMixed[] = "a=extmap-allow-mixed\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118static const int kExtmapId = 1;
119static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
120static const char kExtmap[] =
121 "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
122static const char kExtmapWithDirectionAndAttribute[] =
123 "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
jbauch5869f502017-06-29 12:31:36 -0700124static const char kExtmapWithDirectionAndAttributeEncrypted[] =
125 "a=extmap:1/sendrecv urn:ietf:params:rtp-hdrext:encrypt "
126 "http://example.com/082005/ext.htm#ttime a1 a2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
Peter Boström0c4e06b2015-10-07 12:23:21 +0200128static const uint8_t kIdentityDigest[] = {
129 0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
130 0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
lally@webrtc.org34807282015-02-24 20:19:39 +0000132static const char kDtlsSctp[] = "DTLS/SCTP";
133static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
134static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
lally@webrtc.org36300852015-02-24 20:19:35 +0000135
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136struct CodecParams {
137 int max_ptime;
138 int ptime;
139 int min_ptime;
140 int sprop_stereo;
141 int stereo;
142 int useinband;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000143 int maxaveragebitrate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144};
145
deadbeef9d3584c2016-02-16 17:54:10 -0800146// TODO(deadbeef): In these reference strings, use "a=fingerprint" by default
147// instead of "a=crypto", and have an explicit test for adding "a=crypto".
148// Currently it's the other way around.
149
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150// Reference sdp string
151static const char kSdpFullString[] =
152 "v=0\r\n"
153 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
154 "s=-\r\n"
155 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100156 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800157 "a=msid-semantic: WMS local_stream_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
159 "c=IN IP4 74.125.127.126\r\n"
160 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
161 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
162 "generation 2\r\n"
163 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
164 "generation 2\r\n"
165 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
166 "generation 2\r\n"
167 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
168 "generation 2\r\n"
169 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
170 "raddr 192.168.1.5 rport 2346 "
171 "generation 2\r\n"
172 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
173 "raddr 192.168.1.5 rport 2348 "
174 "generation 2\r\n"
175 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
176 "a=mid:audio_content_name\r\n"
177 "a=sendrecv\r\n"
178 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 12:37:51 -0800179 "a=rtcp-rsize\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
181 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
182 "dummy_session_params\r\n"
183 "a=rtpmap:111 opus/48000/2\r\n"
184 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000185 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000186 "a=ssrc:1 cname:stream_1_cname\r\n"
187 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000188 "a=ssrc:1 mslabel:local_stream_1\r\n"
189 "a=ssrc:1 label:audio_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190 "m=video 3457 RTP/SAVPF 120\r\n"
191 "c=IN IP4 74.125.224.39\r\n"
192 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
193 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
194 "generation 2\r\n"
195 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
196 "generation 2\r\n"
197 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
198 "generation 2\r\n"
199 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
200 "generation 2\r\n"
201 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
202 "generation 2\r\n"
203 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
204 "generation 2\r\n"
205 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
206 "a=mid:video_content_name\r\n"
207 "a=sendrecv\r\n"
208 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
209 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
210 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800211 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212 "a=ssrc:2 cname:stream_1_cname\r\n"
213 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000214 "a=ssrc:2 mslabel:local_stream_1\r\n"
215 "a=ssrc:2 label:video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216 "a=ssrc:3 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000217 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
218 "a=ssrc:3 mslabel:local_stream_1\r\n"
219 "a=ssrc:3 label:video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220
221// SDP reference string without the candidates.
222static const char kSdpString[] =
223 "v=0\r\n"
224 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
225 "s=-\r\n"
226 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100227 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800228 "a=msid-semantic: WMS local_stream_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000229 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000230 "c=IN IP4 0.0.0.0\r\n"
231 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000232 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
233 "a=mid:audio_content_name\r\n"
234 "a=sendrecv\r\n"
235 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 12:37:51 -0800236 "a=rtcp-rsize\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000237 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
238 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
239 "dummy_session_params\r\n"
240 "a=rtpmap:111 opus/48000/2\r\n"
241 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000242 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 "a=ssrc:1 cname:stream_1_cname\r\n"
244 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000245 "a=ssrc:1 mslabel:local_stream_1\r\n"
246 "a=ssrc:1 label:audio_track_id_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000247 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000248 "c=IN IP4 0.0.0.0\r\n"
249 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
251 "a=mid:video_content_name\r\n"
252 "a=sendrecv\r\n"
253 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
254 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
255 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800256 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257 "a=ssrc:2 cname:stream_1_cname\r\n"
258 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000259 "a=ssrc:2 mslabel:local_stream_1\r\n"
260 "a=ssrc:2 label:video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 "a=ssrc:3 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000262 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
263 "a=ssrc:3 mslabel:local_stream_1\r\n"
264 "a=ssrc:3 label:video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265
266static const char kSdpRtpDataChannelString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000267 "m=application 9 RTP/SAVPF 101\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000268 "c=IN IP4 0.0.0.0\r\n"
269 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 "a=ice-ufrag:ufrag_data\r\n"
271 "a=ice-pwd:pwd_data\r\n"
272 "a=mid:data_content_name\r\n"
273 "a=sendrecv\r\n"
274 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
275 "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5\r\n"
276 "a=rtpmap:101 google-data/90000\r\n"
277 "a=ssrc:10 cname:data_channel_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000278 "a=ssrc:10 msid:data_channel data_channeld0\r\n"
279 "a=ssrc:10 mslabel:data_channel\r\n"
280 "a=ssrc:10 label:data_channeld0\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000281
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200282// draft-ietf-mmusic-sctp-sdp-03
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283static const char kSdpSctpDataChannelString[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000284 "m=application 9 UDP/DTLS/SCTP 5000\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000285 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 "a=ice-ufrag:ufrag_data\r\n"
287 "a=ice-pwd:pwd_data\r\n"
288 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000289 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290
lally@webrtc.orgec97c652015-02-24 20:18:48 +0000291// draft-ietf-mmusic-sctp-sdp-12
Harald Alvestrand48cce4d2019-04-11 10:41:24 +0200292// Note - this is invalid per draft-ietf-mmusic-sctp-sdp-26,
293// since the separator after "sctp-port" needs to be a colon.
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +0000294static const char kSdpSctpDataChannelStringWithSctpPort[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000295 "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
lally@webrtc.orgc7848b72015-02-24 20:19:26 +0000296 "a=sctp-port 5000\r\n"
297 "c=IN IP4 0.0.0.0\r\n"
298 "a=ice-ufrag:ufrag_data\r\n"
299 "a=ice-pwd:pwd_data\r\n"
300 "a=mid:data_content_name\r\n";
301
Harald Alvestrand48cce4d2019-04-11 10:41:24 +0200302// draft-ietf-mmusic-sctp-sdp-26
lally69f57602015-10-08 10:15:04 -0700303static const char kSdpSctpDataChannelStringWithSctpColonPort[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000304 "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
lally69f57602015-10-08 10:15:04 -0700305 "a=sctp-port:5000\r\n"
306 "c=IN IP4 0.0.0.0\r\n"
307 "a=ice-ufrag:ufrag_data\r\n"
308 "a=ice-pwd:pwd_data\r\n"
309 "a=mid:data_content_name\r\n";
310
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000311static const char kSdpSctpDataChannelWithCandidatesString[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000312 "m=application 2345 UDP/DTLS/SCTP 5000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000313 "c=IN IP4 74.125.127.126\r\n"
314 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
315 "generation 2\r\n"
316 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
317 "generation 2\r\n"
318 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
319 "raddr 192.168.1.5 rport 2346 "
320 "generation 2\r\n"
321 "a=ice-ufrag:ufrag_data\r\n"
322 "a=ice-pwd:pwd_data\r\n"
323 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000324 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000325
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000326static const char kSdpConferenceString[] =
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000327 "v=0\r\n"
328 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
329 "s=-\r\n"
330 "t=0 0\r\n"
331 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000332 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000333 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000334 "a=x-google-flag:conference\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000335 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000336 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000337 "a=x-google-flag:conference\r\n";
338
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000339static const char kSdpSessionString[] =
340 "v=0\r\n"
341 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
342 "s=-\r\n"
343 "t=0 0\r\n"
344 "a=msid-semantic: WMS local_stream\r\n";
345
346static const char kSdpAudioString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000347 "m=audio 9 RTP/SAVPF 111\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000348 "c=IN IP4 0.0.0.0\r\n"
349 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000350 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
351 "a=mid:audio_content_name\r\n"
352 "a=sendrecv\r\n"
353 "a=rtpmap:111 opus/48000/2\r\n"
354 "a=ssrc:1 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000355 "a=ssrc:1 msid:local_stream audio_track_id_1\r\n"
356 "a=ssrc:1 mslabel:local_stream\r\n"
357 "a=ssrc:1 label:audio_track_id_1\r\n";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000358
359static const char kSdpVideoString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000360 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000361 "c=IN IP4 0.0.0.0\r\n"
362 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000363 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
364 "a=mid:video_content_name\r\n"
365 "a=sendrecv\r\n"
366 "a=rtpmap:120 VP8/90000\r\n"
367 "a=ssrc:2 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000368 "a=ssrc:2 msid:local_stream video_track_id_1\r\n"
369 "a=ssrc:2 mslabel:local_stream\r\n"
370 "a=ssrc:2 label:video_track_id_1\r\n";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000371
deadbeef25ed4352016-12-12 18:37:36 -0800372// Reference sdp string using bundle-only.
373static const char kBundleOnlySdpFullString[] =
374 "v=0\r\n"
375 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
376 "s=-\r\n"
377 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100378 "a=extmap-allow-mixed\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800379 "a=group:BUNDLE audio_content_name video_content_name\r\n"
380 "a=msid-semantic: WMS local_stream_1\r\n"
381 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
382 "c=IN IP4 74.125.127.126\r\n"
383 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
384 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
385 "generation 2\r\n"
386 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
387 "generation 2\r\n"
388 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
389 "generation 2\r\n"
390 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
391 "generation 2\r\n"
392 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
393 "raddr 192.168.1.5 rport 2346 "
394 "generation 2\r\n"
395 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
396 "raddr 192.168.1.5 rport 2348 "
397 "generation 2\r\n"
398 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
399 "a=mid:audio_content_name\r\n"
400 "a=sendrecv\r\n"
401 "a=rtcp-mux\r\n"
402 "a=rtcp-rsize\r\n"
403 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
404 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
405 "dummy_session_params\r\n"
406 "a=rtpmap:111 opus/48000/2\r\n"
407 "a=rtpmap:103 ISAC/16000\r\n"
408 "a=rtpmap:104 ISAC/32000\r\n"
409 "a=ssrc:1 cname:stream_1_cname\r\n"
410 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000411 "a=ssrc:1 mslabel:local_stream_1\r\n"
412 "a=ssrc:1 label:audio_track_id_1\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800413 "m=video 0 RTP/SAVPF 120\r\n"
414 "c=IN IP4 0.0.0.0\r\n"
415 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
416 "a=bundle-only\r\n"
417 "a=mid:video_content_name\r\n"
418 "a=sendrecv\r\n"
419 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
420 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
421 "a=rtpmap:120 VP8/90000\r\n"
422 "a=ssrc-group:FEC 2 3\r\n"
423 "a=ssrc:2 cname:stream_1_cname\r\n"
424 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000425 "a=ssrc:2 mslabel:local_stream_1\r\n"
426 "a=ssrc:2 label:video_track_id_1\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800427 "a=ssrc:3 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000428 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
429 "a=ssrc:3 mslabel:local_stream_1\r\n"
430 "a=ssrc:3 label:video_track_id_1\r\n";
deadbeef25ed4352016-12-12 18:37:36 -0800431
deadbeef9d3584c2016-02-16 17:54:10 -0800432// Plan B SDP reference string, with 2 streams, 2 audio tracks and 3 video
433// tracks.
434static const char kPlanBSdpFullString[] =
435 "v=0\r\n"
436 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
437 "s=-\r\n"
438 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100439 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800440 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
441 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
442 "c=IN IP4 74.125.127.126\r\n"
443 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
444 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
445 "generation 2\r\n"
446 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
447 "generation 2\r\n"
448 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
449 "generation 2\r\n"
450 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
451 "generation 2\r\n"
452 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
453 "raddr 192.168.1.5 rport 2346 "
454 "generation 2\r\n"
455 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
456 "raddr 192.168.1.5 rport 2348 "
457 "generation 2\r\n"
458 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
459 "a=mid:audio_content_name\r\n"
460 "a=sendrecv\r\n"
461 "a=rtcp-mux\r\n"
462 "a=rtcp-rsize\r\n"
463 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
464 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
465 "dummy_session_params\r\n"
466 "a=rtpmap:111 opus/48000/2\r\n"
467 "a=rtpmap:103 ISAC/16000\r\n"
468 "a=rtpmap:104 ISAC/32000\r\n"
469 "a=ssrc:1 cname:stream_1_cname\r\n"
470 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000471 "a=ssrc:1 mslabel:local_stream_1\r\n"
472 "a=ssrc:1 label:audio_track_id_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800473 "a=ssrc:4 cname:stream_2_cname\r\n"
474 "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000475 "a=ssrc:4 mslabel:local_stream_2\r\n"
476 "a=ssrc:4 label:audio_track_id_2\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800477 "m=video 3457 RTP/SAVPF 120\r\n"
478 "c=IN IP4 74.125.224.39\r\n"
479 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
480 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
481 "generation 2\r\n"
482 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
483 "generation 2\r\n"
484 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
485 "generation 2\r\n"
486 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
487 "generation 2\r\n"
488 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
489 "generation 2\r\n"
490 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
491 "generation 2\r\n"
492 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
493 "a=mid:video_content_name\r\n"
494 "a=sendrecv\r\n"
495 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
496 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
497 "a=rtpmap:120 VP8/90000\r\n"
498 "a=ssrc-group:FEC 2 3\r\n"
499 "a=ssrc:2 cname:stream_1_cname\r\n"
500 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000501 "a=ssrc:2 mslabel:local_stream_1\r\n"
502 "a=ssrc:2 label:video_track_id_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800503 "a=ssrc:3 cname:stream_1_cname\r\n"
504 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000505 "a=ssrc:3 mslabel:local_stream_1\r\n"
506 "a=ssrc:3 label:video_track_id_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800507 "a=ssrc:5 cname:stream_2_cname\r\n"
508 "a=ssrc:5 msid:local_stream_2 video_track_id_2\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000509 "a=ssrc:5 mslabel:local_stream_2\r\n"
510 "a=ssrc:5 label:video_track_id_2\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800511 "a=ssrc:6 cname:stream_2_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000512 "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
513 "a=ssrc:6 mslabel:local_stream_2\r\n"
514 "a=ssrc:6 label:video_track_id_3\r\n";
deadbeef9d3584c2016-02-16 17:54:10 -0800515
516// Unified Plan SDP reference string, with 2 streams, 2 audio tracks and 3 video
517// tracks.
518static const char kUnifiedPlanSdpFullString[] =
519 "v=0\r\n"
520 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
521 "s=-\r\n"
522 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100523 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800524 "a=msid-semantic: WMS local_stream_1\r\n"
525 // Audio track 1, stream 1 (with candidates).
526 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
527 "c=IN IP4 74.125.127.126\r\n"
528 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
529 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
530 "generation 2\r\n"
531 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
532 "generation 2\r\n"
533 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
534 "generation 2\r\n"
535 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
536 "generation 2\r\n"
537 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
538 "raddr 192.168.1.5 rport 2346 "
539 "generation 2\r\n"
540 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
541 "raddr 192.168.1.5 rport 2348 "
542 "generation 2\r\n"
543 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
544 "a=mid:audio_content_name\r\n"
545 "a=msid:local_stream_1 audio_track_id_1\r\n"
546 "a=sendrecv\r\n"
547 "a=rtcp-mux\r\n"
548 "a=rtcp-rsize\r\n"
549 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
550 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
551 "dummy_session_params\r\n"
552 "a=rtpmap:111 opus/48000/2\r\n"
553 "a=rtpmap:103 ISAC/16000\r\n"
554 "a=rtpmap:104 ISAC/32000\r\n"
555 "a=ssrc:1 cname:stream_1_cname\r\n"
556 // Video track 1, stream 1 (with candidates).
557 "m=video 3457 RTP/SAVPF 120\r\n"
558 "c=IN IP4 74.125.224.39\r\n"
559 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
560 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
561 "generation 2\r\n"
562 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
563 "generation 2\r\n"
564 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
565 "generation 2\r\n"
566 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
567 "generation 2\r\n"
568 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
569 "generation 2\r\n"
570 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
571 "generation 2\r\n"
572 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
573 "a=mid:video_content_name\r\n"
574 "a=msid:local_stream_1 video_track_id_1\r\n"
575 "a=sendrecv\r\n"
576 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
577 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
578 "a=rtpmap:120 VP8/90000\r\n"
579 "a=ssrc-group:FEC 2 3\r\n"
580 "a=ssrc:2 cname:stream_1_cname\r\n"
581 "a=ssrc:3 cname:stream_1_cname\r\n"
582 // Audio track 2, stream 2.
583 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
584 "c=IN IP4 0.0.0.0\r\n"
585 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
586 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
587 "a=mid:audio_content_name_2\r\n"
588 "a=msid:local_stream_2 audio_track_id_2\r\n"
589 "a=sendrecv\r\n"
590 "a=rtcp-mux\r\n"
591 "a=rtcp-rsize\r\n"
592 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
593 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
594 "dummy_session_params\r\n"
595 "a=rtpmap:111 opus/48000/2\r\n"
596 "a=rtpmap:103 ISAC/16000\r\n"
597 "a=rtpmap:104 ISAC/32000\r\n"
598 "a=ssrc:4 cname:stream_2_cname\r\n"
599 // Video track 2, stream 2.
600 "m=video 9 RTP/SAVPF 120\r\n"
601 "c=IN IP4 0.0.0.0\r\n"
602 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
603 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
604 "a=mid:video_content_name_2\r\n"
605 "a=msid:local_stream_2 video_track_id_2\r\n"
606 "a=sendrecv\r\n"
607 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
608 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
609 "a=rtpmap:120 VP8/90000\r\n"
610 "a=ssrc:5 cname:stream_2_cname\r\n"
611 // Video track 3, stream 2.
612 "m=video 9 RTP/SAVPF 120\r\n"
613 "c=IN IP4 0.0.0.0\r\n"
614 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
615 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
616 "a=mid:video_content_name_3\r\n"
617 "a=msid:local_stream_2 video_track_id_3\r\n"
618 "a=sendrecv\r\n"
619 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
620 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
621 "a=rtpmap:120 VP8/90000\r\n"
622 "a=ssrc:6 cname:stream_2_cname\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623
Seth Hampson5b4f0752018-04-02 16:31:36 -0700624// Unified Plan SDP reference string:
625// - audio track 1 has 1 a=msid lines
626// - audio track 2 has 2 a=msid lines
627// - audio track 3 has 1 a=msid line with the special "-" marker signifying that
628// there are 0 media stream ids.
629// This Unified Plan SDP represents a SDP that signals the msid using both
630// a=msid and a=ssrc msid semantics.
631static const char kUnifiedPlanSdpFullStringWithSpecialMsid[] =
632 "v=0\r\n"
633 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
634 "s=-\r\n"
635 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100636 "a=extmap-allow-mixed\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700637 "a=msid-semantic: WMS local_stream_1\r\n"
638 // Audio track 1, with 1 stream id.
639 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
640 "c=IN IP4 74.125.127.126\r\n"
641 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
642 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
643 "generation 2\r\n"
644 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
645 "generation 2\r\n"
646 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
647 "generation 2\r\n"
648 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
649 "generation 2\r\n"
650 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
651 "raddr 192.168.1.5 rport 2346 "
652 "generation 2\r\n"
653 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
654 "raddr 192.168.1.5 rport 2348 "
655 "generation 2\r\n"
656 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
657 "a=mid:audio_content_name\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700658 "a=sendrecv\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700659 "a=msid:local_stream_1 audio_track_id_1\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700660 "a=rtcp-mux\r\n"
661 "a=rtcp-rsize\r\n"
662 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
663 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
664 "dummy_session_params\r\n"
665 "a=rtpmap:111 opus/48000/2\r\n"
666 "a=rtpmap:103 ISAC/16000\r\n"
667 "a=rtpmap:104 ISAC/32000\r\n"
668 "a=ssrc:1 cname:stream_1_cname\r\n"
669 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000670 "a=ssrc:1 mslabel:local_stream_1\r\n"
671 "a=ssrc:1 label:audio_track_id_1\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700672 // Audio track 2, with two stream ids.
673 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
674 "c=IN IP4 0.0.0.0\r\n"
675 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
676 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
677 "a=mid:audio_content_name_2\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700678 "a=sendrecv\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700679 "a=msid:local_stream_1 audio_track_id_2\r\n"
680 "a=msid:local_stream_2 audio_track_id_2\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700681 "a=rtcp-mux\r\n"
682 "a=rtcp-rsize\r\n"
683 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
684 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
685 "dummy_session_params\r\n"
686 "a=rtpmap:111 opus/48000/2\r\n"
687 "a=rtpmap:103 ISAC/16000\r\n"
688 "a=rtpmap:104 ISAC/32000\r\n"
689 "a=ssrc:4 cname:stream_1_cname\r\n"
690 // The support for Plan B msid signaling only includes the
691 // first media stream id "local_stream_1."
692 "a=ssrc:4 msid:local_stream_1 audio_track_id_2\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000693 "a=ssrc:4 mslabel:local_stream_1\r\n"
694 "a=ssrc:4 label:audio_track_id_2\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700695 // Audio track 3, with no stream ids.
696 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
697 "c=IN IP4 0.0.0.0\r\n"
698 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
699 "a=ice-ufrag:ufrag_voice_3\r\na=ice-pwd:pwd_voice_3\r\n"
700 "a=mid:audio_content_name_3\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700701 "a=sendrecv\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700702 "a=msid:- audio_track_id_3\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700703 "a=rtcp-mux\r\n"
704 "a=rtcp-rsize\r\n"
705 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
706 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
707 "dummy_session_params\r\n"
708 "a=rtpmap:111 opus/48000/2\r\n"
709 "a=rtpmap:103 ISAC/16000\r\n"
710 "a=rtpmap:104 ISAC/32000\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700711 "a=ssrc:7 cname:stream_2_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000712 "a=ssrc:7 msid:- audio_track_id_3\r\n"
713 "a=ssrc:7 mslabel:-\r\n"
714 "a=ssrc:7 label:audio_track_id_3\r\n";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700715
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800716// SDP string for unified plan without SSRCs
717static const char kUnifiedPlanSdpFullStringNoSsrc[] =
718 "v=0\r\n"
719 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
720 "s=-\r\n"
721 "t=0 0\r\n"
722 "a=msid-semantic: WMS local_stream_1\r\n"
723 // Audio track 1, stream 1 (with candidates).
724 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
725 "c=IN IP4 74.125.127.126\r\n"
726 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
727 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
728 "generation 2\r\n"
729 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
730 "generation 2\r\n"
731 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
732 "generation 2\r\n"
733 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
734 "generation 2\r\n"
735 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
736 "raddr 192.168.1.5 rport 2346 "
737 "generation 2\r\n"
738 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
739 "raddr 192.168.1.5 rport 2348 "
740 "generation 2\r\n"
741 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
742 "a=mid:audio_content_name\r\n"
743 "a=msid:local_stream_1 audio_track_id_1\r\n"
744 "a=sendrecv\r\n"
745 "a=rtcp-mux\r\n"
746 "a=rtcp-rsize\r\n"
747 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
748 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
749 "dummy_session_params\r\n"
750 "a=rtpmap:111 opus/48000/2\r\n"
751 "a=rtpmap:103 ISAC/16000\r\n"
752 "a=rtpmap:104 ISAC/32000\r\n"
753 // Video track 1, stream 1 (with candidates).
754 "m=video 3457 RTP/SAVPF 120\r\n"
755 "c=IN IP4 74.125.224.39\r\n"
756 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
757 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
758 "generation 2\r\n"
759 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
760 "generation 2\r\n"
761 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
762 "generation 2\r\n"
763 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
764 "generation 2\r\n"
765 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
766 "generation 2\r\n"
767 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
768 "generation 2\r\n"
769 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
770 "a=mid:video_content_name\r\n"
771 "a=msid:local_stream_1 video_track_id_1\r\n"
772 "a=sendrecv\r\n"
773 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
774 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
775 "a=rtpmap:120 VP8/90000\r\n"
776 // Audio track 2, stream 2.
777 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
778 "c=IN IP4 0.0.0.0\r\n"
779 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
780 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
781 "a=mid:audio_content_name_2\r\n"
782 "a=msid:local_stream_2 audio_track_id_2\r\n"
783 "a=sendrecv\r\n"
784 "a=rtcp-mux\r\n"
785 "a=rtcp-rsize\r\n"
786 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
787 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
788 "dummy_session_params\r\n"
789 "a=rtpmap:111 opus/48000/2\r\n"
790 "a=rtpmap:103 ISAC/16000\r\n"
791 "a=rtpmap:104 ISAC/32000\r\n"
792 // Video track 2, stream 2.
793 "m=video 9 RTP/SAVPF 120\r\n"
794 "c=IN IP4 0.0.0.0\r\n"
795 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
796 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
797 "a=mid:video_content_name_2\r\n"
798 "a=msid:local_stream_2 video_track_id_2\r\n"
799 "a=sendrecv\r\n"
800 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
801 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
802 "a=rtpmap:120 VP8/90000\r\n"
803 // Video track 3, stream 2.
804 "m=video 9 RTP/SAVPF 120\r\n"
805 "c=IN IP4 0.0.0.0\r\n"
806 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
807 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
808 "a=mid:video_content_name_3\r\n"
809 "a=msid:local_stream_2 video_track_id_3\r\n"
810 "a=sendrecv\r\n"
811 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
812 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
813 "a=rtpmap:120 VP8/90000\r\n";
814
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815// One candidate reference string as per W3c spec.
816// candidate:<blah> not a=candidate:<blah>CRLF
817static const char kRawCandidate[] =
818 "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
819// One candidate reference string.
820static const char kSdpOneCandidate[] =
821 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
822 "generation 2\r\n";
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000823
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +0000824static const char kSdpTcpActiveCandidate[] =
825 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
826 "tcptype active generation 2";
827static const char kSdpTcpPassiveCandidate[] =
828 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
829 "tcptype passive generation 2";
830static const char kSdpTcpSOCandidate[] =
831 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
832 "tcptype so generation 2";
833static const char kSdpTcpInvalidCandidate[] =
834 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
835 "tcptype invalid generation 2";
836
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000837// One candidate reference string with IPV6 address.
838static const char kRawIPV6Candidate[] =
839 "candidate:a0+B/1 1 udp 2130706432 "
ehmaldonado121cabb2017-05-05 12:04:36 -0700840 "abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd 1234 typ host generation 2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841
842// One candidate reference string.
honghaiza54a0802015-12-16 18:37:23 -0800843static const char kSdpOneCandidateWithUfragPwd[] =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000844 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
honghaiza54a0802015-12-16 18:37:23 -0800845 " eth0 ufrag user_rtp pwd password_rtp generation 2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846
Zach Steinb336c272018-08-09 01:16:13 -0700847static const char kRawHostnameCandidate[] =
848 "candidate:a0+B/1 1 udp 2130706432 a.test 1234 typ host generation 2";
849
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850// Session id and version
851static const char kSessionId[] = "18446744069414584320";
852static const char kSessionVersion[] = "18446462598732840960";
853
deadbeef9d3584c2016-02-16 17:54:10 -0800854// ICE options.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855static const char kIceOption1[] = "iceoption1";
856static const char kIceOption2[] = "iceoption2";
857static const char kIceOption3[] = "iceoption3";
858
deadbeef9d3584c2016-02-16 17:54:10 -0800859// ICE ufrags/passwords.
860static const char kUfragVoice[] = "ufrag_voice";
861static const char kPwdVoice[] = "pwd_voice";
862static const char kUfragVideo[] = "ufrag_video";
863static const char kPwdVideo[] = "pwd_video";
864static const char kUfragData[] = "ufrag_data";
865static const char kPwdData[] = "pwd_data";
866
867// Extra ufrags/passwords for extra unified plan m= sections.
868static const char kUfragVoice2[] = "ufrag_voice_2";
869static const char kPwdVoice2[] = "pwd_voice_2";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700870static const char kUfragVoice3[] = "ufrag_voice_3";
871static const char kPwdVoice3[] = "pwd_voice_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800872static const char kUfragVideo2[] = "ufrag_video_2";
873static const char kPwdVideo2[] = "pwd_video_2";
874static const char kUfragVideo3[] = "ufrag_video_3";
875static const char kPwdVideo3[] = "pwd_video_3";
876
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877// Content name
878static const char kAudioContentName[] = "audio_content_name";
879static const char kVideoContentName[] = "video_content_name";
880static const char kDataContentName[] = "data_content_name";
881
deadbeef9d3584c2016-02-16 17:54:10 -0800882// Extra content names for extra unified plan m= sections.
883static const char kAudioContentName2[] = "audio_content_name_2";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700884static const char kAudioContentName3[] = "audio_content_name_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800885static const char kVideoContentName2[] = "video_content_name_2";
886static const char kVideoContentName3[] = "video_content_name_3";
887
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888// MediaStream 1
Seth Hampson845e8782018-03-02 11:34:10 -0800889static const char kStreamId1[] = "local_stream_1";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890static const char kStream1Cname[] = "stream_1_cname";
891static const char kAudioTrackId1[] = "audio_track_id_1";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200892static const uint32_t kAudioTrack1Ssrc = 1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893static const char kVideoTrackId1[] = "video_track_id_1";
deadbeef9d3584c2016-02-16 17:54:10 -0800894static const uint32_t kVideoTrack1Ssrc1 = 2;
895static const uint32_t kVideoTrack1Ssrc2 = 3;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896
897// MediaStream 2
Seth Hampson845e8782018-03-02 11:34:10 -0800898static const char kStreamId2[] = "local_stream_2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899static const char kStream2Cname[] = "stream_2_cname";
900static const char kAudioTrackId2[] = "audio_track_id_2";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200901static const uint32_t kAudioTrack2Ssrc = 4;
deadbeef9d3584c2016-02-16 17:54:10 -0800902static const char kVideoTrackId2[] = "video_track_id_2";
903static const uint32_t kVideoTrack2Ssrc = 5;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904static const char kVideoTrackId3[] = "video_track_id_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800905static const uint32_t kVideoTrack3Ssrc = 6;
Seth Hampson5b4f0752018-04-02 16:31:36 -0700906static const char kAudioTrackId3[] = "audio_track_id_3";
907static const uint32_t kAudioTrack3Ssrc = 7;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908
909// DataChannel
910static const char kDataChannelLabel[] = "data_channel";
911static const char kDataChannelMsid[] = "data_channeld0";
912static const char kDataChannelCname[] = "data_channel_cname";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200913static const uint32_t kDataChannelSsrc = 10;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914
915// Candidate
916static const char kDummyMid[] = "dummy_mid";
917static const int kDummyIndex = 123;
918
919// Misc
Steve Antona3a92c22017-12-07 10:27:41 -0800920static SdpType kDummyType = SdpType::kOffer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000921
922// Helper functions
923
924static bool SdpDeserialize(const std::string& message,
925 JsepSessionDescription* jdesc) {
926 return webrtc::SdpDeserialize(message, jdesc, NULL);
927}
928
929static bool SdpDeserializeCandidate(const std::string& message,
930 JsepIceCandidate* candidate) {
931 return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
932}
933
934// Add some extra |newlines| to the |message| after |line|.
935static void InjectAfter(const std::string& line,
936 const std::string& newlines,
937 std::string* message) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -0800938 absl::StrReplaceAll({{line, line + newlines}}, message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939}
940
941static void Replace(const std::string& line,
942 const std::string& newlines,
943 std::string* message) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -0800944 absl::StrReplaceAll({{line, newlines}}, message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000945}
946
Philipp Hanckeb70c9532021-01-13 10:40:06 +0100947// Expect a parse failure on the line containing |bad_part| when attempting to
948// parse |bad_sdp|.
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000949static void ExpectParseFailure(const std::string& bad_sdp,
950 const std::string& bad_part) {
Steve Antona3a92c22017-12-07 10:27:41 -0800951 JsepSessionDescription desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952 SdpParseError error;
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000953 bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
Harald Alvestrand99bcf602021-03-03 07:44:39 +0000954 ASSERT_FALSE(ret);
955 EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()))
956 << "Did not find " << bad_part << " in " << error.line;
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000957}
958
959// Expect fail to parse kSdpFullString if replace |good_part| with |bad_part|.
960static void ExpectParseFailure(const char* good_part, const char* bad_part) {
961 std::string bad_sdp = kSdpFullString;
962 Replace(good_part, bad_part, &bad_sdp);
963 ExpectParseFailure(bad_sdp, bad_part);
964}
965
966// Expect fail to parse kSdpFullString if add |newlines| after |injectpoint|.
967static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
968 const std::string& newlines,
969 const std::string& bad_part) {
970 std::string bad_sdp = kSdpFullString;
971 InjectAfter(injectpoint, newlines, &bad_sdp);
972 ExpectParseFailure(bad_sdp, bad_part);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000973}
974
Steve Anton4e70a722017-11-28 14:57:10 -0800975static void ReplaceDirection(RtpTransceiverDirection direction,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976 std::string* message) {
977 std::string new_direction;
978 switch (direction) {
Steve Anton4e70a722017-11-28 14:57:10 -0800979 case RtpTransceiverDirection::kInactive:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 new_direction = "a=inactive";
981 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800982 case RtpTransceiverDirection::kSendOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 new_direction = "a=sendonly";
984 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800985 case RtpTransceiverDirection::kRecvOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 new_direction = "a=recvonly";
987 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800988 case RtpTransceiverDirection::kSendRecv:
Markus Handell45c104b2020-03-11 10:51:13 +0100989 new_direction = "a=sendrecv";
990 break;
991 case RtpTransceiverDirection::kStopped:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000992 default:
Markus Handell45c104b2020-03-11 10:51:13 +0100993 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000994 new_direction = "a=sendrecv";
995 break;
996 }
997 Replace("a=sendrecv", new_direction, message);
998}
999
Yves Gerey665174f2018-06-19 15:03:05 +02001000static void ReplaceRejected(bool audio_rejected,
1001 bool video_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002 std::string* message) {
1003 if (audio_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -08001004 Replace("m=audio 9", "m=audio 0", message);
1005 Replace(kAttributeIceUfragVoice, "", message);
1006 Replace(kAttributeIcePwdVoice, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001007 }
1008 if (video_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -08001009 Replace("m=video 9", "m=video 0", message);
1010 Replace(kAttributeIceUfragVideo, "", message);
1011 Replace(kAttributeIcePwdVideo, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012 }
1013}
1014
1015// WebRtcSdpTest
1016
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001017class WebRtcSdpTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 public:
Steve Antona3a92c22017-12-07 10:27:41 -08001019 WebRtcSdpTest() : jdesc_(kDummyType) {
phoglund37ebcf02016-01-08 05:04:57 -08001020#ifdef WEBRTC_ANDROID
1021 webrtc::InitializeAndroidObjects();
1022#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 // AudioContentDescription
1024 audio_desc_ = CreateAudioContentDescription();
deadbeef9d3584c2016-02-16 17:54:10 -08001025 StreamParams audio_stream;
1026 audio_stream.id = kAudioTrackId1;
1027 audio_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001028 audio_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-16 17:54:10 -08001029 audio_stream.ssrcs.push_back(kAudioTrack1Ssrc);
1030 audio_desc_->AddStream(audio_stream);
zhihuang38989e52017-03-21 11:04:53 -07001031 rtc::SocketAddress audio_addr("74.125.127.126", 2345);
1032 audio_desc_->set_connection_address(audio_addr);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001033 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1034 absl::WrapUnique(audio_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035
1036 // VideoContentDescription
deadbeef9d3584c2016-02-16 17:54:10 -08001037 video_desc_ = CreateVideoContentDescription();
1038 StreamParams video_stream;
1039 video_stream.id = kVideoTrackId1;
1040 video_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001041 video_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-16 17:54:10 -08001042 video_stream.ssrcs.push_back(kVideoTrack1Ssrc1);
1043 video_stream.ssrcs.push_back(kVideoTrack1Ssrc2);
1044 cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream.ssrcs);
1045 video_stream.ssrc_groups.push_back(ssrc_group);
1046 video_desc_->AddStream(video_stream);
zhihuang38989e52017-03-21 11:04:53 -07001047 rtc::SocketAddress video_addr("74.125.224.39", 3457);
1048 video_desc_->set_connection_address(video_addr);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001049 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1050 absl::WrapUnique(video_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051
1052 // TransportInfo
Steve Anton06817cd2018-12-18 15:55:30 -08001053 desc_.AddTransportInfo(TransportInfo(
1054 kAudioContentName, TransportDescription(kUfragVoice, kPwdVoice)));
1055 desc_.AddTransportInfo(TransportInfo(
1056 kVideoContentName, TransportDescription(kUfragVideo, kPwdVideo)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057
1058 // v4 host
1059 int port = 1234;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001060 rtc::SocketAddress address("192.168.1.5", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001061 Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001062 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1063 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001065 Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001066 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1067 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001069 Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001070 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1071 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001073 Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001074 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1075 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076
1077 // v6 host
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001078 rtc::SocketAddress v6_address("::1", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001079 cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1080 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001081 cricket::LOCAL_PORT_TYPE,
1082 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001083 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001084 cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1085 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001086 cricket::LOCAL_PORT_TYPE,
1087 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001089 cricket::Candidate candidate7(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1090 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001091 cricket::LOCAL_PORT_TYPE,
1092 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001094 cricket::Candidate candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1095 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001096 cricket::LOCAL_PORT_TYPE,
1097 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098
1099 // stun
1100 int port_stun = 2345;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001101 rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
1102 rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001103 cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1104 address_stun, kCandidatePriority, "", "",
1105 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001106 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001107 candidate9.set_related_address(rel_address_stun);
1108
1109 address_stun.SetPort(port_stun++);
1110 rel_address_stun.SetPort(port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001111 cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1112 address_stun, kCandidatePriority, "", "",
1113 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001114 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001115 candidate10.set_related_address(rel_address_stun);
1116
1117 // relay
1118 int port_relay = 3456;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001119 rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001120 cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1121 address_relay, kCandidatePriority, "", "",
1122 cricket::RELAY_PORT_TYPE,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001123 kCandidateGeneration, kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 address_relay.SetPort(port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001125 cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1126 address_relay, kCandidatePriority, "", "",
1127 RELAY_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001128 kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129
1130 // voice
1131 candidates_.push_back(candidate1);
1132 candidates_.push_back(candidate2);
1133 candidates_.push_back(candidate5);
1134 candidates_.push_back(candidate6);
1135 candidates_.push_back(candidate9);
1136 candidates_.push_back(candidate10);
1137
1138 // video
1139 candidates_.push_back(candidate3);
1140 candidates_.push_back(candidate4);
1141 candidates_.push_back(candidate7);
1142 candidates_.push_back(candidate8);
1143 candidates_.push_back(candidate11);
1144 candidates_.push_back(candidate12);
1145
Yves Gerey665174f2018-06-19 15:03:05 +02001146 jcandidate_.reset(
1147 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148
1149 // Set up JsepSessionDescription.
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001150 jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151 std::string mline_id;
1152 int mline_index = 0;
Yves Gerey665174f2018-06-19 15:03:05 +02001153 for (size_t i = 0; i < candidates_.size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001154 // In this test, the audio m line index will be 0, and the video m line
1155 // will be 1.
1156 bool is_video = (i > 5);
1157 mline_id = is_video ? "video_content_name" : "audio_content_name";
1158 mline_index = is_video ? 1 : 0;
Yves Gerey665174f2018-06-19 15:03:05 +02001159 JsepIceCandidate jice(mline_id, mline_index, candidates_.at(i));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001160 jdesc_.AddCandidate(&jice);
1161 }
1162 }
1163
Seth Hampson5b4f0752018-04-02 16:31:36 -07001164 void RemoveVideoCandidates() {
deadbeef25ed4352016-12-12 18:37:36 -08001165 const IceCandidateCollection* video_candidates_collection =
1166 jdesc_.candidates(1);
1167 ASSERT_NE(nullptr, video_candidates_collection);
1168 std::vector<cricket::Candidate> video_candidates;
1169 for (size_t i = 0; i < video_candidates_collection->count(); ++i) {
1170 cricket::Candidate c = video_candidates_collection->at(i)->candidate();
1171 c.set_transport_name("video_content_name");
1172 video_candidates.push_back(c);
1173 }
1174 jdesc_.RemoveCandidates(video_candidates);
Seth Hampson5b4f0752018-04-02 16:31:36 -07001175 }
1176
1177 // Turns the existing reference description into a description using
1178 // a=bundle-only. This means no transport attributes and a 0 port value on
1179 // the m= sections not associated with the BUNDLE-tag.
1180 void MakeBundleOnlyDescription() {
1181 RemoveVideoCandidates();
deadbeef25ed4352016-12-12 18:37:36 -08001182
1183 // And the rest of the transport attributes.
1184 desc_.transport_infos()[1].description.ice_ufrag.clear();
1185 desc_.transport_infos()[1].description.ice_pwd.clear();
1186 desc_.transport_infos()[1].description.connection_role =
1187 cricket::CONNECTIONROLE_NONE;
1188
1189 // Set bundle-only flag.
1190 desc_.contents()[1].bundle_only = true;
1191
1192 // Add BUNDLE group.
1193 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1194 group.AddContentName(kAudioContentName);
1195 group.AddContentName(kVideoContentName);
1196 desc_.AddGroup(group);
1197
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001198 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef25ed4352016-12-12 18:37:36 -08001199 jdesc_.session_version()));
1200 }
1201
deadbeef9d3584c2016-02-16 17:54:10 -08001202 // Turns the existing reference description into a plan B description,
1203 // with 2 audio tracks and 3 video tracks.
1204 void MakePlanBDescription() {
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001205 audio_desc_ = new AudioContentDescription(*audio_desc_);
1206 video_desc_ = new VideoContentDescription(*video_desc_);
deadbeef9d3584c2016-02-16 17:54:10 -08001207
1208 StreamParams audio_track_2;
1209 audio_track_2.id = kAudioTrackId2;
1210 audio_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001211 audio_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001212 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1213 audio_desc_->AddStream(audio_track_2);
1214
1215 StreamParams video_track_2;
1216 video_track_2.id = kVideoTrackId2;
1217 video_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001218 video_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001219 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1220 video_desc_->AddStream(video_track_2);
1221
1222 StreamParams video_track_3;
1223 video_track_3.id = kVideoTrackId3;
1224 video_track_3.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001225 video_track_3.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001226 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1227 video_desc_->AddStream(video_track_3);
1228
1229 desc_.RemoveContentByName(kAudioContentName);
1230 desc_.RemoveContentByName(kVideoContentName);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001231 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1232 absl::WrapUnique(audio_desc_));
1233 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1234 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-16 17:54:10 -08001235
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001236 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef9d3584c2016-02-16 17:54:10 -08001237 jdesc_.session_version()));
1238 }
1239
1240 // Turns the existing reference description into a unified plan description,
1241 // with 2 audio tracks and 3 video tracks.
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001242 void MakeUnifiedPlanDescription(bool use_ssrcs = true) {
deadbeef9d3584c2016-02-16 17:54:10 -08001243 // Audio track 2.
1244 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1245 StreamParams audio_track_2;
1246 audio_track_2.id = kAudioTrackId2;
Seth Hampson845e8782018-03-02 11:34:10 -08001247 audio_track_2.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001248 if (use_ssrcs) {
1249 audio_track_2.cname = kStream2Cname;
1250 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1251 }
deadbeef9d3584c2016-02-16 17:54:10 -08001252 audio_desc_2->AddStream(audio_track_2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001253 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
1254 absl::WrapUnique(audio_desc_2));
Steve Anton06817cd2018-12-18 15:55:30 -08001255 desc_.AddTransportInfo(TransportInfo(
1256 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
deadbeef9d3584c2016-02-16 17:54:10 -08001257 // Video track 2, in stream 2.
1258 VideoContentDescription* video_desc_2 = CreateVideoContentDescription();
1259 StreamParams video_track_2;
1260 video_track_2.id = kVideoTrackId2;
Seth Hampson845e8782018-03-02 11:34:10 -08001261 video_track_2.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001262 if (use_ssrcs) {
1263 video_track_2.cname = kStream2Cname;
1264 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1265 }
deadbeef9d3584c2016-02-16 17:54:10 -08001266 video_desc_2->AddStream(video_track_2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001267 desc_.AddContent(kVideoContentName2, MediaProtocolType::kRtp,
1268 absl::WrapUnique(video_desc_2));
Steve Anton06817cd2018-12-18 15:55:30 -08001269 desc_.AddTransportInfo(TransportInfo(
1270 kVideoContentName2, TransportDescription(kUfragVideo2, kPwdVideo2)));
deadbeef9d3584c2016-02-16 17:54:10 -08001271
1272 // Video track 3, in stream 2.
1273 VideoContentDescription* video_desc_3 = CreateVideoContentDescription();
1274 StreamParams video_track_3;
1275 video_track_3.id = kVideoTrackId3;
Seth Hampson845e8782018-03-02 11:34:10 -08001276 video_track_3.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001277 if (use_ssrcs) {
1278 video_track_3.cname = kStream2Cname;
1279 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1280 }
deadbeef9d3584c2016-02-16 17:54:10 -08001281 video_desc_3->AddStream(video_track_3);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001282 desc_.AddContent(kVideoContentName3, MediaProtocolType::kRtp,
1283 absl::WrapUnique(video_desc_3));
Steve Anton06817cd2018-12-18 15:55:30 -08001284 desc_.AddTransportInfo(TransportInfo(
1285 kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3)));
Steve Antone831b8c2018-02-01 12:22:16 -08001286 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
deadbeef9d3584c2016-02-16 17:54:10 -08001287
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001288 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef9d3584c2016-02-16 17:54:10 -08001289 jdesc_.session_version()));
1290 }
1291
1292 // Creates an audio content description with no streams, and some default
1293 // configuration.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001294 AudioContentDescription* CreateAudioContentDescription() {
1295 AudioContentDescription* audio = new AudioContentDescription();
1296 audio->set_rtcp_mux(true);
deadbeef13871492015-12-09 12:37:51 -08001297 audio->set_rtcp_reduced_size(true);
Yves Gerey665174f2018-06-19 15:03:05 +02001298 audio->AddCrypto(CryptoParams(
1299 1, "AES_CM_128_HMAC_SHA1_32",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
1301 "dummy_session_params"));
1302 audio->set_protocol(cricket::kMediaProtocolSavpf);
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001303 audio->AddCodec(AudioCodec(111, "opus", 48000, 0, 2));
ossue1405ad2017-01-23 08:55:48 -08001304 audio->AddCodec(AudioCodec(103, "ISAC", 16000, 0, 1));
1305 audio->AddCodec(AudioCodec(104, "ISAC", 32000, 0, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 return audio;
1307 }
1308
Seth Hampson5b4f0752018-04-02 16:31:36 -07001309 // Turns the existing reference description into a unified plan description,
1310 // with 3 audio MediaContentDescriptions with special StreamParams that
1311 // contain 0 or multiple stream ids: - audio track 1 has 1 media stream id -
1312 // audio track 2 has 2 media stream ids - audio track 3 has 0 media stream ids
Seth Hampson7fa6ee62018-10-17 10:25:28 -07001313 void MakeUnifiedPlanDescriptionMultipleStreamIds(const int msid_signaling) {
Seth Hampson5b4f0752018-04-02 16:31:36 -07001314 desc_.RemoveContentByName(kVideoContentName);
1315 desc_.RemoveTransportInfoByName(kVideoContentName);
1316 RemoveVideoCandidates();
1317
1318 // Audio track 2 has 2 media stream ids.
1319 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1320 StreamParams audio_track_2;
1321 audio_track_2.id = kAudioTrackId2;
1322 audio_track_2.cname = kStream1Cname;
1323 audio_track_2.set_stream_ids({kStreamId1, kStreamId2});
1324 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1325 audio_desc_2->AddStream(audio_track_2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001326 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
1327 absl::WrapUnique(audio_desc_2));
Steve Anton06817cd2018-12-18 15:55:30 -08001328 desc_.AddTransportInfo(TransportInfo(
1329 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
Seth Hampson5b4f0752018-04-02 16:31:36 -07001330
1331 // Audio track 3 has no stream ids.
1332 AudioContentDescription* audio_desc_3 = CreateAudioContentDescription();
1333 StreamParams audio_track_3;
1334 audio_track_3.id = kAudioTrackId3;
1335 audio_track_3.cname = kStream2Cname;
1336 audio_track_3.set_stream_ids({});
1337 audio_track_3.ssrcs.push_back(kAudioTrack3Ssrc);
1338 audio_desc_3->AddStream(audio_track_3);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001339 desc_.AddContent(kAudioContentName3, MediaProtocolType::kRtp,
1340 absl::WrapUnique(audio_desc_3));
Steve Anton06817cd2018-12-18 15:55:30 -08001341 desc_.AddTransportInfo(TransportInfo(
1342 kAudioContentName3, TransportDescription(kUfragVoice3, kPwdVoice3)));
Seth Hampson7fa6ee62018-10-17 10:25:28 -07001343 desc_.set_msid_signaling(msid_signaling);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001344 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
Seth Hampson5b4f0752018-04-02 16:31:36 -07001345 jdesc_.session_version()));
1346 }
1347
Seth Hampson5897a6e2018-04-03 11:16:33 -07001348 // Turns the existing reference description into a unified plan description
1349 // with one audio MediaContentDescription that contains one StreamParams with
1350 // 0 ssrcs.
1351 void MakeUnifiedPlanDescriptionNoSsrcSignaling() {
1352 desc_.RemoveContentByName(kVideoContentName);
1353 desc_.RemoveContentByName(kAudioContentName);
1354 desc_.RemoveTransportInfoByName(kVideoContentName);
1355 RemoveVideoCandidates();
1356
1357 AudioContentDescription* audio_desc = CreateAudioContentDescription();
1358 StreamParams audio_track;
1359 audio_track.id = kAudioTrackId1;
1360 audio_track.set_stream_ids({kStreamId1});
1361 audio_desc->AddStream(audio_track);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001362 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1363 absl::WrapUnique(audio_desc));
Seth Hampson5897a6e2018-04-03 11:16:33 -07001364
1365 // Enable signaling a=msid lines.
1366 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001367 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
Seth Hampson5897a6e2018-04-03 11:16:33 -07001368 jdesc_.session_version()));
1369 }
1370
deadbeef9d3584c2016-02-16 17:54:10 -08001371 // Creates a video content description with no streams, and some default
1372 // configuration.
1373 VideoContentDescription* CreateVideoContentDescription() {
1374 VideoContentDescription* video = new VideoContentDescription();
1375 video->AddCrypto(CryptoParams(
1376 1, "AES_CM_128_HMAC_SHA1_80",
1377 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
1378 video->set_protocol(cricket::kMediaProtocolSavpf);
1379 video->AddCodec(
perkj26752742016-10-24 01:21:16 -07001380 VideoCodec(120, JsepSessionDescription::kDefaultVideoCodecName));
deadbeef9d3584c2016-02-16 17:54:10 -08001381 return video;
1382 }
1383
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001384 template <class MCD>
Yves Gerey665174f2018-06-19 15:03:05 +02001385 void CompareMediaContentDescription(const MCD* cd1, const MCD* cd2) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001386 // type
Harald Alvestrand1716d392019-06-03 20:35:45 +02001387 EXPECT_EQ(cd1->type(), cd2->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001388
1389 // content direction
1390 EXPECT_EQ(cd1->direction(), cd2->direction());
1391
1392 // rtcp_mux
1393 EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
1394
deadbeef13871492015-12-09 12:37:51 -08001395 // rtcp_reduced_size
1396 EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size());
1397
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001398 // cryptos
1399 EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
1400 if (cd1->cryptos().size() != cd2->cryptos().size()) {
1401 ADD_FAILURE();
1402 return;
1403 }
Yves Gerey665174f2018-06-19 15:03:05 +02001404 for (size_t i = 0; i < cd1->cryptos().size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001405 const CryptoParams c1 = cd1->cryptos().at(i);
1406 const CryptoParams c2 = cd2->cryptos().at(i);
1407 EXPECT_TRUE(c1.Matches(c2));
1408 EXPECT_EQ(c1.key_params, c2.key_params);
1409 EXPECT_EQ(c1.session_params, c2.session_params);
1410 }
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001411
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001412 // protocol
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001413 // Use an equivalence class here, for old and new versions of the
1414 // protocol description.
Yves Gerey665174f2018-06-19 15:03:05 +02001415 if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp ||
1416 cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
1417 cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
lally@webrtc.org36300852015-02-24 20:19:35 +00001418 const bool cd2_is_also_dtls_sctp =
Yves Gerey665174f2018-06-19 15:03:05 +02001419 cd2->protocol() == cricket::kMediaProtocolDtlsSctp ||
1420 cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
1421 cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
lally@webrtc.org36300852015-02-24 20:19:35 +00001422 EXPECT_TRUE(cd2_is_also_dtls_sctp);
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001423 } else {
1424 EXPECT_EQ(cd1->protocol(), cd2->protocol());
1425 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001426
1427 // codecs
1428 EXPECT_EQ(cd1->codecs(), cd2->codecs());
1429
1430 // bandwidth
1431 EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
1432
1433 // streams
1434 EXPECT_EQ(cd1->streams(), cd2->streams());
1435
Johannes Kron0854eb62018-10-10 22:33:20 +02001436 // extmap-allow-mixed
Johannes Kron9581bc42018-10-23 10:17:39 +02001437 EXPECT_EQ(cd1->extmap_allow_mixed_enum(), cd2->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001438
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001439 // extmap
1440 ASSERT_EQ(cd1->rtp_header_extensions().size(),
1441 cd2->rtp_header_extensions().size());
Yves Gerey665174f2018-06-19 15:03:05 +02001442 for (size_t i = 0; i < cd1->rtp_header_extensions().size(); ++i) {
isheriff6f8d6862016-05-26 11:24:55 -07001443 const RtpExtension ext1 = cd1->rtp_header_extensions().at(i);
1444 const RtpExtension ext2 = cd2->rtp_header_extensions().at(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001445 EXPECT_EQ(ext1.uri, ext2.uri);
1446 EXPECT_EQ(ext1.id, ext2.id);
jbauch5869f502017-06-29 12:31:36 -07001447 EXPECT_EQ(ext1.encrypt, ext2.encrypt);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001448 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001449 }
1450
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001451 void CompareRidDescriptionIds(const std::vector<RidDescription>& rids,
1452 const std::vector<std::string>& ids) {
1453 // Order of elements does not matter, only equivalence of sets.
1454 EXPECT_EQ(rids.size(), ids.size());
1455 for (const std::string& id : ids) {
Steve Anton64b626b2019-01-28 17:25:26 -08001456 EXPECT_EQ(1l, absl::c_count_if(rids, [id](const RidDescription& rid) {
1457 return rid.rid == id;
1458 }));
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001459 }
1460 }
1461
Amit Hilbucha2012042018-12-03 11:35:05 -08001462 void CompareSimulcastDescription(const SimulcastDescription& simulcast1,
1463 const SimulcastDescription& simulcast2) {
1464 EXPECT_EQ(simulcast1.send_layers().size(), simulcast2.send_layers().size());
1465 EXPECT_EQ(simulcast1.receive_layers().size(),
1466 simulcast2.receive_layers().size());
1467 }
1468
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001469 void CompareRtpDataContentDescription(const RtpDataContentDescription* dcd1,
1470 const RtpDataContentDescription* dcd2) {
1471 CompareMediaContentDescription<RtpDataContentDescription>(dcd1, dcd2);
1472 }
1473
1474 void CompareSctpDataContentDescription(
1475 const SctpDataContentDescription* dcd1,
1476 const SctpDataContentDescription* dcd2) {
Harald Alvestrand26bf7c42019-04-23 05:20:17 +00001477 EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001478 EXPECT_EQ(dcd1->port(), dcd2->port());
1479 EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size());
Harald Alvestrand26bf7c42019-04-23 05:20:17 +00001480 }
1481
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482 void CompareSessionDescription(const SessionDescription& desc1,
1483 const SessionDescription& desc2) {
1484 // Compare content descriptions.
1485 if (desc1.contents().size() != desc2.contents().size()) {
1486 ADD_FAILURE();
1487 return;
1488 }
Yves Gerey665174f2018-06-19 15:03:05 +02001489 for (size_t i = 0; i < desc1.contents().size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001490 const cricket::ContentInfo& c1 = desc1.contents().at(i);
1491 const cricket::ContentInfo& c2 = desc2.contents().at(i);
deadbeef25ed4352016-12-12 18:37:36 -08001492 // ContentInfo properties.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001493 EXPECT_EQ(c1.name, c2.name);
deadbeef25ed4352016-12-12 18:37:36 -08001494 EXPECT_EQ(c1.type, c2.type);
1495 EXPECT_EQ(c1.rejected, c2.rejected);
1496 EXPECT_EQ(c1.bundle_only, c2.bundle_only);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001497
1498 ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
1499 if (IsAudioContent(&c1)) {
1500 const AudioContentDescription* acd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001501 c1.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001502 const AudioContentDescription* acd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001503 c2.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001504 CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
1505 }
1506
1507 ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
1508 if (IsVideoContent(&c1)) {
1509 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001510 c1.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001512 c2.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001513 CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
1514 }
1515
1516 ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001517 if (c1.media_description()->as_sctp()) {
1518 ASSERT_TRUE(c2.media_description()->as_sctp());
1519 const SctpDataContentDescription* scd1 =
1520 c1.media_description()->as_sctp();
1521 const SctpDataContentDescription* scd2 =
1522 c2.media_description()->as_sctp();
1523 CompareSctpDataContentDescription(scd1, scd2);
1524 } else {
1525 if (IsDataContent(&c1)) {
1526 const RtpDataContentDescription* dcd1 =
1527 c1.media_description()->as_rtp_data();
1528 const RtpDataContentDescription* dcd2 =
1529 c2.media_description()->as_rtp_data();
1530 CompareRtpDataContentDescription(dcd1, dcd2);
1531 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001532 }
Amit Hilbucha2012042018-12-03 11:35:05 -08001533
1534 CompareSimulcastDescription(
1535 c1.media_description()->simulcast_description(),
1536 c2.media_description()->simulcast_description());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 }
1538
1539 // group
1540 const cricket::ContentGroups groups1 = desc1.groups();
1541 const cricket::ContentGroups groups2 = desc2.groups();
1542 EXPECT_EQ(groups1.size(), groups1.size());
1543 if (groups1.size() != groups2.size()) {
1544 ADD_FAILURE();
1545 return;
1546 }
1547 for (size_t i = 0; i < groups1.size(); ++i) {
1548 const cricket::ContentGroup group1 = groups1.at(i);
1549 const cricket::ContentGroup group2 = groups2.at(i);
1550 EXPECT_EQ(group1.semantics(), group2.semantics());
1551 const cricket::ContentNames names1 = group1.content_names();
1552 const cricket::ContentNames names2 = group2.content_names();
1553 EXPECT_EQ(names1.size(), names2.size());
1554 if (names1.size() != names2.size()) {
1555 ADD_FAILURE();
1556 return;
1557 }
1558 cricket::ContentNames::const_iterator iter1 = names1.begin();
1559 cricket::ContentNames::const_iterator iter2 = names2.begin();
1560 while (iter1 != names1.end()) {
1561 EXPECT_EQ(*iter1++, *iter2++);
1562 }
1563 }
1564
1565 // transport info
1566 const cricket::TransportInfos transports1 = desc1.transport_infos();
1567 const cricket::TransportInfos transports2 = desc2.transport_infos();
1568 EXPECT_EQ(transports1.size(), transports2.size());
1569 if (transports1.size() != transports2.size()) {
1570 ADD_FAILURE();
1571 return;
1572 }
1573 for (size_t i = 0; i < transports1.size(); ++i) {
1574 const cricket::TransportInfo transport1 = transports1.at(i);
1575 const cricket::TransportInfo transport2 = transports2.at(i);
1576 EXPECT_EQ(transport1.content_name, transport2.content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577 EXPECT_EQ(transport1.description.ice_ufrag,
1578 transport2.description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +02001579 EXPECT_EQ(transport1.description.ice_pwd, transport2.description.ice_pwd);
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07001580 EXPECT_EQ(transport1.description.ice_mode,
1581 transport2.description.ice_mode);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 if (transport1.description.identity_fingerprint) {
1583 EXPECT_EQ(*transport1.description.identity_fingerprint,
1584 *transport2.description.identity_fingerprint);
1585 } else {
1586 EXPECT_EQ(transport1.description.identity_fingerprint.get(),
1587 transport2.description.identity_fingerprint.get());
1588 }
1589 EXPECT_EQ(transport1.description.transport_options,
1590 transport2.description.transport_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001591 }
deadbeefc80741f2015-10-22 13:14:45 -07001592
1593 // global attributes
1594 EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
Johannes Kron9581bc42018-10-23 10:17:39 +02001595 EXPECT_EQ(desc1.extmap_allow_mixed(), desc2.extmap_allow_mixed());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001596 }
1597
Yves Gerey665174f2018-06-19 15:03:05 +02001598 bool CompareSessionDescription(const JsepSessionDescription& desc1,
1599 const JsepSessionDescription& desc2) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600 EXPECT_EQ(desc1.session_id(), desc2.session_id());
1601 EXPECT_EQ(desc1.session_version(), desc2.session_version());
1602 CompareSessionDescription(*desc1.description(), *desc2.description());
1603 if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
1604 return false;
1605 for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
1606 const IceCandidateCollection* cc1 = desc1.candidates(i);
1607 const IceCandidateCollection* cc2 = desc2.candidates(i);
deadbeef25ed4352016-12-12 18:37:36 -08001608 if (cc1->count() != cc2->count()) {
1609 ADD_FAILURE();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610 return false;
deadbeef25ed4352016-12-12 18:37:36 -08001611 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612 for (size_t j = 0; j < cc1->count(); ++j) {
1613 const IceCandidateInterface* c1 = cc1->at(j);
1614 const IceCandidateInterface* c2 = cc2->at(j);
1615 EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
1616 EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
1617 EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
1618 }
1619 }
1620 return true;
1621 }
1622
1623 // Disable the ice-ufrag and ice-pwd in given |sdp| message by replacing
1624 // them with invalid keywords so that the parser will just ignore them.
1625 bool RemoveCandidateUfragPwd(std::string* sdp) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -08001626 absl::StrReplaceAll(
1627 {{"a=ice-ufrag", "a=xice-ufrag"}, {"a=ice-pwd", "a=xice-pwd"}}, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628 return true;
1629 }
1630
1631 // Update the candidates in |jdesc| to use the given |ufrag| and |pwd|.
Yves Gerey665174f2018-06-19 15:03:05 +02001632 bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc,
1633 int mline_index,
1634 const std::string& ufrag,
1635 const std::string& pwd) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 std::string content_name;
1637 if (mline_index == 0) {
1638 content_name = kAudioContentName;
1639 } else if (mline_index == 1) {
1640 content_name = kVideoContentName;
1641 } else {
nissec80e7412017-01-11 05:56:46 -08001642 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643 }
Yves Gerey665174f2018-06-19 15:03:05 +02001644 TransportInfo transport_info(content_name,
1645 TransportDescription(ufrag, pwd));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646 SessionDescription* desc =
1647 const_cast<SessionDescription*>(jdesc->description());
1648 desc->RemoveTransportInfoByName(content_name);
Steve Anton06817cd2018-12-18 15:55:30 -08001649 desc->AddTransportInfo(transport_info);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
1651 const IceCandidateCollection* cc = jdesc_.candidates(i);
1652 for (size_t j = 0; j < cc->count(); ++j) {
1653 if (cc->at(j)->sdp_mline_index() == mline_index) {
Yves Gerey665174f2018-06-19 15:03:05 +02001654 const_cast<Candidate&>(cc->at(j)->candidate()).set_username(ufrag);
1655 const_cast<Candidate&>(cc->at(j)->candidate()).set_password(pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656 }
1657 }
1658 }
1659 return true;
1660 }
1661
1662 void AddIceOptions(const std::string& content_name,
1663 const std::vector<std::string>& transport_options) {
1664 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1665 cricket::TransportInfo transport_info =
1666 *(desc_.GetTransportInfoByName(content_name));
1667 desc_.RemoveTransportInfoByName(content_name);
1668 transport_info.description.transport_options = transport_options;
1669 desc_.AddTransportInfo(transport_info);
1670 }
1671
deadbeef3f7219b2015-12-28 15:17:14 -08001672 void SetIceUfragPwd(const std::string& content_name,
1673 const std::string& ice_ufrag,
1674 const std::string& ice_pwd) {
1675 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1676 cricket::TransportInfo transport_info =
1677 *(desc_.GetTransportInfoByName(content_name));
1678 desc_.RemoveTransportInfoByName(content_name);
1679 transport_info.description.ice_ufrag = ice_ufrag;
1680 transport_info.description.ice_pwd = ice_pwd;
1681 desc_.AddTransportInfo(transport_info);
1682 }
1683
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684 void AddFingerprint() {
1685 desc_.RemoveTransportInfoByName(kAudioContentName);
1686 desc_.RemoveTransportInfoByName(kVideoContentName);
Steve Anton4905edb2018-10-15 19:27:44 -07001687 rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1, kIdentityDigest);
Steve Anton06817cd2018-12-18 15:55:30 -08001688 desc_.AddTransportInfo(TransportInfo(
deadbeef46eed762016-01-28 13:24:37 -08001689 kAudioContentName,
deadbeef9d3584c2016-02-16 17:54:10 -08001690 TransportDescription(std::vector<std::string>(), kUfragVoice, kPwdVoice,
1691 cricket::ICEMODE_FULL,
Steve Anton06817cd2018-12-18 15:55:30 -08001692 cricket::CONNECTIONROLE_NONE, &fingerprint)));
1693 desc_.AddTransportInfo(TransportInfo(
deadbeef46eed762016-01-28 13:24:37 -08001694 kVideoContentName,
deadbeef9d3584c2016-02-16 17:54:10 -08001695 TransportDescription(std::vector<std::string>(), kUfragVideo, kPwdVideo,
1696 cricket::ICEMODE_FULL,
Steve Anton06817cd2018-12-18 15:55:30 -08001697 cricket::CONNECTIONROLE_NONE, &fingerprint)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698 }
1699
jbauch5869f502017-06-29 12:31:36 -07001700 void AddExtmap(bool encrypted) {
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001701 audio_desc_ = new AudioContentDescription(*audio_desc_);
1702 video_desc_ = new VideoContentDescription(*video_desc_);
jbauch5869f502017-06-29 12:31:36 -07001703 audio_desc_->AddRtpHeaderExtension(
1704 RtpExtension(kExtmapUri, kExtmapId, encrypted));
1705 video_desc_->AddRtpHeaderExtension(
1706 RtpExtension(kExtmapUri, kExtmapId, encrypted));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707 desc_.RemoveContentByName(kAudioContentName);
1708 desc_.RemoveContentByName(kVideoContentName);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001709 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1710 absl::WrapUnique(audio_desc_));
1711 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1712 absl::WrapUnique(video_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713 }
1714
1715 void RemoveCryptos() {
1716 audio_desc_->set_cryptos(std::vector<CryptoParams>());
1717 video_desc_->set_cryptos(std::vector<CryptoParams>());
1718 }
1719
Seth Hampson5897a6e2018-04-03 11:16:33 -07001720 // Removes everything in StreamParams from the session description that is
1721 // used for a=ssrc lines.
1722 void RemoveSsrcSignalingFromStreamParams() {
Harald Alvestrand1716d392019-06-03 20:35:45 +02001723 for (cricket::ContentInfo& content_info :
1724 jdesc_.description()->contents()) {
Seth Hampson5897a6e2018-04-03 11:16:33 -07001725 // With Unified Plan there should be one StreamParams per m= section.
1726 StreamParams& stream =
1727 content_info.media_description()->mutable_streams()[0];
1728 stream.ssrcs.clear();
1729 stream.ssrc_groups.clear();
1730 stream.cname.clear();
1731 }
1732 }
1733
Seth Hampson7fa6ee62018-10-17 10:25:28 -07001734 // Removes all a=ssrc lines from the SDP string, except for the
1735 // "a=ssrc:... cname:..." lines.
1736 void RemoveSsrcMsidLinesFromSdpString(std::string* sdp_string) {
1737 const char kAttributeSsrc[] = "a=ssrc";
1738 const char kAttributeCname[] = "cname";
1739 size_t ssrc_line_pos = sdp_string->find(kAttributeSsrc);
1740 while (ssrc_line_pos != std::string::npos) {
1741 size_t beg_line_pos = sdp_string->rfind('\n', ssrc_line_pos);
1742 size_t end_line_pos = sdp_string->find('\n', ssrc_line_pos);
1743 size_t cname_pos = sdp_string->find(kAttributeCname, ssrc_line_pos);
1744 if (cname_pos == std::string::npos || cname_pos > end_line_pos) {
1745 // Only erase a=ssrc lines that don't contain "cname".
1746 sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
1747 ssrc_line_pos = sdp_string->find(kAttributeSsrc, beg_line_pos);
1748 } else {
1749 // Skip the "a=ssrc:... cname" line and find the next "a=ssrc" line.
1750 ssrc_line_pos = sdp_string->find(kAttributeSsrc, end_line_pos);
1751 }
1752 }
1753 }
1754
Seth Hampson5897a6e2018-04-03 11:16:33 -07001755 // Removes all a=ssrc lines from the SDP string.
1756 void RemoveSsrcLinesFromSdpString(std::string* sdp_string) {
1757 const char kAttributeSsrc[] = "a=ssrc";
1758 while (sdp_string->find(kAttributeSsrc) != std::string::npos) {
1759 size_t pos_ssrc_attribute = sdp_string->find(kAttributeSsrc);
1760 size_t beg_line_pos = sdp_string->rfind('\n', pos_ssrc_attribute);
1761 size_t end_line_pos = sdp_string->find('\n', pos_ssrc_attribute);
1762 sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
1763 }
1764 }
1765
Steve Anton4e70a722017-11-28 14:57:10 -08001766 bool TestSerializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 audio_desc_->set_direction(direction);
1768 video_desc_->set_direction(direction);
1769 std::string new_sdp = kSdpFullString;
1770 ReplaceDirection(direction, &new_sdp);
1771
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001772 if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773 jdesc_.session_version())) {
1774 return false;
1775 }
Steve Antone831b8c2018-02-01 12:22:16 -08001776 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 EXPECT_EQ(new_sdp, message);
1778 return true;
1779 }
1780
1781 bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001782 audio_desc_ = new AudioContentDescription(*audio_desc_);
1783 video_desc_ = new VideoContentDescription(*video_desc_);
zhihuang38989e52017-03-21 11:04:53 -07001784
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785 desc_.RemoveContentByName(kAudioContentName);
1786 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001787 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001788 absl::WrapUnique(audio_desc_));
Steve Anton5adfafd2017-12-20 16:34:00 -08001789 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001790 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-16 17:54:10 -08001791 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1792 audio_rejected ? "" : kPwdVoice);
1793 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1794 video_rejected ? "" : kPwdVideo);
deadbeef3f7219b2015-12-28 15:17:14 -08001795
1796 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001797 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
1798
Steve Antona3a92c22017-12-07 10:27:41 -08001799 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07001800 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 12:22:16 -08001801 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802 EXPECT_EQ(new_sdp, message);
1803 return true;
1804 }
1805
zstein4b2e0822017-02-17 19:48:38 -08001806 void AddSctpDataChannel(bool use_sctpmap) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001807 std::unique_ptr<SctpDataContentDescription> data(
1808 new SctpDataContentDescription());
1809 sctp_desc_ = data.get();
1810 sctp_desc_->set_use_sctpmap(use_sctpmap);
Guido Urdanetacecf87f2019-05-31 10:17:38 +00001811 sctp_desc_->set_protocol(cricket::kMediaProtocolUdpDtlsSctp);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001812 sctp_desc_->set_port(kDefaultSctpPort);
Steve Anton5adfafd2017-12-20 16:34:00 -08001813 desc_.AddContent(kDataContentName, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001814 std::move(data));
Steve Anton06817cd2018-12-18 15:55:30 -08001815 desc_.AddTransportInfo(TransportInfo(
1816 kDataContentName, TransportDescription(kUfragData, kPwdData)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817 }
1818
1819 void AddRtpDataChannel() {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001820 std::unique_ptr<RtpDataContentDescription> data(
1821 new RtpDataContentDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001822 data_desc_ = data.get();
1823
deadbeef67cf2c12016-04-13 10:07:16 -07001824 data_desc_->AddCodec(DataCodec(101, "google-data"));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825 StreamParams data_stream;
1826 data_stream.id = kDataChannelMsid;
1827 data_stream.cname = kDataChannelCname;
Seth Hampson845e8782018-03-02 11:34:10 -08001828 data_stream.set_stream_ids({kDataChannelLabel});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001829 data_stream.ssrcs.push_back(kDataChannelSsrc);
1830 data_desc_->AddStream(data_stream);
Yves Gerey665174f2018-06-19 15:03:05 +02001831 data_desc_->AddCrypto(
1832 CryptoParams(1, "AES_CM_128_HMAC_SHA1_80",
1833 "inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5", ""));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001834 data_desc_->set_protocol(cricket::kMediaProtocolSavpf);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001835 desc_.AddContent(kDataContentName, MediaProtocolType::kRtp,
1836 std::move(data));
Steve Anton06817cd2018-12-18 15:55:30 -08001837 desc_.AddTransportInfo(TransportInfo(
1838 kDataContentName, TransportDescription(kUfragData, kPwdData)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001839 }
1840
Steve Anton4e70a722017-11-28 14:57:10 -08001841 bool TestDeserializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842 std::string new_sdp = kSdpFullString;
1843 ReplaceDirection(direction, &new_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08001844 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845
1846 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
1847
1848 audio_desc_->set_direction(direction);
1849 video_desc_->set_direction(direction);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001850 if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001851 jdesc_.session_version())) {
1852 return false;
1853 }
1854 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
1855 return true;
1856 }
1857
1858 bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -08001859 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001860 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08001861 JsepSessionDescription new_jdesc(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001862 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
deadbeef3f7219b2015-12-28 15:17:14 -08001863
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001864 audio_desc_ = new AudioContentDescription(*audio_desc_);
1865 video_desc_ = new VideoContentDescription(*video_desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001866 desc_.RemoveContentByName(kAudioContentName);
1867 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001868 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001869 absl::WrapUnique(audio_desc_));
Steve Anton5adfafd2017-12-20 16:34:00 -08001870 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001871 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-16 17:54:10 -08001872 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1873 audio_rejected ? "" : kPwdVoice);
1874 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1875 video_rejected ? "" : kPwdVideo);
Steve Antona3a92c22017-12-07 10:27:41 -08001876 JsepSessionDescription jdesc_no_candidates(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001877 if (!jdesc_no_candidates.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef3f7219b2015-12-28 15:17:14 -08001878 jdesc_.session_version())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879 return false;
1880 }
deadbeef3f7219b2015-12-28 15:17:14 -08001881 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001882 return true;
1883 }
1884
Yves Gerey665174f2018-06-19 15:03:05 +02001885 void TestDeserializeExtmap(bool session_level,
1886 bool media_level,
1887 bool encrypted) {
jbauch5869f502017-06-29 12:31:36 -07001888 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08001889 JsepSessionDescription new_jdesc(SdpType::kOffer);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001890 ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001891 jdesc_.session_version()));
Steve Antona3a92c22017-12-07 10:27:41 -08001892 JsepSessionDescription jdesc_with_extmap(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001893 std::string sdp_with_extmap = kSdpString;
1894 if (session_level) {
jbauch5869f502017-06-29 12:31:36 -07001895 InjectAfter(kSessionTime,
1896 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1897 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898 &sdp_with_extmap);
1899 }
1900 if (media_level) {
jbauch5869f502017-06-29 12:31:36 -07001901 InjectAfter(kAttributeIcePwdVoice,
1902 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1903 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 &sdp_with_extmap);
jbauch5869f502017-06-29 12:31:36 -07001905 InjectAfter(kAttributeIcePwdVideo,
1906 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1907 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001908 &sdp_with_extmap);
1909 }
1910 // The extmap can't be present at the same time in both session level and
1911 // media level.
1912 if (session_level && media_level) {
1913 SdpParseError error;
Yves Gerey665174f2018-06-19 15:03:05 +02001914 EXPECT_FALSE(
1915 webrtc::SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001916 EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
1917 } else {
1918 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
1919 EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
1920 }
1921 }
1922
1923 void VerifyCodecParameter(const cricket::CodecParameterMap& params,
Yves Gerey665174f2018-06-19 15:03:05 +02001924 const std::string& name,
1925 int expected_value) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926 cricket::CodecParameterMap::const_iterator found = params.find(name);
1927 ASSERT_TRUE(found != params.end());
Jonas Olsson6b1985d2018-07-05 11:59:48 +02001928 EXPECT_EQ(found->second, rtc::ToString(expected_value));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929 }
1930
1931 void TestDeserializeCodecParams(const CodecParams& params,
1932 JsepSessionDescription* jdesc_output) {
1933 std::string sdp =
1934 "v=0\r\n"
1935 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1936 "s=-\r\n"
1937 "t=0 0\r\n"
1938 // Include semantics for WebRTC Media Streams since it is supported by
1939 // this parser, and will be added to the SDP when serializing a session
1940 // description.
1941 "a=msid-semantic: WMS\r\n"
1942 // Pl type 111 preferred.
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001943 "m=audio 9 RTP/SAVPF 111 104 103 105\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944 // Pltype 111 listed before 103 and 104 in the map.
1945 "a=rtpmap:111 opus/48000/2\r\n"
1946 // Pltype 103 listed before 104.
1947 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001948 "a=rtpmap:104 ISAC/32000\r\n"
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001949 "a=rtpmap:105 telephone-event/8000\r\n"
1950 "a=fmtp:105 0-15,66,70\r\n"
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001951 "a=fmtp:111 ";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 std::ostringstream os;
Donald Curtis144d0182015-05-15 13:14:24 -07001953 os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001954 << "; sprop-stereo=" << params.sprop_stereo
1955 << "; useinbandfec=" << params.useinband
Jonas Olssonb2b20312020-01-14 12:11:31 +01001956 << "; maxaveragebitrate=" << params.maxaveragebitrate
1957 << "\r\n"
1958 "a=ptime:"
1959 << params.ptime
1960 << "\r\n"
1961 "a=maxptime:"
1962 << params.max_ptime << "\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963 sdp += os.str();
1964
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001965 os.clear();
1966 os.str("");
1967 // Pl type 100 preferred.
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00001968 os << "m=video 9 RTP/SAVPF 99 95\r\n"
Jonas Olssonb2b20312020-01-14 12:11:31 +01001969 "a=rtpmap:99 VP8/90000\r\n"
1970 "a=rtpmap:95 RTX/90000\r\n"
1971 "a=fmtp:95 apt=99;\r\n";
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001972 sdp += os.str();
1973
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001974 // Deserialize
1975 SdpParseError error;
1976 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
1977
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001978 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001979 GetFirstAudioContentDescription(jdesc_output->description());
1980 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001981 ASSERT_FALSE(acd->codecs().empty());
1982 cricket::AudioCodec opus = acd->codecs()[0];
1983 EXPECT_EQ("opus", opus.name);
1984 EXPECT_EQ(111, opus.id);
1985 VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
1986 VerifyCodecParameter(opus.params, "stereo", params.stereo);
1987 VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
1988 VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001989 VerifyCodecParameter(opus.params, "maxaveragebitrate",
1990 params.maxaveragebitrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991 for (size_t i = 0; i < acd->codecs().size(); ++i) {
1992 cricket::AudioCodec codec = acd->codecs()[i];
1993 VerifyCodecParameter(codec.params, "ptime", params.ptime);
1994 VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001995 }
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001996
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001997 cricket::AudioCodec dtmf = acd->codecs()[3];
1998 EXPECT_EQ("telephone-event", dtmf.name);
1999 EXPECT_EQ(105, dtmf.id);
2000 EXPECT_EQ(3u,
2001 dtmf.params.size()); // ptime and max_ptime count as parameters.
2002 EXPECT_EQ(dtmf.params.begin()->first, "");
2003 EXPECT_EQ(dtmf.params.begin()->second, "0-15,66,70");
2004
stefan@webrtc.org85d27942014-06-09 12:51:39 +00002005 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002006 GetFirstVideoContentDescription(jdesc_output->description());
2007 ASSERT_TRUE(vcd);
stefan@webrtc.org85d27942014-06-09 12:51:39 +00002008 ASSERT_FALSE(vcd->codecs().empty());
2009 cricket::VideoCodec vp8 = vcd->codecs()[0];
2010 EXPECT_EQ("VP8", vp8.name);
2011 EXPECT_EQ(99, vp8.id);
2012 cricket::VideoCodec rtx = vcd->codecs()[1];
2013 EXPECT_EQ("RTX", rtx.name);
2014 EXPECT_EQ(95, rtx.id);
2015 VerifyCodecParameter(rtx.params, "apt", vp8.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002016 }
2017
2018 void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
2019 bool use_wildcard) {
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00002020 std::string sdp_session_and_audio =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002021 "v=0\r\n"
2022 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2023 "s=-\r\n"
2024 "t=0 0\r\n"
2025 // Include semantics for WebRTC Media Streams since it is supported by
2026 // this parser, and will be added to the SDP when serializing a session
2027 // description.
2028 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00002029 "m=audio 9 RTP/SAVPF 111\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00002030 "a=rtpmap:111 opus/48000/2\r\n";
2031 std::string sdp_video =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032 "m=video 3457 RTP/SAVPF 101\r\n"
2033 "a=rtpmap:101 VP8/90000\r\n"
Elad Alonfadb1812019-05-24 13:40:02 +02002034 "a=rtcp-fb:101 goog-lntf\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002035 "a=rtcp-fb:101 nack\r\n"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00002036 "a=rtcp-fb:101 nack pli\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00002037 "a=rtcp-fb:101 goog-remb\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038 std::ostringstream os;
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00002039 os << sdp_session_and_audio;
Yves Gerey665174f2018-06-19 15:03:05 +02002040 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") << " nack\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00002041 os << sdp_video;
Yves Gerey665174f2018-06-19 15:03:05 +02002042 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") << " ccm fir\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00002043 std::string sdp = os.str();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044 // Deserialize
2045 SdpParseError error;
2046 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002048 GetFirstAudioContentDescription(jdesc_output->description());
2049 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002050 ASSERT_FALSE(acd->codecs().empty());
2051 cricket::AudioCodec opus = acd->codecs()[0];
2052 EXPECT_EQ(111, opus.id);
Yves Gerey665174f2018-06-19 15:03:05 +02002053 EXPECT_TRUE(opus.HasFeedbackParam(cricket::FeedbackParam(
2054 cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002055
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002056 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002057 GetFirstVideoContentDescription(jdesc_output->description());
2058 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002059 ASSERT_FALSE(vcd->codecs().empty());
2060 cricket::VideoCodec vp8 = vcd->codecs()[0];
2061 EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
2062 vp8.name.c_str());
2063 EXPECT_EQ(101, vp8.id);
Yves Gerey665174f2018-06-19 15:03:05 +02002064 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
Elad Alonfadb1812019-05-24 13:40:02 +02002065 cricket::kRtcpFbParamLntf, cricket::kParamValueEmpty)));
2066 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
Yves Gerey665174f2018-06-19 15:03:05 +02002067 cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
2068 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
2069 cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)));
2070 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
2071 cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)));
2072 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
2073 cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002074 }
2075
2076 // Two SDP messages can mean the same thing but be different strings, e.g.
2077 // some of the lines can be serialized in different order.
2078 // However, a deserialized description can be compared field by field and has
2079 // no order. If deserializer has already been tested, serializing then
2080 // deserializing and comparing JsepSessionDescription will test
2081 // the serializer sufficiently.
Steve Antone831b8c2018-02-01 12:22:16 -08002082 void TestSerialize(const JsepSessionDescription& jdesc) {
2083 std::string message = webrtc::SdpSerialize(jdesc);
Steve Antona3a92c22017-12-07 10:27:41 -08002084 JsepSessionDescription jdesc_output_des(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085 SdpParseError error;
2086 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
2087 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
2088 }
2089
zhihuang38989e52017-03-21 11:04:53 -07002090 // Calling 'Initialize' with a copy of the inner SessionDescription will
2091 // create a copy of the JsepSessionDescription without candidates. The
2092 // 'connection address' field, previously set from the candidates, must also
2093 // be reset.
2094 void MakeDescriptionWithoutCandidates(JsepSessionDescription* jdesc) {
2095 rtc::SocketAddress audio_addr("0.0.0.0", 9);
2096 rtc::SocketAddress video_addr("0.0.0.0", 9);
2097 audio_desc_->set_connection_address(audio_addr);
2098 video_desc_->set_connection_address(video_addr);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002099 ASSERT_TRUE(jdesc->Initialize(desc_.Clone(), kSessionId, kSessionVersion));
zhihuang38989e52017-03-21 11:04:53 -07002100 }
2101
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002102 protected:
2103 SessionDescription desc_;
2104 AudioContentDescription* audio_desc_;
2105 VideoContentDescription* video_desc_;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002106 RtpDataContentDescription* data_desc_;
2107 SctpDataContentDescription* sctp_desc_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002108 Candidates candidates_;
kwibergd1fe2812016-04-27 06:47:29 -07002109 std::unique_ptr<IceCandidateInterface> jcandidate_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002110 JsepSessionDescription jdesc_;
2111};
2112
2113void TestMismatch(const std::string& string1, const std::string& string2) {
2114 int position = 0;
2115 for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
2116 if (string1.c_str()[i] != string2.c_str()[i]) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002117 position = static_cast<int>(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002118 break;
2119 }
2120 }
2121 EXPECT_EQ(0, position) << "Strings mismatch at the " << position
2122 << " character\n"
Jonas Olssonb2b20312020-01-14 12:11:31 +01002123 " 1: "
2124 << string1.substr(position, 20)
2125 << "\n"
2126 " 2: "
2127 << string2.substr(position, 20) << "\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002128}
2129
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
2131 // SessionDescription with desc and candidates.
Steve Antone831b8c2018-02-01 12:22:16 -08002132 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002133 TestMismatch(std::string(kSdpFullString), message);
2134}
2135
2136TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
Steve Antona3a92c22017-12-07 10:27:41 -08002137 JsepSessionDescription jdesc_empty(kDummyType);
Steve Antone831b8c2018-02-01 12:22:16 -08002138 EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002139}
2140
2141// This tests serialization of SDP with a=crypto and a=fingerprint, as would be
2142// the case in a DTLS offer.
2143TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
2144 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08002145 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002146 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 12:22:16 -08002147 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002148
2149 std::string sdp_with_fingerprint = kSdpString;
Yves Gerey665174f2018-06-19 15:03:05 +02002150 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2151 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152
2153 EXPECT_EQ(sdp_with_fingerprint, message);
2154}
2155
2156// This tests serialization of SDP with a=fingerprint with no a=crypto, as would
2157// be the case in a DTLS answer.
2158TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
2159 AddFingerprint();
2160 RemoveCryptos();
Steve Antona3a92c22017-12-07 10:27:41 -08002161 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002162 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 12:22:16 -08002163 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164
2165 std::string sdp_with_fingerprint = kSdpString;
2166 Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
2167 Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
Yves Gerey665174f2018-06-19 15:03:05 +02002168 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2169 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002170
2171 EXPECT_EQ(sdp_with_fingerprint, message);
2172}
2173
2174TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
2175 // JsepSessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 10:27:41 -08002176 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002177 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 12:22:16 -08002178 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 EXPECT_EQ(std::string(kSdpString), message);
2180}
2181
2182TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundle) {
2183 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
2184 group.AddContentName(kAudioContentName);
2185 group.AddContentName(kVideoContentName);
2186 desc_.AddGroup(group);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002187 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08002189 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190 std::string sdp_with_bundle = kSdpFullString;
2191 InjectAfter(kSessionTime,
2192 "a=group:BUNDLE audio_content_name video_content_name\r\n",
2193 &sdp_with_bundle);
2194 EXPECT_EQ(sdp_with_bundle, message);
2195}
2196
2197TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
Steve Antonb1c1de12017-12-21 15:14:30 -08002198 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002199 vcd->set_bandwidth(100 * 1000 + 755); // Integer division will drop the 755.
2200 vcd->set_bandwidth_type("AS");
Steve Antonb1c1de12017-12-21 15:14:30 -08002201 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002202 acd->set_bandwidth(555);
2203 acd->set_bandwidth_type("TIAS");
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002204 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002205 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08002206 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002207 std::string sdp_with_bandwidth = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002208 InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209 &sdp_with_bandwidth);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002210 InjectAfter("c=IN IP4 74.125.127.126\r\n", "b=TIAS:555\r\n",
2211 &sdp_with_bandwidth);
2212 EXPECT_EQ(sdp_with_bandwidth, message);
2213}
2214
2215// Should default to b=AS if bandwidth_type isn't set.
2216TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithMissingBandwidthType) {
2217 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2218 vcd->set_bandwidth(100 * 1000);
2219 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2220 jdesc_.session_version()));
2221 std::string message = webrtc::SdpSerialize(jdesc_);
2222 std::string sdp_with_bandwidth = kSdpFullString;
2223 InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002224 &sdp_with_bandwidth);
2225 EXPECT_EQ(sdp_with_bandwidth, message);
2226}
2227
2228TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
2229 std::vector<std::string> transport_options;
2230 transport_options.push_back(kIceOption1);
2231 transport_options.push_back(kIceOption3);
2232 AddIceOptions(kAudioContentName, transport_options);
2233 transport_options.clear();
2234 transport_options.push_back(kIceOption2);
2235 transport_options.push_back(kIceOption3);
2236 AddIceOptions(kVideoContentName, transport_options);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002237 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002238 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08002239 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002240 std::string sdp_with_ice_options = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002241 InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1 iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 15:03:05 +02002243 InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2 iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244 &sdp_with_ice_options);
2245 EXPECT_EQ(sdp_with_ice_options, message);
2246}
2247
2248TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002249 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250}
2251
2252TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002253 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254}
2255
2256TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002257 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002258}
2259
2260TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
2261 EXPECT_TRUE(TestSerializeRejected(true, false));
2262}
2263
2264TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
2265 EXPECT_TRUE(TestSerializeRejected(false, true));
2266}
2267
2268TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
2269 EXPECT_TRUE(TestSerializeRejected(true, true));
2270}
2271
2272TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRtpDataChannel) {
2273 AddRtpDataChannel();
Steve Antona3a92c22017-12-07 10:27:41 -08002274 JsepSessionDescription jsep_desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002275
zhihuang38989e52017-03-21 11:04:53 -07002276 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08002277 std::string message = webrtc::SdpSerialize(jsep_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002278
2279 std::string expected_sdp = kSdpString;
2280 expected_sdp.append(kSdpRtpDataChannelString);
2281 EXPECT_EQ(expected_sdp, message);
2282}
2283
2284TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
zstein4b2e0822017-02-17 19:48:38 -08002285 bool use_sctpmap = true;
2286 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002287 JsepSessionDescription jsep_desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002288
zhihuang38989e52017-03-21 11:04:53 -07002289 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08002290 std::string message = webrtc::SdpSerialize(jsep_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002291
2292 std::string expected_sdp = kSdpString;
2293 expected_sdp.append(kSdpSctpDataChannelString);
2294 EXPECT_EQ(message, expected_sdp);
2295}
2296
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002297void MutateJsepSctpPort(JsepSessionDescription* jdesc,
2298 const SessionDescription& desc,
2299 int port) {
2300 // Take our pre-built session description and change the SCTP port.
2301 std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
2302 SctpDataContentDescription* dcdesc =
2303 mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
2304 dcdesc->set_port(port);
2305 ASSERT_TRUE(
2306 jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion));
2307}
2308
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002309TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
zstein4b2e0822017-02-17 19:48:38 -08002310 bool use_sctpmap = true;
2311 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002312 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002313 MakeDescriptionWithoutCandidates(&jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002314
2315 const int kNewPort = 1234;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002316 MutateJsepSctpPort(&jsep_desc, desc_, kNewPort);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002317
Steve Antone831b8c2018-02-01 12:22:16 -08002318 std::string message = webrtc::SdpSerialize(jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002319
2320 std::string expected_sdp = kSdpString;
2321 expected_sdp.append(kSdpSctpDataChannelString);
2322
Steve Anton1c9c9fc2019-02-14 15:13:09 -08002323 absl::StrReplaceAll(
2324 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kNewPort)}},
2325 &expected_sdp);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002326
2327 EXPECT_EQ(expected_sdp, message);
2328}
2329
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002330TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
Steve Antona3a92c22017-12-07 10:27:41 -08002331 JsepSessionDescription jsep_desc(kDummyType);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002332 AddRtpDataChannel();
Yves Gerey665174f2018-06-19 15:03:05 +02002333 data_desc_->set_bandwidth(100 * 1000);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002334 data_desc_->set_bandwidth_type("AS");
zhihuang38989e52017-03-21 11:04:53 -07002335 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08002336 std::string message = webrtc::SdpSerialize(jsep_desc);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002337
2338 std::string expected_sdp = kSdpString;
2339 expected_sdp.append(kSdpRtpDataChannelString);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002340 // Serializing data content shouldn't ignore bandwidth settings.
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +00002341 InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\n",
Yves Gerey665174f2018-06-19 15:03:05 +02002342 "b=AS:100\r\n", &expected_sdp);
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +00002343 EXPECT_EQ(expected_sdp, message);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002344}
2345
Johannes Kron0854eb62018-10-10 22:33:20 +02002346TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 10:17:39 +02002347 jdesc_.description()->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002348 TestSerialize(jdesc_);
2349}
2350
2351TEST_F(WebRtcSdpTest, SerializeMediaContentDescriptionWithExtmapAllowMixed) {
2352 cricket::MediaContentDescription* video_desc =
2353 jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
2354 ASSERT_TRUE(video_desc);
2355 cricket::MediaContentDescription* audio_desc =
2356 jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
2357 ASSERT_TRUE(audio_desc);
Johannes Kron9581bc42018-10-23 10:17:39 +02002358 video_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002359 cricket::MediaContentDescription::kMedia);
Johannes Kron9581bc42018-10-23 10:17:39 +02002360 audio_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002361 cricket::MediaContentDescription::kMedia);
2362 TestSerialize(jdesc_);
2363}
2364
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002365TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
jbauch5869f502017-06-29 12:31:36 -07002366 bool encrypted = false;
2367 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08002368 JsepSessionDescription desc_with_extmap(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002369 MakeDescriptionWithoutCandidates(&desc_with_extmap);
Steve Antone831b8c2018-02-01 12:22:16 -08002370 std::string message = webrtc::SdpSerialize(desc_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002371
2372 std::string sdp_with_extmap = kSdpString;
Yves Gerey665174f2018-06-19 15:03:05 +02002373 InjectAfter("a=mid:audio_content_name\r\n", kExtmap, &sdp_with_extmap);
2374 InjectAfter("a=mid:video_content_name\r\n", kExtmap, &sdp_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002375
2376 EXPECT_EQ(sdp_with_extmap, message);
2377}
2378
jbauch5869f502017-06-29 12:31:36 -07002379TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapEncrypted) {
2380 bool encrypted = true;
2381 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08002382 JsepSessionDescription desc_with_extmap(kDummyType);
Yves Gerey665174f2018-06-19 15:03:05 +02002383 ASSERT_TRUE(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002384 desc_with_extmap.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
Steve Antone831b8c2018-02-01 12:22:16 -08002385 TestSerialize(desc_with_extmap);
jbauch5869f502017-06-29 12:31:36 -07002386}
2387
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002388TEST_F(WebRtcSdpTest, SerializeCandidates) {
2389 std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
wu@webrtc.orgec9f5fb2014-06-24 17:05:10 +00002390 EXPECT_EQ(std::string(kRawCandidate), message);
honghaiza54a0802015-12-16 18:37:23 -08002391
2392 Candidate candidate_with_ufrag(candidates_.front());
2393 candidate_with_ufrag.set_username("ABC");
2394 jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0,
2395 candidate_with_ufrag));
2396 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2397 EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
honghaiza0c44ea2016-03-23 16:07:48 -07002398
2399 Candidate candidate_with_network_info(candidates_.front());
2400 candidate_with_network_info.set_network_id(1);
2401 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2402 candidate_with_network_info));
2403 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2404 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
2405 candidate_with_network_info.set_network_cost(999);
2406 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2407 candidate_with_network_info));
2408 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2409 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
2410 message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411}
2412
Zach Steinb336c272018-08-09 01:16:13 -07002413TEST_F(WebRtcSdpTest, SerializeHostnameCandidate) {
2414 rtc::SocketAddress address("a.test", 1234);
2415 cricket::Candidate candidate(
2416 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp", address, kCandidatePriority,
2417 "", "", LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
2418 JsepIceCandidate jcandidate(std::string("audio_content_name"), 0, candidate);
2419 std::string message = webrtc::SdpSerializeCandidate(jcandidate);
2420 EXPECT_EQ(std::string(kRawHostnameCandidate), message);
2421}
2422
mallinath@webrtc.orge999bd02014-08-13 06:05:55 +00002423TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00002424 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00002425 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2426 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2427 kCandidateFoundation1);
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002428 candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
kwibergd1fe2812016-04-27 06:47:29 -07002429 std::unique_ptr<IceCandidateInterface> jcandidate(
2430 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002431
2432 std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
2433 EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
2434}
2435
Taylor Brandstetter8206bc02020-04-02 12:36:38 -07002436// Test serializing a TCP candidate that came in with a missing tcptype. This
2437// shouldn't happen according to the spec, but our implementation has been
2438// accepting this for quite some time, treating it as a passive candidate.
2439//
2440// So, we should be able to at least convert such candidates to and from SDP.
2441// See: bugs.webrtc.org/11423
2442TEST_F(WebRtcSdpTest, ParseTcpCandidateWithoutTcptype) {
2443 std::string missing_tcptype =
2444 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9999 typ host";
2445 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2446 EXPECT_TRUE(SdpDeserializeCandidate(missing_tcptype, &jcandidate));
2447
2448 EXPECT_EQ(std::string(cricket::TCPTYPE_PASSIVE_STR),
2449 jcandidate.candidate().tcptype());
2450}
2451
2452TEST_F(WebRtcSdpTest, ParseSslTcpCandidate) {
2453 std::string ssltcp =
2454 "candidate:a0+B/1 1 ssltcp 2130706432 192.168.1.5 9999 typ host tcptype "
2455 "passive";
2456 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2457 EXPECT_TRUE(SdpDeserializeCandidate(ssltcp, &jcandidate));
2458
2459 EXPECT_EQ(std::string("ssltcp"), jcandidate.candidate().protocol());
2460}
2461
htaa6b99442016-04-12 10:29:17 -07002462TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithH264) {
magjed509e4fe2016-11-18 01:34:11 -08002463 cricket::VideoCodec h264_codec("H264");
2464 h264_codec.SetParam("profile-level-id", "42e01f");
2465 h264_codec.SetParam("level-asymmetry-allowed", "1");
2466 h264_codec.SetParam("packetization-mode", "1");
2467 video_desc_->AddCodec(h264_codec);
2468
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002469 jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
htaa6b99442016-04-12 10:29:17 -07002470
Steve Antone831b8c2018-02-01 12:22:16 -08002471 std::string message = webrtc::SdpSerialize(jdesc_);
htaa6b99442016-04-12 10:29:17 -07002472 size_t after_pt = message.find(" H264/90000");
2473 ASSERT_NE(after_pt, std::string::npos);
2474 size_t before_pt = message.rfind("a=rtpmap:", after_pt);
2475 ASSERT_NE(before_pt, std::string::npos);
2476 before_pt += strlen("a=rtpmap:");
2477 std::string pt = message.substr(before_pt, after_pt - before_pt);
2478 // TODO(hta): Check if payload type |pt| occurs in the m=video line.
2479 std::string to_find = "a=fmtp:" + pt + " ";
2480 size_t fmtp_pos = message.find(to_find);
2481 ASSERT_NE(std::string::npos, fmtp_pos) << "Failed to find " << to_find;
Mirko Bonadei37ec55e2019-01-28 11:43:52 +01002482 size_t fmtp_endpos = message.find('\n', fmtp_pos);
htaa6b99442016-04-12 10:29:17 -07002483 ASSERT_NE(std::string::npos, fmtp_endpos);
2484 std::string fmtp_value = message.substr(fmtp_pos, fmtp_endpos);
2485 EXPECT_NE(std::string::npos, fmtp_value.find("level-asymmetry-allowed=1"));
2486 EXPECT_NE(std::string::npos, fmtp_value.find("packetization-mode=1"));
2487 EXPECT_NE(std::string::npos, fmtp_value.find("profile-level-id=42e01f"));
hta62a216e2016-04-15 11:02:14 -07002488 // Check that there are no spaces after semicolons.
2489 // https://bugs.webrtc.org/5793
2490 EXPECT_EQ(std::string::npos, fmtp_value.find("; "));
htaa6b99442016-04-12 10:29:17 -07002491}
2492
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002493TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
Steve Antona3a92c22017-12-07 10:27:41 -08002494 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002495 // Deserialize
2496 EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
2497 // Verify
2498 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2499}
2500
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002501TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
Steve Antona3a92c22017-12-07 10:27:41 -08002502 JsepSessionDescription jdesc(kDummyType);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002503 const char kSdpWithoutMline[] =
Yves Gerey665174f2018-06-19 15:03:05 +02002504 "v=0\r\n"
2505 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2506 "s=-\r\n"
2507 "t=0 0\r\n"
2508 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002509 // Deserialize
2510 EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
2511 EXPECT_EQ(0u, jdesc.description()->contents().size());
2512}
2513
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
Steve Antona3a92c22017-12-07 10:27:41 -08002515 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002516 std::string sdp_without_carriage_return = kSdpFullString;
2517 Replace("\r\n", "\n", &sdp_without_carriage_return);
2518 // Deserialize
2519 EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
2520 // Verify
2521 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2522}
2523
2524TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
2525 // SessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 10:27:41 -08002526 JsepSessionDescription jdesc_no_candidates(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002527 ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Clone(), kSessionId,
Yves Gerey665174f2018-06-19 15:03:05 +02002528 kSessionVersion));
Steve Antona3a92c22017-12-07 10:27:41 -08002529 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530 EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
2531 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
2532}
2533
2534TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
2535 static const char kSdpNoRtpmapString[] =
2536 "v=0\r\n"
2537 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2538 "s=-\r\n"
2539 "t=0 0\r\n"
2540 "m=audio 49232 RTP/AVP 0 18 103\r\n"
2541 // Codec that doesn't appear in the m= line will be ignored.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002542 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002543 // The rtpmap line for static payload codec is optional.
2544 "a=rtpmap:18 G729/16000\r\n"
2545 "a=rtpmap:103 ISAC/16000\r\n";
2546
Steve Antona3a92c22017-12-07 10:27:41 -08002547 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002548 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2549 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08002550 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002551 AudioCodecs ref_codecs;
deadbeef67cf2c12016-04-13 10:07:16 -07002552 // The codecs in the AudioContentDescription should be in the same order as
2553 // the payload types (<fmt>s) on the m= line.
2554 ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1));
2555 ref_codecs.push_back(AudioCodec(18, "G729", 16000, 0, 1));
ossue1405ad2017-01-23 08:55:48 -08002556 ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 0, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002557 EXPECT_EQ(ref_codecs, audio->codecs());
2558}
2559
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002560TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
2561 static const char kSdpNoRtpmapString[] =
2562 "v=0\r\n"
2563 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2564 "s=-\r\n"
2565 "t=0 0\r\n"
2566 "m=audio 49232 RTP/AVP 18 103\r\n"
2567 "a=fmtp:18 annexb=yes\r\n"
2568 "a=rtpmap:103 ISAC/16000\r\n";
2569
Steve Antona3a92c22017-12-07 10:27:41 -08002570 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002571 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2572 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08002573 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002574
2575 cricket::AudioCodec g729 = audio->codecs()[0];
2576 EXPECT_EQ("G729", g729.name);
2577 EXPECT_EQ(8000, g729.clockrate);
2578 EXPECT_EQ(18, g729.id);
Yves Gerey665174f2018-06-19 15:03:05 +02002579 cricket::CodecParameterMap::iterator found = g729.params.find("annexb");
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002580 ASSERT_TRUE(found != g729.params.end());
2581 EXPECT_EQ(found->second, "yes");
2582
2583 cricket::AudioCodec isac = audio->codecs()[1];
2584 EXPECT_EQ("ISAC", isac.name);
2585 EXPECT_EQ(103, isac.id);
2586 EXPECT_EQ(16000, isac.clockrate);
2587}
2588
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002589// Ensure that we can deserialize SDP with a=fingerprint properly.
2590TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
2591 // Add a DTLS a=fingerprint attribute to our session description.
2592 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08002593 JsepSessionDescription new_jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002594 ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002595 jdesc_.session_version()));
2596
Steve Antona3a92c22017-12-07 10:27:41 -08002597 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002598 std::string sdp_with_fingerprint = kSdpString;
2599 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2600 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
2601 EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
2602 EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
2603}
2604
2605TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
Steve Antona3a92c22017-12-07 10:27:41 -08002606 JsepSessionDescription jdesc_with_bundle(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002607 std::string sdp_with_bundle = kSdpFullString;
2608 InjectAfter(kSessionTime,
2609 "a=group:BUNDLE audio_content_name video_content_name\r\n",
2610 &sdp_with_bundle);
2611 EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
2612 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
2613 group.AddContentName(kAudioContentName);
2614 group.AddContentName(kVideoContentName);
2615 desc_.AddGroup(group);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002616 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002617 jdesc_.session_version()));
2618 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
2619}
2620
2621TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
Steve Antona3a92c22017-12-07 10:27:41 -08002622 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002623 std::string sdp_with_bandwidth = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002624 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002625 &sdp_with_bandwidth);
Yves Gerey665174f2018-06-19 15:03:05 +02002626 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=AS:50\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002627 &sdp_with_bandwidth);
Yves Gerey665174f2018-06-19 15:03:05 +02002628 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
Steve Antonb1c1de12017-12-21 15:14:30 -08002629 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630 vcd->set_bandwidth(100 * 1000);
Steve Antonb1c1de12017-12-21 15:14:30 -08002631 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002632 acd->set_bandwidth(50 * 1000);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002633 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002634 jdesc_.session_version()));
2635 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2636}
2637
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002638TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithTiasBandwidth) {
2639 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
2640 std::string sdp_with_bandwidth = kSdpFullString;
2641 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=TIAS:100000\r\n",
2642 &sdp_with_bandwidth);
2643 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=TIAS:50000\r\n",
2644 &sdp_with_bandwidth);
2645 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2646 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2647 vcd->set_bandwidth(100 * 1000);
2648 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
2649 acd->set_bandwidth(50 * 1000);
2650 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2651 jdesc_.session_version()));
2652 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2653}
2654
Philipp Hanckefbbfc022020-07-31 08:30:50 +02002655TEST_F(WebRtcSdpTest,
2656 DeserializeSessionDescriptionWithUnknownBandwidthModifier) {
2657 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
2658 std::string sdp_with_bandwidth = kSdpFullString;
2659 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
2660 "b=unknown:100000\r\n", &sdp_with_bandwidth);
2661 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
2662 "b=unknown:50000\r\n", &sdp_with_bandwidth);
2663 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2664 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2665 vcd->set_bandwidth(-1);
2666 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
2667 acd->set_bandwidth(-1);
2668 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2669 jdesc_.session_version()));
2670 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2671}
2672
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002673TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
Steve Antona3a92c22017-12-07 10:27:41 -08002674 JsepSessionDescription jdesc_with_ice_options(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002675 std::string sdp_with_ice_options = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002676 InjectAfter(kSessionTime, "a=ice-options:iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002677 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 15:03:05 +02002678 InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002679 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 15:03:05 +02002680 InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681 &sdp_with_ice_options);
2682 EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
2683 std::vector<std::string> transport_options;
2684 transport_options.push_back(kIceOption3);
2685 transport_options.push_back(kIceOption1);
2686 AddIceOptions(kAudioContentName, transport_options);
2687 transport_options.clear();
2688 transport_options.push_back(kIceOption3);
2689 transport_options.push_back(kIceOption2);
2690 AddIceOptions(kVideoContentName, transport_options);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002691 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692 jdesc_.session_version()));
2693 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
2694}
2695
2696TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
2697 // Remove the original ice-ufrag and ice-pwd
Steve Antona3a92c22017-12-07 10:27:41 -08002698 JsepSessionDescription jdesc_with_ufrag_pwd(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002699 std::string sdp_with_ufrag_pwd = kSdpFullString;
2700 EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
2701 // Add session level ufrag and pwd
2702 InjectAfter(kSessionTime,
Yves Gerey665174f2018-06-19 15:03:05 +02002703 "a=ice-pwd:session+level+icepwd\r\n"
2704 "a=ice-ufrag:session+level+iceufrag\r\n",
2705 &sdp_with_ufrag_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002706 // Add media level ufrag and pwd for audio
Yves Gerey665174f2018-06-19 15:03:05 +02002707 InjectAfter(
2708 "a=mid:audio_content_name\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002709 "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
2710 &sdp_with_ufrag_pwd);
2711 // Update the candidate ufrag and pwd to the expected ones.
Yves Gerey665174f2018-06-19 15:03:05 +02002712 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0, "media+level+iceufrag",
2713 "media+level+icepwd"));
2714 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1, "session+level+iceufrag",
2715 "session+level+icepwd"));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716 EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
2717 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
2718}
2719
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002721 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722}
2723
2724TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002725 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002726}
2727
2728TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002729 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730}
2731
2732TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
2733 EXPECT_TRUE(TestDeserializeRejected(true, false));
2734}
2735
2736TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
2737 EXPECT_TRUE(TestDeserializeRejected(false, true));
2738}
2739
2740TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
2741 EXPECT_TRUE(TestDeserializeRejected(true, true));
2742}
2743
Artem Titovf0a34f22020-03-16 17:52:04 +00002744// Tests that we can still handle the sdp uses mslabel and label instead of
2745// msid for backward compatibility.
2746TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMsid) {
2747 jdesc_.description()->set_msid_supported(false);
2748 JsepSessionDescription jdesc(kDummyType);
2749 std::string sdp_without_msid = kSdpFullString;
2750 Replace("msid", "xmsid", &sdp_without_msid);
2751 // Deserialize
2752 EXPECT_TRUE(SdpDeserialize(sdp_without_msid, &jdesc));
2753 // Verify
2754 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2755 EXPECT_FALSE(jdesc.description()->msid_signaling() &
2756 ~cricket::kMsidSignalingSsrcAttribute);
2757}
2758
Johannes Kron0854eb62018-10-10 22:33:20 +02002759TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 10:17:39 +02002760 jdesc_.description()->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002761 std::string sdp_with_extmap_allow_mixed = kSdpFullString;
Johannes Kron0854eb62018-10-10 22:33:20 +02002762 // Deserialize
2763 JsepSessionDescription jdesc_deserialized(kDummyType);
Emil Lundmark801c9992021-01-19 13:06:32 +01002764 ASSERT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
Johannes Kron0854eb62018-10-10 22:33:20 +02002765 // Verify
2766 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2767}
2768
2769TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 10:17:39 +02002770 jdesc_.description()->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002771 std::string sdp_without_extmap_allow_mixed = kSdpFullString;
Emil Lundmark801c9992021-01-19 13:06:32 +01002772 Replace(kExtmapAllowMixed, "", &sdp_without_extmap_allow_mixed);
Johannes Kron0854eb62018-10-10 22:33:20 +02002773 // Deserialize
2774 JsepSessionDescription jdesc_deserialized(kDummyType);
Emil Lundmark801c9992021-01-19 13:06:32 +01002775 ASSERT_TRUE(
Johannes Kron0854eb62018-10-10 22:33:20 +02002776 SdpDeserialize(sdp_without_extmap_allow_mixed, &jdesc_deserialized));
2777 // Verify
2778 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2779}
2780
2781TEST_F(WebRtcSdpTest, DeserializeMediaContentDescriptionWithExtmapAllowMixed) {
2782 cricket::MediaContentDescription* video_desc =
2783 jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
2784 ASSERT_TRUE(video_desc);
2785 cricket::MediaContentDescription* audio_desc =
2786 jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
2787 ASSERT_TRUE(audio_desc);
Johannes Kron9581bc42018-10-23 10:17:39 +02002788 video_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002789 cricket::MediaContentDescription::kMedia);
Johannes Kron9581bc42018-10-23 10:17:39 +02002790 audio_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002791 cricket::MediaContentDescription::kMedia);
2792
2793 std::string sdp_with_extmap_allow_mixed = kSdpFullString;
2794 InjectAfter("a=mid:audio_content_name\r\n", kExtmapAllowMixed,
2795 &sdp_with_extmap_allow_mixed);
2796 InjectAfter("a=mid:video_content_name\r\n", kExtmapAllowMixed,
2797 &sdp_with_extmap_allow_mixed);
2798
2799 // Deserialize
2800 JsepSessionDescription jdesc_deserialized(kDummyType);
2801 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
2802 // Verify
2803 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2804}
2805
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002806TEST_F(WebRtcSdpTest, DeserializeCandidate) {
2807 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2808
2809 std::string sdp = kSdpOneCandidate;
2810 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2811 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2812 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2813 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
honghaiza0c44ea2016-03-23 16:07:48 -07002814 EXPECT_EQ(0, jcandidate.candidate().network_cost());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815
2816 // Candidate line without generation extension.
2817 sdp = kSdpOneCandidate;
2818 Replace(" generation 2", "", &sdp);
2819 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2820 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2821 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2822 Candidate expected = jcandidate_->candidate();
2823 expected.set_generation(0);
2824 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2825
honghaiza0c44ea2016-03-23 16:07:48 -07002826 // Candidate with network id and/or cost.
2827 sdp = kSdpOneCandidate;
2828 Replace(" generation 2", " generation 2 network-id 2", &sdp);
2829 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2830 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2831 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2832 expected = jcandidate_->candidate();
2833 expected.set_network_id(2);
2834 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2835 EXPECT_EQ(0, jcandidate.candidate().network_cost());
2836 // Add network cost
2837 Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
2838 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2839 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2840 EXPECT_EQ(9, jcandidate.candidate().network_cost());
2841
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002842 sdp = kSdpTcpActiveCandidate;
2843 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2844 // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00002845 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00002846 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2847 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2848 kCandidateFoundation1);
kwibergd1fe2812016-04-27 06:47:29 -07002849 std::unique_ptr<IceCandidateInterface> jcandidate_template(
2850 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
Yves Gerey665174f2018-06-19 15:03:05 +02002851 EXPECT_TRUE(
2852 jcandidate.candidate().IsEquivalent(jcandidate_template->candidate()));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002853 sdp = kSdpTcpPassiveCandidate;
2854 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2855 sdp = kSdpTcpSOCandidate;
2856 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002857}
2858
2859// This test verifies the deserialization of candidate-attribute
2860// as per RFC 5245. Candiate-attribute will be of the format
2861// candidate:<blah>. This format will be used when candidates
2862// are trickled.
2863TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
2864 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2865
2866 std::string candidate_attribute = kRawCandidate;
2867 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2868 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2869 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2870 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2871 EXPECT_EQ(2u, jcandidate.candidate().generation());
2872
2873 // Candidate line without generation extension.
2874 candidate_attribute = kRawCandidate;
2875 Replace(" generation 2", "", &candidate_attribute);
2876 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2877 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2878 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2879 Candidate expected = jcandidate_->candidate();
2880 expected.set_generation(0);
2881 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2882
2883 // Candidate line without candidate:
2884 candidate_attribute = kRawCandidate;
2885 Replace("candidate:", "", &candidate_attribute);
2886 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2887
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002888 // Candidate line with IPV6 address.
2889 EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
Zach Steinb336c272018-08-09 01:16:13 -07002890
2891 // Candidate line with hostname address.
2892 EXPECT_TRUE(SdpDeserializeCandidate(kRawHostnameCandidate, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002893}
2894
2895// This test verifies that the deserialization of an invalid candidate string
2896// fails.
2897TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
Yves Gerey665174f2018-06-19 15:03:05 +02002898 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002899
2900 std::string candidate_attribute = kRawCandidate;
2901 candidate_attribute.replace(0, 1, "x");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002903
2904 candidate_attribute = kSdpOneCandidate;
2905 candidate_attribute.replace(0, 1, "x");
2906 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2907
2908 candidate_attribute = kRawCandidate;
2909 candidate_attribute.append("\r\n");
2910 candidate_attribute.append(kRawCandidate);
2911 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2912
2913 EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002914}
2915
2916TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannels) {
2917 AddRtpDataChannel();
Steve Antona3a92c22017-12-07 10:27:41 -08002918 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002919 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002920
2921 std::string sdp_with_data = kSdpString;
2922 sdp_with_data.append(kSdpRtpDataChannelString);
Steve Antona3a92c22017-12-07 10:27:41 -08002923 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924
2925 // Deserialize
2926 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2927 // Verify
2928 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2929}
2930
2931TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
zstein4b2e0822017-02-17 19:48:38 -08002932 bool use_sctpmap = true;
2933 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002934 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002935 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002936
2937 std::string sdp_with_data = kSdpString;
2938 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Antona3a92c22017-12-07 10:27:41 -08002939 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002940
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002941 // Verify with UDP/DTLS/SCTP (already in kSdpSctpDataChannelString).
lally@webrtc.org36300852015-02-24 20:19:35 +00002942 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2943 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2944
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002945 // Verify with DTLS/SCTP.
2946 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp), strlen(kUdpDtlsSctp),
2947 kDtlsSctp);
lally@webrtc.org36300852015-02-24 20:19:35 +00002948 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2949 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2950
2951 // Verify with TCP/DTLS/SCTP.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002952 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp), strlen(kDtlsSctp),
Yves Gerey665174f2018-06-19 15:03:05 +02002953 kTcpDtlsSctp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2955 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2956}
2957
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002958TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
zstein4b2e0822017-02-17 19:48:38 -08002959 bool use_sctpmap = false;
2960 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002961 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002962 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002963
2964 std::string sdp_with_data = kSdpString;
2965 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Antona3a92c22017-12-07 10:27:41 -08002966 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002967
lally@webrtc.orgc7848b72015-02-24 20:19:26 +00002968 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2969 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2970}
2971
lally69f57602015-10-08 10:15:04 -07002972TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) {
zstein4b2e0822017-02-17 19:48:38 -08002973 bool use_sctpmap = false;
2974 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002975 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002976 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
lally69f57602015-10-08 10:15:04 -07002977
2978 std::string sdp_with_data = kSdpString;
2979 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
Steve Antona3a92c22017-12-07 10:27:41 -08002980 JsepSessionDescription jdesc_output(kDummyType);
lally69f57602015-10-08 10:15:04 -07002981
lally69f57602015-10-08 10:15:04 -07002982 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2983 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2984}
2985
Philipp Hanckeefc55b02020-06-26 10:17:05 +02002986TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsButWrongMediaType) {
2987 bool use_sctpmap = true;
2988 AddSctpDataChannel(use_sctpmap);
2989 JsepSessionDescription jdesc(kDummyType);
2990 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
2991
2992 std::string sdp = kSdpSessionString;
2993 sdp += kSdpSctpDataChannelString;
2994
2995 const char needle[] = "m=application ";
2996 sdp.replace(sdp.find(needle), strlen(needle), "m=application:bogus ");
2997
2998 JsepSessionDescription jdesc_output(kDummyType);
2999 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
3000
Philipp Hancke4e8c1152020-10-13 12:43:15 +02003001 EXPECT_EQ(1u, jdesc_output.description()->contents().size());
3002 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
Philipp Hanckeefc55b02020-06-26 10:17:05 +02003003}
3004
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02003005// Helper function to set the max-message-size parameter in the
3006// SCTP data codec.
3007void MutateJsepSctpMaxMessageSize(const SessionDescription& desc,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003008 int new_value,
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02003009 JsepSessionDescription* jdesc) {
Harald Alvestrand8da35a62019-05-10 09:31:04 +02003010 std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003011 SctpDataContentDescription* dcdesc =
3012 mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
3013 dcdesc->set_max_message_size(new_value);
Harald Alvestrand8da35a62019-05-10 09:31:04 +02003014 jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion);
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02003015}
3016
3017TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithMaxMessageSize) {
3018 bool use_sctpmap = false;
3019 AddSctpDataChannel(use_sctpmap);
3020 JsepSessionDescription jdesc(kDummyType);
3021 std::string sdp_with_data = kSdpString;
3022
3023 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
3024 sdp_with_data.append("a=max-message-size:12345\r\n");
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003025 MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02003026 JsepSessionDescription jdesc_output(kDummyType);
3027
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02003028 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
3029 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
3030}
3031
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02003032TEST_F(WebRtcSdpTest, SerializeSdpWithSctpDataChannelWithMaxMessageSize) {
3033 bool use_sctpmap = false;
3034 AddSctpDataChannel(use_sctpmap);
3035 JsepSessionDescription jdesc(kDummyType);
3036 MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
3037 std::string message = webrtc::SdpSerialize(jdesc);
3038 EXPECT_NE(std::string::npos,
3039 message.find("\r\na=max-message-size:12345\r\n"));
3040 JsepSessionDescription jdesc_output(kDummyType);
3041 EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
3042 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
3043}
3044
3045TEST_F(WebRtcSdpTest,
3046 SerializeSdpWithSctpDataChannelWithDefaultMaxMessageSize) {
3047 // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
3048 // The default max message size is 64K.
3049 bool use_sctpmap = false;
3050 AddSctpDataChannel(use_sctpmap);
3051 JsepSessionDescription jdesc(kDummyType);
3052 MutateJsepSctpMaxMessageSize(desc_, 65536, &jdesc);
3053 std::string message = webrtc::SdpSerialize(jdesc);
3054 EXPECT_EQ(std::string::npos, message.find("\r\na=max-message-size:"));
3055 JsepSessionDescription jdesc_output(kDummyType);
3056 EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
3057 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
3058}
3059
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00003060// Test to check the behaviour if sctp-port is specified
3061// on the m= line and in a=sctp-port.
3062TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
zstein4b2e0822017-02-17 19:48:38 -08003063 bool use_sctpmap = true;
3064 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08003065 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003066 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00003067
3068 std::string sdp_with_data = kSdpString;
3069 // Append m= attributes
3070 sdp_with_data.append(kSdpSctpDataChannelString);
3071 // Append a=sctp-port attribute
3072 sdp_with_data.append("a=sctp-port 5000\r\n");
Steve Antona3a92c22017-12-07 10:27:41 -08003073 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00003074
3075 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
3076}
3077
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003078// Test behavior if a=rtpmap occurs in an SCTP section.
3079TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpmapAttribute) {
3080 std::string sdp_with_data = kSdpString;
3081 // Append m= attributes
3082 sdp_with_data.append(kSdpSctpDataChannelString);
3083 // Append a=rtpmap attribute
3084 sdp_with_data.append("a=rtpmap:111 opus/48000/2\r\n");
3085 JsepSessionDescription jdesc_output(kDummyType);
3086 // Correct behavior is to ignore the extra attribute.
3087 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
3088}
3089
3090TEST_F(WebRtcSdpTest, DeserializeSdpWithStrangeApplicationProtocolNames) {
3091 static const char* bad_strings[] = {"DTLS/SCTPRTP/", "obviously-bogus",
3092 "UDP/TL/RTSP/SAVPF", "UDP/TL/RTSP/S"};
3093 for (auto proto : bad_strings) {
3094 std::string sdp_with_data = kSdpString;
3095 sdp_with_data.append("m=application 9 ");
3096 sdp_with_data.append(proto);
3097 sdp_with_data.append(" 47\r\n");
3098 JsepSessionDescription jdesc_output(kDummyType);
3099 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output))
3100 << "Parsing should have failed on " << proto;
3101 }
3102 // The following strings are strange, but acceptable as RTP.
3103 static const char* weird_strings[] = {"DTLS/SCTP/RTP/FOO",
3104 "obviously-bogus/RTP/"};
3105 for (auto proto : weird_strings) {
3106 std::string sdp_with_data = kSdpString;
3107 sdp_with_data.append("m=application 9 ");
3108 sdp_with_data.append(proto);
3109 sdp_with_data.append(" 47\r\n");
3110 JsepSessionDescription jdesc_output(kDummyType);
3111 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output))
3112 << "Parsing should have succeeded on " << proto;
3113 }
3114}
3115
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00003116// For crbug/344475.
3117TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
3118 std::string sdp_with_data = kSdpString;
3119 sdp_with_data.append(kSdpSctpDataChannelString);
3120 // Remove the "\n" at the end.
3121 sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
Steve Antona3a92c22017-12-07 10:27:41 -08003122 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00003123
3124 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
3125 // No crash is a pass.
3126}
3127
zstein4b2e0822017-02-17 19:48:38 -08003128TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) {
3129 bool use_sctpmap = true;
3130 AddSctpDataChannel(use_sctpmap);
3131
3132 // First setup the expected JsepSessionDescription.
Steve Antona3a92c22017-12-07 10:27:41 -08003133 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003134 MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
wu@webrtc.org78187522013-10-07 23:32:02 +00003135
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00003136 // Then get the deserialized JsepSessionDescription.
wu@webrtc.org78187522013-10-07 23:32:02 +00003137 std::string sdp_with_data = kSdpString;
3138 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Anton1c9c9fc2019-02-14 15:13:09 -08003139 absl::StrReplaceAll(
3140 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
3141 &sdp_with_data);
Steve Antona3a92c22017-12-07 10:27:41 -08003142 JsepSessionDescription jdesc_output(kDummyType);
wu@webrtc.org78187522013-10-07 23:32:02 +00003143
3144 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
3145 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
zstein4b2e0822017-02-17 19:48:38 -08003146}
3147
3148TEST_F(WebRtcSdpTest,
3149 DeserializeSdpWithSctpDataChannelAndUnusualPortInAttribute) {
3150 bool use_sctpmap = false;
3151 AddSctpDataChannel(use_sctpmap);
3152
Steve Antona3a92c22017-12-07 10:27:41 -08003153 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003154 MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00003155
3156 // We need to test the deserialized JsepSessionDescription from
3157 // kSdpSctpDataChannelStringWithSctpPort for
3158 // draft-ietf-mmusic-sctp-sdp-07
3159 // a=sctp-port
zstein4b2e0822017-02-17 19:48:38 -08003160 std::string sdp_with_data = kSdpString;
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00003161 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Anton1c9c9fc2019-02-14 15:13:09 -08003162 absl::StrReplaceAll(
3163 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
3164 &sdp_with_data);
Steve Antona3a92c22017-12-07 10:27:41 -08003165 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00003166
3167 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
3168 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
wu@webrtc.org78187522013-10-07 23:32:02 +00003169}
3170
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003171TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003172 // We want to test that deserializing data content limits bandwidth
3173 // settings (it should never be greater than the default).
3174 // This should prevent someone from using unlimited data bandwidth through
3175 // JS and "breaking the Internet".
3176 // See: https://code.google.com/p/chromium/issues/detail?id=280726
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003177 std::string sdp_with_bandwidth = kSdpString;
3178 sdp_with_bandwidth.append(kSdpRtpDataChannelString);
Yves Gerey665174f2018-06-19 15:03:05 +02003179 InjectAfter("a=mid:data_content_name\r\n", "b=AS:100\r\n",
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003180 &sdp_with_bandwidth);
Steve Antona3a92c22017-12-07 10:27:41 -08003181 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003182
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003183 EXPECT_FALSE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
3184}
3185
3186TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
zstein4b2e0822017-02-17 19:48:38 -08003187 bool use_sctpmap = true;
3188 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08003189 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003190 SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003191 dcd->set_bandwidth(100 * 1000);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003192 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003193
3194 std::string sdp_with_bandwidth = kSdpString;
3195 sdp_with_bandwidth.append(kSdpSctpDataChannelString);
Yves Gerey665174f2018-06-19 15:03:05 +02003196 InjectAfter("a=mid:data_content_name\r\n", "b=AS:100\r\n",
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003197 &sdp_with_bandwidth);
Steve Antona3a92c22017-12-07 10:27:41 -08003198 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003199
3200 // SCTP has congestion control, so we shouldn't limit the bandwidth
3201 // as we do for RTP.
3202 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003203 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
3204}
3205
Yves Gerey665174f2018-06-19 15:03:05 +02003206class WebRtcSdpExtmapTest : public WebRtcSdpTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003207 public ::testing::WithParamInterface<bool> {};
jbauch5869f502017-06-29 12:31:36 -07003208
3209TEST_P(WebRtcSdpExtmapTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003210 DeserializeSessionDescriptionWithSessionLevelExtmap) {
jbauch5869f502017-06-29 12:31:36 -07003211 bool encrypted = GetParam();
3212 TestDeserializeExtmap(true, false, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003213}
3214
Yves Gerey665174f2018-06-19 15:03:05 +02003215TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
jbauch5869f502017-06-29 12:31:36 -07003216 bool encrypted = GetParam();
3217 TestDeserializeExtmap(false, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003218}
3219
Yves Gerey665174f2018-06-19 15:03:05 +02003220TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithInvalidExtmap) {
jbauch5869f502017-06-29 12:31:36 -07003221 bool encrypted = GetParam();
3222 TestDeserializeExtmap(true, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003223}
3224
Mirko Bonadeic84f6612019-01-31 12:20:57 +01003225INSTANTIATE_TEST_SUITE_P(Encrypted,
3226 WebRtcSdpExtmapTest,
3227 ::testing::Values(false, true));
jbauch5869f502017-06-29 12:31:36 -07003228
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00003229TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
Steve Antona3a92c22017-12-07 10:27:41 -08003230 JsepSessionDescription jdesc(kDummyType);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00003231 std::string sdp = kSdpFullString;
3232 sdp = sdp.substr(0, sdp.size() - 2); // Remove \r\n at the end.
3233 // Deserialize
3234 SdpParseError error;
3235 EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
Artem Titovf0a34f22020-03-16 17:52:04 +00003236 const std::string lastline = "a=ssrc:3 label:video_track_id_1";
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00003237 EXPECT_EQ(lastline, error.line);
3238 EXPECT_EQ("Invalid SDP line.", error.description);
3239}
3240
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003241TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
3242 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
3243 std::string new_sdp = kSdpOneCandidate;
3244 Replace("udp", "unsupported_transport", &new_sdp);
3245 EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
3246 new_sdp = kSdpOneCandidate;
3247 Replace("udp", "uDP", &new_sdp);
3248 EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
3249 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
3250 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
3251 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
3252}
3253
honghaiza54a0802015-12-16 18:37:23 -08003254TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003255 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
honghaiza54a0802015-12-16 18:37:23 -08003256 EXPECT_TRUE(
3257 SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003258 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
3259 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
3260 Candidate ref_candidate = jcandidate_->candidate();
3261 ref_candidate.set_username("user_rtp");
3262 ref_candidate.set_password("password_rtp");
3263 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
3264}
3265
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003266TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 10:27:41 -08003267 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003268
3269 // Deserialize
3270 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
3271
3272 // Verify
3273 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08003274 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003275 EXPECT_TRUE(audio->conference_mode());
3276
3277 cricket::VideoContentDescription* video =
Steve Anton06817cd2018-12-18 15:55:30 -08003278 cricket::GetFirstVideoContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003279 EXPECT_TRUE(video->conference_mode());
3280}
3281
deadbeefd45aea82017-09-16 01:24:29 -07003282TEST_F(WebRtcSdpTest, SerializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 10:27:41 -08003283 JsepSessionDescription jdesc(kDummyType);
deadbeefd45aea82017-09-16 01:24:29 -07003284
3285 // We tested deserialization already above, so just test that if we serialize
3286 // and deserialize the flag doesn't disappear.
3287 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
Steve Antone831b8c2018-02-01 12:22:16 -08003288 std::string reserialized = webrtc::SdpSerialize(jdesc);
deadbeefd45aea82017-09-16 01:24:29 -07003289 EXPECT_TRUE(SdpDeserialize(reserialized, &jdesc));
3290
3291 // Verify.
3292 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08003293 cricket::GetFirstAudioContentDescription(jdesc.description());
deadbeefd45aea82017-09-16 01:24:29 -07003294 EXPECT_TRUE(audio->conference_mode());
3295
3296 cricket::VideoContentDescription* video =
Steve Anton06817cd2018-12-18 15:55:30 -08003297 cricket::GetFirstVideoContentDescription(jdesc.description());
deadbeefd45aea82017-09-16 01:24:29 -07003298 EXPECT_TRUE(video->conference_mode());
3299}
3300
Sebastian Jansson97321b62019-07-24 14:01:18 +02003301TEST_F(WebRtcSdpTest, SerializeAndDeserializeRemoteNetEstimate) {
3302 {
3303 // By default remote estimates are disabled.
3304 JsepSessionDescription dst(kDummyType);
3305 SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
3306 EXPECT_FALSE(cricket::GetFirstVideoContentDescription(dst.description())
3307 ->remote_estimate());
3308 }
3309 {
3310 // When remote estimate is enabled, the setting is propagated via SDP.
3311 cricket::GetFirstVideoContentDescription(jdesc_.description())
3312 ->set_remote_estimate(true);
3313 JsepSessionDescription dst(kDummyType);
3314 SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
3315 EXPECT_TRUE(cricket::GetFirstVideoContentDescription(dst.description())
3316 ->remote_estimate());
3317 }
3318}
3319
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003320TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
3321 const char kSdpDestroyer[] = "!@#$%^&";
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00003322 const char kSdpEmptyType[] = " =candidate";
3323 const char kSdpEqualAsPlus[] = "a+candidate";
3324 const char kSdpSpaceAfterEqual[] = "a= candidate";
3325 const char kSdpUpperType[] = "A=candidate";
3326 const char kSdpEmptyLine[] = "";
3327 const char kSdpMissingValue[] = "a=";
3328
Yves Gerey665174f2018-06-19 15:03:05 +02003329 const char kSdpBrokenFingerprint[] =
3330 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003331 "4AAD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
Yves Gerey665174f2018-06-19 15:03:05 +02003332 const char kSdpExtraField[] =
3333 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003334 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB XXX";
Yves Gerey665174f2018-06-19 15:03:05 +02003335 const char kSdpMissingSpace[] =
3336 "a=fingerprint:sha-1"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003337 "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 +00003338 // MD5 is not allowed in fingerprints.
Yves Gerey665174f2018-06-19 15:03:05 +02003339 const char kSdpMd5[] =
3340 "a=fingerprint:md5 "
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00003341 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003342
3343 // Broken session description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003344 ExpectParseFailure("v=", kSdpDestroyer);
3345 ExpectParseFailure("o=", kSdpDestroyer);
3346 ExpectParseFailure("s=-", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003347 // Broken time description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003348 ExpectParseFailure("t=", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003349
3350 // Broken media description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003351 ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
3352 ExpectParseFailure("m=video", kSdpDestroyer);
Philipp Hanckeefc55b02020-06-26 10:17:05 +02003353 ExpectParseFailure("m=", "c=IN IP4 74.125.224.39");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003354
3355 // Invalid lines
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00003356 ExpectParseFailure("a=candidate", kSdpEmptyType);
3357 ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
3358 ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
3359 ExpectParseFailure("a=candidate", kSdpUpperType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003360
3361 // Bogus fingerprint replacing a=sendrev. We selected this attribute
3362 // because it's orthogonal to what we are replacing and hence
3363 // safe.
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00003364 ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
3365 ExpectParseFailure("a=sendrecv", kSdpExtraField);
3366 ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
3367 ExpectParseFailure("a=sendrecv", kSdpMd5);
3368
3369 // Empty Line
3370 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
3371 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003372}
3373
3374TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
3375 // ssrc
3376 ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
deadbeef9d3584c2016-02-16 17:54:10 -08003377 ExpectParseFailure("a=ssrc-group:FEC 2 3", "a=ssrc-group:FEC badvalue 3");
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003378 // crypto
3379 ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
3380 // rtpmap
3381 ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
3382 ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
3383 ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
3384 // candidate
3385 ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
3386 ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
3387 ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
3388 ExpectParseFailure("rport 2346", "rport badvalue");
3389 ExpectParseFailure("rport 2346 generation 2",
3390 "rport 2346 generation badvalue");
3391 // m line
3392 ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
3393 "m=audio 2345 RTP/SAVPF 111 badvalue 104");
3394
3395 // bandwidth
3396 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
Yves Gerey665174f2018-06-19 15:03:05 +02003397 "b=AS:badvalue\r\n", "b=AS:badvalue");
Philipp Hanckefbbfc022020-07-31 08:30:50 +02003398 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS\r\n",
3399 "b=AS");
3400 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS:\r\n",
3401 "b=AS:");
3402 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3403 "b=AS:12:34\r\n", "b=AS:12:34");
3404
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003405 // rtcp-fb
3406 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3407 "a=rtcp-fb:badvalue nack\r\n",
3408 "a=rtcp-fb:badvalue nack");
3409 // extmap
3410 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3411 "a=extmap:badvalue http://example.com\r\n",
3412 "a=extmap:badvalue http://example.com");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003413}
3414
3415TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
Steve Antona3a92c22017-12-07 10:27:41 -08003416 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003417
3418 const char kSdpWithReorderedPlTypesString[] =
3419 "v=0\r\n"
3420 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3421 "s=-\r\n"
3422 "t=0 0\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00003423 "m=audio 9 RTP/SAVPF 104 103\r\n" // Pl type 104 preferred.
Yves Gerey665174f2018-06-19 15:03:05 +02003424 "a=rtpmap:111 opus/48000/2\r\n" // Pltype 111 listed before 103 and 104
3425 // in the map.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003426 "a=rtpmap:103 ISAC/16000\r\n" // Pltype 103 listed before 104 in the map.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00003427 "a=rtpmap:104 ISAC/32000\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003428
3429 // Deserialize
3430 EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
3431
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003432 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003433 GetFirstAudioContentDescription(jdesc_output.description());
3434 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003435 ASSERT_FALSE(acd->codecs().empty());
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00003436 EXPECT_EQ("ISAC", acd->codecs()[0].name);
3437 EXPECT_EQ(32000, acd->codecs()[0].clockrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003438 EXPECT_EQ(104, acd->codecs()[0].id);
3439}
3440
3441TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
Steve Antona3a92c22017-12-07 10:27:41 -08003442 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003443 CodecParams params;
3444 params.max_ptime = 40;
3445 params.ptime = 30;
3446 params.min_ptime = 10;
3447 params.sprop_stereo = 1;
3448 params.stereo = 1;
3449 params.useinband = 1;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00003450 params.maxaveragebitrate = 128000;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003451 TestDeserializeCodecParams(params, &jdesc_output);
Steve Antone831b8c2018-02-01 12:22:16 -08003452 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003453}
3454
3455TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
3456 const bool kUseWildcard = false;
Steve Antona3a92c22017-12-07 10:27:41 -08003457 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003458 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 12:22:16 -08003459 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460}
3461
3462TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
3463 const bool kUseWildcard = true;
Steve Antona3a92c22017-12-07 10:27:41 -08003464 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003465 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 12:22:16 -08003466 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003467}
3468
3469TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
Steve Antona3a92c22017-12-07 10:27:41 -08003470 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003471
3472 const char kSdpWithFmtpString[] =
3473 "v=0\r\n"
3474 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3475 "s=-\r\n"
3476 "t=0 0\r\n"
3477 "m=video 3457 RTP/SAVPF 120\r\n"
3478 "a=rtpmap:120 VP8/90000\r\n"
Donald Curtis0e07f922015-05-15 09:21:23 -07003479 "a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
3480
3481 // Deserialize
3482 SdpParseError error;
Donald Curtis144d0182015-05-15 13:14:24 -07003483 EXPECT_TRUE(
3484 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
Donald Curtis0e07f922015-05-15 09:21:23 -07003485
Donald Curtis0e07f922015-05-15 09:21:23 -07003486 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003487 GetFirstVideoContentDescription(jdesc_output.description());
3488 ASSERT_TRUE(vcd);
Donald Curtis0e07f922015-05-15 09:21:23 -07003489 ASSERT_FALSE(vcd->codecs().empty());
3490 cricket::VideoCodec vp8 = vcd->codecs()[0];
3491 EXPECT_EQ("VP8", vp8.name);
3492 EXPECT_EQ(120, vp8.id);
3493 cricket::CodecParameterMap::iterator found =
3494 vp8.params.find("x-google-min-bitrate");
3495 ASSERT_TRUE(found != vp8.params.end());
3496 EXPECT_EQ(found->second, "10");
3497 found = vp8.params.find("x-google-max-quantization");
3498 ASSERT_TRUE(found != vp8.params.end());
3499 EXPECT_EQ(found->second, "40");
3500}
3501
johan2d8d23e2016-06-03 01:22:42 -07003502TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSprops) {
Steve Antona3a92c22017-12-07 10:27:41 -08003503 JsepSessionDescription jdesc_output(kDummyType);
johan2d8d23e2016-06-03 01:22:42 -07003504
3505 const char kSdpWithFmtpString[] =
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=video 49170 RTP/AVP 98\r\n"
3511 "a=rtpmap:98 H264/90000\r\n"
3512 "a=fmtp:98 profile-level-id=42A01E; "
3513 "sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==\r\n";
3514
3515 // Deserialize.
3516 SdpParseError error;
3517 EXPECT_TRUE(
3518 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
3519
johan2d8d23e2016-06-03 01:22:42 -07003520 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003521 GetFirstVideoContentDescription(jdesc_output.description());
3522 ASSERT_TRUE(vcd);
johan2d8d23e2016-06-03 01:22:42 -07003523 ASSERT_FALSE(vcd->codecs().empty());
3524 cricket::VideoCodec h264 = vcd->codecs()[0];
3525 EXPECT_EQ("H264", h264.name);
3526 EXPECT_EQ(98, h264.id);
3527 cricket::CodecParameterMap::const_iterator found =
3528 h264.params.find("profile-level-id");
3529 ASSERT_TRUE(found != h264.params.end());
3530 EXPECT_EQ(found->second, "42A01E");
3531 found = h264.params.find("sprop-parameter-sets");
3532 ASSERT_TRUE(found != h264.params.end());
3533 EXPECT_EQ(found->second, "Z0IACpZTBYmI,aMljiA==");
3534}
3535
Donald Curtis0e07f922015-05-15 09:21:23 -07003536TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
Steve Antona3a92c22017-12-07 10:27:41 -08003537 JsepSessionDescription jdesc_output(kDummyType);
Donald Curtis0e07f922015-05-15 09:21:23 -07003538
3539 const char kSdpWithFmtpString[] =
3540 "v=0\r\n"
3541 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3542 "s=-\r\n"
3543 "t=0 0\r\n"
3544 "m=video 3457 RTP/SAVPF 120\r\n"
3545 "a=rtpmap:120 VP8/90000\r\n"
3546 "a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003547
3548 // Deserialize
3549 SdpParseError error;
Yves Gerey665174f2018-06-19 15:03:05 +02003550 EXPECT_TRUE(
3551 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003552
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003553 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003554 GetFirstVideoContentDescription(jdesc_output.description());
3555 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003556 ASSERT_FALSE(vcd->codecs().empty());
3557 cricket::VideoCodec vp8 = vcd->codecs()[0];
3558 EXPECT_EQ("VP8", vp8.name);
3559 EXPECT_EQ(120, vp8.id);
3560 cricket::CodecParameterMap::iterator found =
3561 vp8.params.find("x-google-min-bitrate");
3562 ASSERT_TRUE(found != vp8.params.end());
3563 EXPECT_EQ(found->second, "10");
3564 found = vp8.params.find("x-google-max-quantization");
3565 ASSERT_TRUE(found != vp8.params.end());
3566 EXPECT_EQ(found->second, "40");
3567}
3568
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02003569TEST_F(WebRtcSdpTest, DeserializePacketizationAttributeWithIllegalValue) {
3570 JsepSessionDescription jdesc_output(kDummyType);
3571
3572 const char kSdpWithPacketizationString[] =
3573 "v=0\r\n"
3574 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3575 "s=-\r\n"
3576 "t=0 0\r\n"
3577 "m=audio 9 RTP/SAVPF 111\r\n"
3578 "a=rtpmap:111 opus/48000/2\r\n"
3579 "a=packetization:111 unknownpacketizationattributeforaudio\r\n"
3580 "m=video 3457 RTP/SAVPF 120 121 122\r\n"
3581 "a=rtpmap:120 VP8/90000\r\n"
3582 "a=packetization:120 raw\r\n"
3583 "a=rtpmap:121 VP9/90000\r\n"
3584 "a=rtpmap:122 H264/90000\r\n"
3585 "a=packetization:122 unknownpacketizationattributevalue\r\n";
3586
3587 SdpParseError error;
3588 EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithPacketizationString, &jdesc_output,
3589 &error));
3590
3591 AudioContentDescription* acd =
3592 GetFirstAudioContentDescription(jdesc_output.description());
3593 ASSERT_TRUE(acd);
3594 ASSERT_THAT(acd->codecs(), testing::SizeIs(1));
3595 cricket::AudioCodec opus = acd->codecs()[0];
3596 EXPECT_EQ(opus.name, "opus");
3597 EXPECT_EQ(opus.id, 111);
3598
3599 const VideoContentDescription* vcd =
3600 GetFirstVideoContentDescription(jdesc_output.description());
3601 ASSERT_TRUE(vcd);
3602 ASSERT_THAT(vcd->codecs(), testing::SizeIs(3));
3603 cricket::VideoCodec vp8 = vcd->codecs()[0];
3604 EXPECT_EQ(vp8.name, "VP8");
3605 EXPECT_EQ(vp8.id, 120);
3606 EXPECT_EQ(vp8.packetization, "raw");
3607 cricket::VideoCodec vp9 = vcd->codecs()[1];
3608 EXPECT_EQ(vp9.name, "VP9");
3609 EXPECT_EQ(vp9.id, 121);
3610 EXPECT_EQ(vp9.packetization, absl::nullopt);
3611 cricket::VideoCodec h264 = vcd->codecs()[2];
3612 EXPECT_EQ(h264.name, "H264");
3613 EXPECT_EQ(h264.id, 122);
3614 EXPECT_EQ(h264.packetization, absl::nullopt);
3615}
3616
ossuaa4b0772017-01-30 07:41:18 -08003617TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithUnknownParameter) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003618 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003619
3620 cricket::AudioCodecs codecs = acd->codecs();
3621 codecs[0].params["unknown-future-parameter"] = "SomeFutureValue";
3622 acd->set_codecs(codecs);
3623
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003624 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 07:41:18 -08003625 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003626 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003627 std::string sdp_with_fmtp = kSdpFullString;
3628 InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
3629 "a=fmtp:111 unknown-future-parameter=SomeFutureValue\r\n",
3630 &sdp_with_fmtp);
3631 EXPECT_EQ(sdp_with_fmtp, message);
3632}
3633
3634TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithKnownFmtpParameter) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003635 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003636
3637 cricket::AudioCodecs codecs = acd->codecs();
3638 codecs[0].params["stereo"] = "1";
3639 acd->set_codecs(codecs);
3640
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003641 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 07:41:18 -08003642 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003643 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003644 std::string sdp_with_fmtp = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02003645 InjectAfter("a=rtpmap:111 opus/48000/2\r\n", "a=fmtp:111 stereo=1\r\n",
ossuaa4b0772017-01-30 07:41:18 -08003646 &sdp_with_fmtp);
3647 EXPECT_EQ(sdp_with_fmtp, message);
3648}
3649
3650TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithPTimeAndMaxPTime) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003651 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003652
3653 cricket::AudioCodecs codecs = acd->codecs();
3654 codecs[0].params["ptime"] = "20";
3655 codecs[0].params["maxptime"] = "120";
3656 acd->set_codecs(codecs);
3657
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003658 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 07:41:18 -08003659 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003660 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003661 std::string sdp_with_fmtp = kSdpFullString;
3662 InjectAfter("a=rtpmap:104 ISAC/32000\r\n",
3663 "a=maxptime:120\r\n" // No comma here. String merging!
3664 "a=ptime:20\r\n",
3665 &sdp_with_fmtp);
3666 EXPECT_EQ(sdp_with_fmtp, message);
3667}
3668
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02003669TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithTelephoneEvent) {
3670 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
3671
3672 cricket::AudioCodecs codecs = acd->codecs();
3673 cricket::AudioCodec dtmf(105, "telephone-event", 8000, 0, 1);
3674 dtmf.params[""] = "0-15";
3675 codecs.push_back(dtmf);
3676 acd->set_codecs(codecs);
3677
3678 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
3679 jdesc_.session_version()));
3680 std::string message = webrtc::SdpSerialize(jdesc_);
3681 std::string sdp_with_fmtp = kSdpFullString;
3682 InjectAfter("m=audio 2345 RTP/SAVPF 111 103 104", " 105", &sdp_with_fmtp);
3683 InjectAfter(
3684 "a=rtpmap:104 ISAC/32000\r\n",
3685 "a=rtpmap:105 telephone-event/8000\r\n" // No comma here. String merging!
3686 "a=fmtp:105 0-15\r\n",
3687 &sdp_with_fmtp);
3688 EXPECT_EQ(sdp_with_fmtp, message);
3689}
3690
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003691TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003692 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003693
3694 cricket::VideoCodecs codecs = vcd->codecs();
3695 codecs[0].params["x-google-min-bitrate"] = "10";
3696 vcd->set_codecs(codecs);
3697
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003698 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003699 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003700 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003701 std::string sdp_with_fmtp = kSdpFullString;
3702 InjectAfter("a=rtpmap:120 VP8/90000\r\n",
Yves Gerey665174f2018-06-19 15:03:05 +02003703 "a=fmtp:120 x-google-min-bitrate=10\r\n", &sdp_with_fmtp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003704 EXPECT_EQ(sdp_with_fmtp, message);
3705}
3706
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02003707TEST_F(WebRtcSdpTest, SerializeVideoPacketizationAttribute) {
3708 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
3709
3710 cricket::VideoCodecs codecs = vcd->codecs();
3711 codecs[0].packetization = "raw";
3712 vcd->set_codecs(codecs);
3713
3714 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
3715 jdesc_.session_version()));
3716 std::string message = webrtc::SdpSerialize(jdesc_);
3717 std::string sdp_with_packetization = kSdpFullString;
3718 InjectAfter("a=rtpmap:120 VP8/90000\r\n", "a=packetization:120 raw\r\n",
3719 &sdp_with_packetization);
3720 EXPECT_EQ(sdp_with_packetization, message);
3721}
3722
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07003723TEST_F(WebRtcSdpTest, DeserializeAndSerializeSdpWithIceLite) {
3724 // Deserialize the baseline description, making sure it's ICE full.
Steve Antona3a92c22017-12-07 10:27:41 -08003725 JsepSessionDescription jdesc_with_icelite(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003726 std::string sdp_with_icelite = kSdpFullString;
3727 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3728 cricket::SessionDescription* desc = jdesc_with_icelite.description();
3729 const cricket::TransportInfo* tinfo1 =
3730 desc->GetTransportInfoByName("audio_content_name");
3731 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
3732 const cricket::TransportInfo* tinfo2 =
3733 desc->GetTransportInfoByName("video_content_name");
3734 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07003735
3736 // Add "a=ice-lite" and deserialize, making sure it's ICE lite.
Yves Gerey665174f2018-06-19 15:03:05 +02003737 InjectAfter(kSessionTime, "a=ice-lite\r\n", &sdp_with_icelite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003738 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3739 desc = jdesc_with_icelite.description();
3740 const cricket::TransportInfo* atinfo =
3741 desc->GetTransportInfoByName("audio_content_name");
3742 EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
3743 const cricket::TransportInfo* vtinfo =
Yves Gerey665174f2018-06-19 15:03:05 +02003744 desc->GetTransportInfoByName("video_content_name");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003745 EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07003746
3747 // Now that we know deserialization works, we can use TestSerialize to test
3748 // serialization.
3749 TestSerialize(jdesc_with_icelite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003750}
3751
3752// Verifies that the candidates in the input SDP are parsed and serialized
3753// correctly in the output SDP.
3754TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
3755 std::string sdp_with_data = kSdpString;
3756 sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
Steve Antona3a92c22017-12-07 10:27:41 -08003757 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003758
3759 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
Steve Antone831b8c2018-02-01 12:22:16 -08003760 EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003761}
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003762
3763TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
3764 AddFingerprint();
3765 TransportInfo audio_transport_info =
3766 *(desc_.GetTransportInfoByName(kAudioContentName));
3767 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3768 audio_transport_info.description.connection_role);
3769 audio_transport_info.description.connection_role =
Yves Gerey665174f2018-06-19 15:03:05 +02003770 cricket::CONNECTIONROLE_ACTIVE;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003771
3772 TransportInfo video_transport_info =
3773 *(desc_.GetTransportInfoByName(kVideoContentName));
3774 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3775 video_transport_info.description.connection_role);
3776 video_transport_info.description.connection_role =
Yves Gerey665174f2018-06-19 15:03:05 +02003777 cricket::CONNECTIONROLE_ACTIVE;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003778
3779 desc_.RemoveTransportInfoByName(kAudioContentName);
3780 desc_.RemoveTransportInfoByName(kVideoContentName);
3781
3782 desc_.AddTransportInfo(audio_transport_info);
3783 desc_.AddTransportInfo(video_transport_info);
3784
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003785 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003786 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003787 std::string message = webrtc::SdpSerialize(jdesc_);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003788 std::string sdp_with_dtlssetup = kSdpFullString;
3789
3790 // Fingerprint attribute is necessary to add DTLS setup attribute.
Yves Gerey665174f2018-06-19 15:03:05 +02003791 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_dtlssetup);
3792 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003793 // Now adding |setup| attribute.
Yves Gerey665174f2018-06-19 15:03:05 +02003794 InjectAfter(kFingerprint, "a=setup:active\r\n", &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003795 EXPECT_EQ(sdp_with_dtlssetup, message);
3796}
3797
3798TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttribute) {
Steve Antona3a92c22017-12-07 10:27:41 -08003799 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003800 std::string sdp_with_dtlssetup = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02003801 InjectAfter(kSessionTime, "a=setup:actpass\r\n", &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003802 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3803 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3804 const cricket::TransportInfo* atinfo =
3805 desc->GetTransportInfoByName("audio_content_name");
3806 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3807 atinfo->description.connection_role);
3808 const cricket::TransportInfo* vtinfo =
Yves Gerey665174f2018-06-19 15:03:05 +02003809 desc->GetTransportInfoByName("video_content_name");
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003810 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3811 vtinfo->description.connection_role);
3812}
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003813
3814// Verifies that the order of the serialized m-lines follows the order of the
3815// ContentInfo in SessionDescription, and vise versa for deserialization.
3816TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
Steve Antona3a92c22017-12-07 10:27:41 -08003817 JsepSessionDescription jdesc(kDummyType);
Yves Gerey665174f2018-06-19 15:03:05 +02003818 const std::string media_content_sdps[3] = {kSdpAudioString, kSdpVideoString,
3819 kSdpSctpDataChannelString};
3820 const cricket::MediaType media_types[3] = {cricket::MEDIA_TYPE_AUDIO,
3821 cricket::MEDIA_TYPE_VIDEO,
3822 cricket::MEDIA_TYPE_DATA};
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003823
3824 // Verifies all 6 permutations.
3825 for (size_t i = 0; i < 6; ++i) {
3826 size_t media_content_in_sdp[3];
3827 // The index of the first media content.
3828 media_content_in_sdp[0] = i / 2;
3829 // The index of the second media content.
3830 media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
3831 // The index of the third media content.
3832 media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
3833
3834 std::string sdp_string = kSdpSessionString;
3835 for (size_t i = 0; i < 3; ++i)
3836 sdp_string += media_content_sdps[media_content_in_sdp[i]];
3837
3838 EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
3839 cricket::SessionDescription* desc = jdesc.description();
3840 EXPECT_EQ(3u, desc->contents().size());
3841
3842 for (size_t i = 0; i < 3; ++i) {
3843 const cricket::MediaContentDescription* mdesc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003844 desc->contents()[i].media_description();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003845 EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
3846 }
3847
Steve Antone831b8c2018-02-01 12:22:16 -08003848 std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003849 EXPECT_EQ(sdp_string, serialized_sdp);
3850 }
3851}
deadbeef9d3584c2016-02-16 17:54:10 -08003852
deadbeef25ed4352016-12-12 18:37:36 -08003853TEST_F(WebRtcSdpTest, DeserializeBundleOnlyAttribute) {
3854 MakeBundleOnlyDescription();
Steve Antona3a92c22017-12-07 10:27:41 -08003855 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 13:53:47 -08003856 ASSERT_TRUE(
deadbeef25ed4352016-12-12 18:37:36 -08003857 SdpDeserialize(kBundleOnlySdpFullString, &deserialized_description));
3858 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3859}
3860
deadbeef12771a12017-01-03 13:53:47 -08003861// The semantics of "a=bundle-only" are only defined when it's used in
3862// combination with a 0 port on the m= line. We should ignore it if used with a
3863// nonzero port.
3864TEST_F(WebRtcSdpTest, IgnoreBundleOnlyWithNonzeroPort) {
3865 // Make the base bundle-only description but unset the bundle-only flag.
3866 MakeBundleOnlyDescription();
3867 jdesc_.description()->contents()[1].bundle_only = false;
3868
3869 std::string modified_sdp = kBundleOnlySdpFullString;
3870 Replace("m=video 0", "m=video 9", &modified_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08003871 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 13:53:47 -08003872 ASSERT_TRUE(SdpDeserialize(modified_sdp, &deserialized_description));
3873 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
deadbeef25ed4352016-12-12 18:37:36 -08003874}
3875
3876TEST_F(WebRtcSdpTest, SerializeBundleOnlyAttribute) {
3877 MakeBundleOnlyDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003878 TestSerialize(jdesc_);
deadbeef25ed4352016-12-12 18:37:36 -08003879}
3880
deadbeef9d3584c2016-02-16 17:54:10 -08003881TEST_F(WebRtcSdpTest, DeserializePlanBSessionDescription) {
3882 MakePlanBDescription();
3883
Steve Antona3a92c22017-12-07 10:27:41 -08003884 JsepSessionDescription deserialized_description(kDummyType);
deadbeef9d3584c2016-02-16 17:54:10 -08003885 EXPECT_TRUE(SdpDeserialize(kPlanBSdpFullString, &deserialized_description));
3886
3887 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3888}
3889
3890TEST_F(WebRtcSdpTest, SerializePlanBSessionDescription) {
3891 MakePlanBDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003892 TestSerialize(jdesc_);
deadbeef9d3584c2016-02-16 17:54:10 -08003893}
3894
3895TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescription) {
3896 MakeUnifiedPlanDescription();
3897
Steve Antona3a92c22017-12-07 10:27:41 -08003898 JsepSessionDescription deserialized_description(kDummyType);
deadbeef9d3584c2016-02-16 17:54:10 -08003899 EXPECT_TRUE(
3900 SdpDeserialize(kUnifiedPlanSdpFullString, &deserialized_description));
3901
3902 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3903}
3904
3905TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescription) {
3906 MakeUnifiedPlanDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003907 TestSerialize(jdesc_);
3908}
3909
Seth Hampson5b4f0752018-04-02 16:31:36 -07003910// This tests deserializing a Unified Plan SDP that is compatible with both
Seth Hampson7fa6ee62018-10-17 10:25:28 -07003911// Unified Plan and Plan B style SDP, meaning that it contains both "a=ssrc
3912// msid" lines and "a=msid " lines. It tests the case for audio/video tracks
Seth Hampson5b4f0752018-04-02 16:31:36 -07003913// with no stream ids and multiple stream ids. For parsing this, the Unified
3914// Plan a=msid lines should take priority, because the Plan B style a=ssrc msid
3915// lines do not support multiple stream ids and no stream ids.
Seth Hampson7fa6ee62018-10-17 10:25:28 -07003916TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionSpecialMsid) {
3917 // Create both msid lines for Plan B and Unified Plan support.
3918 MakeUnifiedPlanDescriptionMultipleStreamIds(
3919 cricket::kMsidSignalingMediaSection |
3920 cricket::kMsidSignalingSsrcAttribute);
Seth Hampson5b4f0752018-04-02 16:31:36 -07003921
3922 JsepSessionDescription deserialized_description(kDummyType);
3923 EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
3924 &deserialized_description));
3925
3926 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
Henrik Boström5b147782018-12-04 11:25:05 +01003927 EXPECT_EQ(cricket::kMsidSignalingMediaSection |
3928 cricket::kMsidSignalingSsrcAttribute,
3929 deserialized_description.description()->msid_signaling());
Seth Hampson5b4f0752018-04-02 16:31:36 -07003930}
3931
Seth Hampson7fa6ee62018-10-17 10:25:28 -07003932// Tests the serialization of a Unified Plan SDP that is compatible for both
3933// Unified Plan and Plan B style SDPs, meaning that it contains both "a=ssrc
3934// msid" lines and "a=msid " lines. It tests the case for no stream ids and
3935// multiple stream ids.
3936TEST_F(WebRtcSdpTest, SerializeSessionDescriptionSpecialMsid) {
3937 // Create both msid lines for Plan B and Unified Plan support.
3938 MakeUnifiedPlanDescriptionMultipleStreamIds(
3939 cricket::kMsidSignalingMediaSection |
3940 cricket::kMsidSignalingSsrcAttribute);
3941 std::string serialized_sdp = webrtc::SdpSerialize(jdesc_);
3942 // We explicitly test that the serialized SDP string is equal to the hard
3943 // coded SDP string. This is necessary, because in the parser "a=msid" lines
3944 // take priority over "a=ssrc msid" lines. This means if we just used
3945 // TestSerialize(), it could serialize an SDP that omits "a=ssrc msid" lines,
3946 // and still pass, because the deserialized version would be the same.
3947 EXPECT_EQ(kUnifiedPlanSdpFullStringWithSpecialMsid, serialized_sdp);
3948}
3949
3950// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
3951// that signal stream IDs) is deserialized appropriately. It tests the case for
3952// no stream ids and multiple stream ids.
3953TEST_F(WebRtcSdpTest, UnifiedPlanDeserializeSessionDescriptionSpecialMsid) {
3954 // Only create a=msid lines for strictly Unified Plan stream ID support.
3955 MakeUnifiedPlanDescriptionMultipleStreamIds(
3956 cricket::kMsidSignalingMediaSection);
3957
3958 JsepSessionDescription deserialized_description(kDummyType);
3959 std::string unified_plan_sdp_string =
3960 kUnifiedPlanSdpFullStringWithSpecialMsid;
3961 RemoveSsrcMsidLinesFromSdpString(&unified_plan_sdp_string);
3962 EXPECT_TRUE(
3963 SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
3964
3965 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3966}
3967
3968// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
3969// that signal stream IDs) is serialized appropriately. It tests the case for no
3970// stream ids and multiple stream ids.
3971TEST_F(WebRtcSdpTest, UnifiedPlanSerializeSessionDescriptionSpecialMsid) {
3972 // Only create a=msid lines for strictly Unified Plan stream ID support.
3973 MakeUnifiedPlanDescriptionMultipleStreamIds(
3974 cricket::kMsidSignalingMediaSection);
3975
Seth Hampson5b4f0752018-04-02 16:31:36 -07003976 TestSerialize(jdesc_);
3977}
3978
Seth Hampson5897a6e2018-04-03 11:16:33 -07003979// This tests that a Unified Plan SDP with no a=ssrc lines is
3980// serialized/deserialized appropriately. In this case the
3981// MediaContentDescription will contain a StreamParams object that doesn't have
3982// any SSRCs. Vice versa, this will be created upon deserializing an SDP with no
3983// SSRC lines.
3984TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
3985 MakeUnifiedPlanDescription();
3986 RemoveSsrcSignalingFromStreamParams();
3987 std::string unified_plan_sdp_string = kUnifiedPlanSdpFullString;
3988 RemoveSsrcLinesFromSdpString(&unified_plan_sdp_string);
3989
3990 JsepSessionDescription deserialized_description(kDummyType);
3991 EXPECT_TRUE(
3992 SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
3993 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3994}
3995
3996TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
3997 MakeUnifiedPlanDescription();
3998 RemoveSsrcSignalingFromStreamParams();
3999
4000 TestSerialize(jdesc_);
4001}
4002
Steve Antone831b8c2018-02-01 12:22:16 -08004003TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
4004 JsepSessionDescription jsep_desc(kDummyType);
4005 ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
4006 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
4007}
4008
4009TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
4010 JsepSessionDescription jsep_desc(kDummyType);
4011 std::string sdp = kSdpSessionString;
4012 sdp += kSdpSctpDataChannelString;
4013 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4014 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
4015}
4016
4017TEST_F(WebRtcSdpTest, PlanBHasSsrcAttributeMsidSignaling) {
4018 JsepSessionDescription jsep_desc(kDummyType);
4019 ASSERT_TRUE(SdpDeserialize(kPlanBSdpFullString, &jsep_desc));
4020 EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
4021 jsep_desc.description()->msid_signaling());
4022}
4023
4024TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
4025 JsepSessionDescription jsep_desc(kDummyType);
4026 ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
4027 EXPECT_EQ(cricket::kMsidSignalingMediaSection,
4028 jsep_desc.description()->msid_signaling());
4029}
4030
4031const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";
4032const char kSsrcAttributeMsidLine[] =
4033 "a=ssrc:1 msid:local_stream_1 audio_track_id_1";
4034
4035TEST_F(WebRtcSdpTest, SerializeOnlyMediaSectionMsid) {
4036 jdesc_.description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
4037 std::string sdp = webrtc::SdpSerialize(jdesc_);
4038
4039 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
4040 EXPECT_EQ(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
4041}
4042
4043TEST_F(WebRtcSdpTest, SerializeOnlySsrcAttributeMsid) {
4044 jdesc_.description()->set_msid_signaling(
4045 cricket::kMsidSignalingSsrcAttribute);
4046 std::string sdp = webrtc::SdpSerialize(jdesc_);
4047
4048 EXPECT_EQ(std::string::npos, sdp.find(kMediaSectionMsidLine));
4049 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
4050}
4051
4052TEST_F(WebRtcSdpTest, SerializeBothMediaSectionAndSsrcAttributeMsid) {
4053 jdesc_.description()->set_msid_signaling(
4054 cricket::kMsidSignalingMediaSection |
4055 cricket::kMsidSignalingSsrcAttribute);
4056 std::string sdp = webrtc::SdpSerialize(jdesc_);
4057
4058 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
4059 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
deadbeef9d3584c2016-02-16 17:54:10 -08004060}
deadbeef7e146cb2016-09-28 10:04:34 -07004061
deadbeefb2362572016-12-13 16:37:06 -08004062// Regression test for integer overflow bug:
4063// https://bugs.chromium.org/p/chromium/issues/detail?id=648071
4064TEST_F(WebRtcSdpTest, DeserializeLargeBandwidthLimit) {
deadbeefb2362572016-12-13 16:37:06 -08004065 // Bandwidth attribute is the max signed 32-bit int, which will get
4066 // multiplied by 1000 and cause int overflow if not careful.
deadbeef7bcdb692017-01-20 12:43:58 -08004067 static const char kSdpWithLargeBandwidth[] =
deadbeefb2362572016-12-13 16:37:06 -08004068 "v=0\r\n"
4069 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4070 "s=-\r\n"
4071 "t=0 0\r\n"
4072 "m=video 3457 RTP/SAVPF 120\r\n"
4073 "b=AS:2147483647\r\n"
4074 "foo=fail\r\n";
4075
4076 ExpectParseFailure(std::string(kSdpWithLargeBandwidth), "foo=fail");
4077}
deadbeef7bcdb692017-01-20 12:43:58 -08004078
deadbeefbc88c6b2017-08-02 11:26:34 -07004079// Similar to the above, except that negative values are illegal, not just
4080// error-prone as large values are.
4081// https://bugs.chromium.org/p/chromium/issues/detail?id=675361
4082TEST_F(WebRtcSdpTest, DeserializingNegativeBandwidthLimitFails) {
4083 static const char kSdpWithNegativeBandwidth[] =
4084 "v=0\r\n"
4085 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4086 "s=-\r\n"
4087 "t=0 0\r\n"
4088 "m=video 3457 RTP/SAVPF 120\r\n"
4089 "b=AS:-1000\r\n";
4090
4091 ExpectParseFailure(std::string(kSdpWithNegativeBandwidth), "b=AS:-1000");
4092}
4093
deadbeef3e8016e2017-08-03 17:49:30 -07004094// An exception to the above rule: a value of -1 for b=AS should just be
4095// ignored, resulting in "kAutoBandwidth" in the deserialized object.
4096// Applications historically may be using "b=AS:-1" to mean "no bandwidth
4097// limit", but this is now what ommitting the attribute entirely will do, so
4098// ignoring it will have the intended effect.
4099TEST_F(WebRtcSdpTest, BandwidthLimitOfNegativeOneIgnored) {
4100 static const char kSdpWithBandwidthOfNegativeOne[] =
4101 "v=0\r\n"
4102 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4103 "s=-\r\n"
4104 "t=0 0\r\n"
4105 "m=video 3457 RTP/SAVPF 120\r\n"
4106 "b=AS:-1\r\n";
4107
Steve Antona3a92c22017-12-07 10:27:41 -08004108 JsepSessionDescription jdesc_output(kDummyType);
deadbeef3e8016e2017-08-03 17:49:30 -07004109 EXPECT_TRUE(SdpDeserialize(kSdpWithBandwidthOfNegativeOne, &jdesc_output));
deadbeef3e8016e2017-08-03 17:49:30 -07004110 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004111 GetFirstVideoContentDescription(jdesc_output.description());
4112 ASSERT_TRUE(vcd);
deadbeef3e8016e2017-08-03 17:49:30 -07004113 EXPECT_EQ(cricket::kAutoBandwidth, vcd->bandwidth());
4114}
4115
deadbeef7bcdb692017-01-20 12:43:58 -08004116// Test that "ufrag"/"pwd" in the candidate line itself are ignored, and only
4117// the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
4118// Regression test for:
4119// https://bugs.chromium.org/p/chromium/issues/detail?id=681286
4120TEST_F(WebRtcSdpTest, IceCredentialsInCandidateStringIgnored) {
4121 // Important piece is "ufrag foo pwd bar".
4122 static const char kSdpWithIceCredentialsInCandidateString[] =
4123 "v=0\r\n"
4124 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4125 "s=-\r\n"
4126 "t=0 0\r\n"
4127 "m=audio 9 RTP/SAVPF 111\r\n"
4128 "c=IN IP4 0.0.0.0\r\n"
4129 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
4130 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
4131 "a=rtpmap:111 opus/48000/2\r\n"
4132 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
4133 "generation 2 ufrag foo pwd bar\r\n";
4134
Steve Antona3a92c22017-12-07 10:27:41 -08004135 JsepSessionDescription jdesc_output(kDummyType);
deadbeef7bcdb692017-01-20 12:43:58 -08004136 EXPECT_TRUE(
4137 SdpDeserialize(kSdpWithIceCredentialsInCandidateString, &jdesc_output));
4138 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
4139 ASSERT_NE(nullptr, candidates);
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02004140 ASSERT_EQ(1U, candidates->count());
deadbeef7bcdb692017-01-20 12:43:58 -08004141 cricket::Candidate c = candidates->at(0)->candidate();
4142 EXPECT_EQ("ufrag_voice", c.username());
4143 EXPECT_EQ("pwd_voice", c.password());
4144}
deadbeef90f1e1e2017-02-10 12:35:05 -08004145
Johannes Kron211856b2018-09-06 12:12:28 +02004146// Test that attribute lines "a=ice-ufrag-something"/"a=ice-pwd-something" are
4147// ignored, and only the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
4148// Regression test for:
4149// https://bugs.chromium.org/p/webrtc/issues/detail?id=9712
4150TEST_F(WebRtcSdpTest, AttributeWithPartialMatchingNameIsIgnored) {
4151 static const char kSdpWithFooIceCredentials[] =
4152 "v=0\r\n"
4153 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4154 "s=-\r\n"
4155 "t=0 0\r\n"
4156 "m=audio 9 RTP/SAVPF 111\r\n"
4157 "c=IN IP4 0.0.0.0\r\n"
4158 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
4159 "a=ice-ufrag-something:foo\r\na=ice-pwd-something:bar\r\n"
4160 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
4161 "a=rtpmap:111 opus/48000/2\r\n"
4162 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
4163 "generation 2\r\n";
4164
4165 JsepSessionDescription jdesc_output(kDummyType);
4166 EXPECT_TRUE(SdpDeserialize(kSdpWithFooIceCredentials, &jdesc_output));
4167 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
4168 ASSERT_NE(nullptr, candidates);
4169 ASSERT_EQ(1U, candidates->count());
4170 cricket::Candidate c = candidates->at(0)->candidate();
4171 EXPECT_EQ("ufrag_voice", c.username());
4172 EXPECT_EQ("pwd_voice", c.password());
4173}
4174
deadbeef90f1e1e2017-02-10 12:35:05 -08004175// Test that SDP with an invalid port number in "a=candidate" lines is
4176// rejected, without crashing.
4177// Regression test for:
4178// https://bugs.chromium.org/p/chromium/issues/detail?id=677029
4179TEST_F(WebRtcSdpTest, DeserializeInvalidPortInCandidateAttribute) {
4180 static const char kSdpWithInvalidCandidatePort[] =
4181 "v=0\r\n"
4182 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4183 "s=-\r\n"
4184 "t=0 0\r\n"
4185 "m=audio 9 RTP/SAVPF 111\r\n"
4186 "c=IN IP4 0.0.0.0\r\n"
4187 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
4188 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
4189 "a=rtpmap:111 opus/48000/2\r\n"
4190 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 12345678 typ host "
4191 "generation 2 raddr 192.168.1.1 rport 87654321\r\n";
4192
Steve Antona3a92c22017-12-07 10:27:41 -08004193 JsepSessionDescription jdesc_output(kDummyType);
deadbeef90f1e1e2017-02-10 12:35:05 -08004194 EXPECT_FALSE(SdpDeserialize(kSdpWithInvalidCandidatePort, &jdesc_output));
4195}
deadbeefa4549d62017-02-10 17:26:22 -08004196
4197// Test that "a=msid" with a missing track ID is rejected and doesn't crash.
4198// Regression test for:
4199// https://bugs.chromium.org/p/chromium/issues/detail?id=686405
4200TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingTrackId) {
4201 static const char kSdpWithMissingTrackId[] =
4202 "v=0\r\n"
4203 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4204 "s=-\r\n"
4205 "t=0 0\r\n"
4206 "m=audio 9 RTP/SAVPF 111\r\n"
4207 "c=IN IP4 0.0.0.0\r\n"
4208 "a=rtpmap:111 opus/48000/2\r\n"
4209 "a=msid:stream_id \r\n";
4210
Steve Antona3a92c22017-12-07 10:27:41 -08004211 JsepSessionDescription jdesc_output(kDummyType);
deadbeefa4549d62017-02-10 17:26:22 -08004212 EXPECT_FALSE(SdpDeserialize(kSdpWithMissingTrackId, &jdesc_output));
4213}
4214
4215TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingStreamId) {
4216 static const char kSdpWithMissingStreamId[] =
4217 "v=0\r\n"
4218 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4219 "s=-\r\n"
4220 "t=0 0\r\n"
4221 "m=audio 9 RTP/SAVPF 111\r\n"
4222 "c=IN IP4 0.0.0.0\r\n"
4223 "a=rtpmap:111 opus/48000/2\r\n"
4224 "a=msid: track_id\r\n";
4225
Steve Antona3a92c22017-12-07 10:27:41 -08004226 JsepSessionDescription jdesc_output(kDummyType);
deadbeefa4549d62017-02-10 17:26:22 -08004227 EXPECT_FALSE(SdpDeserialize(kSdpWithMissingStreamId, &jdesc_output));
4228}
zhihuang38989e52017-03-21 11:04:53 -07004229
4230// Tests that if both session-level address and media-level address exist, use
4231// the media-level address.
4232TEST_F(WebRtcSdpTest, ParseConnectionData) {
Steve Antona3a92c22017-12-07 10:27:41 -08004233 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004234
4235 // Sesssion-level address.
4236 std::string sdp = kSdpFullString;
4237 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
4238 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4239
4240 const auto& content1 = jsep_desc.description()->contents()[0];
4241 EXPECT_EQ("74.125.127.126:2345",
Steve Antonb1c1de12017-12-21 15:14:30 -08004242 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004243 const auto& content2 = jsep_desc.description()->contents()[1];
4244 EXPECT_EQ("74.125.224.39:3457",
Steve Antonb1c1de12017-12-21 15:14:30 -08004245 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004246}
4247
4248// Tests that the session-level connection address will be used if the media
4249// level-addresses are not specified.
4250TEST_F(WebRtcSdpTest, ParseConnectionDataSessionLevelOnly) {
Steve Antona3a92c22017-12-07 10:27:41 -08004251 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004252
4253 // Sesssion-level address.
4254 std::string sdp = kSdpString;
4255 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
4256 // Remove the media level addresses.
4257 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
4258 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
4259 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4260
4261 const auto& content1 = jsep_desc.description()->contents()[0];
4262 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004263 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004264 const auto& content2 = jsep_desc.description()->contents()[1];
4265 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004266 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004267}
4268
4269TEST_F(WebRtcSdpTest, ParseConnectionDataIPv6) {
Steve Antona3a92c22017-12-07 10:27:41 -08004270 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004271
4272 std::string sdp = kSdpString;
4273 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4274 Replace("m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP4 0.0.0.0\r\n",
4275 "m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP6 "
4276 "2001:0db8:85a3:0000:0000:8a2e:0370:7335\r\n",
4277 &sdp);
4278 Replace("m=video 9 RTP/SAVPF 120\r\nc=IN IP4 0.0.0.0\r\n",
4279 "m=video 9 RTP/SAVPF 120\r\nc=IN IP6 "
4280 "2001:0db8:85a3:0000:0000:8a2e:0370:7336\r\n",
4281 &sdp);
4282 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4283 const auto& content1 = jsep_desc.description()->contents()[0];
4284 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7335]:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004285 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004286 const auto& content2 = jsep_desc.description()->contents()[1];
4287 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7336]:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004288 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004289}
4290
Qingsi Wang56991422019-02-08 12:53:06 -08004291// Test that a c= line that contains a hostname connection address can be
4292// parsed.
4293TEST_F(WebRtcSdpTest, ParseConnectionDataWithHostnameConnectionAddress) {
4294 JsepSessionDescription jsep_desc(kDummyType);
4295 std::string sdp = kSdpString;
4296 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4297
4298 sdp = kSdpString;
4299 Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
4300 Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
4301 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4302
4303 ASSERT_NE(nullptr, jsep_desc.description());
4304 const auto& content1 = jsep_desc.description()->contents()[0];
4305 EXPECT_EQ("example.local:9",
4306 content1.media_description()->connection_address().ToString());
4307 const auto& content2 = jsep_desc.description()->contents()[1];
4308 EXPECT_EQ("example.local:9",
4309 content2.media_description()->connection_address().ToString());
4310}
4311
4312// Test that the invalid or unsupported connection data cannot be parsed.
zhihuang38989e52017-03-21 11:04:53 -07004313TEST_F(WebRtcSdpTest, ParseConnectionDataFailure) {
Steve Antona3a92c22017-12-07 10:27:41 -08004314 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004315 std::string sdp = kSdpString;
4316 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4317
4318 // Unsupported multicast IPv4 address.
4319 sdp = kSdpFullString;
4320 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP4 74.125.224.39/127\r\n", &sdp);
4321 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4322
4323 // Unsupported multicast IPv6 address.
4324 sdp = kSdpFullString;
4325 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 ::1/3\r\n", &sdp);
4326 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4327
4328 // Mismatched address type.
4329 sdp = kSdpFullString;
4330 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 74.125.224.39\r\n", &sdp);
4331 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4332
4333 sdp = kSdpFullString;
4334 Replace("c=IN IP4 74.125.224.39\r\n",
4335 "c=IN IP4 2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n", &sdp);
4336 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4337}
4338
4339TEST_F(WebRtcSdpTest, SerializeAndDeserializeWithConnectionAddress) {
Steve Antona3a92c22017-12-07 10:27:41 -08004340 JsepSessionDescription expected_jsep(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004341 MakeDescriptionWithoutCandidates(&expected_jsep);
4342 // Serialization.
Steve Antone831b8c2018-02-01 12:22:16 -08004343 std::string message = webrtc::SdpSerialize(expected_jsep);
zhihuang38989e52017-03-21 11:04:53 -07004344 // Deserialization.
Steve Antona3a92c22017-12-07 10:27:41 -08004345 JsepSessionDescription jdesc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004346 EXPECT_TRUE(SdpDeserialize(message, &jdesc));
Steve Antonb1c1de12017-12-21 15:14:30 -08004347 auto audio_desc = jdesc.description()
4348 ->GetContentByName(kAudioContentName)
4349 ->media_description();
4350 auto video_desc = jdesc.description()
4351 ->GetContentByName(kVideoContentName)
4352 ->media_description();
zhihuang38989e52017-03-21 11:04:53 -07004353 EXPECT_EQ(audio_desc_->connection_address().ToString(),
4354 audio_desc->connection_address().ToString());
4355 EXPECT_EQ(video_desc_->connection_address().ToString(),
4356 video_desc->connection_address().ToString());
4357}
Taylor Brandstetter93a7b242018-04-16 10:45:24 -07004358
4359// RFC4566 says "If a session has no meaningful name, the value "s= " SHOULD be
4360// used (i.e., a single space as the session name)." So we should accept that.
4361TEST_F(WebRtcSdpTest, DeserializeEmptySessionName) {
4362 JsepSessionDescription jsep_desc(kDummyType);
4363 std::string sdp = kSdpString;
4364 Replace("s=-\r\n", "s= \r\n", &sdp);
4365 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4366}
Amit Hilbucha2012042018-12-03 11:35:05 -08004367
4368// Simulcast malformed input test for invalid format.
4369TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_EmptyAttribute) {
Artem Titovf0a34f22020-03-16 17:52:04 +00004370 ExpectParseFailureWithNewLines("a=ssrc:3 label:video_track_id_1\r\n",
4371 "a=simulcast:\r\n", "a=simulcast:");
Amit Hilbucha2012042018-12-03 11:35:05 -08004372}
4373
4374// Tests that duplicate simulcast entries in the SDP triggers a parse failure.
4375TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_DuplicateAttribute) {
Artem Titovf0a34f22020-03-16 17:52:04 +00004376 ExpectParseFailureWithNewLines("a=ssrc:3 label:video_track_id_1\r\n",
4377 "a=simulcast:send 1\r\na=simulcast:recv 2\r\n",
4378 "a=simulcast:");
Amit Hilbucha2012042018-12-03 11:35:05 -08004379}
4380
4381// Validates that deserialization uses the a=simulcast: attribute
4382TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttribute) {
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004383 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4384 sdp += "a=rid:1 send\r\n";
4385 sdp += "a=rid:2 send\r\n";
4386 sdp += "a=rid:3 send\r\n";
4387 sdp += "a=rid:4 recv\r\n";
4388 sdp += "a=rid:5 recv\r\n";
4389 sdp += "a=rid:6 recv\r\n";
Amit Hilbucha2012042018-12-03 11:35:05 -08004390 sdp += "a=simulcast:send 1,2;3 recv 4;5;6\r\n";
4391 JsepSessionDescription output(kDummyType);
4392 SdpParseError error;
4393 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4394 const cricket::ContentInfos& contents = output.description()->contents();
4395 const cricket::MediaContentDescription* media =
4396 contents.back().media_description();
4397 EXPECT_TRUE(media->HasSimulcast());
4398 EXPECT_EQ(2ul, media->simulcast_description().send_layers().size());
4399 EXPECT_EQ(3ul, media->simulcast_description().receive_layers().size());
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004400 EXPECT_FALSE(media->streams().empty());
4401 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4402 CompareRidDescriptionIds(rids, {"1", "2", "3"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004403}
4404
4405// Validates that deserialization removes rids that do not appear in SDP
4406TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttributeRemovesUnknownRids) {
4407 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4408 sdp += "a=rid:1 send\r\n";
4409 sdp += "a=rid:3 send\r\n";
4410 sdp += "a=rid:4 recv\r\n";
4411 sdp += "a=simulcast:send 1,2;3 recv 4;5,6\r\n";
4412 JsepSessionDescription output(kDummyType);
4413 SdpParseError error;
4414 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4415 const cricket::ContentInfos& contents = output.description()->contents();
4416 const cricket::MediaContentDescription* media =
4417 contents.back().media_description();
4418 EXPECT_TRUE(media->HasSimulcast());
4419 const SimulcastDescription& simulcast = media->simulcast_description();
4420 EXPECT_EQ(2ul, simulcast.send_layers().size());
4421 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4422
4423 std::vector<SimulcastLayer> all_send_layers =
4424 simulcast.send_layers().GetAllLayers();
4425 EXPECT_EQ(2ul, all_send_layers.size());
Steve Anton64b626b2019-01-28 17:25:26 -08004426 EXPECT_EQ(0,
4427 absl::c_count_if(all_send_layers, [](const SimulcastLayer& layer) {
4428 return layer.rid == "2";
4429 }));
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004430
4431 std::vector<SimulcastLayer> all_receive_layers =
4432 simulcast.receive_layers().GetAllLayers();
4433 ASSERT_EQ(1ul, all_receive_layers.size());
4434 EXPECT_EQ("4", all_receive_layers[0].rid);
4435
4436 EXPECT_FALSE(media->streams().empty());
4437 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4438 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004439}
4440
4441// Validates that Simulcast removes rids that appear in both send and receive.
4442TEST_F(WebRtcSdpTest,
4443 TestDeserializeSimulcastAttributeRemovesDuplicateSendReceive) {
4444 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4445 sdp += "a=rid:1 send\r\n";
4446 sdp += "a=rid:2 send\r\n";
4447 sdp += "a=rid:3 send\r\n";
4448 sdp += "a=rid:4 recv\r\n";
4449 sdp += "a=simulcast:send 1;2;3 recv 2;4\r\n";
4450 JsepSessionDescription output(kDummyType);
4451 SdpParseError error;
4452 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4453 const cricket::ContentInfos& contents = output.description()->contents();
4454 const cricket::MediaContentDescription* media =
4455 contents.back().media_description();
4456 EXPECT_TRUE(media->HasSimulcast());
4457 const SimulcastDescription& simulcast = media->simulcast_description();
4458 EXPECT_EQ(2ul, simulcast.send_layers().size());
4459 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4460 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4461 EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
4462
4463 EXPECT_FALSE(media->streams().empty());
4464 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4465 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004466}
4467
4468// Ignores empty rid line.
4469TEST_F(WebRtcSdpTest, TestDeserializeIgnoresEmptyRidLines) {
4470 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4471 sdp += "a=rid:1 send\r\n";
4472 sdp += "a=rid:2 send\r\n";
4473 sdp += "a=rid\r\n"; // Should ignore this line.
4474 sdp += "a=rid:\r\n"; // Should ignore this line.
4475 sdp += "a=simulcast:send 1;2\r\n";
4476 JsepSessionDescription output(kDummyType);
4477 SdpParseError error;
4478 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4479 const cricket::ContentInfos& contents = output.description()->contents();
4480 const cricket::MediaContentDescription* media =
4481 contents.back().media_description();
4482 EXPECT_TRUE(media->HasSimulcast());
4483 const SimulcastDescription& simulcast = media->simulcast_description();
4484 EXPECT_TRUE(simulcast.receive_layers().empty());
4485 EXPECT_EQ(2ul, simulcast.send_layers().size());
4486 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4487
4488 EXPECT_FALSE(media->streams().empty());
4489 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4490 CompareRidDescriptionIds(rids, {"1", "2"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004491}
4492
4493// Ignores malformed rid lines.
4494TEST_F(WebRtcSdpTest, TestDeserializeIgnoresMalformedRidLines) {
4495 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4496 sdp += "a=rid:1 send pt=\r\n"; // Should ignore this line.
4497 sdp += "a=rid:2 receive\r\n"; // Should ignore this line.
4498 sdp += "a=rid:3 max-width=720;pt=120\r\n"; // Should ignore this line.
4499 sdp += "a=rid:4\r\n"; // Should ignore this line.
4500 sdp += "a=rid:5 send\r\n";
4501 sdp += "a=simulcast:send 1,2,3;4,5\r\n";
4502 JsepSessionDescription output(kDummyType);
4503 SdpParseError error;
4504 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4505 const cricket::ContentInfos& contents = output.description()->contents();
4506 const cricket::MediaContentDescription* media =
4507 contents.back().media_description();
4508 EXPECT_TRUE(media->HasSimulcast());
4509 const SimulcastDescription& simulcast = media->simulcast_description();
4510 EXPECT_TRUE(simulcast.receive_layers().empty());
4511 EXPECT_EQ(1ul, simulcast.send_layers().size());
4512 EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
4513
4514 EXPECT_FALSE(media->streams().empty());
4515 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4516 CompareRidDescriptionIds(rids, {"5"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004517}
4518
4519// Removes RIDs that specify a different format than the m= section.
4520TEST_F(WebRtcSdpTest, TestDeserializeRemovesRidsWithInvalidCodec) {
4521 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4522 sdp += "a=rid:1 send pt=121,120\r\n"; // Should remove 121 and keep RID.
4523 sdp += "a=rid:2 send pt=121\r\n"; // Should remove RID altogether.
4524 sdp += "a=simulcast:send 1;2\r\n";
4525 JsepSessionDescription output(kDummyType);
4526 SdpParseError error;
4527 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4528 const cricket::ContentInfos& contents = output.description()->contents();
4529 const cricket::MediaContentDescription* media =
4530 contents.back().media_description();
4531 EXPECT_TRUE(media->HasSimulcast());
4532 const SimulcastDescription& simulcast = media->simulcast_description();
4533 EXPECT_TRUE(simulcast.receive_layers().empty());
4534 EXPECT_EQ(1ul, simulcast.send_layers().size());
4535 EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
4536 EXPECT_EQ("1", simulcast.send_layers()[0][0].rid);
4537 EXPECT_EQ(1ul, media->streams().size());
4538 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4539 EXPECT_EQ(1ul, rids.size());
4540 EXPECT_EQ("1", rids[0].rid);
4541 EXPECT_EQ(1ul, rids[0].payload_types.size());
4542 EXPECT_EQ(120, rids[0].payload_types[0]);
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004543}
4544
4545// Ignores duplicate rid lines
4546TEST_F(WebRtcSdpTest, TestDeserializeIgnoresDuplicateRidLines) {
4547 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4548 sdp += "a=rid:1 send\r\n";
4549 sdp += "a=rid:2 send\r\n";
4550 sdp += "a=rid:2 send\r\n";
4551 sdp += "a=rid:3 send\r\n";
4552 sdp += "a=rid:4 recv\r\n";
4553 sdp += "a=simulcast:send 1,2;3 recv 4\r\n";
4554 JsepSessionDescription output(kDummyType);
4555 SdpParseError error;
4556 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4557 const cricket::ContentInfos& contents = output.description()->contents();
4558 const cricket::MediaContentDescription* media =
4559 contents.back().media_description();
4560 EXPECT_TRUE(media->HasSimulcast());
4561 const SimulcastDescription& simulcast = media->simulcast_description();
4562 EXPECT_EQ(2ul, simulcast.send_layers().size());
4563 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4564 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4565 EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
4566
4567 EXPECT_FALSE(media->streams().empty());
4568 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4569 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbucha2012042018-12-03 11:35:05 -08004570}
4571
Florent Castellic4421972019-07-02 20:27:42 +02004572TEST_F(WebRtcSdpTest, TestDeserializeRidSendDirection) {
4573 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4574 sdp += "a=rid:1 recv\r\n";
4575 sdp += "a=rid:2 recv\r\n";
4576 sdp += "a=simulcast:send 1;2\r\n";
4577 JsepSessionDescription output(kDummyType);
4578 SdpParseError error;
4579 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4580 const cricket::ContentInfos& contents = output.description()->contents();
4581 const cricket::MediaContentDescription* media =
4582 contents.back().media_description();
4583 EXPECT_FALSE(media->HasSimulcast());
4584}
4585
4586TEST_F(WebRtcSdpTest, TestDeserializeRidRecvDirection) {
4587 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4588 sdp += "a=rid:1 send\r\n";
4589 sdp += "a=rid:2 send\r\n";
4590 sdp += "a=simulcast:recv 1;2\r\n";
4591 JsepSessionDescription output(kDummyType);
4592 SdpParseError error;
4593 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4594 const cricket::ContentInfos& contents = output.description()->contents();
4595 const cricket::MediaContentDescription* media =
4596 contents.back().media_description();
4597 EXPECT_FALSE(media->HasSimulcast());
4598}
4599
4600TEST_F(WebRtcSdpTest, TestDeserializeIgnoresWrongRidDirectionLines) {
4601 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4602 sdp += "a=rid:1 send\r\n";
4603 sdp += "a=rid:2 send\r\n";
4604 sdp += "a=rid:3 send\r\n";
4605 sdp += "a=rid:4 recv\r\n";
4606 sdp += "a=rid:5 recv\r\n";
4607 sdp += "a=rid:6 recv\r\n";
4608 sdp += "a=simulcast:send 1;5;3 recv 4;2;6\r\n";
4609 JsepSessionDescription output(kDummyType);
4610 SdpParseError error;
4611 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4612 const cricket::ContentInfos& contents = output.description()->contents();
4613 const cricket::MediaContentDescription* media =
4614 contents.back().media_description();
4615 EXPECT_TRUE(media->HasSimulcast());
4616 const SimulcastDescription& simulcast = media->simulcast_description();
4617 EXPECT_EQ(2ul, simulcast.send_layers().size());
4618 EXPECT_EQ(2ul, simulcast.receive_layers().size());
4619 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4620 EXPECT_EQ(2ul, simulcast.receive_layers().GetAllLayers().size());
4621
4622 EXPECT_FALSE(media->streams().empty());
4623 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4624 CompareRidDescriptionIds(rids, {"1", "3"});
4625}
4626
Amit Hilbucha2012042018-12-03 11:35:05 -08004627// Simulcast serialization integration test.
4628// This test will serialize and deserialize the description and compare.
4629// More detailed tests for parsing simulcast can be found in
4630// unit tests for SdpSerializer.
4631TEST_F(WebRtcSdpTest, SerializeSimulcast_ComplexSerialization) {
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004632 MakeUnifiedPlanDescription(/* use_ssrcs = */ false);
Amit Hilbucha2012042018-12-03 11:35:05 -08004633 auto description = jdesc_.description();
4634 auto media = description->GetContentDescriptionByName(kVideoContentName3);
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004635 ASSERT_EQ(media->streams().size(), 1ul);
4636 StreamParams& send_stream = media->mutable_streams()[0];
4637 std::vector<RidDescription> send_rids;
4638 send_rids.push_back(RidDescription("1", RidDirection::kSend));
4639 send_rids.push_back(RidDescription("2", RidDirection::kSend));
4640 send_rids.push_back(RidDescription("3", RidDirection::kSend));
4641 send_rids.push_back(RidDescription("4", RidDirection::kSend));
4642 send_stream.set_rids(send_rids);
Florent Castellib60141b2019-07-03 12:47:54 +02004643 std::vector<RidDescription> receive_rids;
4644 receive_rids.push_back(RidDescription("5", RidDirection::kReceive));
4645 receive_rids.push_back(RidDescription("6", RidDirection::kReceive));
4646 receive_rids.push_back(RidDescription("7", RidDirection::kReceive));
4647 media->set_receive_rids(receive_rids);
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004648
Amit Hilbucha2012042018-12-03 11:35:05 -08004649 SimulcastDescription& simulcast = media->simulcast_description();
4650 simulcast.send_layers().AddLayerWithAlternatives(
4651 {SimulcastLayer("2", false), SimulcastLayer("1", true)});
4652 simulcast.send_layers().AddLayerWithAlternatives(
4653 {SimulcastLayer("4", false), SimulcastLayer("3", false)});
Florent Castellib60141b2019-07-03 12:47:54 +02004654 simulcast.receive_layers().AddLayer({SimulcastLayer("5", false)});
4655 simulcast.receive_layers().AddLayer({SimulcastLayer("6", false)});
4656 simulcast.receive_layers().AddLayer({SimulcastLayer("7", false)});
Amit Hilbucha2012042018-12-03 11:35:05 -08004657
Amit Hilbucha2012042018-12-03 11:35:05 -08004658 TestSerialize(jdesc_);
4659}
Steve Anton06817cd2018-12-18 15:55:30 -08004660
4661// Test that the content name is empty if the media section does not have an
4662// a=mid line.
4663TEST_F(WebRtcSdpTest, ParseNoMid) {
4664 std::string sdp = kSdpString;
4665 Replace("a=mid:audio_content_name\r\n", "", &sdp);
4666 Replace("a=mid:video_content_name\r\n", "", &sdp);
4667
4668 JsepSessionDescription output(kDummyType);
4669 SdpParseError error;
4670 ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4671
4672 EXPECT_THAT(output.description()->contents(),
4673 ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
4674 Field("name", &cricket::ContentInfo::name, "")));
4675}
Piotr (Peter) Slatala13e570f2019-02-27 11:34:26 -08004676
Guido Urdanetacecf87f2019-05-31 10:17:38 +00004677TEST_F(WebRtcSdpTest, SerializeWithDefaultSctpProtocol) {
4678 AddSctpDataChannel(false); // Don't use sctpmap
4679 JsepSessionDescription jsep_desc(kDummyType);
4680 MakeDescriptionWithoutCandidates(&jsep_desc);
4681 std::string message = webrtc::SdpSerialize(jsep_desc);
4682 EXPECT_NE(std::string::npos,
4683 message.find(cricket::kMediaProtocolUdpDtlsSctp));
4684}
4685
4686TEST_F(WebRtcSdpTest, DeserializeWithAllSctpProtocols) {
4687 AddSctpDataChannel(false);
4688 std::string protocols[] = {cricket::kMediaProtocolDtlsSctp,
4689 cricket::kMediaProtocolUdpDtlsSctp,
4690 cricket::kMediaProtocolTcpDtlsSctp};
4691 for (const auto& protocol : protocols) {
4692 sctp_desc_->set_protocol(protocol);
4693 JsepSessionDescription jsep_desc(kDummyType);
4694 MakeDescriptionWithoutCandidates(&jsep_desc);
4695 std::string message = webrtc::SdpSerialize(jsep_desc);
4696 EXPECT_NE(std::string::npos, message.find(protocol));
4697 JsepSessionDescription jsep_output(kDummyType);
4698 SdpParseError error;
4699 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jsep_output, &error));
4700 }
4701}
Taylor Brandstetter4256df02020-02-18 14:05:07 -08004702
4703// According to https://tools.ietf.org/html/rfc5576#section-6.1, the CNAME
4704// attribute is mandatory, but we relax that restriction.
4705TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCname) {
4706 std::string sdp_without_cname = kSdpFullString;
4707 Replace("a=ssrc:1 cname:stream_1_cname\r\n", "", &sdp_without_cname);
4708 JsepSessionDescription new_jdesc(kDummyType);
4709 EXPECT_TRUE(SdpDeserialize(sdp_without_cname, &new_jdesc));
4710
4711 audio_desc_->mutable_streams()[0].cname = "";
4712 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
4713 jdesc_.session_version()));
4714 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
4715}
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004716
4717TEST_F(WebRtcSdpTest, DeserializeSdpWithUnsupportedMediaType) {
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004718 std::string sdp = kSdpSessionString;
4719 sdp +=
4720 "m=bogus 9 RTP/SAVPF 0 8\r\n"
Philipp Hancke4e8c1152020-10-13 12:43:15 +02004721 "c=IN IP4 0.0.0.0\r\n"
4722 "a=mid:bogusmid\r\n";
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004723 sdp +=
4724 "m=audio/something 9 RTP/SAVPF 0 8\r\n"
Philipp Hancke4e8c1152020-10-13 12:43:15 +02004725 "c=IN IP4 0.0.0.0\r\n"
4726 "a=mid:somethingmid\r\n";
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004727
4728 JsepSessionDescription jdesc_output(kDummyType);
4729 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4730
Philipp Hancke4e8c1152020-10-13 12:43:15 +02004731 ASSERT_EQ(2u, jdesc_output.description()->contents().size());
4732 ASSERT_NE(nullptr, jdesc_output.description()
4733 ->contents()[0]
4734 .media_description()
4735 ->as_unsupported());
4736 ASSERT_NE(nullptr, jdesc_output.description()
4737 ->contents()[1]
4738 .media_description()
4739 ->as_unsupported());
4740
4741 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
4742 EXPECT_TRUE(jdesc_output.description()->contents()[1].rejected);
4743
4744 EXPECT_EQ(jdesc_output.description()->contents()[0].name, "bogusmid");
4745 EXPECT_EQ(jdesc_output.description()->contents()[1].name, "somethingmid");
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004746}
Philipp Hanckeb70c9532021-01-13 10:40:06 +01004747
4748TEST_F(WebRtcSdpTest, MediaTypeProtocolMismatch) {
4749 std::string sdp =
4750 "v=0\r\n"
4751 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4752 "s=-\r\n"
4753 "t=0 0\r\n";
4754
4755 ExpectParseFailure(std::string(sdp + "m=audio 9 UDP/DTLS/SCTP 120\r\n"),
4756 "m=audio");
4757 ExpectParseFailure(std::string(sdp + "m=video 9 UDP/DTLS/SCTP 120\r\n"),
4758 "m=video");
4759 ExpectParseFailure(std::string(sdp + "m=video 9 SOMETHING 120\r\n"),
4760 "m=video");
4761 ExpectParseFailure(std::string(sdp + "m=application 9 SOMETHING 120\r\n"),
4762 "m=application");
4763}
Philipp Hanckecd467b52021-01-29 09:29:47 +01004764
4765// Regression test for:
4766// https://bugs.chromium.org/p/chromium/issues/detail?id=1171965
4767TEST_F(WebRtcSdpTest, SctpPortInUnsupportedContent) {
4768 std::string sdp =
4769 "v=0\r\n"
4770 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4771 "s=-\r\n"
4772 "t=0 0\r\n"
4773 "m=o 1 DTLS/SCTP 5000\r\n"
4774 "a=sctp-port\r\n";
4775
4776 JsepSessionDescription jdesc_output(kDummyType);
4777 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4778}
Harald Alvestrand99bcf602021-03-03 07:44:39 +00004779
4780TEST_F(WebRtcSdpTest, IllegalMidCharacterValue) {
4781 std::string sdp = kSdpString;
4782 // [ is an illegal token value.
4783 Replace("a=mid:", "a=mid:[]", &sdp);
4784 ExpectParseFailure(std::string(sdp), "a=mid:[]");
4785}