blob: 1daac0f99e150ab82fde4001780e0969809f9a74 [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/jsep_session_description.h"
27#include "api/media_types.h"
28#include "api/rtp_parameters.h"
29#include "api/rtp_transceiver_interface.h"
Yves Gerey3e707812018-11-28 16:47:49 +010030#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "media/base/media_constants.h"
32#include "media/base/stream_params.h"
33#include "p2p/base/p2p_constants.h"
Yves Gerey665174f2018-06-19 15:03:05 +020034#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "p2p/base/transport_description.h"
36#include "p2p/base/transport_info.h"
37#include "pc/media_session.h"
38#include "pc/session_description.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020039#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080040#include "rtc_base/message_digest.h"
41#include "rtc_base/socket_address.h"
42#include "rtc_base/ssl_fingerprint.h"
43#include "rtc_base/string_encode.h"
Steve Anton06817cd2018-12-18 15:55:30 -080044#include "test/gmock.h"
Yves Gerey3e707812018-11-28 16:47:49 +010045#include "test/gtest.h"
Patrik Höglund563934e2017-09-15 09:04:28 +020046
ossu7bb87ee2017-01-23 04:56:25 -080047#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080048#include "pc/test/android_test_initializer.h"
ossu7bb87ee2017-01-23 04:56:25 -080049#endif
Steve Anton10542f22019-01-11 09:11:00 -080050#include "pc/webrtc_sdp.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051
52using cricket::AudioCodec;
53using cricket::AudioContentDescription;
54using cricket::Candidate;
Steve Anton06817cd2018-12-18 15:55:30 -080055using cricket::ContentGroup;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056using cricket::ContentInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
58using cricket::ICE_CANDIDATE_COMPONENT_RTP;
59using cricket::kFecSsrcGroupSemantics;
60using cricket::LOCAL_PORT_TYPE;
Steve Anton5adfafd2017-12-20 16:34:00 -080061using cricket::MediaProtocolType;
Steve Anton06817cd2018-12-18 15:55:30 -080062using cricket::RELAY_PORT_TYPE;
Amit Hilbuchc57d5732018-12-11 15:30:11 -080063using cricket::RidDescription;
64using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020065using cricket::SctpDataContentDescription;
Steve Anton06817cd2018-12-18 15:55:30 -080066using cricket::SessionDescription;
Amit Hilbucha2012042018-12-03 11:35:05 -080067using cricket::SimulcastDescription;
68using cricket::SimulcastLayer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::StreamParams;
70using cricket::STUN_PORT_TYPE;
71using cricket::TransportDescription;
72using cricket::TransportInfo;
73using cricket::VideoCodec;
74using cricket::VideoContentDescription;
Steve Anton06817cd2018-12-18 15:55:30 -080075using ::testing::ElementsAre;
76using ::testing::Field;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077using webrtc::IceCandidateCollection;
78using webrtc::IceCandidateInterface;
79using webrtc::JsepIceCandidate;
80using webrtc::JsepSessionDescription;
isheriff6f8d6862016-05-26 11:24:55 -070081using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080082using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083using webrtc::SdpParseError;
Steve Antona3a92c22017-12-07 10:27:41 -080084using webrtc::SdpType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085using webrtc::SessionDescriptionInterface;
86
87typedef std::vector<AudioCodec> AudioCodecs;
88typedef std::vector<Candidate> Candidates;
89
Peter Boström0c4e06b2015-10-07 12:23:21 +020090static const uint32_t kDefaultSctpPort = 5000;
zstein4b2e0822017-02-17 19:48:38 -080091static const uint16_t kUnusualSctpPort = 9556;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092static const char kSessionTime[] = "t=0 0\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020093static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0
deadbeef3f7219b2015-12-28 15:17:14 -080094static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
deadbeef3f7219b2015-12-28 15:17:14 -080096static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
Peter Boström0c4e06b2015-10-07 12:23:21 +020098static const uint32_t kCandidateGeneration = 2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099static const char kCandidateFoundation1[] = "a0+B/1";
100static const char kCandidateFoundation2[] = "a0+B/2";
101static const char kCandidateFoundation3[] = "a0+B/3";
102static const char kCandidateFoundation4[] = "a0+B/4";
103static const char kAttributeCryptoVoice[] =
104 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
105 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
106 "dummy_session_params\r\n";
107static const char kAttributeCryptoVideo[] =
108 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
109 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
Yves Gerey665174f2018-06-19 15:03:05 +0200110static const char kFingerprint[] =
111 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112 "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 +0200113static const char kExtmapAllowMixed[] = "a=extmap-allow-mixed\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114static const int kExtmapId = 1;
115static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
116static const char kExtmap[] =
117 "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
118static const char kExtmapWithDirectionAndAttribute[] =
119 "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
jbauch5869f502017-06-29 12:31:36 -0700120static const char kExtmapWithDirectionAndAttributeEncrypted[] =
121 "a=extmap:1/sendrecv urn:ietf:params:rtp-hdrext:encrypt "
122 "http://example.com/082005/ext.htm#ttime a1 a2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123
Peter Boström0c4e06b2015-10-07 12:23:21 +0200124static const uint8_t kIdentityDigest[] = {
125 0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
126 0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
lally@webrtc.org34807282015-02-24 20:19:39 +0000128static const char kDtlsSctp[] = "DTLS/SCTP";
129static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
130static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
lally@webrtc.org36300852015-02-24 20:19:35 +0000131
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132struct CodecParams {
133 int max_ptime;
134 int ptime;
135 int min_ptime;
136 int sprop_stereo;
137 int stereo;
138 int useinband;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000139 int maxaveragebitrate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140};
141
Harald Alvestrandee212a72021-11-02 12:06:45 +0000142// Note: The reference strings do not contain a=fingerprint, which is
143// required for DTLS negotiation.
144// Neither do they contain the obsolete a=crypto lines.
deadbeef9d3584c2016-02-16 17:54:10 -0800145
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146// Reference sdp string
147static const char kSdpFullString[] =
148 "v=0\r\n"
149 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
150 "s=-\r\n"
151 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100152 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800153 "a=msid-semantic: WMS local_stream_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
155 "c=IN IP4 74.125.127.126\r\n"
156 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
157 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
158 "generation 2\r\n"
159 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
160 "generation 2\r\n"
161 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
162 "generation 2\r\n"
163 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
164 "generation 2\r\n"
165 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
166 "raddr 192.168.1.5 rport 2346 "
167 "generation 2\r\n"
168 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
169 "raddr 192.168.1.5 rport 2348 "
170 "generation 2\r\n"
171 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
172 "a=mid:audio_content_name\r\n"
173 "a=sendrecv\r\n"
174 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 12:37:51 -0800175 "a=rtcp-rsize\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176 "a=rtpmap:111 opus/48000/2\r\n"
177 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000178 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179 "a=ssrc:1 cname:stream_1_cname\r\n"
180 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000181 "a=ssrc:1 mslabel:local_stream_1\r\n"
182 "a=ssrc:1 label:audio_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000183 "m=video 3457 RTP/SAVPF 120\r\n"
184 "c=IN IP4 74.125.224.39\r\n"
185 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
186 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
187 "generation 2\r\n"
188 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
189 "generation 2\r\n"
190 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
191 "generation 2\r\n"
192 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
193 "generation 2\r\n"
194 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
195 "generation 2\r\n"
196 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
197 "generation 2\r\n"
198 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
199 "a=mid:video_content_name\r\n"
200 "a=sendrecv\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800202 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203 "a=ssrc:2 cname:stream_1_cname\r\n"
204 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000205 "a=ssrc:2 mslabel:local_stream_1\r\n"
206 "a=ssrc:2 label:video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207 "a=ssrc:3 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000208 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
209 "a=ssrc:3 mslabel:local_stream_1\r\n"
210 "a=ssrc:3 label:video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211
212// SDP reference string without the candidates.
213static const char kSdpString[] =
214 "v=0\r\n"
215 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
216 "s=-\r\n"
217 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100218 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800219 "a=msid-semantic: WMS local_stream_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000220 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000221 "c=IN IP4 0.0.0.0\r\n"
222 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
224 "a=mid:audio_content_name\r\n"
225 "a=sendrecv\r\n"
226 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 12:37:51 -0800227 "a=rtcp-rsize\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228 "a=rtpmap:111 opus/48000/2\r\n"
229 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +0000230 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000231 "a=ssrc:1 cname:stream_1_cname\r\n"
232 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000233 "a=ssrc:1 mslabel:local_stream_1\r\n"
234 "a=ssrc:1 label:audio_track_id_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000235 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000236 "c=IN IP4 0.0.0.0\r\n"
237 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000238 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
239 "a=mid:video_content_name\r\n"
240 "a=sendrecv\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800242 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 "a=ssrc:2 cname:stream_1_cname\r\n"
244 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000245 "a=ssrc:2 mslabel:local_stream_1\r\n"
246 "a=ssrc:2 label:video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000247 "a=ssrc:3 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000248 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
249 "a=ssrc:3 mslabel:local_stream_1\r\n"
250 "a=ssrc:3 label:video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000251
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200252// draft-ietf-mmusic-sctp-sdp-03
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253static const char kSdpSctpDataChannelString[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000254 "m=application 9 UDP/DTLS/SCTP 5000\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000255 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256 "a=ice-ufrag:ufrag_data\r\n"
257 "a=ice-pwd:pwd_data\r\n"
258 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000259 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260
lally@webrtc.orgec97c652015-02-24 20:18:48 +0000261// draft-ietf-mmusic-sctp-sdp-12
Harald Alvestrand48cce4d2019-04-11 10:41:24 +0200262// Note - this is invalid per draft-ietf-mmusic-sctp-sdp-26,
263// since the separator after "sctp-port" needs to be a colon.
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +0000264static const char kSdpSctpDataChannelStringWithSctpPort[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000265 "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
lally@webrtc.orgc7848b72015-02-24 20:19:26 +0000266 "a=sctp-port 5000\r\n"
267 "c=IN IP4 0.0.0.0\r\n"
268 "a=ice-ufrag:ufrag_data\r\n"
269 "a=ice-pwd:pwd_data\r\n"
270 "a=mid:data_content_name\r\n";
271
Harald Alvestrand48cce4d2019-04-11 10:41:24 +0200272// draft-ietf-mmusic-sctp-sdp-26
lally69f57602015-10-08 10:15:04 -0700273static const char kSdpSctpDataChannelStringWithSctpColonPort[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000274 "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
lally69f57602015-10-08 10:15:04 -0700275 "a=sctp-port:5000\r\n"
276 "c=IN IP4 0.0.0.0\r\n"
277 "a=ice-ufrag:ufrag_data\r\n"
278 "a=ice-pwd:pwd_data\r\n"
279 "a=mid:data_content_name\r\n";
280
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000281static const char kSdpSctpDataChannelWithCandidatesString[] =
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000282 "m=application 2345 UDP/DTLS/SCTP 5000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 "c=IN IP4 74.125.127.126\r\n"
284 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
285 "generation 2\r\n"
286 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
287 "generation 2\r\n"
288 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
289 "raddr 192.168.1.5 rport 2346 "
290 "generation 2\r\n"
291 "a=ice-ufrag:ufrag_data\r\n"
292 "a=ice-pwd:pwd_data\r\n"
293 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33 +0000294 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000295
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000296static const char kSdpConferenceString[] =
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000297 "v=0\r\n"
298 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
299 "s=-\r\n"
300 "t=0 0\r\n"
301 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000302 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000303 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000304 "a=x-google-flag:conference\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000305 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000306 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000307 "a=x-google-flag:conference\r\n";
308
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000309static const char kSdpSessionString[] =
310 "v=0\r\n"
311 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
312 "s=-\r\n"
313 "t=0 0\r\n"
314 "a=msid-semantic: WMS local_stream\r\n";
315
316static const char kSdpAudioString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000317 "m=audio 9 RTP/SAVPF 111\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000318 "c=IN IP4 0.0.0.0\r\n"
319 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000320 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
321 "a=mid:audio_content_name\r\n"
322 "a=sendrecv\r\n"
323 "a=rtpmap:111 opus/48000/2\r\n"
324 "a=ssrc:1 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000325 "a=ssrc:1 msid:local_stream audio_track_id_1\r\n"
326 "a=ssrc:1 mslabel:local_stream\r\n"
327 "a=ssrc:1 label:audio_track_id_1\r\n";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000328
329static const char kSdpVideoString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +0000330 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06 +0000331 "c=IN IP4 0.0.0.0\r\n"
332 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000333 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
334 "a=mid:video_content_name\r\n"
335 "a=sendrecv\r\n"
336 "a=rtpmap:120 VP8/90000\r\n"
337 "a=ssrc:2 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000338 "a=ssrc:2 msid:local_stream video_track_id_1\r\n"
339 "a=ssrc:2 mslabel:local_stream\r\n"
340 "a=ssrc:2 label:video_track_id_1\r\n";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000341
deadbeef25ed4352016-12-12 18:37:36 -0800342// Reference sdp string using bundle-only.
343static const char kBundleOnlySdpFullString[] =
344 "v=0\r\n"
345 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
346 "s=-\r\n"
347 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100348 "a=extmap-allow-mixed\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800349 "a=group:BUNDLE audio_content_name video_content_name\r\n"
350 "a=msid-semantic: WMS local_stream_1\r\n"
351 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
352 "c=IN IP4 74.125.127.126\r\n"
353 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
354 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
355 "generation 2\r\n"
356 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
357 "generation 2\r\n"
358 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
359 "generation 2\r\n"
360 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
361 "generation 2\r\n"
362 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
363 "raddr 192.168.1.5 rport 2346 "
364 "generation 2\r\n"
365 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
366 "raddr 192.168.1.5 rport 2348 "
367 "generation 2\r\n"
368 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
369 "a=mid:audio_content_name\r\n"
370 "a=sendrecv\r\n"
371 "a=rtcp-mux\r\n"
372 "a=rtcp-rsize\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800373 "a=rtpmap:111 opus/48000/2\r\n"
374 "a=rtpmap:103 ISAC/16000\r\n"
375 "a=rtpmap:104 ISAC/32000\r\n"
376 "a=ssrc:1 cname:stream_1_cname\r\n"
377 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000378 "a=ssrc:1 mslabel:local_stream_1\r\n"
379 "a=ssrc:1 label:audio_track_id_1\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800380 "m=video 0 RTP/SAVPF 120\r\n"
381 "c=IN IP4 0.0.0.0\r\n"
382 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
383 "a=bundle-only\r\n"
384 "a=mid:video_content_name\r\n"
385 "a=sendrecv\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800386 "a=rtpmap:120 VP8/90000\r\n"
387 "a=ssrc-group:FEC 2 3\r\n"
388 "a=ssrc:2 cname:stream_1_cname\r\n"
389 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000390 "a=ssrc:2 mslabel:local_stream_1\r\n"
391 "a=ssrc:2 label:video_track_id_1\r\n"
deadbeef25ed4352016-12-12 18:37:36 -0800392 "a=ssrc:3 cname:stream_1_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000393 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
394 "a=ssrc:3 mslabel:local_stream_1\r\n"
395 "a=ssrc:3 label:video_track_id_1\r\n";
deadbeef25ed4352016-12-12 18:37:36 -0800396
deadbeef9d3584c2016-02-16 17:54:10 -0800397// Plan B SDP reference string, with 2 streams, 2 audio tracks and 3 video
398// tracks.
399static const char kPlanBSdpFullString[] =
400 "v=0\r\n"
401 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
402 "s=-\r\n"
403 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100404 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800405 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
406 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
407 "c=IN IP4 74.125.127.126\r\n"
408 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
409 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
410 "generation 2\r\n"
411 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
412 "generation 2\r\n"
413 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
414 "generation 2\r\n"
415 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
416 "generation 2\r\n"
417 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
418 "raddr 192.168.1.5 rport 2346 "
419 "generation 2\r\n"
420 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
421 "raddr 192.168.1.5 rport 2348 "
422 "generation 2\r\n"
423 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
424 "a=mid:audio_content_name\r\n"
425 "a=sendrecv\r\n"
426 "a=rtcp-mux\r\n"
427 "a=rtcp-rsize\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800428 "a=rtpmap:111 opus/48000/2\r\n"
429 "a=rtpmap:103 ISAC/16000\r\n"
430 "a=rtpmap:104 ISAC/32000\r\n"
431 "a=ssrc:1 cname:stream_1_cname\r\n"
432 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000433 "a=ssrc:1 mslabel:local_stream_1\r\n"
434 "a=ssrc:1 label:audio_track_id_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800435 "a=ssrc:4 cname:stream_2_cname\r\n"
436 "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000437 "a=ssrc:4 mslabel:local_stream_2\r\n"
438 "a=ssrc:4 label:audio_track_id_2\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800439 "m=video 3457 RTP/SAVPF 120\r\n"
440 "c=IN IP4 74.125.224.39\r\n"
441 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
442 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
443 "generation 2\r\n"
444 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
445 "generation 2\r\n"
446 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
447 "generation 2\r\n"
448 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
449 "generation 2\r\n"
450 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
451 "generation 2\r\n"
452 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
453 "generation 2\r\n"
454 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
455 "a=mid:video_content_name\r\n"
456 "a=sendrecv\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800457 "a=rtpmap:120 VP8/90000\r\n"
458 "a=ssrc-group:FEC 2 3\r\n"
459 "a=ssrc:2 cname:stream_1_cname\r\n"
460 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000461 "a=ssrc:2 mslabel:local_stream_1\r\n"
462 "a=ssrc:2 label:video_track_id_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800463 "a=ssrc:3 cname:stream_1_cname\r\n"
464 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000465 "a=ssrc:3 mslabel:local_stream_1\r\n"
466 "a=ssrc:3 label:video_track_id_1\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800467 "a=ssrc:5 cname:stream_2_cname\r\n"
468 "a=ssrc:5 msid:local_stream_2 video_track_id_2\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000469 "a=ssrc:5 mslabel:local_stream_2\r\n"
470 "a=ssrc:5 label:video_track_id_2\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800471 "a=ssrc:6 cname:stream_2_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000472 "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n"
473 "a=ssrc:6 mslabel:local_stream_2\r\n"
474 "a=ssrc:6 label:video_track_id_3\r\n";
deadbeef9d3584c2016-02-16 17:54:10 -0800475
476// Unified Plan SDP reference string, with 2 streams, 2 audio tracks and 3 video
477// tracks.
478static const char kUnifiedPlanSdpFullString[] =
479 "v=0\r\n"
480 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
481 "s=-\r\n"
482 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100483 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800484 "a=msid-semantic: WMS local_stream_1\r\n"
485 // Audio track 1, stream 1 (with candidates).
486 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
487 "c=IN IP4 74.125.127.126\r\n"
488 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
489 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
490 "generation 2\r\n"
491 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
492 "generation 2\r\n"
493 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
494 "generation 2\r\n"
495 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
496 "generation 2\r\n"
497 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
498 "raddr 192.168.1.5 rport 2346 "
499 "generation 2\r\n"
500 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
501 "raddr 192.168.1.5 rport 2348 "
502 "generation 2\r\n"
503 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
504 "a=mid:audio_content_name\r\n"
505 "a=msid:local_stream_1 audio_track_id_1\r\n"
506 "a=sendrecv\r\n"
507 "a=rtcp-mux\r\n"
508 "a=rtcp-rsize\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800509 "a=rtpmap:111 opus/48000/2\r\n"
510 "a=rtpmap:103 ISAC/16000\r\n"
511 "a=rtpmap:104 ISAC/32000\r\n"
512 "a=ssrc:1 cname:stream_1_cname\r\n"
513 // Video track 1, stream 1 (with candidates).
514 "m=video 3457 RTP/SAVPF 120\r\n"
515 "c=IN IP4 74.125.224.39\r\n"
516 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
517 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
518 "generation 2\r\n"
519 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
520 "generation 2\r\n"
521 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
522 "generation 2\r\n"
523 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
524 "generation 2\r\n"
525 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
526 "generation 2\r\n"
527 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
528 "generation 2\r\n"
529 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
530 "a=mid:video_content_name\r\n"
531 "a=msid:local_stream_1 video_track_id_1\r\n"
532 "a=sendrecv\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800533 "a=rtpmap:120 VP8/90000\r\n"
534 "a=ssrc-group:FEC 2 3\r\n"
535 "a=ssrc:2 cname:stream_1_cname\r\n"
536 "a=ssrc:3 cname:stream_1_cname\r\n"
537 // Audio track 2, stream 2.
538 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
539 "c=IN IP4 0.0.0.0\r\n"
540 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
541 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
542 "a=mid:audio_content_name_2\r\n"
543 "a=msid:local_stream_2 audio_track_id_2\r\n"
544 "a=sendrecv\r\n"
545 "a=rtcp-mux\r\n"
546 "a=rtcp-rsize\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800547 "a=rtpmap:111 opus/48000/2\r\n"
548 "a=rtpmap:103 ISAC/16000\r\n"
549 "a=rtpmap:104 ISAC/32000\r\n"
550 "a=ssrc:4 cname:stream_2_cname\r\n"
551 // Video track 2, stream 2.
552 "m=video 9 RTP/SAVPF 120\r\n"
553 "c=IN IP4 0.0.0.0\r\n"
554 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
555 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
556 "a=mid:video_content_name_2\r\n"
557 "a=msid:local_stream_2 video_track_id_2\r\n"
558 "a=sendrecv\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800559 "a=rtpmap:120 VP8/90000\r\n"
560 "a=ssrc:5 cname:stream_2_cname\r\n"
561 // Video track 3, stream 2.
562 "m=video 9 RTP/SAVPF 120\r\n"
563 "c=IN IP4 0.0.0.0\r\n"
564 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
565 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
566 "a=mid:video_content_name_3\r\n"
567 "a=msid:local_stream_2 video_track_id_3\r\n"
568 "a=sendrecv\r\n"
deadbeef9d3584c2016-02-16 17:54:10 -0800569 "a=rtpmap:120 VP8/90000\r\n"
570 "a=ssrc:6 cname:stream_2_cname\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571
Seth Hampson5b4f0752018-04-02 16:31:36 -0700572// Unified Plan SDP reference string:
573// - audio track 1 has 1 a=msid lines
574// - audio track 2 has 2 a=msid lines
575// - audio track 3 has 1 a=msid line with the special "-" marker signifying that
576// there are 0 media stream ids.
577// This Unified Plan SDP represents a SDP that signals the msid using both
578// a=msid and a=ssrc msid semantics.
579static const char kUnifiedPlanSdpFullStringWithSpecialMsid[] =
580 "v=0\r\n"
581 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
582 "s=-\r\n"
583 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 13:06:32 +0100584 "a=extmap-allow-mixed\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700585 "a=msid-semantic: WMS local_stream_1\r\n"
586 // Audio track 1, with 1 stream id.
587 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
588 "c=IN IP4 74.125.127.126\r\n"
589 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
590 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
591 "generation 2\r\n"
592 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
593 "generation 2\r\n"
594 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
595 "generation 2\r\n"
596 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
597 "generation 2\r\n"
598 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
599 "raddr 192.168.1.5 rport 2346 "
600 "generation 2\r\n"
601 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
602 "raddr 192.168.1.5 rport 2348 "
603 "generation 2\r\n"
604 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
605 "a=mid:audio_content_name\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700606 "a=sendrecv\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700607 "a=msid:local_stream_1 audio_track_id_1\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700608 "a=rtcp-mux\r\n"
609 "a=rtcp-rsize\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700610 "a=rtpmap:111 opus/48000/2\r\n"
611 "a=rtpmap:103 ISAC/16000\r\n"
612 "a=rtpmap:104 ISAC/32000\r\n"
613 "a=ssrc:1 cname:stream_1_cname\r\n"
614 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000615 "a=ssrc:1 mslabel:local_stream_1\r\n"
616 "a=ssrc:1 label:audio_track_id_1\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700617 // Audio track 2, with two stream ids.
618 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
619 "c=IN IP4 0.0.0.0\r\n"
620 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
621 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
622 "a=mid:audio_content_name_2\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700623 "a=sendrecv\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700624 "a=msid:local_stream_1 audio_track_id_2\r\n"
625 "a=msid:local_stream_2 audio_track_id_2\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700626 "a=rtcp-mux\r\n"
627 "a=rtcp-rsize\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700628 "a=rtpmap:111 opus/48000/2\r\n"
629 "a=rtpmap:103 ISAC/16000\r\n"
630 "a=rtpmap:104 ISAC/32000\r\n"
631 "a=ssrc:4 cname:stream_1_cname\r\n"
632 // The support for Plan B msid signaling only includes the
633 // first media stream id "local_stream_1."
634 "a=ssrc:4 msid:local_stream_1 audio_track_id_2\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000635 "a=ssrc:4 mslabel:local_stream_1\r\n"
636 "a=ssrc:4 label:audio_track_id_2\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700637 // Audio track 3, with no stream ids.
638 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
639 "c=IN IP4 0.0.0.0\r\n"
640 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
641 "a=ice-ufrag:ufrag_voice_3\r\na=ice-pwd:pwd_voice_3\r\n"
642 "a=mid:audio_content_name_3\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700643 "a=sendrecv\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700644 "a=msid:- audio_track_id_3\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700645 "a=rtcp-mux\r\n"
646 "a=rtcp-rsize\r\n"
Seth Hampson5b4f0752018-04-02 16:31:36 -0700647 "a=rtpmap:111 opus/48000/2\r\n"
648 "a=rtpmap:103 ISAC/16000\r\n"
649 "a=rtpmap:104 ISAC/32000\r\n"
Seth Hampson7fa6ee62018-10-17 10:25:28 -0700650 "a=ssrc:7 cname:stream_2_cname\r\n"
Artem Titovf0a34f22020-03-16 17:52:04 +0000651 "a=ssrc:7 msid:- audio_track_id_3\r\n"
652 "a=ssrc:7 mslabel:-\r\n"
653 "a=ssrc:7 label:audio_track_id_3\r\n";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700654
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800655// SDP string for unified plan without SSRCs
656static const char kUnifiedPlanSdpFullStringNoSsrc[] =
657 "v=0\r\n"
658 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
659 "s=-\r\n"
660 "t=0 0\r\n"
661 "a=msid-semantic: WMS local_stream_1\r\n"
662 // Audio track 1, stream 1 (with candidates).
663 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
664 "c=IN IP4 74.125.127.126\r\n"
665 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
666 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
667 "generation 2\r\n"
668 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
669 "generation 2\r\n"
670 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
671 "generation 2\r\n"
672 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
673 "generation 2\r\n"
674 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
675 "raddr 192.168.1.5 rport 2346 "
676 "generation 2\r\n"
677 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
678 "raddr 192.168.1.5 rport 2348 "
679 "generation 2\r\n"
680 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
681 "a=mid:audio_content_name\r\n"
682 "a=msid:local_stream_1 audio_track_id_1\r\n"
683 "a=sendrecv\r\n"
684 "a=rtcp-mux\r\n"
685 "a=rtcp-rsize\r\n"
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800686 "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 // Video track 1, stream 1 (with candidates).
690 "m=video 3457 RTP/SAVPF 120\r\n"
691 "c=IN IP4 74.125.224.39\r\n"
692 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
693 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
694 "generation 2\r\n"
695 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
696 "generation 2\r\n"
697 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
698 "generation 2\r\n"
699 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
700 "generation 2\r\n"
701 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
702 "generation 2\r\n"
703 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
704 "generation 2\r\n"
705 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
706 "a=mid:video_content_name\r\n"
707 "a=msid:local_stream_1 video_track_id_1\r\n"
708 "a=sendrecv\r\n"
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800709 "a=rtpmap:120 VP8/90000\r\n"
710 // Audio track 2, stream 2.
711 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
712 "c=IN IP4 0.0.0.0\r\n"
713 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
714 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
715 "a=mid:audio_content_name_2\r\n"
716 "a=msid:local_stream_2 audio_track_id_2\r\n"
717 "a=sendrecv\r\n"
718 "a=rtcp-mux\r\n"
719 "a=rtcp-rsize\r\n"
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800720 "a=rtpmap:111 opus/48000/2\r\n"
721 "a=rtpmap:103 ISAC/16000\r\n"
722 "a=rtpmap:104 ISAC/32000\r\n"
723 // Video track 2, stream 2.
724 "m=video 9 RTP/SAVPF 120\r\n"
725 "c=IN IP4 0.0.0.0\r\n"
726 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
727 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
728 "a=mid:video_content_name_2\r\n"
729 "a=msid:local_stream_2 video_track_id_2\r\n"
730 "a=sendrecv\r\n"
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800731 "a=rtpmap:120 VP8/90000\r\n"
732 // Video track 3, stream 2.
733 "m=video 9 RTP/SAVPF 120\r\n"
734 "c=IN IP4 0.0.0.0\r\n"
735 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
736 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
737 "a=mid:video_content_name_3\r\n"
738 "a=msid:local_stream_2 video_track_id_3\r\n"
739 "a=sendrecv\r\n"
Amit Hilbuchc57d5732018-12-11 15:30:11 -0800740 "a=rtpmap:120 VP8/90000\r\n";
741
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742// One candidate reference string as per W3c spec.
743// candidate:<blah> not a=candidate:<blah>CRLF
744static const char kRawCandidate[] =
745 "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
746// One candidate reference string.
747static const char kSdpOneCandidate[] =
748 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
749 "generation 2\r\n";
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000750
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +0000751static const char kSdpTcpActiveCandidate[] =
752 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
753 "tcptype active generation 2";
754static const char kSdpTcpPassiveCandidate[] =
755 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
756 "tcptype passive generation 2";
757static const char kSdpTcpSOCandidate[] =
758 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
759 "tcptype so generation 2";
760static const char kSdpTcpInvalidCandidate[] =
761 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
762 "tcptype invalid generation 2";
763
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +0000764// One candidate reference string with IPV6 address.
765static const char kRawIPV6Candidate[] =
766 "candidate:a0+B/1 1 udp 2130706432 "
ehmaldonado121cabb2017-05-05 12:04:36 -0700767 "abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd 1234 typ host generation 2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768
769// One candidate reference string.
honghaiza54a0802015-12-16 18:37:23 -0800770static const char kSdpOneCandidateWithUfragPwd[] =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
honghaiza54a0802015-12-16 18:37:23 -0800772 " eth0 ufrag user_rtp pwd password_rtp generation 2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773
Zach Steinb336c272018-08-09 01:16:13 -0700774static const char kRawHostnameCandidate[] =
775 "candidate:a0+B/1 1 udp 2130706432 a.test 1234 typ host generation 2";
776
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777// Session id and version
778static const char kSessionId[] = "18446744069414584320";
779static const char kSessionVersion[] = "18446462598732840960";
780
deadbeef9d3584c2016-02-16 17:54:10 -0800781// ICE options.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782static const char kIceOption1[] = "iceoption1";
783static const char kIceOption2[] = "iceoption2";
784static const char kIceOption3[] = "iceoption3";
785
deadbeef9d3584c2016-02-16 17:54:10 -0800786// ICE ufrags/passwords.
787static const char kUfragVoice[] = "ufrag_voice";
788static const char kPwdVoice[] = "pwd_voice";
789static const char kUfragVideo[] = "ufrag_video";
790static const char kPwdVideo[] = "pwd_video";
791static const char kUfragData[] = "ufrag_data";
792static const char kPwdData[] = "pwd_data";
793
794// Extra ufrags/passwords for extra unified plan m= sections.
795static const char kUfragVoice2[] = "ufrag_voice_2";
796static const char kPwdVoice2[] = "pwd_voice_2";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700797static const char kUfragVoice3[] = "ufrag_voice_3";
798static const char kPwdVoice3[] = "pwd_voice_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800799static const char kUfragVideo2[] = "ufrag_video_2";
800static const char kPwdVideo2[] = "pwd_video_2";
801static const char kUfragVideo3[] = "ufrag_video_3";
802static const char kPwdVideo3[] = "pwd_video_3";
803
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804// Content name
805static const char kAudioContentName[] = "audio_content_name";
806static const char kVideoContentName[] = "video_content_name";
807static const char kDataContentName[] = "data_content_name";
808
deadbeef9d3584c2016-02-16 17:54:10 -0800809// Extra content names for extra unified plan m= sections.
810static const char kAudioContentName2[] = "audio_content_name_2";
Seth Hampson5b4f0752018-04-02 16:31:36 -0700811static const char kAudioContentName3[] = "audio_content_name_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800812static const char kVideoContentName2[] = "video_content_name_2";
813static const char kVideoContentName3[] = "video_content_name_3";
814
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815// MediaStream 1
Seth Hampson845e8782018-03-02 11:34:10 -0800816static const char kStreamId1[] = "local_stream_1";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817static const char kStream1Cname[] = "stream_1_cname";
818static const char kAudioTrackId1[] = "audio_track_id_1";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200819static const uint32_t kAudioTrack1Ssrc = 1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820static const char kVideoTrackId1[] = "video_track_id_1";
deadbeef9d3584c2016-02-16 17:54:10 -0800821static const uint32_t kVideoTrack1Ssrc1 = 2;
822static const uint32_t kVideoTrack1Ssrc2 = 3;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823
824// MediaStream 2
Seth Hampson845e8782018-03-02 11:34:10 -0800825static const char kStreamId2[] = "local_stream_2";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826static const char kStream2Cname[] = "stream_2_cname";
827static const char kAudioTrackId2[] = "audio_track_id_2";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200828static const uint32_t kAudioTrack2Ssrc = 4;
deadbeef9d3584c2016-02-16 17:54:10 -0800829static const char kVideoTrackId2[] = "video_track_id_2";
830static const uint32_t kVideoTrack2Ssrc = 5;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831static const char kVideoTrackId3[] = "video_track_id_3";
deadbeef9d3584c2016-02-16 17:54:10 -0800832static const uint32_t kVideoTrack3Ssrc = 6;
Seth Hampson5b4f0752018-04-02 16:31:36 -0700833static const char kAudioTrackId3[] = "audio_track_id_3";
834static const uint32_t kAudioTrack3Ssrc = 7;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836// Candidate
837static const char kDummyMid[] = "dummy_mid";
838static const int kDummyIndex = 123;
839
840// Misc
Steve Antona3a92c22017-12-07 10:27:41 -0800841static SdpType kDummyType = SdpType::kOffer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842
843// Helper functions
844
845static bool SdpDeserialize(const std::string& message,
846 JsepSessionDescription* jdesc) {
847 return webrtc::SdpDeserialize(message, jdesc, NULL);
848}
849
850static bool SdpDeserializeCandidate(const std::string& message,
851 JsepIceCandidate* candidate) {
852 return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
853}
854
Artem Titov880fa812021-07-30 22:30:23 +0200855// Add some extra `newlines` to the `message` after `line`.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856static void InjectAfter(const std::string& line,
857 const std::string& newlines,
858 std::string* message) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -0800859 absl::StrReplaceAll({{line, line + newlines}}, message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860}
861
862static void Replace(const std::string& line,
863 const std::string& newlines,
864 std::string* message) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -0800865 absl::StrReplaceAll({{line, newlines}}, message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866}
867
Artem Titov880fa812021-07-30 22:30:23 +0200868// Expect a parse failure on the line containing `bad_part` when attempting to
869// parse `bad_sdp`.
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000870static void ExpectParseFailure(const std::string& bad_sdp,
871 const std::string& bad_part) {
Steve Antona3a92c22017-12-07 10:27:41 -0800872 JsepSessionDescription desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 SdpParseError error;
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000874 bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
Harald Alvestrand99bcf602021-03-03 07:44:39 +0000875 ASSERT_FALSE(ret);
876 EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()))
877 << "Did not find " << bad_part << " in " << error.line;
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000878}
879
Artem Titov880fa812021-07-30 22:30:23 +0200880// Expect fail to parse kSdpFullString if replace `good_part` with `bad_part`.
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000881static void ExpectParseFailure(const char* good_part, const char* bad_part) {
882 std::string bad_sdp = kSdpFullString;
883 Replace(good_part, bad_part, &bad_sdp);
884 ExpectParseFailure(bad_sdp, bad_part);
885}
886
Artem Titov880fa812021-07-30 22:30:23 +0200887// Expect fail to parse kSdpFullString if add `newlines` after `injectpoint`.
wu@webrtc.org5e760e72014-04-02 23:19:09 +0000888static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
889 const std::string& newlines,
890 const std::string& bad_part) {
891 std::string bad_sdp = kSdpFullString;
892 InjectAfter(injectpoint, newlines, &bad_sdp);
893 ExpectParseFailure(bad_sdp, bad_part);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894}
895
Steve Anton4e70a722017-11-28 14:57:10 -0800896static void ReplaceDirection(RtpTransceiverDirection direction,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 std::string* message) {
898 std::string new_direction;
899 switch (direction) {
Steve Anton4e70a722017-11-28 14:57:10 -0800900 case RtpTransceiverDirection::kInactive:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 new_direction = "a=inactive";
902 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800903 case RtpTransceiverDirection::kSendOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904 new_direction = "a=sendonly";
905 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800906 case RtpTransceiverDirection::kRecvOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907 new_direction = "a=recvonly";
908 break;
Steve Anton4e70a722017-11-28 14:57:10 -0800909 case RtpTransceiverDirection::kSendRecv:
Markus Handell45c104b2020-03-11 10:51:13 +0100910 new_direction = "a=sendrecv";
911 break;
912 case RtpTransceiverDirection::kStopped:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000913 default:
Markus Handell45c104b2020-03-11 10:51:13 +0100914 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 new_direction = "a=sendrecv";
916 break;
917 }
918 Replace("a=sendrecv", new_direction, message);
919}
920
Yves Gerey665174f2018-06-19 15:03:05 +0200921static void ReplaceRejected(bool audio_rejected,
922 bool video_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 std::string* message) {
924 if (audio_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -0800925 Replace("m=audio 9", "m=audio 0", message);
926 Replace(kAttributeIceUfragVoice, "", message);
927 Replace(kAttributeIcePwdVoice, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000928 }
929 if (video_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -0800930 Replace("m=video 9", "m=video 0", message);
931 Replace(kAttributeIceUfragVideo, "", message);
932 Replace(kAttributeIcePwdVideo, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000933 }
934}
935
936// WebRtcSdpTest
937
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200938class WebRtcSdpTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939 public:
Steve Antona3a92c22017-12-07 10:27:41 -0800940 WebRtcSdpTest() : jdesc_(kDummyType) {
phoglund37ebcf02016-01-08 05:04:57 -0800941#ifdef WEBRTC_ANDROID
942 webrtc::InitializeAndroidObjects();
943#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944 // AudioContentDescription
945 audio_desc_ = CreateAudioContentDescription();
deadbeef9d3584c2016-02-16 17:54:10 -0800946 StreamParams audio_stream;
947 audio_stream.id = kAudioTrackId1;
948 audio_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800949 audio_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-16 17:54:10 -0800950 audio_stream.ssrcs.push_back(kAudioTrack1Ssrc);
951 audio_desc_->AddStream(audio_stream);
zhihuang38989e52017-03-21 11:04:53 -0700952 rtc::SocketAddress audio_addr("74.125.127.126", 2345);
953 audio_desc_->set_connection_address(audio_addr);
Harald Alvestrand1716d392019-06-03 20:35:45 +0200954 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
955 absl::WrapUnique(audio_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956
957 // VideoContentDescription
deadbeef9d3584c2016-02-16 17:54:10 -0800958 video_desc_ = CreateVideoContentDescription();
959 StreamParams video_stream;
960 video_stream.id = kVideoTrackId1;
961 video_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800962 video_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-16 17:54:10 -0800963 video_stream.ssrcs.push_back(kVideoTrack1Ssrc1);
964 video_stream.ssrcs.push_back(kVideoTrack1Ssrc2);
965 cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream.ssrcs);
966 video_stream.ssrc_groups.push_back(ssrc_group);
967 video_desc_->AddStream(video_stream);
zhihuang38989e52017-03-21 11:04:53 -0700968 rtc::SocketAddress video_addr("74.125.224.39", 3457);
969 video_desc_->set_connection_address(video_addr);
Harald Alvestrand1716d392019-06-03 20:35:45 +0200970 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
971 absl::WrapUnique(video_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000972
973 // TransportInfo
Steve Anton06817cd2018-12-18 15:55:30 -0800974 desc_.AddTransportInfo(TransportInfo(
975 kAudioContentName, TransportDescription(kUfragVoice, kPwdVoice)));
976 desc_.AddTransportInfo(TransportInfo(
977 kVideoContentName, TransportDescription(kUfragVideo, kPwdVideo)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000978
979 // v4 host
980 int port = 1234;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000981 rtc::SocketAddress address("192.168.1.5", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000982 Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000983 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
984 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000986 Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000987 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
988 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000990 Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000991 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
992 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000994 Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000995 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
996 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000997
998 // v6 host
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000999 rtc::SocketAddress v6_address("::1", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001000 cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1001 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001002 cricket::LOCAL_PORT_TYPE,
1003 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001004 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001005 cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1006 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001007 cricket::LOCAL_PORT_TYPE,
1008 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001009 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001010 cricket::Candidate candidate7(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1011 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001012 cricket::LOCAL_PORT_TYPE,
1013 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001014 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001015 cricket::Candidate candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1016 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001017 cricket::LOCAL_PORT_TYPE,
1018 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019
1020 // stun
1021 int port_stun = 2345;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001022 rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
1023 rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001024 cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1025 address_stun, kCandidatePriority, "", "",
1026 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001027 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001028 candidate9.set_related_address(rel_address_stun);
1029
1030 address_stun.SetPort(port_stun++);
1031 rel_address_stun.SetPort(port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001032 cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1033 address_stun, kCandidatePriority, "", "",
1034 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001035 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001036 candidate10.set_related_address(rel_address_stun);
1037
1038 // relay
1039 int port_relay = 3456;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001040 rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001041 cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1042 address_relay, kCandidatePriority, "", "",
1043 cricket::RELAY_PORT_TYPE,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001044 kCandidateGeneration, kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 address_relay.SetPort(port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00001046 cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1047 address_relay, kCandidatePriority, "", "",
1048 RELAY_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001049 kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050
1051 // voice
1052 candidates_.push_back(candidate1);
1053 candidates_.push_back(candidate2);
1054 candidates_.push_back(candidate5);
1055 candidates_.push_back(candidate6);
1056 candidates_.push_back(candidate9);
1057 candidates_.push_back(candidate10);
1058
1059 // video
1060 candidates_.push_back(candidate3);
1061 candidates_.push_back(candidate4);
1062 candidates_.push_back(candidate7);
1063 candidates_.push_back(candidate8);
1064 candidates_.push_back(candidate11);
1065 candidates_.push_back(candidate12);
1066
Yves Gerey665174f2018-06-19 15:03:05 +02001067 jcandidate_.reset(
1068 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069
1070 // Set up JsepSessionDescription.
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001071 jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 std::string mline_id;
1073 int mline_index = 0;
Yves Gerey665174f2018-06-19 15:03:05 +02001074 for (size_t i = 0; i < candidates_.size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001075 // In this test, the audio m line index will be 0, and the video m line
1076 // will be 1.
1077 bool is_video = (i > 5);
1078 mline_id = is_video ? "video_content_name" : "audio_content_name";
1079 mline_index = is_video ? 1 : 0;
Yves Gerey665174f2018-06-19 15:03:05 +02001080 JsepIceCandidate jice(mline_id, mline_index, candidates_.at(i));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081 jdesc_.AddCandidate(&jice);
1082 }
1083 }
1084
Seth Hampson5b4f0752018-04-02 16:31:36 -07001085 void RemoveVideoCandidates() {
deadbeef25ed4352016-12-12 18:37:36 -08001086 const IceCandidateCollection* video_candidates_collection =
1087 jdesc_.candidates(1);
1088 ASSERT_NE(nullptr, video_candidates_collection);
1089 std::vector<cricket::Candidate> video_candidates;
1090 for (size_t i = 0; i < video_candidates_collection->count(); ++i) {
1091 cricket::Candidate c = video_candidates_collection->at(i)->candidate();
1092 c.set_transport_name("video_content_name");
1093 video_candidates.push_back(c);
1094 }
1095 jdesc_.RemoveCandidates(video_candidates);
Seth Hampson5b4f0752018-04-02 16:31:36 -07001096 }
1097
1098 // Turns the existing reference description into a description using
1099 // a=bundle-only. This means no transport attributes and a 0 port value on
1100 // the m= sections not associated with the BUNDLE-tag.
1101 void MakeBundleOnlyDescription() {
1102 RemoveVideoCandidates();
deadbeef25ed4352016-12-12 18:37:36 -08001103
1104 // And the rest of the transport attributes.
1105 desc_.transport_infos()[1].description.ice_ufrag.clear();
1106 desc_.transport_infos()[1].description.ice_pwd.clear();
1107 desc_.transport_infos()[1].description.connection_role =
1108 cricket::CONNECTIONROLE_NONE;
1109
1110 // Set bundle-only flag.
1111 desc_.contents()[1].bundle_only = true;
1112
1113 // Add BUNDLE group.
1114 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1115 group.AddContentName(kAudioContentName);
1116 group.AddContentName(kVideoContentName);
1117 desc_.AddGroup(group);
1118
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001119 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef25ed4352016-12-12 18:37:36 -08001120 jdesc_.session_version()));
1121 }
1122
deadbeef9d3584c2016-02-16 17:54:10 -08001123 // Turns the existing reference description into a plan B description,
1124 // with 2 audio tracks and 3 video tracks.
1125 void MakePlanBDescription() {
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001126 audio_desc_ = new AudioContentDescription(*audio_desc_);
1127 video_desc_ = new VideoContentDescription(*video_desc_);
deadbeef9d3584c2016-02-16 17:54:10 -08001128
1129 StreamParams audio_track_2;
1130 audio_track_2.id = kAudioTrackId2;
1131 audio_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001132 audio_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001133 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1134 audio_desc_->AddStream(audio_track_2);
1135
1136 StreamParams video_track_2;
1137 video_track_2.id = kVideoTrackId2;
1138 video_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001139 video_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001140 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1141 video_desc_->AddStream(video_track_2);
1142
1143 StreamParams video_track_3;
1144 video_track_3.id = kVideoTrackId3;
1145 video_track_3.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 11:34:10 -08001146 video_track_3.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-16 17:54:10 -08001147 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1148 video_desc_->AddStream(video_track_3);
1149
1150 desc_.RemoveContentByName(kAudioContentName);
1151 desc_.RemoveContentByName(kVideoContentName);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001152 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1153 absl::WrapUnique(audio_desc_));
1154 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1155 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-16 17:54:10 -08001156
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001157 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef9d3584c2016-02-16 17:54:10 -08001158 jdesc_.session_version()));
1159 }
1160
1161 // Turns the existing reference description into a unified plan description,
1162 // with 2 audio tracks and 3 video tracks.
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001163 void MakeUnifiedPlanDescription(bool use_ssrcs = true) {
deadbeef9d3584c2016-02-16 17:54:10 -08001164 // Audio track 2.
1165 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1166 StreamParams audio_track_2;
1167 audio_track_2.id = kAudioTrackId2;
Seth Hampson845e8782018-03-02 11:34:10 -08001168 audio_track_2.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001169 if (use_ssrcs) {
1170 audio_track_2.cname = kStream2Cname;
1171 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1172 }
deadbeef9d3584c2016-02-16 17:54:10 -08001173 audio_desc_2->AddStream(audio_track_2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001174 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
1175 absl::WrapUnique(audio_desc_2));
Steve Anton06817cd2018-12-18 15:55:30 -08001176 desc_.AddTransportInfo(TransportInfo(
1177 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
deadbeef9d3584c2016-02-16 17:54:10 -08001178 // Video track 2, in stream 2.
1179 VideoContentDescription* video_desc_2 = CreateVideoContentDescription();
1180 StreamParams video_track_2;
1181 video_track_2.id = kVideoTrackId2;
Seth Hampson845e8782018-03-02 11:34:10 -08001182 video_track_2.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001183 if (use_ssrcs) {
1184 video_track_2.cname = kStream2Cname;
1185 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1186 }
deadbeef9d3584c2016-02-16 17:54:10 -08001187 video_desc_2->AddStream(video_track_2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001188 desc_.AddContent(kVideoContentName2, MediaProtocolType::kRtp,
1189 absl::WrapUnique(video_desc_2));
Steve Anton06817cd2018-12-18 15:55:30 -08001190 desc_.AddTransportInfo(TransportInfo(
1191 kVideoContentName2, TransportDescription(kUfragVideo2, kPwdVideo2)));
deadbeef9d3584c2016-02-16 17:54:10 -08001192
1193 // Video track 3, in stream 2.
1194 VideoContentDescription* video_desc_3 = CreateVideoContentDescription();
1195 StreamParams video_track_3;
1196 video_track_3.id = kVideoTrackId3;
Seth Hampson845e8782018-03-02 11:34:10 -08001197 video_track_3.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001198 if (use_ssrcs) {
1199 video_track_3.cname = kStream2Cname;
1200 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1201 }
deadbeef9d3584c2016-02-16 17:54:10 -08001202 video_desc_3->AddStream(video_track_3);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001203 desc_.AddContent(kVideoContentName3, MediaProtocolType::kRtp,
1204 absl::WrapUnique(video_desc_3));
Steve Anton06817cd2018-12-18 15:55:30 -08001205 desc_.AddTransportInfo(TransportInfo(
1206 kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3)));
Steve Antone831b8c2018-02-01 12:22:16 -08001207 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
deadbeef9d3584c2016-02-16 17:54:10 -08001208
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001209 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef9d3584c2016-02-16 17:54:10 -08001210 jdesc_.session_version()));
1211 }
1212
1213 // Creates an audio content description with no streams, and some default
1214 // configuration.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215 AudioContentDescription* CreateAudioContentDescription() {
1216 AudioContentDescription* audio = new AudioContentDescription();
1217 audio->set_rtcp_mux(true);
deadbeef13871492015-12-09 12:37:51 -08001218 audio->set_rtcp_reduced_size(true);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219 audio->set_protocol(cricket::kMediaProtocolSavpf);
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001220 audio->AddCodec(AudioCodec(111, "opus", 48000, 0, 2));
ossue1405ad2017-01-23 08:55:48 -08001221 audio->AddCodec(AudioCodec(103, "ISAC", 16000, 0, 1));
1222 audio->AddCodec(AudioCodec(104, "ISAC", 32000, 0, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223 return audio;
1224 }
1225
Seth Hampson5b4f0752018-04-02 16:31:36 -07001226 // Turns the existing reference description into a unified plan description,
1227 // with 3 audio MediaContentDescriptions with special StreamParams that
1228 // contain 0 or multiple stream ids: - audio track 1 has 1 media stream id -
1229 // audio track 2 has 2 media stream ids - audio track 3 has 0 media stream ids
Seth Hampson7fa6ee62018-10-17 10:25:28 -07001230 void MakeUnifiedPlanDescriptionMultipleStreamIds(const int msid_signaling) {
Seth Hampson5b4f0752018-04-02 16:31:36 -07001231 desc_.RemoveContentByName(kVideoContentName);
1232 desc_.RemoveTransportInfoByName(kVideoContentName);
1233 RemoveVideoCandidates();
1234
1235 // Audio track 2 has 2 media stream ids.
1236 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1237 StreamParams audio_track_2;
1238 audio_track_2.id = kAudioTrackId2;
1239 audio_track_2.cname = kStream1Cname;
1240 audio_track_2.set_stream_ids({kStreamId1, kStreamId2});
1241 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1242 audio_desc_2->AddStream(audio_track_2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001243 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
1244 absl::WrapUnique(audio_desc_2));
Steve Anton06817cd2018-12-18 15:55:30 -08001245 desc_.AddTransportInfo(TransportInfo(
1246 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
Seth Hampson5b4f0752018-04-02 16:31:36 -07001247
1248 // Audio track 3 has no stream ids.
1249 AudioContentDescription* audio_desc_3 = CreateAudioContentDescription();
1250 StreamParams audio_track_3;
1251 audio_track_3.id = kAudioTrackId3;
1252 audio_track_3.cname = kStream2Cname;
1253 audio_track_3.set_stream_ids({});
1254 audio_track_3.ssrcs.push_back(kAudioTrack3Ssrc);
1255 audio_desc_3->AddStream(audio_track_3);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001256 desc_.AddContent(kAudioContentName3, MediaProtocolType::kRtp,
1257 absl::WrapUnique(audio_desc_3));
Steve Anton06817cd2018-12-18 15:55:30 -08001258 desc_.AddTransportInfo(TransportInfo(
1259 kAudioContentName3, TransportDescription(kUfragVoice3, kPwdVoice3)));
Seth Hampson7fa6ee62018-10-17 10:25:28 -07001260 desc_.set_msid_signaling(msid_signaling);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001261 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
Seth Hampson5b4f0752018-04-02 16:31:36 -07001262 jdesc_.session_version()));
1263 }
1264
Seth Hampson5897a6e2018-04-03 11:16:33 -07001265 // Turns the existing reference description into a unified plan description
1266 // with one audio MediaContentDescription that contains one StreamParams with
1267 // 0 ssrcs.
1268 void MakeUnifiedPlanDescriptionNoSsrcSignaling() {
1269 desc_.RemoveContentByName(kVideoContentName);
1270 desc_.RemoveContentByName(kAudioContentName);
1271 desc_.RemoveTransportInfoByName(kVideoContentName);
1272 RemoveVideoCandidates();
1273
1274 AudioContentDescription* audio_desc = CreateAudioContentDescription();
1275 StreamParams audio_track;
1276 audio_track.id = kAudioTrackId1;
1277 audio_track.set_stream_ids({kStreamId1});
1278 audio_desc->AddStream(audio_track);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001279 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1280 absl::WrapUnique(audio_desc));
Seth Hampson5897a6e2018-04-03 11:16:33 -07001281
1282 // Enable signaling a=msid lines.
1283 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001284 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
Seth Hampson5897a6e2018-04-03 11:16:33 -07001285 jdesc_.session_version()));
1286 }
1287
deadbeef9d3584c2016-02-16 17:54:10 -08001288 // Creates a video content description with no streams, and some default
1289 // configuration.
1290 VideoContentDescription* CreateVideoContentDescription() {
1291 VideoContentDescription* video = new VideoContentDescription();
deadbeef9d3584c2016-02-16 17:54:10 -08001292 video->set_protocol(cricket::kMediaProtocolSavpf);
1293 video->AddCodec(
perkj26752742016-10-24 01:21:16 -07001294 VideoCodec(120, JsepSessionDescription::kDefaultVideoCodecName));
deadbeef9d3584c2016-02-16 17:54:10 -08001295 return video;
1296 }
1297
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 template <class MCD>
Yves Gerey665174f2018-06-19 15:03:05 +02001299 void CompareMediaContentDescription(const MCD* cd1, const MCD* cd2) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 // type
Harald Alvestrand1716d392019-06-03 20:35:45 +02001301 EXPECT_EQ(cd1->type(), cd2->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302
1303 // content direction
1304 EXPECT_EQ(cd1->direction(), cd2->direction());
1305
1306 // rtcp_mux
1307 EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
1308
deadbeef13871492015-12-09 12:37:51 -08001309 // rtcp_reduced_size
1310 EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size());
1311
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 // protocol
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001313 // Use an equivalence class here, for old and new versions of the
1314 // protocol description.
Yves Gerey665174f2018-06-19 15:03:05 +02001315 if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp ||
1316 cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
1317 cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
lally@webrtc.org36300852015-02-24 20:19:35 +00001318 const bool cd2_is_also_dtls_sctp =
Yves Gerey665174f2018-06-19 15:03:05 +02001319 cd2->protocol() == cricket::kMediaProtocolDtlsSctp ||
1320 cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
1321 cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
lally@webrtc.org36300852015-02-24 20:19:35 +00001322 EXPECT_TRUE(cd2_is_also_dtls_sctp);
lally@webrtc.orgd7b61652015-02-24 20:18:55 +00001323 } else {
1324 EXPECT_EQ(cd1->protocol(), cd2->protocol());
1325 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326
1327 // codecs
1328 EXPECT_EQ(cd1->codecs(), cd2->codecs());
1329
1330 // bandwidth
1331 EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
1332
1333 // streams
1334 EXPECT_EQ(cd1->streams(), cd2->streams());
1335
Johannes Kron0854eb62018-10-10 22:33:20 +02001336 // extmap-allow-mixed
Johannes Kron9581bc42018-10-23 10:17:39 +02001337 EXPECT_EQ(cd1->extmap_allow_mixed_enum(), cd2->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001338
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339 // extmap
1340 ASSERT_EQ(cd1->rtp_header_extensions().size(),
1341 cd2->rtp_header_extensions().size());
Yves Gerey665174f2018-06-19 15:03:05 +02001342 for (size_t i = 0; i < cd1->rtp_header_extensions().size(); ++i) {
isheriff6f8d6862016-05-26 11:24:55 -07001343 const RtpExtension ext1 = cd1->rtp_header_extensions().at(i);
1344 const RtpExtension ext2 = cd2->rtp_header_extensions().at(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001345 EXPECT_EQ(ext1.uri, ext2.uri);
1346 EXPECT_EQ(ext1.id, ext2.id);
jbauch5869f502017-06-29 12:31:36 -07001347 EXPECT_EQ(ext1.encrypt, ext2.encrypt);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001348 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349 }
1350
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001351 void CompareRidDescriptionIds(const std::vector<RidDescription>& rids,
1352 const std::vector<std::string>& ids) {
1353 // Order of elements does not matter, only equivalence of sets.
1354 EXPECT_EQ(rids.size(), ids.size());
1355 for (const std::string& id : ids) {
Steve Anton64b626b2019-01-28 17:25:26 -08001356 EXPECT_EQ(1l, absl::c_count_if(rids, [id](const RidDescription& rid) {
1357 return rid.rid == id;
1358 }));
Amit Hilbuchc57d5732018-12-11 15:30:11 -08001359 }
1360 }
1361
Amit Hilbucha2012042018-12-03 11:35:05 -08001362 void CompareSimulcastDescription(const SimulcastDescription& simulcast1,
1363 const SimulcastDescription& simulcast2) {
1364 EXPECT_EQ(simulcast1.send_layers().size(), simulcast2.send_layers().size());
1365 EXPECT_EQ(simulcast1.receive_layers().size(),
1366 simulcast2.receive_layers().size());
1367 }
1368
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001369 void CompareSctpDataContentDescription(
1370 const SctpDataContentDescription* dcd1,
1371 const SctpDataContentDescription* dcd2) {
Harald Alvestrand26bf7c42019-04-23 05:20:17 +00001372 EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001373 EXPECT_EQ(dcd1->port(), dcd2->port());
1374 EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size());
Harald Alvestrand26bf7c42019-04-23 05:20:17 +00001375 }
1376
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001377 void CompareSessionDescription(const SessionDescription& desc1,
1378 const SessionDescription& desc2) {
1379 // Compare content descriptions.
1380 if (desc1.contents().size() != desc2.contents().size()) {
1381 ADD_FAILURE();
1382 return;
1383 }
Yves Gerey665174f2018-06-19 15:03:05 +02001384 for (size_t i = 0; i < desc1.contents().size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001385 const cricket::ContentInfo& c1 = desc1.contents().at(i);
1386 const cricket::ContentInfo& c2 = desc2.contents().at(i);
deadbeef25ed4352016-12-12 18:37:36 -08001387 // ContentInfo properties.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001388 EXPECT_EQ(c1.name, c2.name);
deadbeef25ed4352016-12-12 18:37:36 -08001389 EXPECT_EQ(c1.type, c2.type);
1390 EXPECT_EQ(c1.rejected, c2.rejected);
1391 EXPECT_EQ(c1.bundle_only, c2.bundle_only);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001392
1393 ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
1394 if (IsAudioContent(&c1)) {
1395 const AudioContentDescription* acd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001396 c1.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397 const AudioContentDescription* acd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001398 c2.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399 CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
1400 }
1401
1402 ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
1403 if (IsVideoContent(&c1)) {
1404 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001405 c1.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001406 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08001407 c2.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001408 CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
1409 }
1410
1411 ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001412 if (c1.media_description()->as_sctp()) {
1413 ASSERT_TRUE(c2.media_description()->as_sctp());
1414 const SctpDataContentDescription* scd1 =
1415 c1.media_description()->as_sctp();
1416 const SctpDataContentDescription* scd2 =
1417 c2.media_description()->as_sctp();
1418 CompareSctpDataContentDescription(scd1, scd2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001419 }
Amit Hilbucha2012042018-12-03 11:35:05 -08001420
1421 CompareSimulcastDescription(
1422 c1.media_description()->simulcast_description(),
1423 c2.media_description()->simulcast_description());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001424 }
1425
1426 // group
1427 const cricket::ContentGroups groups1 = desc1.groups();
1428 const cricket::ContentGroups groups2 = desc2.groups();
1429 EXPECT_EQ(groups1.size(), groups1.size());
1430 if (groups1.size() != groups2.size()) {
1431 ADD_FAILURE();
1432 return;
1433 }
1434 for (size_t i = 0; i < groups1.size(); ++i) {
1435 const cricket::ContentGroup group1 = groups1.at(i);
1436 const cricket::ContentGroup group2 = groups2.at(i);
1437 EXPECT_EQ(group1.semantics(), group2.semantics());
1438 const cricket::ContentNames names1 = group1.content_names();
1439 const cricket::ContentNames names2 = group2.content_names();
1440 EXPECT_EQ(names1.size(), names2.size());
1441 if (names1.size() != names2.size()) {
1442 ADD_FAILURE();
1443 return;
1444 }
1445 cricket::ContentNames::const_iterator iter1 = names1.begin();
1446 cricket::ContentNames::const_iterator iter2 = names2.begin();
1447 while (iter1 != names1.end()) {
1448 EXPECT_EQ(*iter1++, *iter2++);
1449 }
1450 }
1451
1452 // transport info
1453 const cricket::TransportInfos transports1 = desc1.transport_infos();
1454 const cricket::TransportInfos transports2 = desc2.transport_infos();
1455 EXPECT_EQ(transports1.size(), transports2.size());
1456 if (transports1.size() != transports2.size()) {
1457 ADD_FAILURE();
1458 return;
1459 }
1460 for (size_t i = 0; i < transports1.size(); ++i) {
1461 const cricket::TransportInfo transport1 = transports1.at(i);
1462 const cricket::TransportInfo transport2 = transports2.at(i);
1463 EXPECT_EQ(transport1.content_name, transport2.content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001464 EXPECT_EQ(transport1.description.ice_ufrag,
1465 transport2.description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +02001466 EXPECT_EQ(transport1.description.ice_pwd, transport2.description.ice_pwd);
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07001467 EXPECT_EQ(transport1.description.ice_mode,
1468 transport2.description.ice_mode);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469 if (transport1.description.identity_fingerprint) {
1470 EXPECT_EQ(*transport1.description.identity_fingerprint,
1471 *transport2.description.identity_fingerprint);
1472 } else {
1473 EXPECT_EQ(transport1.description.identity_fingerprint.get(),
1474 transport2.description.identity_fingerprint.get());
1475 }
1476 EXPECT_EQ(transport1.description.transport_options,
1477 transport2.description.transport_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001478 }
deadbeefc80741f2015-10-22 13:14:45 -07001479
1480 // global attributes
1481 EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
Johannes Kron9581bc42018-10-23 10:17:39 +02001482 EXPECT_EQ(desc1.extmap_allow_mixed(), desc2.extmap_allow_mixed());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001483 }
1484
Yves Gerey665174f2018-06-19 15:03:05 +02001485 bool CompareSessionDescription(const JsepSessionDescription& desc1,
1486 const JsepSessionDescription& desc2) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001487 EXPECT_EQ(desc1.session_id(), desc2.session_id());
1488 EXPECT_EQ(desc1.session_version(), desc2.session_version());
Harald Alvestrandee212a72021-11-02 12:06:45 +00001489 EXPECT_TRUE(desc1.description());
1490 EXPECT_TRUE(desc2.description());
1491 if (!desc1.description() || !desc2.description()) {
1492 return false;
1493 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494 CompareSessionDescription(*desc1.description(), *desc2.description());
1495 if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
1496 return false;
1497 for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
1498 const IceCandidateCollection* cc1 = desc1.candidates(i);
1499 const IceCandidateCollection* cc2 = desc2.candidates(i);
deadbeef25ed4352016-12-12 18:37:36 -08001500 if (cc1->count() != cc2->count()) {
1501 ADD_FAILURE();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001502 return false;
deadbeef25ed4352016-12-12 18:37:36 -08001503 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001504 for (size_t j = 0; j < cc1->count(); ++j) {
1505 const IceCandidateInterface* c1 = cc1->at(j);
1506 const IceCandidateInterface* c2 = cc2->at(j);
1507 EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
1508 EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
1509 EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
1510 }
1511 }
1512 return true;
1513 }
1514
Artem Titov880fa812021-07-30 22:30:23 +02001515 // Disable the ice-ufrag and ice-pwd in given `sdp` message by replacing
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001516 // them with invalid keywords so that the parser will just ignore them.
1517 bool RemoveCandidateUfragPwd(std::string* sdp) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -08001518 absl::StrReplaceAll(
1519 {{"a=ice-ufrag", "a=xice-ufrag"}, {"a=ice-pwd", "a=xice-pwd"}}, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001520 return true;
1521 }
1522
Artem Titov880fa812021-07-30 22:30:23 +02001523 // Update the candidates in `jdesc` to use the given `ufrag` and `pwd`.
Yves Gerey665174f2018-06-19 15:03:05 +02001524 bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc,
1525 int mline_index,
1526 const std::string& ufrag,
1527 const std::string& pwd) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001528 std::string content_name;
1529 if (mline_index == 0) {
1530 content_name = kAudioContentName;
1531 } else if (mline_index == 1) {
1532 content_name = kVideoContentName;
1533 } else {
nissec80e7412017-01-11 05:56:46 -08001534 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535 }
Yves Gerey665174f2018-06-19 15:03:05 +02001536 TransportInfo transport_info(content_name,
1537 TransportDescription(ufrag, pwd));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 SessionDescription* desc =
1539 const_cast<SessionDescription*>(jdesc->description());
1540 desc->RemoveTransportInfoByName(content_name);
Steve Anton06817cd2018-12-18 15:55:30 -08001541 desc->AddTransportInfo(transport_info);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542 for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
1543 const IceCandidateCollection* cc = jdesc_.candidates(i);
1544 for (size_t j = 0; j < cc->count(); ++j) {
1545 if (cc->at(j)->sdp_mline_index() == mline_index) {
Yves Gerey665174f2018-06-19 15:03:05 +02001546 const_cast<Candidate&>(cc->at(j)->candidate()).set_username(ufrag);
1547 const_cast<Candidate&>(cc->at(j)->candidate()).set_password(pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001548 }
1549 }
1550 }
1551 return true;
1552 }
1553
1554 void AddIceOptions(const std::string& content_name,
1555 const std::vector<std::string>& transport_options) {
1556 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1557 cricket::TransportInfo transport_info =
1558 *(desc_.GetTransportInfoByName(content_name));
1559 desc_.RemoveTransportInfoByName(content_name);
1560 transport_info.description.transport_options = transport_options;
1561 desc_.AddTransportInfo(transport_info);
1562 }
1563
deadbeef3f7219b2015-12-28 15:17:14 -08001564 void SetIceUfragPwd(const std::string& content_name,
1565 const std::string& ice_ufrag,
1566 const std::string& ice_pwd) {
1567 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1568 cricket::TransportInfo transport_info =
1569 *(desc_.GetTransportInfoByName(content_name));
1570 desc_.RemoveTransportInfoByName(content_name);
1571 transport_info.description.ice_ufrag = ice_ufrag;
1572 transport_info.description.ice_pwd = ice_pwd;
1573 desc_.AddTransportInfo(transport_info);
1574 }
1575
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001576 void AddFingerprint() {
1577 desc_.RemoveTransportInfoByName(kAudioContentName);
1578 desc_.RemoveTransportInfoByName(kVideoContentName);
Steve Anton4905edb2018-10-15 19:27:44 -07001579 rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1, kIdentityDigest);
Steve Anton06817cd2018-12-18 15:55:30 -08001580 desc_.AddTransportInfo(TransportInfo(
deadbeef46eed762016-01-28 13:24:37 -08001581 kAudioContentName,
deadbeef9d3584c2016-02-16 17:54:10 -08001582 TransportDescription(std::vector<std::string>(), kUfragVoice, kPwdVoice,
1583 cricket::ICEMODE_FULL,
Steve Anton06817cd2018-12-18 15:55:30 -08001584 cricket::CONNECTIONROLE_NONE, &fingerprint)));
1585 desc_.AddTransportInfo(TransportInfo(
deadbeef46eed762016-01-28 13:24:37 -08001586 kVideoContentName,
deadbeef9d3584c2016-02-16 17:54:10 -08001587 TransportDescription(std::vector<std::string>(), kUfragVideo, kPwdVideo,
1588 cricket::ICEMODE_FULL,
Steve Anton06817cd2018-12-18 15:55:30 -08001589 cricket::CONNECTIONROLE_NONE, &fingerprint)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001590 }
1591
jbauch5869f502017-06-29 12:31:36 -07001592 void AddExtmap(bool encrypted) {
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001593 audio_desc_ = new AudioContentDescription(*audio_desc_);
1594 video_desc_ = new VideoContentDescription(*video_desc_);
jbauch5869f502017-06-29 12:31:36 -07001595 audio_desc_->AddRtpHeaderExtension(
1596 RtpExtension(kExtmapUri, kExtmapId, encrypted));
1597 video_desc_->AddRtpHeaderExtension(
1598 RtpExtension(kExtmapUri, kExtmapId, encrypted));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599 desc_.RemoveContentByName(kAudioContentName);
1600 desc_.RemoveContentByName(kVideoContentName);
Harald Alvestrand1716d392019-06-03 20:35:45 +02001601 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1602 absl::WrapUnique(audio_desc_));
1603 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1604 absl::WrapUnique(video_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605 }
1606
Seth Hampson5897a6e2018-04-03 11:16:33 -07001607 // Removes everything in StreamParams from the session description that is
1608 // used for a=ssrc lines.
1609 void RemoveSsrcSignalingFromStreamParams() {
Harald Alvestrand1716d392019-06-03 20:35:45 +02001610 for (cricket::ContentInfo& content_info :
1611 jdesc_.description()->contents()) {
Seth Hampson5897a6e2018-04-03 11:16:33 -07001612 // With Unified Plan there should be one StreamParams per m= section.
1613 StreamParams& stream =
1614 content_info.media_description()->mutable_streams()[0];
1615 stream.ssrcs.clear();
1616 stream.ssrc_groups.clear();
1617 stream.cname.clear();
1618 }
1619 }
1620
Seth Hampson7fa6ee62018-10-17 10:25:28 -07001621 // Removes all a=ssrc lines from the SDP string, except for the
1622 // "a=ssrc:... cname:..." lines.
1623 void RemoveSsrcMsidLinesFromSdpString(std::string* sdp_string) {
1624 const char kAttributeSsrc[] = "a=ssrc";
1625 const char kAttributeCname[] = "cname";
1626 size_t ssrc_line_pos = sdp_string->find(kAttributeSsrc);
1627 while (ssrc_line_pos != std::string::npos) {
1628 size_t beg_line_pos = sdp_string->rfind('\n', ssrc_line_pos);
1629 size_t end_line_pos = sdp_string->find('\n', ssrc_line_pos);
1630 size_t cname_pos = sdp_string->find(kAttributeCname, ssrc_line_pos);
1631 if (cname_pos == std::string::npos || cname_pos > end_line_pos) {
1632 // Only erase a=ssrc lines that don't contain "cname".
1633 sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
1634 ssrc_line_pos = sdp_string->find(kAttributeSsrc, beg_line_pos);
1635 } else {
1636 // Skip the "a=ssrc:... cname" line and find the next "a=ssrc" line.
1637 ssrc_line_pos = sdp_string->find(kAttributeSsrc, end_line_pos);
1638 }
1639 }
1640 }
1641
Seth Hampson5897a6e2018-04-03 11:16:33 -07001642 // Removes all a=ssrc lines from the SDP string.
1643 void RemoveSsrcLinesFromSdpString(std::string* sdp_string) {
1644 const char kAttributeSsrc[] = "a=ssrc";
1645 while (sdp_string->find(kAttributeSsrc) != std::string::npos) {
1646 size_t pos_ssrc_attribute = sdp_string->find(kAttributeSsrc);
1647 size_t beg_line_pos = sdp_string->rfind('\n', pos_ssrc_attribute);
1648 size_t end_line_pos = sdp_string->find('\n', pos_ssrc_attribute);
1649 sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
1650 }
1651 }
1652
Steve Anton4e70a722017-11-28 14:57:10 -08001653 bool TestSerializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001654 audio_desc_->set_direction(direction);
1655 video_desc_->set_direction(direction);
1656 std::string new_sdp = kSdpFullString;
1657 ReplaceDirection(direction, &new_sdp);
1658
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001659 if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001660 jdesc_.session_version())) {
1661 return false;
1662 }
Steve Antone831b8c2018-02-01 12:22:16 -08001663 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001664 EXPECT_EQ(new_sdp, message);
1665 return true;
1666 }
1667
1668 bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001669 audio_desc_ = new AudioContentDescription(*audio_desc_);
1670 video_desc_ = new VideoContentDescription(*video_desc_);
zhihuang38989e52017-03-21 11:04:53 -07001671
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001672 desc_.RemoveContentByName(kAudioContentName);
1673 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001674 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001675 absl::WrapUnique(audio_desc_));
Steve Anton5adfafd2017-12-20 16:34:00 -08001676 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001677 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-16 17:54:10 -08001678 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1679 audio_rejected ? "" : kPwdVoice);
1680 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1681 video_rejected ? "" : kPwdVideo);
deadbeef3f7219b2015-12-28 15:17:14 -08001682
1683 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
1685
Steve Antona3a92c22017-12-07 10:27:41 -08001686 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07001687 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 12:22:16 -08001688 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001689 EXPECT_EQ(new_sdp, message);
1690 return true;
1691 }
1692
zstein4b2e0822017-02-17 19:48:38 -08001693 void AddSctpDataChannel(bool use_sctpmap) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001694 std::unique_ptr<SctpDataContentDescription> data(
1695 new SctpDataContentDescription());
1696 sctp_desc_ = data.get();
1697 sctp_desc_->set_use_sctpmap(use_sctpmap);
Guido Urdanetacecf87f2019-05-31 10:17:38 +00001698 sctp_desc_->set_protocol(cricket::kMediaProtocolUdpDtlsSctp);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001699 sctp_desc_->set_port(kDefaultSctpPort);
Steve Anton5adfafd2017-12-20 16:34:00 -08001700 desc_.AddContent(kDataContentName, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001701 std::move(data));
Steve Anton06817cd2018-12-18 15:55:30 -08001702 desc_.AddTransportInfo(TransportInfo(
1703 kDataContentName, TransportDescription(kUfragData, kPwdData)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001704 }
1705
Steve Anton4e70a722017-11-28 14:57:10 -08001706 bool TestDeserializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707 std::string new_sdp = kSdpFullString;
1708 ReplaceDirection(direction, &new_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08001709 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001710
1711 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
1712
1713 audio_desc_->set_direction(direction);
1714 video_desc_->set_direction(direction);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001715 if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001716 jdesc_.session_version())) {
1717 return false;
1718 }
1719 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
1720 return true;
1721 }
1722
1723 bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
deadbeef3f7219b2015-12-28 15:17:14 -08001724 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001725 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08001726 JsepSessionDescription new_jdesc(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
deadbeef3f7219b2015-12-28 15:17:14 -08001728
Harald Alvestrandb97d2fe2020-02-28 11:54:40 +01001729 audio_desc_ = new AudioContentDescription(*audio_desc_);
1730 video_desc_ = new VideoContentDescription(*video_desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 desc_.RemoveContentByName(kAudioContentName);
1732 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-20 16:34:00 -08001733 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001734 absl::WrapUnique(audio_desc_));
Steve Anton5adfafd2017-12-20 16:34:00 -08001735 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001736 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-16 17:54:10 -08001737 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1738 audio_rejected ? "" : kPwdVoice);
1739 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1740 video_rejected ? "" : kPwdVideo);
Steve Antona3a92c22017-12-07 10:27:41 -08001741 JsepSessionDescription jdesc_no_candidates(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001742 if (!jdesc_no_candidates.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef3f7219b2015-12-28 15:17:14 -08001743 jdesc_.session_version())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744 return false;
1745 }
deadbeef3f7219b2015-12-28 15:17:14 -08001746 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 return true;
1748 }
1749
Yves Gerey665174f2018-06-19 15:03:05 +02001750 void TestDeserializeExtmap(bool session_level,
1751 bool media_level,
1752 bool encrypted) {
jbauch5869f502017-06-29 12:31:36 -07001753 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08001754 JsepSessionDescription new_jdesc(SdpType::kOffer);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001755 ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756 jdesc_.session_version()));
Steve Antona3a92c22017-12-07 10:27:41 -08001757 JsepSessionDescription jdesc_with_extmap(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001758 std::string sdp_with_extmap = kSdpString;
1759 if (session_level) {
jbauch5869f502017-06-29 12:31:36 -07001760 InjectAfter(kSessionTime,
1761 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1762 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763 &sdp_with_extmap);
1764 }
1765 if (media_level) {
jbauch5869f502017-06-29 12:31:36 -07001766 InjectAfter(kAttributeIcePwdVoice,
1767 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1768 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001769 &sdp_with_extmap);
jbauch5869f502017-06-29 12:31:36 -07001770 InjectAfter(kAttributeIcePwdVideo,
1771 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1772 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773 &sdp_with_extmap);
1774 }
1775 // The extmap can't be present at the same time in both session level and
1776 // media level.
1777 if (session_level && media_level) {
1778 SdpParseError error;
Yves Gerey665174f2018-06-19 15:03:05 +02001779 EXPECT_FALSE(
1780 webrtc::SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001781 EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
1782 } else {
1783 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
1784 EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
1785 }
1786 }
1787
1788 void VerifyCodecParameter(const cricket::CodecParameterMap& params,
Yves Gerey665174f2018-06-19 15:03:05 +02001789 const std::string& name,
1790 int expected_value) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001791 cricket::CodecParameterMap::const_iterator found = params.find(name);
1792 ASSERT_TRUE(found != params.end());
Jonas Olsson6b1985d2018-07-05 11:59:48 +02001793 EXPECT_EQ(found->second, rtc::ToString(expected_value));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001794 }
1795
1796 void TestDeserializeCodecParams(const CodecParams& params,
1797 JsepSessionDescription* jdesc_output) {
1798 std::string sdp =
1799 "v=0\r\n"
1800 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1801 "s=-\r\n"
1802 "t=0 0\r\n"
1803 // Include semantics for WebRTC Media Streams since it is supported by
1804 // this parser, and will be added to the SDP when serializing a session
1805 // description.
1806 "a=msid-semantic: WMS\r\n"
1807 // Pl type 111 preferred.
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001808 "m=audio 9 RTP/SAVPF 111 104 103 105\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 // Pltype 111 listed before 103 and 104 in the map.
1810 "a=rtpmap:111 opus/48000/2\r\n"
1811 // Pltype 103 listed before 104.
1812 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00001813 "a=rtpmap:104 ISAC/32000\r\n"
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001814 "a=rtpmap:105 telephone-event/8000\r\n"
1815 "a=fmtp:105 0-15,66,70\r\n"
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001816 "a=fmtp:111 ";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817 std::ostringstream os;
Donald Curtis144d0182015-05-15 13:14:24 -07001818 os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
mallinath@webrtc.orga5506692013-08-12 21:18:15 +00001819 << "; sprop-stereo=" << params.sprop_stereo
1820 << "; useinbandfec=" << params.useinband
Jonas Olssonb2b20312020-01-14 12:11:31 +01001821 << "; maxaveragebitrate=" << params.maxaveragebitrate
1822 << "\r\n"
1823 "a=ptime:"
1824 << params.ptime
1825 << "\r\n"
1826 "a=maxptime:"
1827 << params.max_ptime << "\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001828 sdp += os.str();
1829
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001830 os.clear();
1831 os.str("");
1832 // Pl type 100 preferred.
Philipp Hanckeb7bc2432021-03-11 15:28:00 +01001833 os << "m=video 9 RTP/SAVPF 99 95 96\r\n"
1834 "a=rtpmap:96 VP9/90000\r\n" // out-of-order wrt the m= line.
Jonas Olssonb2b20312020-01-14 12:11:31 +01001835 "a=rtpmap:99 VP8/90000\r\n"
1836 "a=rtpmap:95 RTX/90000\r\n"
1837 "a=fmtp:95 apt=99;\r\n";
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001838 sdp += os.str();
1839
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 // Deserialize
1841 SdpParseError error;
1842 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
1843
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001845 GetFirstAudioContentDescription(jdesc_output->description());
1846 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 ASSERT_FALSE(acd->codecs().empty());
1848 cricket::AudioCodec opus = acd->codecs()[0];
1849 EXPECT_EQ("opus", opus.name);
1850 EXPECT_EQ(111, opus.id);
1851 VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
1852 VerifyCodecParameter(opus.params, "stereo", params.stereo);
1853 VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
1854 VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001855 VerifyCodecParameter(opus.params, "maxaveragebitrate",
1856 params.maxaveragebitrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001857 for (size_t i = 0; i < acd->codecs().size(); ++i) {
1858 cricket::AudioCodec codec = acd->codecs()[i];
1859 VerifyCodecParameter(codec.params, "ptime", params.ptime);
1860 VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861 }
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001862
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02001863 cricket::AudioCodec dtmf = acd->codecs()[3];
1864 EXPECT_EQ("telephone-event", dtmf.name);
1865 EXPECT_EQ(105, dtmf.id);
1866 EXPECT_EQ(3u,
1867 dtmf.params.size()); // ptime and max_ptime count as parameters.
1868 EXPECT_EQ(dtmf.params.begin()->first, "");
1869 EXPECT_EQ(dtmf.params.begin()->second, "0-15,66,70");
1870
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001871 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001872 GetFirstVideoContentDescription(jdesc_output->description());
1873 ASSERT_TRUE(vcd);
stefan@webrtc.org85d27942014-06-09 12:51:39 +00001874 ASSERT_FALSE(vcd->codecs().empty());
1875 cricket::VideoCodec vp8 = vcd->codecs()[0];
1876 EXPECT_EQ("VP8", vp8.name);
1877 EXPECT_EQ(99, vp8.id);
1878 cricket::VideoCodec rtx = vcd->codecs()[1];
1879 EXPECT_EQ("RTX", rtx.name);
1880 EXPECT_EQ(95, rtx.id);
1881 VerifyCodecParameter(rtx.params, "apt", vp8.id);
Philipp Hanckeb7bc2432021-03-11 15:28:00 +01001882 // VP9 is listed last in the m= line so should come after VP8 and RTX.
1883 cricket::VideoCodec vp9 = vcd->codecs()[2];
1884 EXPECT_EQ("VP9", vp9.name);
1885 EXPECT_EQ(96, vp9.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001886 }
1887
1888 void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
1889 bool use_wildcard) {
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001890 std::string sdp_session_and_audio =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001891 "v=0\r\n"
1892 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1893 "s=-\r\n"
1894 "t=0 0\r\n"
1895 // Include semantics for WebRTC Media Streams since it is supported by
1896 // this parser, and will be added to the SDP when serializing a session
1897 // description.
1898 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00001899 "m=audio 9 RTP/SAVPF 111\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001900 "a=rtpmap:111 opus/48000/2\r\n";
1901 std::string sdp_video =
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902 "m=video 3457 RTP/SAVPF 101\r\n"
1903 "a=rtpmap:101 VP8/90000\r\n"
Elad Alonfadb1812019-05-24 13:40:02 +02001904 "a=rtcp-fb:101 goog-lntf\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001905 "a=rtcp-fb:101 nack\r\n"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001906 "a=rtcp-fb:101 nack pli\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001907 "a=rtcp-fb:101 goog-remb\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001908 std::ostringstream os;
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001909 os << sdp_session_and_audio;
Yves Gerey665174f2018-06-19 15:03:05 +02001910 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") << " nack\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001911 os << sdp_video;
Yves Gerey665174f2018-06-19 15:03:05 +02001912 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") << " ccm fir\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:46 +00001913 std::string sdp = os.str();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001914 // Deserialize
1915 SdpParseError error;
1916 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001918 GetFirstAudioContentDescription(jdesc_output->description());
1919 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001920 ASSERT_FALSE(acd->codecs().empty());
1921 cricket::AudioCodec opus = acd->codecs()[0];
1922 EXPECT_EQ(111, opus.id);
Yves Gerey665174f2018-06-19 15:03:05 +02001923 EXPECT_TRUE(opus.HasFeedbackParam(cricket::FeedbackParam(
1924 cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001925
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001927 GetFirstVideoContentDescription(jdesc_output->description());
1928 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929 ASSERT_FALSE(vcd->codecs().empty());
1930 cricket::VideoCodec vp8 = vcd->codecs()[0];
1931 EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
1932 vp8.name.c_str());
1933 EXPECT_EQ(101, vp8.id);
Yves Gerey665174f2018-06-19 15:03:05 +02001934 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
Elad Alonfadb1812019-05-24 13:40:02 +02001935 cricket::kRtcpFbParamLntf, cricket::kParamValueEmpty)));
1936 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
Yves Gerey665174f2018-06-19 15:03:05 +02001937 cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
1938 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
1939 cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)));
1940 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
1941 cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)));
1942 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
1943 cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944 }
1945
1946 // Two SDP messages can mean the same thing but be different strings, e.g.
1947 // some of the lines can be serialized in different order.
1948 // However, a deserialized description can be compared field by field and has
1949 // no order. If deserializer has already been tested, serializing then
1950 // deserializing and comparing JsepSessionDescription will test
1951 // the serializer sufficiently.
Steve Antone831b8c2018-02-01 12:22:16 -08001952 void TestSerialize(const JsepSessionDescription& jdesc) {
1953 std::string message = webrtc::SdpSerialize(jdesc);
Steve Antona3a92c22017-12-07 10:27:41 -08001954 JsepSessionDescription jdesc_output_des(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955 SdpParseError error;
1956 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
1957 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
1958 }
1959
zhihuang38989e52017-03-21 11:04:53 -07001960 // Calling 'Initialize' with a copy of the inner SessionDescription will
1961 // create a copy of the JsepSessionDescription without candidates. The
1962 // 'connection address' field, previously set from the candidates, must also
1963 // be reset.
1964 void MakeDescriptionWithoutCandidates(JsepSessionDescription* jdesc) {
1965 rtc::SocketAddress audio_addr("0.0.0.0", 9);
1966 rtc::SocketAddress video_addr("0.0.0.0", 9);
1967 audio_desc_->set_connection_address(audio_addr);
1968 video_desc_->set_connection_address(video_addr);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02001969 ASSERT_TRUE(jdesc->Initialize(desc_.Clone(), kSessionId, kSessionVersion));
zhihuang38989e52017-03-21 11:04:53 -07001970 }
1971
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001972 protected:
1973 SessionDescription desc_;
1974 AudioContentDescription* audio_desc_;
1975 VideoContentDescription* video_desc_;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001976 SctpDataContentDescription* sctp_desc_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 Candidates candidates_;
kwibergd1fe2812016-04-27 06:47:29 -07001978 std::unique_ptr<IceCandidateInterface> jcandidate_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001979 JsepSessionDescription jdesc_;
1980};
1981
1982void TestMismatch(const std::string& string1, const std::string& string2) {
1983 int position = 0;
1984 for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
1985 if (string1.c_str()[i] != string2.c_str()[i]) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001986 position = static_cast<int>(i);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001987 break;
1988 }
1989 }
1990 EXPECT_EQ(0, position) << "Strings mismatch at the " << position
1991 << " character\n"
Jonas Olssonb2b20312020-01-14 12:11:31 +01001992 " 1: "
1993 << string1.substr(position, 20)
1994 << "\n"
1995 " 2: "
1996 << string2.substr(position, 20) << "\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997}
1998
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
2000 // SessionDescription with desc and candidates.
Steve Antone831b8c2018-02-01 12:22:16 -08002001 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002002 TestMismatch(std::string(kSdpFullString), message);
2003}
2004
2005TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
Steve Antona3a92c22017-12-07 10:27:41 -08002006 JsepSessionDescription jdesc_empty(kDummyType);
Steve Antone831b8c2018-02-01 12:22:16 -08002007 EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008}
2009
Harald Alvestrandee212a72021-11-02 12:06:45 +00002010// This tests serialization of SDP with a=fingerprint, as would be
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011// the case in a DTLS offer.
2012TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
2013 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08002014 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002015 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 12:22:16 -08002016 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017
2018 std::string sdp_with_fingerprint = kSdpString;
Yves Gerey665174f2018-06-19 15:03:05 +02002019 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2020 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002021
2022 EXPECT_EQ(sdp_with_fingerprint, message);
2023}
2024
2025// This tests serialization of SDP with a=fingerprint with no a=crypto, as would
2026// be the case in a DTLS answer.
2027TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
2028 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08002029 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002030 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 12:22:16 -08002031 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032
2033 std::string sdp_with_fingerprint = kSdpString;
2034 Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
2035 Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
Yves Gerey665174f2018-06-19 15:03:05 +02002036 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2037 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038
2039 EXPECT_EQ(sdp_with_fingerprint, message);
2040}
2041
2042TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
2043 // JsepSessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 10:27:41 -08002044 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002045 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 12:22:16 -08002046 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047 EXPECT_EQ(std::string(kSdpString), message);
2048}
2049
Henrik Boströmf8187e02021-04-26 21:04:26 +02002050TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundles) {
2051 ContentGroup group1(cricket::GROUP_TYPE_BUNDLE);
2052 group1.AddContentName(kAudioContentName);
2053 group1.AddContentName(kVideoContentName);
2054 desc_.AddGroup(group1);
2055 ContentGroup group2(cricket::GROUP_TYPE_BUNDLE);
2056 group2.AddContentName(kAudioContentName2);
2057 desc_.AddGroup(group2);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002058 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002059 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08002060 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002061 std::string sdp_with_bundle = kSdpFullString;
2062 InjectAfter(kSessionTime,
Henrik Boströmf8187e02021-04-26 21:04:26 +02002063 "a=group:BUNDLE audio_content_name video_content_name\r\n"
2064 "a=group:BUNDLE audio_content_name_2\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 &sdp_with_bundle);
2066 EXPECT_EQ(sdp_with_bundle, message);
2067}
2068
2069TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
Steve Antonb1c1de12017-12-21 15:14:30 -08002070 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002071 vcd->set_bandwidth(100 * 1000 + 755); // Integer division will drop the 755.
2072 vcd->set_bandwidth_type("AS");
Steve Antonb1c1de12017-12-21 15:14:30 -08002073 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002074 acd->set_bandwidth(555);
2075 acd->set_bandwidth_type("TIAS");
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002076 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002077 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08002078 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002079 std::string sdp_with_bandwidth = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002080 InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081 &sdp_with_bandwidth);
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002082 InjectAfter("c=IN IP4 74.125.127.126\r\n", "b=TIAS:555\r\n",
2083 &sdp_with_bandwidth);
2084 EXPECT_EQ(sdp_with_bandwidth, message);
2085}
2086
2087// Should default to b=AS if bandwidth_type isn't set.
2088TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithMissingBandwidthType) {
2089 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2090 vcd->set_bandwidth(100 * 1000);
2091 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2092 jdesc_.session_version()));
2093 std::string message = webrtc::SdpSerialize(jdesc_);
2094 std::string sdp_with_bandwidth = kSdpFullString;
2095 InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002096 &sdp_with_bandwidth);
2097 EXPECT_EQ(sdp_with_bandwidth, message);
2098}
2099
2100TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
2101 std::vector<std::string> transport_options;
2102 transport_options.push_back(kIceOption1);
2103 transport_options.push_back(kIceOption3);
2104 AddIceOptions(kAudioContentName, transport_options);
2105 transport_options.clear();
2106 transport_options.push_back(kIceOption2);
2107 transport_options.push_back(kIceOption3);
2108 AddIceOptions(kVideoContentName, transport_options);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002109 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002110 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08002111 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112 std::string sdp_with_ice_options = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002113 InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1 iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002114 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 15:03:05 +02002115 InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2 iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116 &sdp_with_ice_options);
2117 EXPECT_EQ(sdp_with_ice_options, message);
2118}
2119
2120TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002121 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002122}
2123
2124TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002125 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002126}
2127
2128TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002129 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130}
2131
2132TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
2133 EXPECT_TRUE(TestSerializeRejected(true, false));
2134}
2135
2136TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
2137 EXPECT_TRUE(TestSerializeRejected(false, true));
2138}
2139
2140TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
2141 EXPECT_TRUE(TestSerializeRejected(true, true));
2142}
2143
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002144TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
zstein4b2e0822017-02-17 19:48:38 -08002145 bool use_sctpmap = true;
2146 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002147 JsepSessionDescription jsep_desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002148
zhihuang38989e52017-03-21 11:04:53 -07002149 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 12:22:16 -08002150 std::string message = webrtc::SdpSerialize(jsep_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151
2152 std::string expected_sdp = kSdpString;
2153 expected_sdp.append(kSdpSctpDataChannelString);
2154 EXPECT_EQ(message, expected_sdp);
2155}
2156
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002157void MutateJsepSctpPort(JsepSessionDescription* jdesc,
2158 const SessionDescription& desc,
2159 int port) {
2160 // Take our pre-built session description and change the SCTP port.
2161 std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
2162 SctpDataContentDescription* dcdesc =
2163 mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
2164 dcdesc->set_port(port);
2165 ASSERT_TRUE(
2166 jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion));
2167}
2168
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002169TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
zstein4b2e0822017-02-17 19:48:38 -08002170 bool use_sctpmap = true;
2171 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002172 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002173 MakeDescriptionWithoutCandidates(&jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002174
2175 const int kNewPort = 1234;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002176 MutateJsepSctpPort(&jsep_desc, desc_, kNewPort);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002177
Steve Antone831b8c2018-02-01 12:22:16 -08002178 std::string message = webrtc::SdpSerialize(jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002179
2180 std::string expected_sdp = kSdpString;
2181 expected_sdp.append(kSdpSctpDataChannelString);
2182
Steve Anton1c9c9fc2019-02-14 15:13:09 -08002183 absl::StrReplaceAll(
2184 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kNewPort)}},
2185 &expected_sdp);
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002186
2187 EXPECT_EQ(expected_sdp, message);
2188}
2189
Johannes Kron0854eb62018-10-10 22:33:20 +02002190TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 10:17:39 +02002191 jdesc_.description()->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002192 TestSerialize(jdesc_);
2193}
2194
2195TEST_F(WebRtcSdpTest, SerializeMediaContentDescriptionWithExtmapAllowMixed) {
2196 cricket::MediaContentDescription* video_desc =
2197 jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
2198 ASSERT_TRUE(video_desc);
2199 cricket::MediaContentDescription* audio_desc =
2200 jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
2201 ASSERT_TRUE(audio_desc);
Johannes Kron9581bc42018-10-23 10:17:39 +02002202 video_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002203 cricket::MediaContentDescription::kMedia);
Johannes Kron9581bc42018-10-23 10:17:39 +02002204 audio_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002205 cricket::MediaContentDescription::kMedia);
2206 TestSerialize(jdesc_);
2207}
2208
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
jbauch5869f502017-06-29 12:31:36 -07002210 bool encrypted = false;
2211 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08002212 JsepSessionDescription desc_with_extmap(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07002213 MakeDescriptionWithoutCandidates(&desc_with_extmap);
Steve Antone831b8c2018-02-01 12:22:16 -08002214 std::string message = webrtc::SdpSerialize(desc_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002215
2216 std::string sdp_with_extmap = kSdpString;
Yves Gerey665174f2018-06-19 15:03:05 +02002217 InjectAfter("a=mid:audio_content_name\r\n", kExtmap, &sdp_with_extmap);
2218 InjectAfter("a=mid:video_content_name\r\n", kExtmap, &sdp_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002219
2220 EXPECT_EQ(sdp_with_extmap, message);
2221}
2222
jbauch5869f502017-06-29 12:31:36 -07002223TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapEncrypted) {
2224 bool encrypted = true;
2225 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 10:27:41 -08002226 JsepSessionDescription desc_with_extmap(kDummyType);
Yves Gerey665174f2018-06-19 15:03:05 +02002227 ASSERT_TRUE(
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002228 desc_with_extmap.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
Steve Antone831b8c2018-02-01 12:22:16 -08002229 TestSerialize(desc_with_extmap);
jbauch5869f502017-06-29 12:31:36 -07002230}
2231
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002232TEST_F(WebRtcSdpTest, SerializeCandidates) {
2233 std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
wu@webrtc.orgec9f5fb2014-06-24 17:05:10 +00002234 EXPECT_EQ(std::string(kRawCandidate), message);
honghaiza54a0802015-12-16 18:37:23 -08002235
2236 Candidate candidate_with_ufrag(candidates_.front());
2237 candidate_with_ufrag.set_username("ABC");
2238 jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0,
2239 candidate_with_ufrag));
2240 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2241 EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
honghaiza0c44ea2016-03-23 16:07:48 -07002242
2243 Candidate candidate_with_network_info(candidates_.front());
2244 candidate_with_network_info.set_network_id(1);
2245 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2246 candidate_with_network_info));
2247 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2248 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
2249 candidate_with_network_info.set_network_cost(999);
2250 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2251 candidate_with_network_info));
2252 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2253 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
2254 message);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255}
2256
Zach Steinb336c272018-08-09 01:16:13 -07002257TEST_F(WebRtcSdpTest, SerializeHostnameCandidate) {
2258 rtc::SocketAddress address("a.test", 1234);
2259 cricket::Candidate candidate(
2260 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp", address, kCandidatePriority,
2261 "", "", LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
2262 JsepIceCandidate jcandidate(std::string("audio_content_name"), 0, candidate);
2263 std::string message = webrtc::SdpSerializeCandidate(jcandidate);
2264 EXPECT_EQ(std::string(kRawHostnameCandidate), message);
2265}
2266
mallinath@webrtc.orge999bd02014-08-13 06:05:55 +00002267TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00002268 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00002269 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2270 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2271 kCandidateFoundation1);
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002272 candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
kwibergd1fe2812016-04-27 06:47:29 -07002273 std::unique_ptr<IceCandidateInterface> jcandidate(
2274 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002275
2276 std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
2277 EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
2278}
2279
Taylor Brandstetter8206bc02020-04-02 12:36:38 -07002280// Test serializing a TCP candidate that came in with a missing tcptype. This
2281// shouldn't happen according to the spec, but our implementation has been
2282// accepting this for quite some time, treating it as a passive candidate.
2283//
2284// So, we should be able to at least convert such candidates to and from SDP.
2285// See: bugs.webrtc.org/11423
2286TEST_F(WebRtcSdpTest, ParseTcpCandidateWithoutTcptype) {
2287 std::string missing_tcptype =
2288 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9999 typ host";
2289 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2290 EXPECT_TRUE(SdpDeserializeCandidate(missing_tcptype, &jcandidate));
2291
2292 EXPECT_EQ(std::string(cricket::TCPTYPE_PASSIVE_STR),
2293 jcandidate.candidate().tcptype());
2294}
2295
2296TEST_F(WebRtcSdpTest, ParseSslTcpCandidate) {
2297 std::string ssltcp =
2298 "candidate:a0+B/1 1 ssltcp 2130706432 192.168.1.5 9999 typ host tcptype "
2299 "passive";
2300 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2301 EXPECT_TRUE(SdpDeserializeCandidate(ssltcp, &jcandidate));
2302
2303 EXPECT_EQ(std::string("ssltcp"), jcandidate.candidate().protocol());
2304}
2305
htaa6b99442016-04-12 10:29:17 -07002306TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithH264) {
magjed509e4fe2016-11-18 01:34:11 -08002307 cricket::VideoCodec h264_codec("H264");
2308 h264_codec.SetParam("profile-level-id", "42e01f");
2309 h264_codec.SetParam("level-asymmetry-allowed", "1");
2310 h264_codec.SetParam("packetization-mode", "1");
2311 video_desc_->AddCodec(h264_codec);
2312
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002313 jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
htaa6b99442016-04-12 10:29:17 -07002314
Steve Antone831b8c2018-02-01 12:22:16 -08002315 std::string message = webrtc::SdpSerialize(jdesc_);
htaa6b99442016-04-12 10:29:17 -07002316 size_t after_pt = message.find(" H264/90000");
2317 ASSERT_NE(after_pt, std::string::npos);
2318 size_t before_pt = message.rfind("a=rtpmap:", after_pt);
2319 ASSERT_NE(before_pt, std::string::npos);
2320 before_pt += strlen("a=rtpmap:");
2321 std::string pt = message.substr(before_pt, after_pt - before_pt);
Artem Titov880fa812021-07-30 22:30:23 +02002322 // TODO(hta): Check if payload type `pt` occurs in the m=video line.
htaa6b99442016-04-12 10:29:17 -07002323 std::string to_find = "a=fmtp:" + pt + " ";
2324 size_t fmtp_pos = message.find(to_find);
2325 ASSERT_NE(std::string::npos, fmtp_pos) << "Failed to find " << to_find;
Mirko Bonadei37ec55e2019-01-28 11:43:52 +01002326 size_t fmtp_endpos = message.find('\n', fmtp_pos);
htaa6b99442016-04-12 10:29:17 -07002327 ASSERT_NE(std::string::npos, fmtp_endpos);
2328 std::string fmtp_value = message.substr(fmtp_pos, fmtp_endpos);
2329 EXPECT_NE(std::string::npos, fmtp_value.find("level-asymmetry-allowed=1"));
2330 EXPECT_NE(std::string::npos, fmtp_value.find("packetization-mode=1"));
2331 EXPECT_NE(std::string::npos, fmtp_value.find("profile-level-id=42e01f"));
hta62a216e2016-04-15 11:02:14 -07002332 // Check that there are no spaces after semicolons.
2333 // https://bugs.webrtc.org/5793
2334 EXPECT_EQ(std::string::npos, fmtp_value.find("; "));
htaa6b99442016-04-12 10:29:17 -07002335}
2336
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002337TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
Steve Antona3a92c22017-12-07 10:27:41 -08002338 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339 // Deserialize
2340 EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
2341 // Verify
2342 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2343}
2344
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002345TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
Steve Antona3a92c22017-12-07 10:27:41 -08002346 JsepSessionDescription jdesc(kDummyType);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002347 const char kSdpWithoutMline[] =
Yves Gerey665174f2018-06-19 15:03:05 +02002348 "v=0\r\n"
2349 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2350 "s=-\r\n"
2351 "t=0 0\r\n"
2352 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002353 // Deserialize
2354 EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
2355 EXPECT_EQ(0u, jdesc.description()->contents().size());
2356}
2357
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002358TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
Steve Antona3a92c22017-12-07 10:27:41 -08002359 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360 std::string sdp_without_carriage_return = kSdpFullString;
2361 Replace("\r\n", "\n", &sdp_without_carriage_return);
2362 // Deserialize
2363 EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
2364 // Verify
2365 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2366}
2367
2368TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
2369 // SessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 10:27:41 -08002370 JsepSessionDescription jdesc_no_candidates(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002371 ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Clone(), kSessionId,
Yves Gerey665174f2018-06-19 15:03:05 +02002372 kSessionVersion));
Steve Antona3a92c22017-12-07 10:27:41 -08002373 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002374 EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
2375 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
2376}
2377
2378TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
2379 static const char kSdpNoRtpmapString[] =
2380 "v=0\r\n"
2381 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2382 "s=-\r\n"
2383 "t=0 0\r\n"
2384 "m=audio 49232 RTP/AVP 0 18 103\r\n"
2385 // Codec that doesn't appear in the m= line will be ignored.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00002386 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387 // The rtpmap line for static payload codec is optional.
2388 "a=rtpmap:18 G729/16000\r\n"
2389 "a=rtpmap:103 ISAC/16000\r\n";
2390
Steve Antona3a92c22017-12-07 10:27:41 -08002391 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002392 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2393 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08002394 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002395 AudioCodecs ref_codecs;
deadbeef67cf2c12016-04-13 10:07:16 -07002396 // The codecs in the AudioContentDescription should be in the same order as
2397 // the payload types (<fmt>s) on the m= line.
2398 ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1));
2399 ref_codecs.push_back(AudioCodec(18, "G729", 16000, 0, 1));
ossue1405ad2017-01-23 08:55:48 -08002400 ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 0, 1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002401 EXPECT_EQ(ref_codecs, audio->codecs());
2402}
2403
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002404TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
2405 static const char kSdpNoRtpmapString[] =
2406 "v=0\r\n"
2407 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2408 "s=-\r\n"
2409 "t=0 0\r\n"
2410 "m=audio 49232 RTP/AVP 18 103\r\n"
2411 "a=fmtp:18 annexb=yes\r\n"
2412 "a=rtpmap:103 ISAC/16000\r\n";
2413
Steve Antona3a92c22017-12-07 10:27:41 -08002414 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002415 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2416 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08002417 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002418
2419 cricket::AudioCodec g729 = audio->codecs()[0];
2420 EXPECT_EQ("G729", g729.name);
2421 EXPECT_EQ(8000, g729.clockrate);
2422 EXPECT_EQ(18, g729.id);
Yves Gerey665174f2018-06-19 15:03:05 +02002423 cricket::CodecParameterMap::iterator found = g729.params.find("annexb");
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00002424 ASSERT_TRUE(found != g729.params.end());
2425 EXPECT_EQ(found->second, "yes");
2426
2427 cricket::AudioCodec isac = audio->codecs()[1];
2428 EXPECT_EQ("ISAC", isac.name);
2429 EXPECT_EQ(103, isac.id);
2430 EXPECT_EQ(16000, isac.clockrate);
2431}
2432
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433// Ensure that we can deserialize SDP with a=fingerprint properly.
2434TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
2435 // Add a DTLS a=fingerprint attribute to our session description.
2436 AddFingerprint();
Steve Antona3a92c22017-12-07 10:27:41 -08002437 JsepSessionDescription new_jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002438 ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002439 jdesc_.session_version()));
2440
Steve Antona3a92c22017-12-07 10:27:41 -08002441 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002442 std::string sdp_with_fingerprint = kSdpString;
2443 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2444 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
2445 EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
2446 EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
2447}
2448
2449TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
Steve Antona3a92c22017-12-07 10:27:41 -08002450 JsepSessionDescription jdesc_with_bundle(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002451 std::string sdp_with_bundle = kSdpFullString;
2452 InjectAfter(kSessionTime,
2453 "a=group:BUNDLE audio_content_name video_content_name\r\n",
2454 &sdp_with_bundle);
2455 EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
2456 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
2457 group.AddContentName(kAudioContentName);
2458 group.AddContentName(kVideoContentName);
2459 desc_.AddGroup(group);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002460 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002461 jdesc_.session_version()));
2462 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
2463}
2464
2465TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
Steve Antona3a92c22017-12-07 10:27:41 -08002466 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002467 std::string sdp_with_bandwidth = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002468 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002469 &sdp_with_bandwidth);
Yves Gerey665174f2018-06-19 15:03:05 +02002470 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=AS:50\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002471 &sdp_with_bandwidth);
Yves Gerey665174f2018-06-19 15:03:05 +02002472 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
Steve Antonb1c1de12017-12-21 15:14:30 -08002473 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002474 vcd->set_bandwidth(100 * 1000);
Steve Antonb1c1de12017-12-21 15:14:30 -08002475 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476 acd->set_bandwidth(50 * 1000);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002477 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002478 jdesc_.session_version()));
2479 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2480}
2481
Taylor Brandstetteree8c2462020-07-27 15:52:02 -07002482TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithTiasBandwidth) {
2483 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
2484 std::string sdp_with_bandwidth = kSdpFullString;
2485 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=TIAS:100000\r\n",
2486 &sdp_with_bandwidth);
2487 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=TIAS:50000\r\n",
2488 &sdp_with_bandwidth);
2489 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2490 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2491 vcd->set_bandwidth(100 * 1000);
2492 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
2493 acd->set_bandwidth(50 * 1000);
2494 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2495 jdesc_.session_version()));
2496 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2497}
2498
Philipp Hanckefbbfc022020-07-31 08:30:50 +02002499TEST_F(WebRtcSdpTest,
2500 DeserializeSessionDescriptionWithUnknownBandwidthModifier) {
2501 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
2502 std::string sdp_with_bandwidth = kSdpFullString;
2503 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
2504 "b=unknown:100000\r\n", &sdp_with_bandwidth);
2505 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
2506 "b=unknown:50000\r\n", &sdp_with_bandwidth);
2507 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2508 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2509 vcd->set_bandwidth(-1);
2510 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
2511 acd->set_bandwidth(-1);
2512 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2513 jdesc_.session_version()));
2514 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2515}
2516
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
Steve Antona3a92c22017-12-07 10:27:41 -08002518 JsepSessionDescription jdesc_with_ice_options(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002519 std::string sdp_with_ice_options = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02002520 InjectAfter(kSessionTime, "a=ice-options:iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002521 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 15:03:05 +02002522 InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 15:03:05 +02002524 InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525 &sdp_with_ice_options);
2526 EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
2527 std::vector<std::string> transport_options;
2528 transport_options.push_back(kIceOption3);
2529 transport_options.push_back(kIceOption1);
2530 AddIceOptions(kAudioContentName, transport_options);
2531 transport_options.clear();
2532 transport_options.push_back(kIceOption3);
2533 transport_options.push_back(kIceOption2);
2534 AddIceOptions(kVideoContentName, transport_options);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002535 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002536 jdesc_.session_version()));
2537 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
2538}
2539
2540TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
2541 // Remove the original ice-ufrag and ice-pwd
Steve Antona3a92c22017-12-07 10:27:41 -08002542 JsepSessionDescription jdesc_with_ufrag_pwd(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002543 std::string sdp_with_ufrag_pwd = kSdpFullString;
2544 EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
2545 // Add session level ufrag and pwd
2546 InjectAfter(kSessionTime,
Yves Gerey665174f2018-06-19 15:03:05 +02002547 "a=ice-pwd:session+level+icepwd\r\n"
2548 "a=ice-ufrag:session+level+iceufrag\r\n",
2549 &sdp_with_ufrag_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002550 // Add media level ufrag and pwd for audio
Yves Gerey665174f2018-06-19 15:03:05 +02002551 InjectAfter(
2552 "a=mid:audio_content_name\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002553 "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
2554 &sdp_with_ufrag_pwd);
2555 // Update the candidate ufrag and pwd to the expected ones.
Yves Gerey665174f2018-06-19 15:03:05 +02002556 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0, "media+level+iceufrag",
2557 "media+level+icepwd"));
2558 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1, "session+level+iceufrag",
2559 "session+level+icepwd"));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002560 EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
2561 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
2562}
2563
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002564TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002565 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002566}
2567
2568TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002569 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002570}
2571
2572TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 14:57:10 -08002573 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002574}
2575
2576TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
2577 EXPECT_TRUE(TestDeserializeRejected(true, false));
2578}
2579
2580TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
2581 EXPECT_TRUE(TestDeserializeRejected(false, true));
2582}
2583
2584TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
2585 EXPECT_TRUE(TestDeserializeRejected(true, true));
2586}
2587
Artem Titovf0a34f22020-03-16 17:52:04 +00002588// Tests that we can still handle the sdp uses mslabel and label instead of
2589// msid for backward compatibility.
2590TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMsid) {
2591 jdesc_.description()->set_msid_supported(false);
2592 JsepSessionDescription jdesc(kDummyType);
2593 std::string sdp_without_msid = kSdpFullString;
2594 Replace("msid", "xmsid", &sdp_without_msid);
2595 // Deserialize
2596 EXPECT_TRUE(SdpDeserialize(sdp_without_msid, &jdesc));
2597 // Verify
2598 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2599 EXPECT_FALSE(jdesc.description()->msid_signaling() &
2600 ~cricket::kMsidSignalingSsrcAttribute);
2601}
2602
Johannes Kron0854eb62018-10-10 22:33:20 +02002603TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 10:17:39 +02002604 jdesc_.description()->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002605 std::string sdp_with_extmap_allow_mixed = kSdpFullString;
Johannes Kron0854eb62018-10-10 22:33:20 +02002606 // Deserialize
2607 JsepSessionDescription jdesc_deserialized(kDummyType);
Emil Lundmark801c9992021-01-19 13:06:32 +01002608 ASSERT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
Johannes Kron0854eb62018-10-10 22:33:20 +02002609 // Verify
2610 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2611}
2612
2613TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 10:17:39 +02002614 jdesc_.description()->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002615 std::string sdp_without_extmap_allow_mixed = kSdpFullString;
Emil Lundmark801c9992021-01-19 13:06:32 +01002616 Replace(kExtmapAllowMixed, "", &sdp_without_extmap_allow_mixed);
Johannes Kron0854eb62018-10-10 22:33:20 +02002617 // Deserialize
2618 JsepSessionDescription jdesc_deserialized(kDummyType);
Emil Lundmark801c9992021-01-19 13:06:32 +01002619 ASSERT_TRUE(
Johannes Kron0854eb62018-10-10 22:33:20 +02002620 SdpDeserialize(sdp_without_extmap_allow_mixed, &jdesc_deserialized));
2621 // Verify
2622 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2623}
2624
2625TEST_F(WebRtcSdpTest, DeserializeMediaContentDescriptionWithExtmapAllowMixed) {
2626 cricket::MediaContentDescription* video_desc =
2627 jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
2628 ASSERT_TRUE(video_desc);
2629 cricket::MediaContentDescription* audio_desc =
2630 jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
2631 ASSERT_TRUE(audio_desc);
Johannes Kron9581bc42018-10-23 10:17:39 +02002632 video_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002633 cricket::MediaContentDescription::kMedia);
Johannes Kron9581bc42018-10-23 10:17:39 +02002634 audio_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 22:33:20 +02002635 cricket::MediaContentDescription::kMedia);
2636
2637 std::string sdp_with_extmap_allow_mixed = kSdpFullString;
2638 InjectAfter("a=mid:audio_content_name\r\n", kExtmapAllowMixed,
2639 &sdp_with_extmap_allow_mixed);
2640 InjectAfter("a=mid:video_content_name\r\n", kExtmapAllowMixed,
2641 &sdp_with_extmap_allow_mixed);
2642
2643 // Deserialize
2644 JsepSessionDescription jdesc_deserialized(kDummyType);
2645 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
2646 // Verify
2647 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2648}
2649
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002650TEST_F(WebRtcSdpTest, DeserializeCandidate) {
2651 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2652
2653 std::string sdp = kSdpOneCandidate;
2654 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2655 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2656 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2657 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
honghaiza0c44ea2016-03-23 16:07:48 -07002658 EXPECT_EQ(0, jcandidate.candidate().network_cost());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659
2660 // Candidate line without generation extension.
2661 sdp = kSdpOneCandidate;
2662 Replace(" generation 2", "", &sdp);
2663 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2664 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2665 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2666 Candidate expected = jcandidate_->candidate();
2667 expected.set_generation(0);
2668 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2669
honghaiza0c44ea2016-03-23 16:07:48 -07002670 // Candidate with network id and/or cost.
2671 sdp = kSdpOneCandidate;
2672 Replace(" generation 2", " generation 2 network-id 2", &sdp);
2673 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2674 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2675 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2676 expected = jcandidate_->candidate();
2677 expected.set_network_id(2);
2678 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2679 EXPECT_EQ(0, jcandidate.candidate().network_cost());
2680 // Add network cost
2681 Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
2682 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2683 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2684 EXPECT_EQ(9, jcandidate.candidate().network_cost());
2685
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002686 sdp = kSdpTcpActiveCandidate;
2687 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2688 // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
guoweis@webrtc.org61c12472015-01-15 06:53:07 +00002689 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00002690 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2691 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2692 kCandidateFoundation1);
kwibergd1fe2812016-04-27 06:47:29 -07002693 std::unique_ptr<IceCandidateInterface> jcandidate_template(
2694 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
Yves Gerey665174f2018-06-19 15:03:05 +02002695 EXPECT_TRUE(
2696 jcandidate.candidate().IsEquivalent(jcandidate_template->candidate()));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20 +00002697 sdp = kSdpTcpPassiveCandidate;
2698 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2699 sdp = kSdpTcpSOCandidate;
2700 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701}
2702
2703// This test verifies the deserialization of candidate-attribute
2704// as per RFC 5245. Candiate-attribute will be of the format
2705// candidate:<blah>. This format will be used when candidates
2706// are trickled.
2707TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
2708 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2709
2710 std::string candidate_attribute = kRawCandidate;
2711 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2712 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2713 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2714 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2715 EXPECT_EQ(2u, jcandidate.candidate().generation());
2716
2717 // Candidate line without generation extension.
2718 candidate_attribute = kRawCandidate;
2719 Replace(" generation 2", "", &candidate_attribute);
2720 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2721 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2722 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2723 Candidate expected = jcandidate_->candidate();
2724 expected.set_generation(0);
2725 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2726
2727 // Candidate line without candidate:
2728 candidate_attribute = kRawCandidate;
2729 Replace("candidate:", "", &candidate_attribute);
2730 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2731
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002732 // Candidate line with IPV6 address.
2733 EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
Zach Steinb336c272018-08-09 01:16:13 -07002734
2735 // Candidate line with hostname address.
2736 EXPECT_TRUE(SdpDeserializeCandidate(kRawHostnameCandidate, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002737}
2738
2739// This test verifies that the deserialization of an invalid candidate string
2740// fails.
2741TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
Yves Gerey665174f2018-06-19 15:03:05 +02002742 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002743
2744 std::string candidate_attribute = kRawCandidate;
2745 candidate_attribute.replace(0, 1, "x");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002746 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15 +00002747
2748 candidate_attribute = kSdpOneCandidate;
2749 candidate_attribute.replace(0, 1, "x");
2750 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2751
2752 candidate_attribute = kRawCandidate;
2753 candidate_attribute.append("\r\n");
2754 candidate_attribute.append(kRawCandidate);
2755 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2756
2757 EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758}
2759
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002760TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
zstein4b2e0822017-02-17 19:48:38 -08002761 bool use_sctpmap = true;
2762 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002763 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002764 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765
2766 std::string sdp_with_data = kSdpString;
2767 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Antona3a92c22017-12-07 10:27:41 -08002768 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002769
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002770 // Verify with UDP/DTLS/SCTP (already in kSdpSctpDataChannelString).
lally@webrtc.org36300852015-02-24 20:19:35 +00002771 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2772 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2773
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002774 // Verify with DTLS/SCTP.
2775 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp), strlen(kUdpDtlsSctp),
2776 kDtlsSctp);
lally@webrtc.org36300852015-02-24 20:19:35 +00002777 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2778 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2779
2780 // Verify with TCP/DTLS/SCTP.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002781 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp), strlen(kDtlsSctp),
Yves Gerey665174f2018-06-19 15:03:05 +02002782 kTcpDtlsSctp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2784 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2785}
2786
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002787TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
zstein4b2e0822017-02-17 19:48:38 -08002788 bool use_sctpmap = false;
2789 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002790 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002791 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002792
2793 std::string sdp_with_data = kSdpString;
2794 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Antona3a92c22017-12-07 10:27:41 -08002795 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002796
lally@webrtc.orgc7848b72015-02-24 20:19:26 +00002797 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2798 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2799}
2800
lally69f57602015-10-08 10:15:04 -07002801TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) {
zstein4b2e0822017-02-17 19:48:38 -08002802 bool use_sctpmap = false;
2803 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002804 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002805 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
lally69f57602015-10-08 10:15:04 -07002806
2807 std::string sdp_with_data = kSdpString;
2808 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
Steve Antona3a92c22017-12-07 10:27:41 -08002809 JsepSessionDescription jdesc_output(kDummyType);
lally69f57602015-10-08 10:15:04 -07002810
lally69f57602015-10-08 10:15:04 -07002811 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2812 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2813}
2814
Philipp Hanckeefc55b02020-06-26 10:17:05 +02002815TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsButWrongMediaType) {
2816 bool use_sctpmap = true;
2817 AddSctpDataChannel(use_sctpmap);
2818 JsepSessionDescription jdesc(kDummyType);
2819 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
2820
2821 std::string sdp = kSdpSessionString;
2822 sdp += kSdpSctpDataChannelString;
2823
2824 const char needle[] = "m=application ";
2825 sdp.replace(sdp.find(needle), strlen(needle), "m=application:bogus ");
2826
2827 JsepSessionDescription jdesc_output(kDummyType);
2828 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
2829
Philipp Hancke4e8c1152020-10-13 12:43:15 +02002830 EXPECT_EQ(1u, jdesc_output.description()->contents().size());
2831 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
Philipp Hanckeefc55b02020-06-26 10:17:05 +02002832}
2833
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02002834// Helper function to set the max-message-size parameter in the
2835// SCTP data codec.
2836void MutateJsepSctpMaxMessageSize(const SessionDescription& desc,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002837 int new_value,
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02002838 JsepSessionDescription* jdesc) {
Harald Alvestrand8da35a62019-05-10 09:31:04 +02002839 std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002840 SctpDataContentDescription* dcdesc =
2841 mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
2842 dcdesc->set_max_message_size(new_value);
Harald Alvestrand8da35a62019-05-10 09:31:04 +02002843 jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion);
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02002844}
2845
2846TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithMaxMessageSize) {
2847 bool use_sctpmap = false;
2848 AddSctpDataChannel(use_sctpmap);
2849 JsepSessionDescription jdesc(kDummyType);
2850 std::string sdp_with_data = kSdpString;
2851
2852 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
2853 sdp_with_data.append("a=max-message-size:12345\r\n");
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002854 MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02002855 JsepSessionDescription jdesc_output(kDummyType);
2856
Harald Alvestrand48cce4d2019-04-11 10:41:24 +02002857 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2858 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2859}
2860
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002861TEST_F(WebRtcSdpTest, SerializeSdpWithSctpDataChannelWithMaxMessageSize) {
2862 bool use_sctpmap = false;
2863 AddSctpDataChannel(use_sctpmap);
2864 JsepSessionDescription jdesc(kDummyType);
2865 MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
2866 std::string message = webrtc::SdpSerialize(jdesc);
2867 EXPECT_NE(std::string::npos,
2868 message.find("\r\na=max-message-size:12345\r\n"));
2869 JsepSessionDescription jdesc_output(kDummyType);
2870 EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
2871 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2872}
2873
2874TEST_F(WebRtcSdpTest,
2875 SerializeSdpWithSctpDataChannelWithDefaultMaxMessageSize) {
2876 // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
2877 // The default max message size is 64K.
2878 bool use_sctpmap = false;
2879 AddSctpDataChannel(use_sctpmap);
2880 JsepSessionDescription jdesc(kDummyType);
2881 MutateJsepSctpMaxMessageSize(desc_, 65536, &jdesc);
2882 std::string message = webrtc::SdpSerialize(jdesc);
2883 EXPECT_EQ(std::string::npos, message.find("\r\na=max-message-size:"));
2884 JsepSessionDescription jdesc_output(kDummyType);
2885 EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
2886 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2887}
2888
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002889// Test to check the behaviour if sctp-port is specified
2890// on the m= line and in a=sctp-port.
2891TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
zstein4b2e0822017-02-17 19:48:38 -08002892 bool use_sctpmap = true;
2893 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002894 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002895 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002896
2897 std::string sdp_with_data = kSdpString;
2898 // Append m= attributes
2899 sdp_with_data.append(kSdpSctpDataChannelString);
2900 // Append a=sctp-port attribute
2901 sdp_with_data.append("a=sctp-port 5000\r\n");
Steve Antona3a92c22017-12-07 10:27:41 -08002902 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002903
2904 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2905}
2906
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002907// Test behavior if a=rtpmap occurs in an SCTP section.
2908TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpmapAttribute) {
2909 std::string sdp_with_data = kSdpString;
2910 // Append m= attributes
2911 sdp_with_data.append(kSdpSctpDataChannelString);
2912 // Append a=rtpmap attribute
2913 sdp_with_data.append("a=rtpmap:111 opus/48000/2\r\n");
2914 JsepSessionDescription jdesc_output(kDummyType);
2915 // Correct behavior is to ignore the extra attribute.
2916 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2917}
2918
2919TEST_F(WebRtcSdpTest, DeserializeSdpWithStrangeApplicationProtocolNames) {
Harald Alvestrand7af57c62021-04-16 11:12:14 +00002920 static const char* bad_strings[] = {
2921 "DTLS/SCTPRTP/", "obviously-bogus", "UDP/TL/RTSP/SAVPF",
2922 "UDP/TL/RTSP/S", "DTLS/SCTP/RTP/FOO", "obviously-bogus/RTP/"};
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002923 for (auto proto : bad_strings) {
2924 std::string sdp_with_data = kSdpString;
2925 sdp_with_data.append("m=application 9 ");
2926 sdp_with_data.append(proto);
2927 sdp_with_data.append(" 47\r\n");
2928 JsepSessionDescription jdesc_output(kDummyType);
2929 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output))
2930 << "Parsing should have failed on " << proto;
2931 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002932}
2933
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00002934// For crbug/344475.
2935TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
2936 std::string sdp_with_data = kSdpString;
2937 sdp_with_data.append(kSdpSctpDataChannelString);
2938 // Remove the "\n" at the end.
2939 sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
Steve Antona3a92c22017-12-07 10:27:41 -08002940 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org571df2d2014-02-19 23:04:26 +00002941
2942 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2943 // No crash is a pass.
2944}
2945
zstein4b2e0822017-02-17 19:48:38 -08002946TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) {
2947 bool use_sctpmap = true;
2948 AddSctpDataChannel(use_sctpmap);
2949
2950 // First setup the expected JsepSessionDescription.
Steve Antona3a92c22017-12-07 10:27:41 -08002951 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002952 MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
wu@webrtc.org78187522013-10-07 23:32:02 +00002953
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +00002954 // Then get the deserialized JsepSessionDescription.
wu@webrtc.org78187522013-10-07 23:32:02 +00002955 std::string sdp_with_data = kSdpString;
2956 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Anton1c9c9fc2019-02-14 15:13:09 -08002957 absl::StrReplaceAll(
2958 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
2959 &sdp_with_data);
Steve Antona3a92c22017-12-07 10:27:41 -08002960 JsepSessionDescription jdesc_output(kDummyType);
wu@webrtc.org78187522013-10-07 23:32:02 +00002961
2962 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2963 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
zstein4b2e0822017-02-17 19:48:38 -08002964}
2965
2966TEST_F(WebRtcSdpTest,
2967 DeserializeSdpWithSctpDataChannelAndUnusualPortInAttribute) {
2968 bool use_sctpmap = false;
2969 AddSctpDataChannel(use_sctpmap);
2970
Steve Antona3a92c22017-12-07 10:27:41 -08002971 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002972 MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002973
2974 // We need to test the deserialized JsepSessionDescription from
2975 // kSdpSctpDataChannelStringWithSctpPort for
2976 // draft-ietf-mmusic-sctp-sdp-07
2977 // a=sctp-port
zstein4b2e0822017-02-17 19:48:38 -08002978 std::string sdp_with_data = kSdpString;
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002979 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Anton1c9c9fc2019-02-14 15:13:09 -08002980 absl::StrReplaceAll(
2981 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
2982 &sdp_with_data);
Steve Antona3a92c22017-12-07 10:27:41 -08002983 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56 +00002984
2985 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2986 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
wu@webrtc.org78187522013-10-07 23:32:02 +00002987}
2988
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002989TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
zstein4b2e0822017-02-17 19:48:38 -08002990 bool use_sctpmap = true;
2991 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 10:27:41 -08002992 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002993 SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002994 dcd->set_bandwidth(100 * 1000);
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02002995 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
Peter Thatcherc0c3a862015-06-24 15:31:25 -07002996
2997 std::string sdp_with_bandwidth = kSdpString;
2998 sdp_with_bandwidth.append(kSdpSctpDataChannelString);
Yves Gerey665174f2018-06-19 15:03:05 +02002999 InjectAfter("a=mid:data_content_name\r\n", "b=AS:100\r\n",
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003000 &sdp_with_bandwidth);
Steve Antona3a92c22017-12-07 10:27:41 -08003001 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
Peter Thatcherc0c3a862015-06-24 15:31:25 -07003002
3003 // SCTP has congestion control, so we shouldn't limit the bandwidth
3004 // as we do for RTP.
3005 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003006 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
3007}
3008
Yves Gerey665174f2018-06-19 15:03:05 +02003009class WebRtcSdpExtmapTest : public WebRtcSdpTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003010 public ::testing::WithParamInterface<bool> {};
jbauch5869f502017-06-29 12:31:36 -07003011
3012TEST_P(WebRtcSdpExtmapTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003013 DeserializeSessionDescriptionWithSessionLevelExtmap) {
jbauch5869f502017-06-29 12:31:36 -07003014 bool encrypted = GetParam();
3015 TestDeserializeExtmap(true, false, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016}
3017
Yves Gerey665174f2018-06-19 15:03:05 +02003018TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
jbauch5869f502017-06-29 12:31:36 -07003019 bool encrypted = GetParam();
3020 TestDeserializeExtmap(false, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003021}
3022
Yves Gerey665174f2018-06-19 15:03:05 +02003023TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithInvalidExtmap) {
jbauch5869f502017-06-29 12:31:36 -07003024 bool encrypted = GetParam();
3025 TestDeserializeExtmap(true, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003026}
3027
Mirko Bonadeic84f6612019-01-31 12:20:57 +01003028INSTANTIATE_TEST_SUITE_P(Encrypted,
3029 WebRtcSdpExtmapTest,
3030 ::testing::Values(false, true));
jbauch5869f502017-06-29 12:31:36 -07003031
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00003032TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
Steve Antona3a92c22017-12-07 10:27:41 -08003033 JsepSessionDescription jdesc(kDummyType);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00003034 std::string sdp = kSdpFullString;
3035 sdp = sdp.substr(0, sdp.size() - 2); // Remove \r\n at the end.
3036 // Deserialize
3037 SdpParseError error;
3038 EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
Artem Titovf0a34f22020-03-16 17:52:04 +00003039 const std::string lastline = "a=ssrc:3 label:video_track_id_1";
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00003040 EXPECT_EQ(lastline, error.line);
3041 EXPECT_EQ("Invalid SDP line.", error.description);
3042}
3043
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003044TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
3045 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
3046 std::string new_sdp = kSdpOneCandidate;
3047 Replace("udp", "unsupported_transport", &new_sdp);
3048 EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
3049 new_sdp = kSdpOneCandidate;
3050 Replace("udp", "uDP", &new_sdp);
3051 EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
3052 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
3053 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
3054 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
3055}
3056
honghaiza54a0802015-12-16 18:37:23 -08003057TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003058 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
honghaiza54a0802015-12-16 18:37:23 -08003059 EXPECT_TRUE(
3060 SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003061 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
3062 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
3063 Candidate ref_candidate = jcandidate_->candidate();
3064 ref_candidate.set_username("user_rtp");
3065 ref_candidate.set_password("password_rtp");
3066 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
3067}
3068
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003069TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 10:27:41 -08003070 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003071
3072 // Deserialize
3073 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
3074
3075 // Verify
3076 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08003077 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003078 EXPECT_TRUE(audio->conference_mode());
3079
3080 cricket::VideoContentDescription* video =
Steve Anton06817cd2018-12-18 15:55:30 -08003081 cricket::GetFirstVideoContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00003082 EXPECT_TRUE(video->conference_mode());
3083}
3084
deadbeefd45aea82017-09-16 01:24:29 -07003085TEST_F(WebRtcSdpTest, SerializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 10:27:41 -08003086 JsepSessionDescription jdesc(kDummyType);
deadbeefd45aea82017-09-16 01:24:29 -07003087
3088 // We tested deserialization already above, so just test that if we serialize
3089 // and deserialize the flag doesn't disappear.
3090 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
Steve Antone831b8c2018-02-01 12:22:16 -08003091 std::string reserialized = webrtc::SdpSerialize(jdesc);
deadbeefd45aea82017-09-16 01:24:29 -07003092 EXPECT_TRUE(SdpDeserialize(reserialized, &jdesc));
3093
3094 // Verify.
3095 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 15:55:30 -08003096 cricket::GetFirstAudioContentDescription(jdesc.description());
deadbeefd45aea82017-09-16 01:24:29 -07003097 EXPECT_TRUE(audio->conference_mode());
3098
3099 cricket::VideoContentDescription* video =
Steve Anton06817cd2018-12-18 15:55:30 -08003100 cricket::GetFirstVideoContentDescription(jdesc.description());
deadbeefd45aea82017-09-16 01:24:29 -07003101 EXPECT_TRUE(video->conference_mode());
3102}
3103
Sebastian Jansson97321b62019-07-24 14:01:18 +02003104TEST_F(WebRtcSdpTest, SerializeAndDeserializeRemoteNetEstimate) {
3105 {
3106 // By default remote estimates are disabled.
3107 JsepSessionDescription dst(kDummyType);
3108 SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
3109 EXPECT_FALSE(cricket::GetFirstVideoContentDescription(dst.description())
3110 ->remote_estimate());
3111 }
3112 {
3113 // When remote estimate is enabled, the setting is propagated via SDP.
3114 cricket::GetFirstVideoContentDescription(jdesc_.description())
3115 ->set_remote_estimate(true);
3116 JsepSessionDescription dst(kDummyType);
3117 SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
3118 EXPECT_TRUE(cricket::GetFirstVideoContentDescription(dst.description())
3119 ->remote_estimate());
3120 }
3121}
3122
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003123TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
3124 const char kSdpDestroyer[] = "!@#$%^&";
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00003125 const char kSdpEmptyType[] = " =candidate";
3126 const char kSdpEqualAsPlus[] = "a+candidate";
3127 const char kSdpSpaceAfterEqual[] = "a= candidate";
3128 const char kSdpUpperType[] = "A=candidate";
3129 const char kSdpEmptyLine[] = "";
3130 const char kSdpMissingValue[] = "a=";
3131
Yves Gerey665174f2018-06-19 15:03:05 +02003132 const char kSdpBrokenFingerprint[] =
3133 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134 "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 +02003135 const char kSdpExtraField[] =
3136 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003137 "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 +02003138 const char kSdpMissingSpace[] =
3139 "a=fingerprint:sha-1"
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003140 "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 +00003141 // MD5 is not allowed in fingerprints.
Yves Gerey665174f2018-06-19 15:03:05 +02003142 const char kSdpMd5[] =
3143 "a=fingerprint:md5 "
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00003144 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003145
3146 // Broken session description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003147 ExpectParseFailure("v=", kSdpDestroyer);
3148 ExpectParseFailure("o=", kSdpDestroyer);
3149 ExpectParseFailure("s=-", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003150 // Broken time description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003151 ExpectParseFailure("t=", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003152
3153 // Broken media description
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003154 ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
3155 ExpectParseFailure("m=video", kSdpDestroyer);
Philipp Hanckeefc55b02020-06-26 10:17:05 +02003156 ExpectParseFailure("m=", "c=IN IP4 74.125.224.39");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003157
3158 // Invalid lines
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00003159 ExpectParseFailure("a=candidate", kSdpEmptyType);
3160 ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
3161 ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
3162 ExpectParseFailure("a=candidate", kSdpUpperType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003163
3164 // Bogus fingerprint replacing a=sendrev. We selected this attribute
3165 // because it's orthogonal to what we are replacing and hence
3166 // safe.
decurtis@webrtc.org8af11042015-01-07 19:15:51 +00003167 ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
3168 ExpectParseFailure("a=sendrecv", kSdpExtraField);
3169 ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
3170 ExpectParseFailure("a=sendrecv", kSdpMd5);
3171
3172 // Empty Line
3173 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
3174 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003175}
3176
3177TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
3178 // ssrc
3179 ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
deadbeef9d3584c2016-02-16 17:54:10 -08003180 ExpectParseFailure("a=ssrc-group:FEC 2 3", "a=ssrc-group:FEC badvalue 3");
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003181 // rtpmap
3182 ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
3183 ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
3184 ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
3185 // candidate
3186 ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
3187 ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
3188 ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
3189 ExpectParseFailure("rport 2346", "rport badvalue");
3190 ExpectParseFailure("rport 2346 generation 2",
3191 "rport 2346 generation badvalue");
3192 // m line
3193 ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
3194 "m=audio 2345 RTP/SAVPF 111 badvalue 104");
3195
3196 // bandwidth
3197 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
Yves Gerey665174f2018-06-19 15:03:05 +02003198 "b=AS:badvalue\r\n", "b=AS:badvalue");
Philipp Hanckefbbfc022020-07-31 08:30:50 +02003199 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS\r\n",
3200 "b=AS");
3201 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS:\r\n",
3202 "b=AS:");
3203 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3204 "b=AS:12:34\r\n", "b=AS:12:34");
3205
wu@webrtc.org5e760e72014-04-02 23:19:09 +00003206 // rtcp-fb
3207 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3208 "a=rtcp-fb:badvalue nack\r\n",
3209 "a=rtcp-fb:badvalue nack");
3210 // extmap
3211 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3212 "a=extmap:badvalue http://example.com\r\n",
3213 "a=extmap:badvalue http://example.com");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003214}
3215
3216TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
Steve Antona3a92c22017-12-07 10:27:41 -08003217 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003218
3219 const char kSdpWithReorderedPlTypesString[] =
3220 "v=0\r\n"
3221 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3222 "s=-\r\n"
3223 "t=0 0\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22 +00003224 "m=audio 9 RTP/SAVPF 104 103\r\n" // Pl type 104 preferred.
Yves Gerey665174f2018-06-19 15:03:05 +02003225 "a=rtpmap:111 opus/48000/2\r\n" // Pltype 111 listed before 103 and 104
3226 // in the map.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003227 "a=rtpmap:103 ISAC/16000\r\n" // Pltype 103 listed before 104 in the map.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00003228 "a=rtpmap:104 ISAC/32000\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003229
3230 // Deserialize
3231 EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
3232
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003233 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003234 GetFirstAudioContentDescription(jdesc_output.description());
3235 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003236 ASSERT_FALSE(acd->codecs().empty());
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41 +00003237 EXPECT_EQ("ISAC", acd->codecs()[0].name);
3238 EXPECT_EQ(32000, acd->codecs()[0].clockrate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003239 EXPECT_EQ(104, acd->codecs()[0].id);
3240}
3241
3242TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
Steve Antona3a92c22017-12-07 10:27:41 -08003243 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003244 CodecParams params;
3245 params.max_ptime = 40;
3246 params.ptime = 30;
3247 params.min_ptime = 10;
3248 params.sprop_stereo = 1;
3249 params.stereo = 1;
3250 params.useinband = 1;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00003251 params.maxaveragebitrate = 128000;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003252 TestDeserializeCodecParams(params, &jdesc_output);
Steve Antone831b8c2018-02-01 12:22:16 -08003253 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003254}
3255
3256TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
3257 const bool kUseWildcard = false;
Steve Antona3a92c22017-12-07 10:27:41 -08003258 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003259 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 12:22:16 -08003260 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003261}
3262
3263TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
3264 const bool kUseWildcard = true;
Steve Antona3a92c22017-12-07 10:27:41 -08003265 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003266 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 12:22:16 -08003267 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003268}
3269
3270TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
Steve Antona3a92c22017-12-07 10:27:41 -08003271 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003272
3273 const char kSdpWithFmtpString[] =
3274 "v=0\r\n"
3275 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3276 "s=-\r\n"
3277 "t=0 0\r\n"
3278 "m=video 3457 RTP/SAVPF 120\r\n"
3279 "a=rtpmap:120 VP8/90000\r\n"
Donald Curtis0e07f922015-05-15 09:21:23 -07003280 "a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
3281
3282 // Deserialize
3283 SdpParseError error;
Donald Curtis144d0182015-05-15 13:14:24 -07003284 EXPECT_TRUE(
3285 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
Donald Curtis0e07f922015-05-15 09:21:23 -07003286
Donald Curtis0e07f922015-05-15 09:21:23 -07003287 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003288 GetFirstVideoContentDescription(jdesc_output.description());
3289 ASSERT_TRUE(vcd);
Donald Curtis0e07f922015-05-15 09:21:23 -07003290 ASSERT_FALSE(vcd->codecs().empty());
3291 cricket::VideoCodec vp8 = vcd->codecs()[0];
3292 EXPECT_EQ("VP8", vp8.name);
3293 EXPECT_EQ(120, vp8.id);
3294 cricket::CodecParameterMap::iterator found =
3295 vp8.params.find("x-google-min-bitrate");
3296 ASSERT_TRUE(found != vp8.params.end());
3297 EXPECT_EQ(found->second, "10");
3298 found = vp8.params.find("x-google-max-quantization");
3299 ASSERT_TRUE(found != vp8.params.end());
3300 EXPECT_EQ(found->second, "40");
3301}
3302
johan2d8d23e2016-06-03 01:22:42 -07003303TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSprops) {
Steve Antona3a92c22017-12-07 10:27:41 -08003304 JsepSessionDescription jdesc_output(kDummyType);
johan2d8d23e2016-06-03 01:22:42 -07003305
3306 const char kSdpWithFmtpString[] =
3307 "v=0\r\n"
3308 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3309 "s=-\r\n"
3310 "t=0 0\r\n"
3311 "m=video 49170 RTP/AVP 98\r\n"
3312 "a=rtpmap:98 H264/90000\r\n"
3313 "a=fmtp:98 profile-level-id=42A01E; "
3314 "sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==\r\n";
3315
3316 // Deserialize.
3317 SdpParseError error;
3318 EXPECT_TRUE(
3319 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
3320
johan2d8d23e2016-06-03 01:22:42 -07003321 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003322 GetFirstVideoContentDescription(jdesc_output.description());
3323 ASSERT_TRUE(vcd);
johan2d8d23e2016-06-03 01:22:42 -07003324 ASSERT_FALSE(vcd->codecs().empty());
3325 cricket::VideoCodec h264 = vcd->codecs()[0];
3326 EXPECT_EQ("H264", h264.name);
3327 EXPECT_EQ(98, h264.id);
3328 cricket::CodecParameterMap::const_iterator found =
3329 h264.params.find("profile-level-id");
3330 ASSERT_TRUE(found != h264.params.end());
3331 EXPECT_EQ(found->second, "42A01E");
3332 found = h264.params.find("sprop-parameter-sets");
3333 ASSERT_TRUE(found != h264.params.end());
3334 EXPECT_EQ(found->second, "Z0IACpZTBYmI,aMljiA==");
3335}
3336
Donald Curtis0e07f922015-05-15 09:21:23 -07003337TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
Steve Antona3a92c22017-12-07 10:27:41 -08003338 JsepSessionDescription jdesc_output(kDummyType);
Donald Curtis0e07f922015-05-15 09:21:23 -07003339
3340 const char kSdpWithFmtpString[] =
3341 "v=0\r\n"
3342 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3343 "s=-\r\n"
3344 "t=0 0\r\n"
3345 "m=video 3457 RTP/SAVPF 120\r\n"
3346 "a=rtpmap:120 VP8/90000\r\n"
3347 "a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003348
3349 // Deserialize
3350 SdpParseError error;
Yves Gerey665174f2018-06-19 15:03:05 +02003351 EXPECT_TRUE(
3352 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003353
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003354 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003355 GetFirstVideoContentDescription(jdesc_output.description());
3356 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003357 ASSERT_FALSE(vcd->codecs().empty());
3358 cricket::VideoCodec vp8 = vcd->codecs()[0];
3359 EXPECT_EQ("VP8", vp8.name);
3360 EXPECT_EQ(120, vp8.id);
3361 cricket::CodecParameterMap::iterator found =
3362 vp8.params.find("x-google-min-bitrate");
3363 ASSERT_TRUE(found != vp8.params.end());
3364 EXPECT_EQ(found->second, "10");
3365 found = vp8.params.find("x-google-max-quantization");
3366 ASSERT_TRUE(found != vp8.params.end());
3367 EXPECT_EQ(found->second, "40");
3368}
3369
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02003370TEST_F(WebRtcSdpTest, DeserializePacketizationAttributeWithIllegalValue) {
3371 JsepSessionDescription jdesc_output(kDummyType);
3372
3373 const char kSdpWithPacketizationString[] =
3374 "v=0\r\n"
3375 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3376 "s=-\r\n"
3377 "t=0 0\r\n"
3378 "m=audio 9 RTP/SAVPF 111\r\n"
3379 "a=rtpmap:111 opus/48000/2\r\n"
3380 "a=packetization:111 unknownpacketizationattributeforaudio\r\n"
3381 "m=video 3457 RTP/SAVPF 120 121 122\r\n"
3382 "a=rtpmap:120 VP8/90000\r\n"
3383 "a=packetization:120 raw\r\n"
3384 "a=rtpmap:121 VP9/90000\r\n"
3385 "a=rtpmap:122 H264/90000\r\n"
3386 "a=packetization:122 unknownpacketizationattributevalue\r\n";
3387
3388 SdpParseError error;
3389 EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithPacketizationString, &jdesc_output,
3390 &error));
3391
3392 AudioContentDescription* acd =
3393 GetFirstAudioContentDescription(jdesc_output.description());
3394 ASSERT_TRUE(acd);
3395 ASSERT_THAT(acd->codecs(), testing::SizeIs(1));
3396 cricket::AudioCodec opus = acd->codecs()[0];
3397 EXPECT_EQ(opus.name, "opus");
3398 EXPECT_EQ(opus.id, 111);
3399
3400 const VideoContentDescription* vcd =
3401 GetFirstVideoContentDescription(jdesc_output.description());
3402 ASSERT_TRUE(vcd);
3403 ASSERT_THAT(vcd->codecs(), testing::SizeIs(3));
3404 cricket::VideoCodec vp8 = vcd->codecs()[0];
3405 EXPECT_EQ(vp8.name, "VP8");
3406 EXPECT_EQ(vp8.id, 120);
3407 EXPECT_EQ(vp8.packetization, "raw");
3408 cricket::VideoCodec vp9 = vcd->codecs()[1];
3409 EXPECT_EQ(vp9.name, "VP9");
3410 EXPECT_EQ(vp9.id, 121);
3411 EXPECT_EQ(vp9.packetization, absl::nullopt);
3412 cricket::VideoCodec h264 = vcd->codecs()[2];
3413 EXPECT_EQ(h264.name, "H264");
3414 EXPECT_EQ(h264.id, 122);
3415 EXPECT_EQ(h264.packetization, absl::nullopt);
3416}
3417
ossuaa4b0772017-01-30 07:41:18 -08003418TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithUnknownParameter) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003419 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003420
3421 cricket::AudioCodecs codecs = acd->codecs();
3422 codecs[0].params["unknown-future-parameter"] = "SomeFutureValue";
3423 acd->set_codecs(codecs);
3424
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003425 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 07:41:18 -08003426 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003427 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003428 std::string sdp_with_fmtp = kSdpFullString;
3429 InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
3430 "a=fmtp:111 unknown-future-parameter=SomeFutureValue\r\n",
3431 &sdp_with_fmtp);
3432 EXPECT_EQ(sdp_with_fmtp, message);
3433}
3434
3435TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithKnownFmtpParameter) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003436 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003437
3438 cricket::AudioCodecs codecs = acd->codecs();
3439 codecs[0].params["stereo"] = "1";
3440 acd->set_codecs(codecs);
3441
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003442 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 07:41:18 -08003443 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003444 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003445 std::string sdp_with_fmtp = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02003446 InjectAfter("a=rtpmap:111 opus/48000/2\r\n", "a=fmtp:111 stereo=1\r\n",
ossuaa4b0772017-01-30 07:41:18 -08003447 &sdp_with_fmtp);
3448 EXPECT_EQ(sdp_with_fmtp, message);
3449}
3450
3451TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithPTimeAndMaxPTime) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003452 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 07:41:18 -08003453
3454 cricket::AudioCodecs codecs = acd->codecs();
3455 codecs[0].params["ptime"] = "20";
3456 codecs[0].params["maxptime"] = "120";
3457 acd->set_codecs(codecs);
3458
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003459 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 07:41:18 -08003460 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003461 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 07:41:18 -08003462 std::string sdp_with_fmtp = kSdpFullString;
3463 InjectAfter("a=rtpmap:104 ISAC/32000\r\n",
3464 "a=maxptime:120\r\n" // No comma here. String merging!
3465 "a=ptime:20\r\n",
3466 &sdp_with_fmtp);
3467 EXPECT_EQ(sdp_with_fmtp, message);
3468}
3469
Philipp Hanckef2a4ec12020-07-01 21:07:32 +02003470TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithTelephoneEvent) {
3471 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
3472
3473 cricket::AudioCodecs codecs = acd->codecs();
3474 cricket::AudioCodec dtmf(105, "telephone-event", 8000, 0, 1);
3475 dtmf.params[""] = "0-15";
3476 codecs.push_back(dtmf);
3477 acd->set_codecs(codecs);
3478
3479 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
3480 jdesc_.session_version()));
3481 std::string message = webrtc::SdpSerialize(jdesc_);
3482 std::string sdp_with_fmtp = kSdpFullString;
3483 InjectAfter("m=audio 2345 RTP/SAVPF 111 103 104", " 105", &sdp_with_fmtp);
3484 InjectAfter(
3485 "a=rtpmap:104 ISAC/32000\r\n",
3486 "a=rtpmap:105 telephone-event/8000\r\n" // No comma here. String merging!
3487 "a=fmtp:105 0-15\r\n",
3488 &sdp_with_fmtp);
3489 EXPECT_EQ(sdp_with_fmtp, message);
3490}
3491
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003492TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003493 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003494
3495 cricket::VideoCodecs codecs = vcd->codecs();
3496 codecs[0].params["x-google-min-bitrate"] = "10";
3497 vcd->set_codecs(codecs);
3498
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003499 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003500 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003501 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003502 std::string sdp_with_fmtp = kSdpFullString;
3503 InjectAfter("a=rtpmap:120 VP8/90000\r\n",
Yves Gerey665174f2018-06-19 15:03:05 +02003504 "a=fmtp:120 x-google-min-bitrate=10\r\n", &sdp_with_fmtp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003505 EXPECT_EQ(sdp_with_fmtp, message);
3506}
3507
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02003508TEST_F(WebRtcSdpTest, SerializeVideoPacketizationAttribute) {
3509 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
3510
3511 cricket::VideoCodecs codecs = vcd->codecs();
3512 codecs[0].packetization = "raw";
3513 vcd->set_codecs(codecs);
3514
3515 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
3516 jdesc_.session_version()));
3517 std::string message = webrtc::SdpSerialize(jdesc_);
3518 std::string sdp_with_packetization = kSdpFullString;
3519 InjectAfter("a=rtpmap:120 VP8/90000\r\n", "a=packetization:120 raw\r\n",
3520 &sdp_with_packetization);
3521 EXPECT_EQ(sdp_with_packetization, message);
3522}
3523
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07003524TEST_F(WebRtcSdpTest, DeserializeAndSerializeSdpWithIceLite) {
3525 // Deserialize the baseline description, making sure it's ICE full.
Steve Antona3a92c22017-12-07 10:27:41 -08003526 JsepSessionDescription jdesc_with_icelite(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003527 std::string sdp_with_icelite = kSdpFullString;
3528 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3529 cricket::SessionDescription* desc = jdesc_with_icelite.description();
3530 const cricket::TransportInfo* tinfo1 =
3531 desc->GetTransportInfoByName("audio_content_name");
3532 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
3533 const cricket::TransportInfo* tinfo2 =
3534 desc->GetTransportInfoByName("video_content_name");
3535 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07003536
3537 // Add "a=ice-lite" and deserialize, making sure it's ICE lite.
Yves Gerey665174f2018-06-19 15:03:05 +02003538 InjectAfter(kSessionTime, "a=ice-lite\r\n", &sdp_with_icelite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003539 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3540 desc = jdesc_with_icelite.description();
3541 const cricket::TransportInfo* atinfo =
3542 desc->GetTransportInfoByName("audio_content_name");
3543 EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
3544 const cricket::TransportInfo* vtinfo =
Yves Gerey665174f2018-06-19 15:03:05 +02003545 desc->GetTransportInfoByName("video_content_name");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003546 EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
Taylor Brandstetter2f65ec52018-05-24 11:37:28 -07003547
3548 // Now that we know deserialization works, we can use TestSerialize to test
3549 // serialization.
3550 TestSerialize(jdesc_with_icelite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003551}
3552
3553// Verifies that the candidates in the input SDP are parsed and serialized
3554// correctly in the output SDP.
3555TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
3556 std::string sdp_with_data = kSdpString;
3557 sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
Steve Antona3a92c22017-12-07 10:27:41 -08003558 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003559
3560 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
Steve Antone831b8c2018-02-01 12:22:16 -08003561 EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003562}
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003563
3564TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
3565 AddFingerprint();
3566 TransportInfo audio_transport_info =
3567 *(desc_.GetTransportInfoByName(kAudioContentName));
3568 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3569 audio_transport_info.description.connection_role);
3570 audio_transport_info.description.connection_role =
Yves Gerey665174f2018-06-19 15:03:05 +02003571 cricket::CONNECTIONROLE_ACTIVE;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003572
3573 TransportInfo video_transport_info =
3574 *(desc_.GetTransportInfoByName(kVideoContentName));
3575 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3576 video_transport_info.description.connection_role);
3577 video_transport_info.description.connection_role =
Yves Gerey665174f2018-06-19 15:03:05 +02003578 cricket::CONNECTIONROLE_ACTIVE;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003579
3580 desc_.RemoveTransportInfoByName(kAudioContentName);
3581 desc_.RemoveTransportInfoByName(kVideoContentName);
3582
3583 desc_.AddTransportInfo(audio_transport_info);
3584 desc_.AddTransportInfo(video_transport_info);
3585
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003586 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003587 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 12:22:16 -08003588 std::string message = webrtc::SdpSerialize(jdesc_);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003589 std::string sdp_with_dtlssetup = kSdpFullString;
3590
3591 // Fingerprint attribute is necessary to add DTLS setup attribute.
Yves Gerey665174f2018-06-19 15:03:05 +02003592 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_dtlssetup);
3593 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_dtlssetup);
Artem Titov880fa812021-07-30 22:30:23 +02003594 // Now adding `setup` attribute.
Yves Gerey665174f2018-06-19 15:03:05 +02003595 InjectAfter(kFingerprint, "a=setup:active\r\n", &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003596 EXPECT_EQ(sdp_with_dtlssetup, message);
3597}
3598
Harald Alvestrandefece422021-08-19 09:12:51 +00003599TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributeActpass) {
Steve Antona3a92c22017-12-07 10:27:41 -08003600 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003601 std::string sdp_with_dtlssetup = kSdpFullString;
Yves Gerey665174f2018-06-19 15:03:05 +02003602 InjectAfter(kSessionTime, "a=setup:actpass\r\n", &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003603 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3604 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3605 const cricket::TransportInfo* atinfo =
3606 desc->GetTransportInfoByName("audio_content_name");
3607 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3608 atinfo->description.connection_role);
3609 const cricket::TransportInfo* vtinfo =
Yves Gerey665174f2018-06-19 15:03:05 +02003610 desc->GetTransportInfoByName("video_content_name");
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00003611 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3612 vtinfo->description.connection_role);
3613}
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003614
Harald Alvestrandefece422021-08-19 09:12:51 +00003615TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributeActive) {
3616 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
3617 std::string sdp_with_dtlssetup = kSdpFullString;
3618 InjectAfter(kSessionTime, "a=setup:active\r\n", &sdp_with_dtlssetup);
3619 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3620 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3621 const cricket::TransportInfo* atinfo =
3622 desc->GetTransportInfoByName("audio_content_name");
3623 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
3624 atinfo->description.connection_role);
3625 const cricket::TransportInfo* vtinfo =
3626 desc->GetTransportInfoByName("video_content_name");
3627 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
3628 vtinfo->description.connection_role);
3629}
3630TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributePassive) {
3631 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
3632 std::string sdp_with_dtlssetup = kSdpFullString;
3633 InjectAfter(kSessionTime, "a=setup:passive\r\n", &sdp_with_dtlssetup);
3634 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3635 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3636 const cricket::TransportInfo* atinfo =
3637 desc->GetTransportInfoByName("audio_content_name");
3638 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
3639 atinfo->description.connection_role);
3640 const cricket::TransportInfo* vtinfo =
3641 desc->GetTransportInfoByName("video_content_name");
3642 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
3643 vtinfo->description.connection_role);
3644}
3645
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003646// Verifies that the order of the serialized m-lines follows the order of the
3647// ContentInfo in SessionDescription, and vise versa for deserialization.
3648TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
Steve Antona3a92c22017-12-07 10:27:41 -08003649 JsepSessionDescription jdesc(kDummyType);
Yves Gerey665174f2018-06-19 15:03:05 +02003650 const std::string media_content_sdps[3] = {kSdpAudioString, kSdpVideoString,
3651 kSdpSctpDataChannelString};
3652 const cricket::MediaType media_types[3] = {cricket::MEDIA_TYPE_AUDIO,
3653 cricket::MEDIA_TYPE_VIDEO,
3654 cricket::MEDIA_TYPE_DATA};
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003655
3656 // Verifies all 6 permutations.
3657 for (size_t i = 0; i < 6; ++i) {
3658 size_t media_content_in_sdp[3];
3659 // The index of the first media content.
3660 media_content_in_sdp[0] = i / 2;
3661 // The index of the second media content.
3662 media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
3663 // The index of the third media content.
3664 media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
3665
3666 std::string sdp_string = kSdpSessionString;
3667 for (size_t i = 0; i < 3; ++i)
3668 sdp_string += media_content_sdps[media_content_in_sdp[i]];
3669
3670 EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
3671 cricket::SessionDescription* desc = jdesc.description();
3672 EXPECT_EQ(3u, desc->contents().size());
3673
3674 for (size_t i = 0; i < 3; ++i) {
3675 const cricket::MediaContentDescription* mdesc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003676 desc->contents()[i].media_description();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003677 EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
3678 }
3679
Steve Antone831b8c2018-02-01 12:22:16 -08003680 std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00003681 EXPECT_EQ(sdp_string, serialized_sdp);
3682 }
3683}
deadbeef9d3584c2016-02-16 17:54:10 -08003684
deadbeef25ed4352016-12-12 18:37:36 -08003685TEST_F(WebRtcSdpTest, DeserializeBundleOnlyAttribute) {
3686 MakeBundleOnlyDescription();
Steve Antona3a92c22017-12-07 10:27:41 -08003687 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 13:53:47 -08003688 ASSERT_TRUE(
deadbeef25ed4352016-12-12 18:37:36 -08003689 SdpDeserialize(kBundleOnlySdpFullString, &deserialized_description));
3690 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3691}
3692
deadbeef12771a12017-01-03 13:53:47 -08003693// The semantics of "a=bundle-only" are only defined when it's used in
3694// combination with a 0 port on the m= line. We should ignore it if used with a
3695// nonzero port.
3696TEST_F(WebRtcSdpTest, IgnoreBundleOnlyWithNonzeroPort) {
3697 // Make the base bundle-only description but unset the bundle-only flag.
3698 MakeBundleOnlyDescription();
3699 jdesc_.description()->contents()[1].bundle_only = false;
3700
3701 std::string modified_sdp = kBundleOnlySdpFullString;
3702 Replace("m=video 0", "m=video 9", &modified_sdp);
Steve Antona3a92c22017-12-07 10:27:41 -08003703 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 13:53:47 -08003704 ASSERT_TRUE(SdpDeserialize(modified_sdp, &deserialized_description));
3705 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
deadbeef25ed4352016-12-12 18:37:36 -08003706}
3707
3708TEST_F(WebRtcSdpTest, SerializeBundleOnlyAttribute) {
3709 MakeBundleOnlyDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003710 TestSerialize(jdesc_);
deadbeef25ed4352016-12-12 18:37:36 -08003711}
3712
deadbeef9d3584c2016-02-16 17:54:10 -08003713TEST_F(WebRtcSdpTest, DeserializePlanBSessionDescription) {
3714 MakePlanBDescription();
3715
Steve Antona3a92c22017-12-07 10:27:41 -08003716 JsepSessionDescription deserialized_description(kDummyType);
deadbeef9d3584c2016-02-16 17:54:10 -08003717 EXPECT_TRUE(SdpDeserialize(kPlanBSdpFullString, &deserialized_description));
3718
3719 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3720}
3721
3722TEST_F(WebRtcSdpTest, SerializePlanBSessionDescription) {
3723 MakePlanBDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003724 TestSerialize(jdesc_);
deadbeef9d3584c2016-02-16 17:54:10 -08003725}
3726
3727TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescription) {
3728 MakeUnifiedPlanDescription();
3729
Steve Antona3a92c22017-12-07 10:27:41 -08003730 JsepSessionDescription deserialized_description(kDummyType);
Harald Alvestrandee212a72021-11-02 12:06:45 +00003731 ASSERT_TRUE(
deadbeef9d3584c2016-02-16 17:54:10 -08003732 SdpDeserialize(kUnifiedPlanSdpFullString, &deserialized_description));
3733
3734 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3735}
3736
3737TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescription) {
3738 MakeUnifiedPlanDescription();
Steve Antone831b8c2018-02-01 12:22:16 -08003739 TestSerialize(jdesc_);
3740}
3741
Seth Hampson5b4f0752018-04-02 16:31:36 -07003742// This tests deserializing a Unified Plan SDP that is compatible with both
Seth Hampson7fa6ee62018-10-17 10:25:28 -07003743// Unified Plan and Plan B style SDP, meaning that it contains both "a=ssrc
3744// msid" lines and "a=msid " lines. It tests the case for audio/video tracks
Seth Hampson5b4f0752018-04-02 16:31:36 -07003745// with no stream ids and multiple stream ids. For parsing this, the Unified
3746// Plan a=msid lines should take priority, because the Plan B style a=ssrc msid
3747// lines do not support multiple stream ids and no stream ids.
Seth Hampson7fa6ee62018-10-17 10:25:28 -07003748TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionSpecialMsid) {
3749 // Create both msid lines for Plan B and Unified Plan support.
3750 MakeUnifiedPlanDescriptionMultipleStreamIds(
3751 cricket::kMsidSignalingMediaSection |
3752 cricket::kMsidSignalingSsrcAttribute);
Seth Hampson5b4f0752018-04-02 16:31:36 -07003753
3754 JsepSessionDescription deserialized_description(kDummyType);
3755 EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
3756 &deserialized_description));
3757
3758 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
Henrik Boström5b147782018-12-04 11:25:05 +01003759 EXPECT_EQ(cricket::kMsidSignalingMediaSection |
3760 cricket::kMsidSignalingSsrcAttribute,
3761 deserialized_description.description()->msid_signaling());
Seth Hampson5b4f0752018-04-02 16:31:36 -07003762}
3763
Seth Hampson7fa6ee62018-10-17 10:25:28 -07003764// Tests the serialization of a Unified Plan SDP that is compatible for both
3765// Unified Plan and Plan B style SDPs, meaning that it contains both "a=ssrc
3766// msid" lines and "a=msid " lines. It tests the case for no stream ids and
3767// multiple stream ids.
3768TEST_F(WebRtcSdpTest, SerializeSessionDescriptionSpecialMsid) {
3769 // Create both msid lines for Plan B and Unified Plan support.
3770 MakeUnifiedPlanDescriptionMultipleStreamIds(
3771 cricket::kMsidSignalingMediaSection |
3772 cricket::kMsidSignalingSsrcAttribute);
3773 std::string serialized_sdp = webrtc::SdpSerialize(jdesc_);
3774 // We explicitly test that the serialized SDP string is equal to the hard
3775 // coded SDP string. This is necessary, because in the parser "a=msid" lines
3776 // take priority over "a=ssrc msid" lines. This means if we just used
3777 // TestSerialize(), it could serialize an SDP that omits "a=ssrc msid" lines,
3778 // and still pass, because the deserialized version would be the same.
3779 EXPECT_EQ(kUnifiedPlanSdpFullStringWithSpecialMsid, serialized_sdp);
3780}
3781
3782// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
3783// that signal stream IDs) is deserialized appropriately. It tests the case for
3784// no stream ids and multiple stream ids.
3785TEST_F(WebRtcSdpTest, UnifiedPlanDeserializeSessionDescriptionSpecialMsid) {
3786 // Only create a=msid lines for strictly Unified Plan stream ID support.
3787 MakeUnifiedPlanDescriptionMultipleStreamIds(
3788 cricket::kMsidSignalingMediaSection);
3789
3790 JsepSessionDescription deserialized_description(kDummyType);
3791 std::string unified_plan_sdp_string =
3792 kUnifiedPlanSdpFullStringWithSpecialMsid;
3793 RemoveSsrcMsidLinesFromSdpString(&unified_plan_sdp_string);
3794 EXPECT_TRUE(
3795 SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
3796
3797 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3798}
3799
3800// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
3801// that signal stream IDs) is serialized appropriately. It tests the case for no
3802// stream ids and multiple stream ids.
3803TEST_F(WebRtcSdpTest, UnifiedPlanSerializeSessionDescriptionSpecialMsid) {
3804 // Only create a=msid lines for strictly Unified Plan stream ID support.
3805 MakeUnifiedPlanDescriptionMultipleStreamIds(
3806 cricket::kMsidSignalingMediaSection);
3807
Seth Hampson5b4f0752018-04-02 16:31:36 -07003808 TestSerialize(jdesc_);
3809}
3810
Seth Hampson5897a6e2018-04-03 11:16:33 -07003811// This tests that a Unified Plan SDP with no a=ssrc lines is
3812// serialized/deserialized appropriately. In this case the
3813// MediaContentDescription will contain a StreamParams object that doesn't have
3814// any SSRCs. Vice versa, this will be created upon deserializing an SDP with no
3815// SSRC lines.
3816TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
3817 MakeUnifiedPlanDescription();
3818 RemoveSsrcSignalingFromStreamParams();
3819 std::string unified_plan_sdp_string = kUnifiedPlanSdpFullString;
3820 RemoveSsrcLinesFromSdpString(&unified_plan_sdp_string);
3821
3822 JsepSessionDescription deserialized_description(kDummyType);
3823 EXPECT_TRUE(
3824 SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
3825 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3826}
3827
3828TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
3829 MakeUnifiedPlanDescription();
3830 RemoveSsrcSignalingFromStreamParams();
3831
3832 TestSerialize(jdesc_);
3833}
3834
Steve Antone831b8c2018-02-01 12:22:16 -08003835TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
3836 JsepSessionDescription jsep_desc(kDummyType);
3837 ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
3838 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
3839}
3840
3841TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
3842 JsepSessionDescription jsep_desc(kDummyType);
3843 std::string sdp = kSdpSessionString;
3844 sdp += kSdpSctpDataChannelString;
3845 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3846 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
3847}
3848
3849TEST_F(WebRtcSdpTest, PlanBHasSsrcAttributeMsidSignaling) {
3850 JsepSessionDescription jsep_desc(kDummyType);
3851 ASSERT_TRUE(SdpDeserialize(kPlanBSdpFullString, &jsep_desc));
3852 EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
3853 jsep_desc.description()->msid_signaling());
3854}
3855
3856TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
3857 JsepSessionDescription jsep_desc(kDummyType);
3858 ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
3859 EXPECT_EQ(cricket::kMsidSignalingMediaSection,
3860 jsep_desc.description()->msid_signaling());
3861}
3862
3863const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";
3864const char kSsrcAttributeMsidLine[] =
3865 "a=ssrc:1 msid:local_stream_1 audio_track_id_1";
3866
3867TEST_F(WebRtcSdpTest, SerializeOnlyMediaSectionMsid) {
3868 jdesc_.description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
3869 std::string sdp = webrtc::SdpSerialize(jdesc_);
3870
3871 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
3872 EXPECT_EQ(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
3873}
3874
3875TEST_F(WebRtcSdpTest, SerializeOnlySsrcAttributeMsid) {
3876 jdesc_.description()->set_msid_signaling(
3877 cricket::kMsidSignalingSsrcAttribute);
3878 std::string sdp = webrtc::SdpSerialize(jdesc_);
3879
3880 EXPECT_EQ(std::string::npos, sdp.find(kMediaSectionMsidLine));
3881 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
3882}
3883
3884TEST_F(WebRtcSdpTest, SerializeBothMediaSectionAndSsrcAttributeMsid) {
3885 jdesc_.description()->set_msid_signaling(
3886 cricket::kMsidSignalingMediaSection |
3887 cricket::kMsidSignalingSsrcAttribute);
3888 std::string sdp = webrtc::SdpSerialize(jdesc_);
3889
3890 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
3891 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
deadbeef9d3584c2016-02-16 17:54:10 -08003892}
deadbeef7e146cb2016-09-28 10:04:34 -07003893
deadbeefb2362572016-12-13 16:37:06 -08003894// Regression test for integer overflow bug:
3895// https://bugs.chromium.org/p/chromium/issues/detail?id=648071
3896TEST_F(WebRtcSdpTest, DeserializeLargeBandwidthLimit) {
deadbeefb2362572016-12-13 16:37:06 -08003897 // Bandwidth attribute is the max signed 32-bit int, which will get
3898 // multiplied by 1000 and cause int overflow if not careful.
deadbeef7bcdb692017-01-20 12:43:58 -08003899 static const char kSdpWithLargeBandwidth[] =
deadbeefb2362572016-12-13 16:37:06 -08003900 "v=0\r\n"
3901 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3902 "s=-\r\n"
3903 "t=0 0\r\n"
3904 "m=video 3457 RTP/SAVPF 120\r\n"
3905 "b=AS:2147483647\r\n"
3906 "foo=fail\r\n";
3907
3908 ExpectParseFailure(std::string(kSdpWithLargeBandwidth), "foo=fail");
3909}
deadbeef7bcdb692017-01-20 12:43:58 -08003910
deadbeefbc88c6b2017-08-02 11:26:34 -07003911// Similar to the above, except that negative values are illegal, not just
3912// error-prone as large values are.
3913// https://bugs.chromium.org/p/chromium/issues/detail?id=675361
3914TEST_F(WebRtcSdpTest, DeserializingNegativeBandwidthLimitFails) {
3915 static const char kSdpWithNegativeBandwidth[] =
3916 "v=0\r\n"
3917 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3918 "s=-\r\n"
3919 "t=0 0\r\n"
3920 "m=video 3457 RTP/SAVPF 120\r\n"
3921 "b=AS:-1000\r\n";
3922
3923 ExpectParseFailure(std::string(kSdpWithNegativeBandwidth), "b=AS:-1000");
3924}
3925
deadbeef3e8016e2017-08-03 17:49:30 -07003926// An exception to the above rule: a value of -1 for b=AS should just be
3927// ignored, resulting in "kAutoBandwidth" in the deserialized object.
3928// Applications historically may be using "b=AS:-1" to mean "no bandwidth
3929// limit", but this is now what ommitting the attribute entirely will do, so
3930// ignoring it will have the intended effect.
3931TEST_F(WebRtcSdpTest, BandwidthLimitOfNegativeOneIgnored) {
3932 static const char kSdpWithBandwidthOfNegativeOne[] =
3933 "v=0\r\n"
3934 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3935 "s=-\r\n"
3936 "t=0 0\r\n"
3937 "m=video 3457 RTP/SAVPF 120\r\n"
3938 "b=AS:-1\r\n";
3939
Steve Antona3a92c22017-12-07 10:27:41 -08003940 JsepSessionDescription jdesc_output(kDummyType);
deadbeef3e8016e2017-08-03 17:49:30 -07003941 EXPECT_TRUE(SdpDeserialize(kSdpWithBandwidthOfNegativeOne, &jdesc_output));
deadbeef3e8016e2017-08-03 17:49:30 -07003942 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003943 GetFirstVideoContentDescription(jdesc_output.description());
3944 ASSERT_TRUE(vcd);
deadbeef3e8016e2017-08-03 17:49:30 -07003945 EXPECT_EQ(cricket::kAutoBandwidth, vcd->bandwidth());
3946}
3947
deadbeef7bcdb692017-01-20 12:43:58 -08003948// Test that "ufrag"/"pwd" in the candidate line itself are ignored, and only
3949// the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
3950// Regression test for:
3951// https://bugs.chromium.org/p/chromium/issues/detail?id=681286
3952TEST_F(WebRtcSdpTest, IceCredentialsInCandidateStringIgnored) {
3953 // Important piece is "ufrag foo pwd bar".
3954 static const char kSdpWithIceCredentialsInCandidateString[] =
3955 "v=0\r\n"
3956 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3957 "s=-\r\n"
3958 "t=0 0\r\n"
3959 "m=audio 9 RTP/SAVPF 111\r\n"
3960 "c=IN IP4 0.0.0.0\r\n"
3961 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
3962 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
3963 "a=rtpmap:111 opus/48000/2\r\n"
3964 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
3965 "generation 2 ufrag foo pwd bar\r\n";
3966
Steve Antona3a92c22017-12-07 10:27:41 -08003967 JsepSessionDescription jdesc_output(kDummyType);
deadbeef7bcdb692017-01-20 12:43:58 -08003968 EXPECT_TRUE(
3969 SdpDeserialize(kSdpWithIceCredentialsInCandidateString, &jdesc_output));
3970 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
3971 ASSERT_NE(nullptr, candidates);
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02003972 ASSERT_EQ(1U, candidates->count());
deadbeef7bcdb692017-01-20 12:43:58 -08003973 cricket::Candidate c = candidates->at(0)->candidate();
3974 EXPECT_EQ("ufrag_voice", c.username());
3975 EXPECT_EQ("pwd_voice", c.password());
3976}
deadbeef90f1e1e2017-02-10 12:35:05 -08003977
Johannes Kron211856b2018-09-06 12:12:28 +02003978// Test that attribute lines "a=ice-ufrag-something"/"a=ice-pwd-something" are
3979// ignored, and only the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
3980// Regression test for:
3981// https://bugs.chromium.org/p/webrtc/issues/detail?id=9712
3982TEST_F(WebRtcSdpTest, AttributeWithPartialMatchingNameIsIgnored) {
3983 static const char kSdpWithFooIceCredentials[] =
3984 "v=0\r\n"
3985 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3986 "s=-\r\n"
3987 "t=0 0\r\n"
3988 "m=audio 9 RTP/SAVPF 111\r\n"
3989 "c=IN IP4 0.0.0.0\r\n"
3990 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
3991 "a=ice-ufrag-something:foo\r\na=ice-pwd-something:bar\r\n"
3992 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
3993 "a=rtpmap:111 opus/48000/2\r\n"
3994 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
3995 "generation 2\r\n";
3996
3997 JsepSessionDescription jdesc_output(kDummyType);
3998 EXPECT_TRUE(SdpDeserialize(kSdpWithFooIceCredentials, &jdesc_output));
3999 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
4000 ASSERT_NE(nullptr, candidates);
4001 ASSERT_EQ(1U, candidates->count());
4002 cricket::Candidate c = candidates->at(0)->candidate();
4003 EXPECT_EQ("ufrag_voice", c.username());
4004 EXPECT_EQ("pwd_voice", c.password());
4005}
4006
deadbeef90f1e1e2017-02-10 12:35:05 -08004007// Test that SDP with an invalid port number in "a=candidate" lines is
4008// rejected, without crashing.
4009// Regression test for:
4010// https://bugs.chromium.org/p/chromium/issues/detail?id=677029
4011TEST_F(WebRtcSdpTest, DeserializeInvalidPortInCandidateAttribute) {
4012 static const char kSdpWithInvalidCandidatePort[] =
4013 "v=0\r\n"
4014 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4015 "s=-\r\n"
4016 "t=0 0\r\n"
4017 "m=audio 9 RTP/SAVPF 111\r\n"
4018 "c=IN IP4 0.0.0.0\r\n"
4019 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
4020 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
4021 "a=rtpmap:111 opus/48000/2\r\n"
4022 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 12345678 typ host "
4023 "generation 2 raddr 192.168.1.1 rport 87654321\r\n";
4024
Steve Antona3a92c22017-12-07 10:27:41 -08004025 JsepSessionDescription jdesc_output(kDummyType);
deadbeef90f1e1e2017-02-10 12:35:05 -08004026 EXPECT_FALSE(SdpDeserialize(kSdpWithInvalidCandidatePort, &jdesc_output));
4027}
deadbeefa4549d62017-02-10 17:26:22 -08004028
4029// Test that "a=msid" with a missing track ID is rejected and doesn't crash.
4030// Regression test for:
4031// https://bugs.chromium.org/p/chromium/issues/detail?id=686405
4032TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingTrackId) {
4033 static const char kSdpWithMissingTrackId[] =
4034 "v=0\r\n"
4035 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4036 "s=-\r\n"
4037 "t=0 0\r\n"
4038 "m=audio 9 RTP/SAVPF 111\r\n"
4039 "c=IN IP4 0.0.0.0\r\n"
4040 "a=rtpmap:111 opus/48000/2\r\n"
4041 "a=msid:stream_id \r\n";
4042
Steve Antona3a92c22017-12-07 10:27:41 -08004043 JsepSessionDescription jdesc_output(kDummyType);
deadbeefa4549d62017-02-10 17:26:22 -08004044 EXPECT_FALSE(SdpDeserialize(kSdpWithMissingTrackId, &jdesc_output));
4045}
4046
4047TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingStreamId) {
4048 static const char kSdpWithMissingStreamId[] =
4049 "v=0\r\n"
4050 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4051 "s=-\r\n"
4052 "t=0 0\r\n"
4053 "m=audio 9 RTP/SAVPF 111\r\n"
4054 "c=IN IP4 0.0.0.0\r\n"
4055 "a=rtpmap:111 opus/48000/2\r\n"
4056 "a=msid: track_id\r\n";
4057
Steve Antona3a92c22017-12-07 10:27:41 -08004058 JsepSessionDescription jdesc_output(kDummyType);
deadbeefa4549d62017-02-10 17:26:22 -08004059 EXPECT_FALSE(SdpDeserialize(kSdpWithMissingStreamId, &jdesc_output));
4060}
zhihuang38989e52017-03-21 11:04:53 -07004061
4062// Tests that if both session-level address and media-level address exist, use
4063// the media-level address.
4064TEST_F(WebRtcSdpTest, ParseConnectionData) {
Steve Antona3a92c22017-12-07 10:27:41 -08004065 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004066
4067 // Sesssion-level address.
4068 std::string sdp = kSdpFullString;
4069 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
4070 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4071
4072 const auto& content1 = jsep_desc.description()->contents()[0];
4073 EXPECT_EQ("74.125.127.126:2345",
Steve Antonb1c1de12017-12-21 15:14:30 -08004074 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004075 const auto& content2 = jsep_desc.description()->contents()[1];
4076 EXPECT_EQ("74.125.224.39:3457",
Steve Antonb1c1de12017-12-21 15:14:30 -08004077 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004078}
4079
4080// Tests that the session-level connection address will be used if the media
4081// level-addresses are not specified.
4082TEST_F(WebRtcSdpTest, ParseConnectionDataSessionLevelOnly) {
Steve Antona3a92c22017-12-07 10:27:41 -08004083 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004084
4085 // Sesssion-level address.
4086 std::string sdp = kSdpString;
4087 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
4088 // Remove the media level addresses.
4089 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
4090 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
4091 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4092
4093 const auto& content1 = jsep_desc.description()->contents()[0];
4094 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004095 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004096 const auto& content2 = jsep_desc.description()->contents()[1];
4097 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004098 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004099}
4100
4101TEST_F(WebRtcSdpTest, ParseConnectionDataIPv6) {
Steve Antona3a92c22017-12-07 10:27:41 -08004102 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004103
4104 std::string sdp = kSdpString;
4105 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4106 Replace("m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP4 0.0.0.0\r\n",
4107 "m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP6 "
4108 "2001:0db8:85a3:0000:0000:8a2e:0370:7335\r\n",
4109 &sdp);
4110 Replace("m=video 9 RTP/SAVPF 120\r\nc=IN IP4 0.0.0.0\r\n",
4111 "m=video 9 RTP/SAVPF 120\r\nc=IN IP6 "
4112 "2001:0db8:85a3:0000:0000:8a2e:0370:7336\r\n",
4113 &sdp);
4114 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4115 const auto& content1 = jsep_desc.description()->contents()[0];
4116 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7335]:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004117 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004118 const auto& content2 = jsep_desc.description()->contents()[1];
4119 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7336]:9",
Steve Antonb1c1de12017-12-21 15:14:30 -08004120 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 11:04:53 -07004121}
4122
Qingsi Wang56991422019-02-08 12:53:06 -08004123// Test that a c= line that contains a hostname connection address can be
4124// parsed.
4125TEST_F(WebRtcSdpTest, ParseConnectionDataWithHostnameConnectionAddress) {
4126 JsepSessionDescription jsep_desc(kDummyType);
4127 std::string sdp = kSdpString;
4128 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4129
4130 sdp = kSdpString;
4131 Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
4132 Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
4133 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4134
4135 ASSERT_NE(nullptr, jsep_desc.description());
4136 const auto& content1 = jsep_desc.description()->contents()[0];
4137 EXPECT_EQ("example.local:9",
4138 content1.media_description()->connection_address().ToString());
4139 const auto& content2 = jsep_desc.description()->contents()[1];
4140 EXPECT_EQ("example.local:9",
4141 content2.media_description()->connection_address().ToString());
4142}
4143
4144// Test that the invalid or unsupported connection data cannot be parsed.
zhihuang38989e52017-03-21 11:04:53 -07004145TEST_F(WebRtcSdpTest, ParseConnectionDataFailure) {
Steve Antona3a92c22017-12-07 10:27:41 -08004146 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004147 std::string sdp = kSdpString;
4148 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4149
4150 // Unsupported multicast IPv4 address.
4151 sdp = kSdpFullString;
4152 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP4 74.125.224.39/127\r\n", &sdp);
4153 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4154
4155 // Unsupported multicast IPv6 address.
4156 sdp = kSdpFullString;
4157 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 ::1/3\r\n", &sdp);
4158 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4159
4160 // Mismatched address type.
4161 sdp = kSdpFullString;
4162 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 74.125.224.39\r\n", &sdp);
4163 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4164
4165 sdp = kSdpFullString;
4166 Replace("c=IN IP4 74.125.224.39\r\n",
4167 "c=IN IP4 2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n", &sdp);
4168 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4169}
4170
4171TEST_F(WebRtcSdpTest, SerializeAndDeserializeWithConnectionAddress) {
Steve Antona3a92c22017-12-07 10:27:41 -08004172 JsepSessionDescription expected_jsep(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004173 MakeDescriptionWithoutCandidates(&expected_jsep);
4174 // Serialization.
Steve Antone831b8c2018-02-01 12:22:16 -08004175 std::string message = webrtc::SdpSerialize(expected_jsep);
zhihuang38989e52017-03-21 11:04:53 -07004176 // Deserialization.
Steve Antona3a92c22017-12-07 10:27:41 -08004177 JsepSessionDescription jdesc(kDummyType);
zhihuang38989e52017-03-21 11:04:53 -07004178 EXPECT_TRUE(SdpDeserialize(message, &jdesc));
Steve Antonb1c1de12017-12-21 15:14:30 -08004179 auto audio_desc = jdesc.description()
4180 ->GetContentByName(kAudioContentName)
4181 ->media_description();
4182 auto video_desc = jdesc.description()
4183 ->GetContentByName(kVideoContentName)
4184 ->media_description();
zhihuang38989e52017-03-21 11:04:53 -07004185 EXPECT_EQ(audio_desc_->connection_address().ToString(),
4186 audio_desc->connection_address().ToString());
4187 EXPECT_EQ(video_desc_->connection_address().ToString(),
4188 video_desc->connection_address().ToString());
4189}
Taylor Brandstetter93a7b242018-04-16 10:45:24 -07004190
4191// RFC4566 says "If a session has no meaningful name, the value "s= " SHOULD be
4192// used (i.e., a single space as the session name)." So we should accept that.
4193TEST_F(WebRtcSdpTest, DeserializeEmptySessionName) {
4194 JsepSessionDescription jsep_desc(kDummyType);
4195 std::string sdp = kSdpString;
4196 Replace("s=-\r\n", "s= \r\n", &sdp);
4197 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4198}
Amit Hilbucha2012042018-12-03 11:35:05 -08004199
4200// Simulcast malformed input test for invalid format.
4201TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_EmptyAttribute) {
Artem Titovf0a34f22020-03-16 17:52:04 +00004202 ExpectParseFailureWithNewLines("a=ssrc:3 label:video_track_id_1\r\n",
4203 "a=simulcast:\r\n", "a=simulcast:");
Amit Hilbucha2012042018-12-03 11:35:05 -08004204}
4205
4206// Tests that duplicate simulcast entries in the SDP triggers a parse failure.
4207TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_DuplicateAttribute) {
Artem Titovf0a34f22020-03-16 17:52:04 +00004208 ExpectParseFailureWithNewLines("a=ssrc:3 label:video_track_id_1\r\n",
4209 "a=simulcast:send 1\r\na=simulcast:recv 2\r\n",
4210 "a=simulcast:");
Amit Hilbucha2012042018-12-03 11:35:05 -08004211}
4212
4213// Validates that deserialization uses the a=simulcast: attribute
4214TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttribute) {
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004215 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4216 sdp += "a=rid:1 send\r\n";
4217 sdp += "a=rid:2 send\r\n";
4218 sdp += "a=rid:3 send\r\n";
4219 sdp += "a=rid:4 recv\r\n";
4220 sdp += "a=rid:5 recv\r\n";
4221 sdp += "a=rid:6 recv\r\n";
Amit Hilbucha2012042018-12-03 11:35:05 -08004222 sdp += "a=simulcast:send 1,2;3 recv 4;5;6\r\n";
4223 JsepSessionDescription output(kDummyType);
4224 SdpParseError error;
4225 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4226 const cricket::ContentInfos& contents = output.description()->contents();
4227 const cricket::MediaContentDescription* media =
4228 contents.back().media_description();
4229 EXPECT_TRUE(media->HasSimulcast());
4230 EXPECT_EQ(2ul, media->simulcast_description().send_layers().size());
4231 EXPECT_EQ(3ul, media->simulcast_description().receive_layers().size());
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004232 EXPECT_FALSE(media->streams().empty());
4233 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4234 CompareRidDescriptionIds(rids, {"1", "2", "3"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004235}
4236
4237// Validates that deserialization removes rids that do not appear in SDP
4238TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttributeRemovesUnknownRids) {
4239 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4240 sdp += "a=rid:1 send\r\n";
4241 sdp += "a=rid:3 send\r\n";
4242 sdp += "a=rid:4 recv\r\n";
4243 sdp += "a=simulcast:send 1,2;3 recv 4;5,6\r\n";
4244 JsepSessionDescription output(kDummyType);
4245 SdpParseError error;
4246 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4247 const cricket::ContentInfos& contents = output.description()->contents();
4248 const cricket::MediaContentDescription* media =
4249 contents.back().media_description();
4250 EXPECT_TRUE(media->HasSimulcast());
4251 const SimulcastDescription& simulcast = media->simulcast_description();
4252 EXPECT_EQ(2ul, simulcast.send_layers().size());
4253 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4254
4255 std::vector<SimulcastLayer> all_send_layers =
4256 simulcast.send_layers().GetAllLayers();
4257 EXPECT_EQ(2ul, all_send_layers.size());
Steve Anton64b626b2019-01-28 17:25:26 -08004258 EXPECT_EQ(0,
4259 absl::c_count_if(all_send_layers, [](const SimulcastLayer& layer) {
4260 return layer.rid == "2";
4261 }));
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004262
4263 std::vector<SimulcastLayer> all_receive_layers =
4264 simulcast.receive_layers().GetAllLayers();
4265 ASSERT_EQ(1ul, all_receive_layers.size());
4266 EXPECT_EQ("4", all_receive_layers[0].rid);
4267
4268 EXPECT_FALSE(media->streams().empty());
4269 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4270 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004271}
4272
4273// Validates that Simulcast removes rids that appear in both send and receive.
4274TEST_F(WebRtcSdpTest,
4275 TestDeserializeSimulcastAttributeRemovesDuplicateSendReceive) {
4276 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4277 sdp += "a=rid:1 send\r\n";
4278 sdp += "a=rid:2 send\r\n";
4279 sdp += "a=rid:3 send\r\n";
4280 sdp += "a=rid:4 recv\r\n";
4281 sdp += "a=simulcast:send 1;2;3 recv 2;4\r\n";
4282 JsepSessionDescription output(kDummyType);
4283 SdpParseError error;
4284 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4285 const cricket::ContentInfos& contents = output.description()->contents();
4286 const cricket::MediaContentDescription* media =
4287 contents.back().media_description();
4288 EXPECT_TRUE(media->HasSimulcast());
4289 const SimulcastDescription& simulcast = media->simulcast_description();
4290 EXPECT_EQ(2ul, simulcast.send_layers().size());
4291 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4292 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4293 EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
4294
4295 EXPECT_FALSE(media->streams().empty());
4296 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4297 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004298}
4299
4300// Ignores empty rid line.
4301TEST_F(WebRtcSdpTest, TestDeserializeIgnoresEmptyRidLines) {
4302 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4303 sdp += "a=rid:1 send\r\n";
4304 sdp += "a=rid:2 send\r\n";
4305 sdp += "a=rid\r\n"; // Should ignore this line.
4306 sdp += "a=rid:\r\n"; // Should ignore this line.
4307 sdp += "a=simulcast:send 1;2\r\n";
4308 JsepSessionDescription output(kDummyType);
4309 SdpParseError error;
4310 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4311 const cricket::ContentInfos& contents = output.description()->contents();
4312 const cricket::MediaContentDescription* media =
4313 contents.back().media_description();
4314 EXPECT_TRUE(media->HasSimulcast());
4315 const SimulcastDescription& simulcast = media->simulcast_description();
4316 EXPECT_TRUE(simulcast.receive_layers().empty());
4317 EXPECT_EQ(2ul, simulcast.send_layers().size());
4318 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4319
4320 EXPECT_FALSE(media->streams().empty());
4321 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4322 CompareRidDescriptionIds(rids, {"1", "2"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004323}
4324
4325// Ignores malformed rid lines.
4326TEST_F(WebRtcSdpTest, TestDeserializeIgnoresMalformedRidLines) {
4327 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4328 sdp += "a=rid:1 send pt=\r\n"; // Should ignore this line.
4329 sdp += "a=rid:2 receive\r\n"; // Should ignore this line.
4330 sdp += "a=rid:3 max-width=720;pt=120\r\n"; // Should ignore this line.
4331 sdp += "a=rid:4\r\n"; // Should ignore this line.
4332 sdp += "a=rid:5 send\r\n";
4333 sdp += "a=simulcast:send 1,2,3;4,5\r\n";
4334 JsepSessionDescription output(kDummyType);
4335 SdpParseError error;
4336 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4337 const cricket::ContentInfos& contents = output.description()->contents();
4338 const cricket::MediaContentDescription* media =
4339 contents.back().media_description();
4340 EXPECT_TRUE(media->HasSimulcast());
4341 const SimulcastDescription& simulcast = media->simulcast_description();
4342 EXPECT_TRUE(simulcast.receive_layers().empty());
4343 EXPECT_EQ(1ul, simulcast.send_layers().size());
4344 EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
4345
4346 EXPECT_FALSE(media->streams().empty());
4347 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4348 CompareRidDescriptionIds(rids, {"5"});
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004349}
4350
4351// Removes RIDs that specify a different format than the m= section.
4352TEST_F(WebRtcSdpTest, TestDeserializeRemovesRidsWithInvalidCodec) {
4353 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4354 sdp += "a=rid:1 send pt=121,120\r\n"; // Should remove 121 and keep RID.
4355 sdp += "a=rid:2 send pt=121\r\n"; // Should remove RID altogether.
4356 sdp += "a=simulcast:send 1;2\r\n";
4357 JsepSessionDescription output(kDummyType);
4358 SdpParseError error;
4359 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4360 const cricket::ContentInfos& contents = output.description()->contents();
4361 const cricket::MediaContentDescription* media =
4362 contents.back().media_description();
4363 EXPECT_TRUE(media->HasSimulcast());
4364 const SimulcastDescription& simulcast = media->simulcast_description();
4365 EXPECT_TRUE(simulcast.receive_layers().empty());
4366 EXPECT_EQ(1ul, simulcast.send_layers().size());
4367 EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
4368 EXPECT_EQ("1", simulcast.send_layers()[0][0].rid);
4369 EXPECT_EQ(1ul, media->streams().size());
4370 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4371 EXPECT_EQ(1ul, rids.size());
4372 EXPECT_EQ("1", rids[0].rid);
4373 EXPECT_EQ(1ul, rids[0].payload_types.size());
4374 EXPECT_EQ(120, rids[0].payload_types[0]);
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004375}
4376
4377// Ignores duplicate rid lines
4378TEST_F(WebRtcSdpTest, TestDeserializeIgnoresDuplicateRidLines) {
4379 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4380 sdp += "a=rid:1 send\r\n";
4381 sdp += "a=rid:2 send\r\n";
4382 sdp += "a=rid:2 send\r\n";
4383 sdp += "a=rid:3 send\r\n";
4384 sdp += "a=rid:4 recv\r\n";
4385 sdp += "a=simulcast:send 1,2;3 recv 4\r\n";
4386 JsepSessionDescription output(kDummyType);
4387 SdpParseError error;
4388 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4389 const cricket::ContentInfos& contents = output.description()->contents();
4390 const cricket::MediaContentDescription* media =
4391 contents.back().media_description();
4392 EXPECT_TRUE(media->HasSimulcast());
4393 const SimulcastDescription& simulcast = media->simulcast_description();
4394 EXPECT_EQ(2ul, simulcast.send_layers().size());
4395 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4396 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4397 EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
4398
4399 EXPECT_FALSE(media->streams().empty());
4400 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4401 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbucha2012042018-12-03 11:35:05 -08004402}
4403
Florent Castellic4421972019-07-02 20:27:42 +02004404TEST_F(WebRtcSdpTest, TestDeserializeRidSendDirection) {
4405 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4406 sdp += "a=rid:1 recv\r\n";
4407 sdp += "a=rid:2 recv\r\n";
4408 sdp += "a=simulcast:send 1;2\r\n";
4409 JsepSessionDescription output(kDummyType);
4410 SdpParseError error;
4411 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4412 const cricket::ContentInfos& contents = output.description()->contents();
4413 const cricket::MediaContentDescription* media =
4414 contents.back().media_description();
4415 EXPECT_FALSE(media->HasSimulcast());
4416}
4417
4418TEST_F(WebRtcSdpTest, TestDeserializeRidRecvDirection) {
4419 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4420 sdp += "a=rid:1 send\r\n";
4421 sdp += "a=rid:2 send\r\n";
4422 sdp += "a=simulcast:recv 1;2\r\n";
4423 JsepSessionDescription output(kDummyType);
4424 SdpParseError error;
4425 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4426 const cricket::ContentInfos& contents = output.description()->contents();
4427 const cricket::MediaContentDescription* media =
4428 contents.back().media_description();
4429 EXPECT_FALSE(media->HasSimulcast());
4430}
4431
4432TEST_F(WebRtcSdpTest, TestDeserializeIgnoresWrongRidDirectionLines) {
4433 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4434 sdp += "a=rid:1 send\r\n";
4435 sdp += "a=rid:2 send\r\n";
4436 sdp += "a=rid:3 send\r\n";
4437 sdp += "a=rid:4 recv\r\n";
4438 sdp += "a=rid:5 recv\r\n";
4439 sdp += "a=rid:6 recv\r\n";
4440 sdp += "a=simulcast:send 1;5;3 recv 4;2;6\r\n";
4441 JsepSessionDescription output(kDummyType);
4442 SdpParseError error;
4443 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4444 const cricket::ContentInfos& contents = output.description()->contents();
4445 const cricket::MediaContentDescription* media =
4446 contents.back().media_description();
4447 EXPECT_TRUE(media->HasSimulcast());
4448 const SimulcastDescription& simulcast = media->simulcast_description();
4449 EXPECT_EQ(2ul, simulcast.send_layers().size());
4450 EXPECT_EQ(2ul, simulcast.receive_layers().size());
4451 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4452 EXPECT_EQ(2ul, simulcast.receive_layers().GetAllLayers().size());
4453
4454 EXPECT_FALSE(media->streams().empty());
4455 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4456 CompareRidDescriptionIds(rids, {"1", "3"});
4457}
4458
Amit Hilbucha2012042018-12-03 11:35:05 -08004459// Simulcast serialization integration test.
4460// This test will serialize and deserialize the description and compare.
4461// More detailed tests for parsing simulcast can be found in
4462// unit tests for SdpSerializer.
4463TEST_F(WebRtcSdpTest, SerializeSimulcast_ComplexSerialization) {
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004464 MakeUnifiedPlanDescription(/* use_ssrcs = */ false);
Amit Hilbucha2012042018-12-03 11:35:05 -08004465 auto description = jdesc_.description();
4466 auto media = description->GetContentDescriptionByName(kVideoContentName3);
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004467 ASSERT_EQ(media->streams().size(), 1ul);
4468 StreamParams& send_stream = media->mutable_streams()[0];
4469 std::vector<RidDescription> send_rids;
4470 send_rids.push_back(RidDescription("1", RidDirection::kSend));
4471 send_rids.push_back(RidDescription("2", RidDirection::kSend));
4472 send_rids.push_back(RidDescription("3", RidDirection::kSend));
4473 send_rids.push_back(RidDescription("4", RidDirection::kSend));
4474 send_stream.set_rids(send_rids);
Florent Castellib60141b2019-07-03 12:47:54 +02004475 std::vector<RidDescription> receive_rids;
4476 receive_rids.push_back(RidDescription("5", RidDirection::kReceive));
4477 receive_rids.push_back(RidDescription("6", RidDirection::kReceive));
4478 receive_rids.push_back(RidDescription("7", RidDirection::kReceive));
4479 media->set_receive_rids(receive_rids);
Amit Hilbuchc57d5732018-12-11 15:30:11 -08004480
Amit Hilbucha2012042018-12-03 11:35:05 -08004481 SimulcastDescription& simulcast = media->simulcast_description();
4482 simulcast.send_layers().AddLayerWithAlternatives(
4483 {SimulcastLayer("2", false), SimulcastLayer("1", true)});
4484 simulcast.send_layers().AddLayerWithAlternatives(
4485 {SimulcastLayer("4", false), SimulcastLayer("3", false)});
Florent Castellib60141b2019-07-03 12:47:54 +02004486 simulcast.receive_layers().AddLayer({SimulcastLayer("5", false)});
4487 simulcast.receive_layers().AddLayer({SimulcastLayer("6", false)});
4488 simulcast.receive_layers().AddLayer({SimulcastLayer("7", false)});
Amit Hilbucha2012042018-12-03 11:35:05 -08004489
Amit Hilbucha2012042018-12-03 11:35:05 -08004490 TestSerialize(jdesc_);
4491}
Steve Anton06817cd2018-12-18 15:55:30 -08004492
4493// Test that the content name is empty if the media section does not have an
4494// a=mid line.
4495TEST_F(WebRtcSdpTest, ParseNoMid) {
4496 std::string sdp = kSdpString;
4497 Replace("a=mid:audio_content_name\r\n", "", &sdp);
4498 Replace("a=mid:video_content_name\r\n", "", &sdp);
4499
4500 JsepSessionDescription output(kDummyType);
4501 SdpParseError error;
4502 ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4503
4504 EXPECT_THAT(output.description()->contents(),
4505 ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
4506 Field("name", &cricket::ContentInfo::name, "")));
4507}
Piotr (Peter) Slatala13e570f2019-02-27 11:34:26 -08004508
Guido Urdanetacecf87f2019-05-31 10:17:38 +00004509TEST_F(WebRtcSdpTest, SerializeWithDefaultSctpProtocol) {
4510 AddSctpDataChannel(false); // Don't use sctpmap
4511 JsepSessionDescription jsep_desc(kDummyType);
4512 MakeDescriptionWithoutCandidates(&jsep_desc);
4513 std::string message = webrtc::SdpSerialize(jsep_desc);
4514 EXPECT_NE(std::string::npos,
4515 message.find(cricket::kMediaProtocolUdpDtlsSctp));
4516}
4517
4518TEST_F(WebRtcSdpTest, DeserializeWithAllSctpProtocols) {
4519 AddSctpDataChannel(false);
4520 std::string protocols[] = {cricket::kMediaProtocolDtlsSctp,
4521 cricket::kMediaProtocolUdpDtlsSctp,
4522 cricket::kMediaProtocolTcpDtlsSctp};
4523 for (const auto& protocol : protocols) {
4524 sctp_desc_->set_protocol(protocol);
4525 JsepSessionDescription jsep_desc(kDummyType);
4526 MakeDescriptionWithoutCandidates(&jsep_desc);
4527 std::string message = webrtc::SdpSerialize(jsep_desc);
4528 EXPECT_NE(std::string::npos, message.find(protocol));
4529 JsepSessionDescription jsep_output(kDummyType);
4530 SdpParseError error;
4531 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jsep_output, &error));
4532 }
4533}
Taylor Brandstetter4256df02020-02-18 14:05:07 -08004534
4535// According to https://tools.ietf.org/html/rfc5576#section-6.1, the CNAME
4536// attribute is mandatory, but we relax that restriction.
4537TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCname) {
4538 std::string sdp_without_cname = kSdpFullString;
4539 Replace("a=ssrc:1 cname:stream_1_cname\r\n", "", &sdp_without_cname);
4540 JsepSessionDescription new_jdesc(kDummyType);
4541 EXPECT_TRUE(SdpDeserialize(sdp_without_cname, &new_jdesc));
4542
4543 audio_desc_->mutable_streams()[0].cname = "";
4544 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
4545 jdesc_.session_version()));
4546 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
4547}
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004548
4549TEST_F(WebRtcSdpTest, DeserializeSdpWithUnsupportedMediaType) {
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004550 std::string sdp = kSdpSessionString;
4551 sdp +=
4552 "m=bogus 9 RTP/SAVPF 0 8\r\n"
Philipp Hancke4e8c1152020-10-13 12:43:15 +02004553 "c=IN IP4 0.0.0.0\r\n"
4554 "a=mid:bogusmid\r\n";
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004555 sdp +=
4556 "m=audio/something 9 RTP/SAVPF 0 8\r\n"
Philipp Hancke4e8c1152020-10-13 12:43:15 +02004557 "c=IN IP4 0.0.0.0\r\n"
4558 "a=mid:somethingmid\r\n";
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004559
4560 JsepSessionDescription jdesc_output(kDummyType);
4561 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4562
Philipp Hancke4e8c1152020-10-13 12:43:15 +02004563 ASSERT_EQ(2u, jdesc_output.description()->contents().size());
4564 ASSERT_NE(nullptr, jdesc_output.description()
4565 ->contents()[0]
4566 .media_description()
4567 ->as_unsupported());
4568 ASSERT_NE(nullptr, jdesc_output.description()
4569 ->contents()[1]
4570 .media_description()
4571 ->as_unsupported());
4572
4573 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
4574 EXPECT_TRUE(jdesc_output.description()->contents()[1].rejected);
4575
4576 EXPECT_EQ(jdesc_output.description()->contents()[0].name, "bogusmid");
4577 EXPECT_EQ(jdesc_output.description()->contents()[1].name, "somethingmid");
Philipp Hanckeefc55b02020-06-26 10:17:05 +02004578}
Philipp Hanckeb70c9532021-01-13 10:40:06 +01004579
4580TEST_F(WebRtcSdpTest, MediaTypeProtocolMismatch) {
4581 std::string sdp =
4582 "v=0\r\n"
4583 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4584 "s=-\r\n"
4585 "t=0 0\r\n";
4586
4587 ExpectParseFailure(std::string(sdp + "m=audio 9 UDP/DTLS/SCTP 120\r\n"),
4588 "m=audio");
4589 ExpectParseFailure(std::string(sdp + "m=video 9 UDP/DTLS/SCTP 120\r\n"),
4590 "m=video");
4591 ExpectParseFailure(std::string(sdp + "m=video 9 SOMETHING 120\r\n"),
4592 "m=video");
4593 ExpectParseFailure(std::string(sdp + "m=application 9 SOMETHING 120\r\n"),
4594 "m=application");
4595}
Philipp Hanckecd467b52021-01-29 09:29:47 +01004596
4597// Regression test for:
4598// https://bugs.chromium.org/p/chromium/issues/detail?id=1171965
4599TEST_F(WebRtcSdpTest, SctpPortInUnsupportedContent) {
4600 std::string sdp =
4601 "v=0\r\n"
4602 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4603 "s=-\r\n"
4604 "t=0 0\r\n"
4605 "m=o 1 DTLS/SCTP 5000\r\n"
4606 "a=sctp-port\r\n";
4607
4608 JsepSessionDescription jdesc_output(kDummyType);
4609 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4610}
Harald Alvestrand99bcf602021-03-03 07:44:39 +00004611
4612TEST_F(WebRtcSdpTest, IllegalMidCharacterValue) {
4613 std::string sdp = kSdpString;
4614 // [ is an illegal token value.
4615 Replace("a=mid:", "a=mid:[]", &sdp);
4616 ExpectParseFailure(std::string(sdp), "a=mid:[]");
4617}