blob: 1c0c4dde94d089c78321b59f259b96172b6cbf82 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:361/*
kjellanderb24317b2016-02-10 15:54:432 * Copyright 2011 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:363 *
kjellanderb24317b2016-02-10 15:54:434 * 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:369 */
10
Yves Gerey3e707812018-11-28 15:47:4911#include <stdio.h>
12#include <string.h>
Jonas Olssona4d87372019-07-05 17:08:3313
Yves Gerey3e707812018-11-28 15:47:4914#include <cstdint>
15#include <map>
kwibergd1fe2812016-04-27 13:47:2916#include <memory>
Harald Alvestrandc24a2182022-02-23 13:44:5917#include <sstream>
henrike@webrtc.org28e20752013-07-10 00:45:3618#include <string>
Yves Gerey3e707812018-11-28 15:47:4919#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:3620#include <vector>
21
Steve Anton64b626b2019-01-29 01:25:2622#include "absl/algorithm/container.h"
Piotr (Peter) Slatalab1ae10b2019-03-01 19:14:0523#include "absl/memory/memory.h"
Steve Anton1c9c9fc2019-02-14 23:13:0924#include "absl/strings/str_replace.h"
Harald Alvestrandc24a2182022-02-23 13:44:5925#include "absl/strings/string_view.h"
26#include "absl/types/optional.h"
Yves Gerey3e707812018-11-28 15:47:4927#include "api/array_view.h"
Harald Alvestrand0d018412021-11-04 13:52:3128#include "api/crypto_params.h"
Steve Anton10542f22019-01-11 17:11:0029#include "api/jsep_session_description.h"
30#include "api/media_types.h"
31#include "api/rtp_parameters.h"
Harald Alvestrandc24a2182022-02-23 13:44:5932#include "api/rtp_transceiver_direction.h"
Yves Gerey3e707812018-11-28 15:47:4933#include "media/base/codec.h"
Steve Anton10542f22019-01-11 17:11:0034#include "media/base/media_constants.h"
Harald Alvestrandc24a2182022-02-23 13:44:5935#include "media/base/rid_description.h"
Steve Anton10542f22019-01-11 17:11:0036#include "media/base/stream_params.h"
37#include "p2p/base/p2p_constants.h"
Yves Gerey665174f2018-06-19 13:03:0538#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 17:11:0039#include "p2p/base/transport_description.h"
40#include "p2p/base/transport_info.h"
Harald Alvestrandc24a2182022-02-23 13:44:5941#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 17:11:0042#include "pc/media_session.h"
43#include "pc/session_description.h"
Harald Alvestrandc24a2182022-02-23 13:44:5944#include "pc/simulcast_description.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3145#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0046#include "rtc_base/message_digest.h"
47#include "rtc_base/socket_address.h"
48#include "rtc_base/ssl_fingerprint.h"
49#include "rtc_base/string_encode.h"
Steve Anton06817cd2018-12-18 23:55:3050#include "test/gmock.h"
Yves Gerey3e707812018-11-28 15:47:4951#include "test/gtest.h"
Patrik Höglund563934e2017-09-15 07:04:2852
ossu7bb87ee2017-01-23 12:56:2553#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0054#include "pc/test/android_test_initializer.h"
ossu7bb87ee2017-01-23 12:56:2555#endif
Steve Anton10542f22019-01-11 17:11:0056#include "pc/webrtc_sdp.h"
henrike@webrtc.org28e20752013-07-10 00:45:3657
58using cricket::AudioCodec;
59using cricket::AudioContentDescription;
60using cricket::Candidate;
Steve Anton06817cd2018-12-18 23:55:3061using cricket::ContentGroup;
henrike@webrtc.org28e20752013-07-10 00:45:3662using cricket::ContentInfo;
Harald Alvestrand0d018412021-11-04 13:52:3163using cricket::CryptoParams;
henrike@webrtc.org28e20752013-07-10 00:45:3664using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
65using cricket::ICE_CANDIDATE_COMPONENT_RTP;
66using cricket::kFecSsrcGroupSemantics;
67using cricket::LOCAL_PORT_TYPE;
Steve Anton5adfafd2017-12-21 00:34:0068using cricket::MediaProtocolType;
Steve Anton06817cd2018-12-18 23:55:3069using cricket::RELAY_PORT_TYPE;
Amit Hilbuchc57d5732018-12-11 23:30:1170using cricket::RidDescription;
71using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 11:36:1672using cricket::SctpDataContentDescription;
Steve Anton06817cd2018-12-18 23:55:3073using cricket::SessionDescription;
Amit Hilbucha2012042018-12-03 19:35:0574using cricket::SimulcastDescription;
75using cricket::SimulcastLayer;
henrike@webrtc.org28e20752013-07-10 00:45:3676using cricket::StreamParams;
77using cricket::STUN_PORT_TYPE;
78using cricket::TransportDescription;
79using cricket::TransportInfo;
80using cricket::VideoCodec;
81using cricket::VideoContentDescription;
Steve Anton06817cd2018-12-18 23:55:3082using ::testing::ElementsAre;
83using ::testing::Field;
henrike@webrtc.org28e20752013-07-10 00:45:3684using webrtc::IceCandidateCollection;
85using webrtc::IceCandidateInterface;
86using webrtc::JsepIceCandidate;
87using webrtc::JsepSessionDescription;
isheriff6f8d6862016-05-26 18:24:5588using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 22:57:1089using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:3690using webrtc::SdpParseError;
Steve Antona3a92c22017-12-07 18:27:4191using webrtc::SdpType;
henrike@webrtc.org28e20752013-07-10 00:45:3692using webrtc::SessionDescriptionInterface;
93
94typedef std::vector<AudioCodec> AudioCodecs;
95typedef std::vector<Candidate> Candidates;
96
Peter Boström0c4e06b2015-10-07 10:23:2197static const uint32_t kDefaultSctpPort = 5000;
zstein4b2e0822017-02-18 03:48:3898static const uint16_t kUnusualSctpPort = 9556;
henrike@webrtc.org28e20752013-07-10 00:45:3699static const char kSessionTime[] = "t=0 0\r\n";
Peter Boström0c4e06b2015-10-07 10:23:21100static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0
deadbeef3f7219b2015-12-28 23:17:14101static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36102static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
deadbeef3f7219b2015-12-28 23:17:14103static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36104static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
Peter Boström0c4e06b2015-10-07 10:23:21105static const uint32_t kCandidateGeneration = 2;
henrike@webrtc.org28e20752013-07-10 00:45:36106static const char kCandidateFoundation1[] = "a0+B/1";
107static const char kCandidateFoundation2[] = "a0+B/2";
108static const char kCandidateFoundation3[] = "a0+B/3";
109static const char kCandidateFoundation4[] = "a0+B/4";
110static const char kAttributeCryptoVoice[] =
111 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
112 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
113 "dummy_session_params\r\n";
114static const char kAttributeCryptoVideo[] =
115 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
116 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
Yves Gerey665174f2018-06-19 13:03:05117static const char kFingerprint[] =
118 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:36119 "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 20:33:20120static const char kExtmapAllowMixed[] = "a=extmap-allow-mixed\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36121static const int kExtmapId = 1;
122static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
123static const char kExtmap[] =
124 "a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
125static const char kExtmapWithDirectionAndAttribute[] =
126 "a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
jbauch5869f502017-06-29 19:31:36127static const char kExtmapWithDirectionAndAttributeEncrypted[] =
128 "a=extmap:1/sendrecv urn:ietf:params:rtp-hdrext:encrypt "
129 "http://example.com/082005/ext.htm#ttime a1 a2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36130
Peter Boström0c4e06b2015-10-07 10:23:21131static const uint8_t kIdentityDigest[] = {
132 0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
133 0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
henrike@webrtc.org28e20752013-07-10 00:45:36134
lally@webrtc.org34807282015-02-24 20:19:39135static const char kDtlsSctp[] = "DTLS/SCTP";
136static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
137static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
lally@webrtc.org36300852015-02-24 20:19:35138
henrike@webrtc.org28e20752013-07-10 00:45:36139struct CodecParams {
140 int max_ptime;
141 int ptime;
142 int min_ptime;
143 int sprop_stereo;
144 int stereo;
145 int useinband;
henrike@webrtc.org1e09a712013-07-26 19:17:59146 int maxaveragebitrate;
henrike@webrtc.org28e20752013-07-10 00:45:36147};
148
Harald Alvestrand0d018412021-11-04 13:52:31149// TODO(deadbeef): In these reference strings, use "a=fingerprint" by default
150// instead of "a=crypto", and have an explicit test for adding "a=crypto".
151// Currently it's the other way around.
deadbeef9d3584c2016-02-17 01:54:10152
henrike@webrtc.org28e20752013-07-10 00:45:36153// Reference sdp string
154static const char kSdpFullString[] =
155 "v=0\r\n"
156 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
157 "s=-\r\n"
158 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 12:06:32159 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-17 01:54:10160 "a=msid-semantic: WMS local_stream_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36161 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
162 "c=IN IP4 74.125.127.126\r\n"
163 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
164 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
165 "generation 2\r\n"
166 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
167 "generation 2\r\n"
168 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
169 "generation 2\r\n"
170 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
171 "generation 2\r\n"
172 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
173 "raddr 192.168.1.5 rport 2346 "
174 "generation 2\r\n"
175 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
176 "raddr 192.168.1.5 rport 2348 "
177 "generation 2\r\n"
178 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
179 "a=mid:audio_content_name\r\n"
180 "a=sendrecv\r\n"
181 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 20:37:51182 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31183 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
184 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
185 "dummy_session_params\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36186 "a=rtpmap:111 opus/48000/2\r\n"
187 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41188 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36189 "a=ssrc:1 cname:stream_1_cname\r\n"
190 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36191 "m=video 3457 RTP/SAVPF 120\r\n"
192 "c=IN IP4 74.125.224.39\r\n"
193 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
194 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
195 "generation 2\r\n"
196 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
197 "generation 2\r\n"
198 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
199 "generation 2\r\n"
200 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
201 "generation 2\r\n"
202 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
203 "generation 2\r\n"
204 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
205 "generation 2\r\n"
206 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
207 "a=mid:video_content_name\r\n"
208 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31209 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
210 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36211 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-17 01:54:10212 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36213 "a=ssrc:2 cname:stream_1_cname\r\n"
214 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36215 "a=ssrc:3 cname:stream_1_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51216 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36217
218// SDP reference string without the candidates.
219static const char kSdpString[] =
220 "v=0\r\n"
221 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
222 "s=-\r\n"
223 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 12:06:32224 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-17 01:54:10225 "a=msid-semantic: WMS local_stream_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22226 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06227 "c=IN IP4 0.0.0.0\r\n"
228 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36229 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
230 "a=mid:audio_content_name\r\n"
231 "a=sendrecv\r\n"
232 "a=rtcp-mux\r\n"
deadbeef13871492015-12-09 20:37:51233 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31234 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
235 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
236 "dummy_session_params\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36237 "a=rtpmap:111 opus/48000/2\r\n"
238 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:41239 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36240 "a=ssrc:1 cname:stream_1_cname\r\n"
241 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22242 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06243 "c=IN IP4 0.0.0.0\r\n"
244 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36245 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
246 "a=mid:video_content_name\r\n"
247 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31248 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
249 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36250 "a=rtpmap:120 VP8/90000\r\n"
deadbeef9d3584c2016-02-17 01:54:10251 "a=ssrc-group:FEC 2 3\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36252 "a=ssrc:2 cname:stream_1_cname\r\n"
253 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36254 "a=ssrc:3 cname:stream_1_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51255 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36256
Harald Alvestrand5fc28b12019-05-13 11:36:16257// draft-ietf-mmusic-sctp-sdp-03
henrike@webrtc.org28e20752013-07-10 00:45:36258static const char kSdpSctpDataChannelString[] =
Guido Urdanetacecf87f2019-05-31 10:17:38259 "m=application 9 UDP/DTLS/SCTP 5000\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06260 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36261 "a=ice-ufrag:ufrag_data\r\n"
262 "a=ice-pwd:pwd_data\r\n"
263 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33264 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36265
lally@webrtc.orgec97c652015-02-24 20:18:48266// draft-ietf-mmusic-sctp-sdp-12
Harald Alvestrand48cce4d2019-04-11 08:41:24267// Note - this is invalid per draft-ietf-mmusic-sctp-sdp-26,
268// since the separator after "sctp-port" needs to be a colon.
jiayl@webrtc.orgddb85ab2014-09-05 16:31:56269static const char kSdpSctpDataChannelStringWithSctpPort[] =
Guido Urdanetacecf87f2019-05-31 10:17:38270 "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
lally@webrtc.orgc7848b72015-02-24 20:19:26271 "a=sctp-port 5000\r\n"
272 "c=IN IP4 0.0.0.0\r\n"
273 "a=ice-ufrag:ufrag_data\r\n"
274 "a=ice-pwd:pwd_data\r\n"
275 "a=mid:data_content_name\r\n";
276
Harald Alvestrand48cce4d2019-04-11 08:41:24277// draft-ietf-mmusic-sctp-sdp-26
lally69f57602015-10-08 17:15:04278static const char kSdpSctpDataChannelStringWithSctpColonPort[] =
Guido Urdanetacecf87f2019-05-31 10:17:38279 "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
lally69f57602015-10-08 17:15:04280 "a=sctp-port:5000\r\n"
281 "c=IN IP4 0.0.0.0\r\n"
282 "a=ice-ufrag:ufrag_data\r\n"
283 "a=ice-pwd:pwd_data\r\n"
284 "a=mid:data_content_name\r\n";
285
henrike@webrtc.org28e20752013-07-10 00:45:36286static const char kSdpSctpDataChannelWithCandidatesString[] =
Guido Urdanetacecf87f2019-05-31 10:17:38287 "m=application 2345 UDP/DTLS/SCTP 5000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:36288 "c=IN IP4 74.125.127.126\r\n"
289 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
290 "generation 2\r\n"
291 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
292 "generation 2\r\n"
293 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
294 "raddr 192.168.1.5 rport 2346 "
295 "generation 2\r\n"
296 "a=ice-ufrag:ufrag_data\r\n"
297 "a=ice-pwd:pwd_data\r\n"
298 "a=mid:data_content_name\r\n"
wu@webrtc.org97077a32013-10-25 21:18:33299 "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36300
jiayl@webrtc.org9c16c392014-05-01 18:30:30301static const char kSdpConferenceString[] =
henrike@webrtc.org704bf9e2014-02-27 17:52:04302 "v=0\r\n"
303 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
304 "s=-\r\n"
305 "t=0 0\r\n"
306 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22307 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06308 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04309 "a=x-google-flag:conference\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22310 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06311 "c=IN IP4 0.0.0.0\r\n"
henrike@webrtc.org704bf9e2014-02-27 17:52:04312 "a=x-google-flag:conference\r\n";
313
jiayl@webrtc.orge7d47a12014-08-05 19:19:05314static const char kSdpSessionString[] =
315 "v=0\r\n"
316 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
317 "s=-\r\n"
318 "t=0 0\r\n"
319 "a=msid-semantic: WMS local_stream\r\n";
320
321static const char kSdpAudioString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22322 "m=audio 9 RTP/SAVPF 111\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06323 "c=IN IP4 0.0.0.0\r\n"
324 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05325 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
326 "a=mid:audio_content_name\r\n"
327 "a=sendrecv\r\n"
328 "a=rtpmap:111 opus/48000/2\r\n"
329 "a=ssrc:1 cname:stream_1_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51330 "a=ssrc:1 msid:local_stream audio_track_id_1\r\n";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05331
332static const char kSdpVideoString[] =
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:22333 "m=video 9 RTP/SAVPF 120\r\n"
perkj@webrtc.orgd105cc82014-11-07 11:22:06334 "c=IN IP4 0.0.0.0\r\n"
335 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
jiayl@webrtc.orge7d47a12014-08-05 19:19:05336 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
337 "a=mid:video_content_name\r\n"
338 "a=sendrecv\r\n"
339 "a=rtpmap:120 VP8/90000\r\n"
340 "a=ssrc:2 cname:stream_1_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51341 "a=ssrc:2 msid:local_stream video_track_id_1\r\n";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05342
deadbeef25ed4352016-12-13 02:37:36343// Reference sdp string using bundle-only.
344static const char kBundleOnlySdpFullString[] =
345 "v=0\r\n"
346 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
347 "s=-\r\n"
348 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 12:06:32349 "a=extmap-allow-mixed\r\n"
deadbeef25ed4352016-12-13 02:37:36350 "a=group:BUNDLE audio_content_name video_content_name\r\n"
351 "a=msid-semantic: WMS local_stream_1\r\n"
352 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
353 "c=IN IP4 74.125.127.126\r\n"
354 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
355 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
356 "generation 2\r\n"
357 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
358 "generation 2\r\n"
359 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
360 "generation 2\r\n"
361 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
362 "generation 2\r\n"
363 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
364 "raddr 192.168.1.5 rport 2346 "
365 "generation 2\r\n"
366 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
367 "raddr 192.168.1.5 rport 2348 "
368 "generation 2\r\n"
369 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
370 "a=mid:audio_content_name\r\n"
371 "a=sendrecv\r\n"
372 "a=rtcp-mux\r\n"
373 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31374 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
375 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
376 "dummy_session_params\r\n"
deadbeef25ed4352016-12-13 02:37:36377 "a=rtpmap:111 opus/48000/2\r\n"
378 "a=rtpmap:103 ISAC/16000\r\n"
379 "a=rtpmap:104 ISAC/32000\r\n"
380 "a=ssrc:1 cname:stream_1_cname\r\n"
381 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
deadbeef25ed4352016-12-13 02:37:36382 "m=video 0 RTP/SAVPF 120\r\n"
383 "c=IN IP4 0.0.0.0\r\n"
384 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
385 "a=bundle-only\r\n"
386 "a=mid:video_content_name\r\n"
387 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31388 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
389 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
deadbeef25ed4352016-12-13 02:37:36390 "a=rtpmap:120 VP8/90000\r\n"
391 "a=ssrc-group:FEC 2 3\r\n"
392 "a=ssrc:2 cname:stream_1_cname\r\n"
393 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
deadbeef25ed4352016-12-13 02:37:36394 "a=ssrc:3 cname:stream_1_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51395 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n";
deadbeef25ed4352016-12-13 02:37:36396
deadbeef9d3584c2016-02-17 01:54:10397// 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 12:06:32404 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-17 01:54:10405 "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"
Harald Alvestrand0d018412021-11-04 13:52:31428 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
429 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
430 "dummy_session_params\r\n"
deadbeef9d3584c2016-02-17 01:54:10431 "a=rtpmap:111 opus/48000/2\r\n"
432 "a=rtpmap:103 ISAC/16000\r\n"
433 "a=rtpmap:104 ISAC/32000\r\n"
434 "a=ssrc:1 cname:stream_1_cname\r\n"
435 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
deadbeef9d3584c2016-02-17 01:54:10436 "a=ssrc:4 cname:stream_2_cname\r\n"
437 "a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
deadbeef9d3584c2016-02-17 01:54:10438 "m=video 3457 RTP/SAVPF 120\r\n"
439 "c=IN IP4 74.125.224.39\r\n"
440 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
441 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
442 "generation 2\r\n"
443 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
444 "generation 2\r\n"
445 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
446 "generation 2\r\n"
447 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
448 "generation 2\r\n"
449 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
450 "generation 2\r\n"
451 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
452 "generation 2\r\n"
453 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
454 "a=mid:video_content_name\r\n"
455 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31456 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
457 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
deadbeef9d3584c2016-02-17 01:54:10458 "a=rtpmap:120 VP8/90000\r\n"
459 "a=ssrc-group:FEC 2 3\r\n"
460 "a=ssrc:2 cname:stream_1_cname\r\n"
461 "a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
deadbeef9d3584c2016-02-17 01:54:10462 "a=ssrc:3 cname:stream_1_cname\r\n"
463 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
deadbeef9d3584c2016-02-17 01:54:10464 "a=ssrc:5 cname:stream_2_cname\r\n"
465 "a=ssrc:5 msid:local_stream_2 video_track_id_2\r\n"
deadbeef9d3584c2016-02-17 01:54:10466 "a=ssrc:6 cname:stream_2_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51467 "a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n";
deadbeef9d3584c2016-02-17 01:54:10468
469// Unified Plan SDP reference string, with 2 streams, 2 audio tracks and 3 video
470// tracks.
471static const char kUnifiedPlanSdpFullString[] =
472 "v=0\r\n"
473 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
474 "s=-\r\n"
475 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 12:06:32476 "a=extmap-allow-mixed\r\n"
deadbeef9d3584c2016-02-17 01:54:10477 "a=msid-semantic: WMS local_stream_1\r\n"
478 // Audio track 1, stream 1 (with candidates).
479 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
480 "c=IN IP4 74.125.127.126\r\n"
481 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
482 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
483 "generation 2\r\n"
484 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
485 "generation 2\r\n"
486 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
487 "generation 2\r\n"
488 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
489 "generation 2\r\n"
490 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
491 "raddr 192.168.1.5 rport 2346 "
492 "generation 2\r\n"
493 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
494 "raddr 192.168.1.5 rport 2348 "
495 "generation 2\r\n"
496 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
497 "a=mid:audio_content_name\r\n"
498 "a=msid:local_stream_1 audio_track_id_1\r\n"
499 "a=sendrecv\r\n"
500 "a=rtcp-mux\r\n"
501 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31502 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
503 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
504 "dummy_session_params\r\n"
deadbeef9d3584c2016-02-17 01:54:10505 "a=rtpmap:111 opus/48000/2\r\n"
506 "a=rtpmap:103 ISAC/16000\r\n"
507 "a=rtpmap:104 ISAC/32000\r\n"
508 "a=ssrc:1 cname:stream_1_cname\r\n"
509 // Video track 1, stream 1 (with candidates).
510 "m=video 3457 RTP/SAVPF 120\r\n"
511 "c=IN IP4 74.125.224.39\r\n"
512 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
513 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
514 "generation 2\r\n"
515 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
516 "generation 2\r\n"
517 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
518 "generation 2\r\n"
519 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
520 "generation 2\r\n"
521 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
522 "generation 2\r\n"
523 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
524 "generation 2\r\n"
525 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
526 "a=mid:video_content_name\r\n"
527 "a=msid:local_stream_1 video_track_id_1\r\n"
528 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31529 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
530 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
deadbeef9d3584c2016-02-17 01:54:10531 "a=rtpmap:120 VP8/90000\r\n"
532 "a=ssrc-group:FEC 2 3\r\n"
533 "a=ssrc:2 cname:stream_1_cname\r\n"
534 "a=ssrc:3 cname:stream_1_cname\r\n"
535 // Audio track 2, stream 2.
536 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
537 "c=IN IP4 0.0.0.0\r\n"
538 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
539 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
540 "a=mid:audio_content_name_2\r\n"
541 "a=msid:local_stream_2 audio_track_id_2\r\n"
542 "a=sendrecv\r\n"
543 "a=rtcp-mux\r\n"
544 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31545 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
546 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
547 "dummy_session_params\r\n"
deadbeef9d3584c2016-02-17 01:54:10548 "a=rtpmap:111 opus/48000/2\r\n"
549 "a=rtpmap:103 ISAC/16000\r\n"
550 "a=rtpmap:104 ISAC/32000\r\n"
551 "a=ssrc:4 cname:stream_2_cname\r\n"
552 // Video track 2, stream 2.
553 "m=video 9 RTP/SAVPF 120\r\n"
554 "c=IN IP4 0.0.0.0\r\n"
555 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
556 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
557 "a=mid:video_content_name_2\r\n"
558 "a=msid:local_stream_2 video_track_id_2\r\n"
559 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31560 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
561 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
deadbeef9d3584c2016-02-17 01:54:10562 "a=rtpmap:120 VP8/90000\r\n"
563 "a=ssrc:5 cname:stream_2_cname\r\n"
564 // Video track 3, stream 2.
565 "m=video 9 RTP/SAVPF 120\r\n"
566 "c=IN IP4 0.0.0.0\r\n"
567 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
568 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
569 "a=mid:video_content_name_3\r\n"
570 "a=msid:local_stream_2 video_track_id_3\r\n"
571 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31572 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
573 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
deadbeef9d3584c2016-02-17 01:54:10574 "a=rtpmap:120 VP8/90000\r\n"
575 "a=ssrc:6 cname:stream_2_cname\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36576
Seth Hampson5b4f0752018-04-02 23:31:36577// Unified Plan SDP reference string:
578// - audio track 1 has 1 a=msid lines
579// - audio track 2 has 2 a=msid lines
580// - audio track 3 has 1 a=msid line with the special "-" marker signifying that
581// there are 0 media stream ids.
582// This Unified Plan SDP represents a SDP that signals the msid using both
583// a=msid and a=ssrc msid semantics.
584static const char kUnifiedPlanSdpFullStringWithSpecialMsid[] =
585 "v=0\r\n"
586 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
587 "s=-\r\n"
588 "t=0 0\r\n"
Emil Lundmark801c9992021-01-19 12:06:32589 "a=extmap-allow-mixed\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36590 "a=msid-semantic: WMS local_stream_1\r\n"
591 // Audio track 1, with 1 stream id.
592 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
593 "c=IN IP4 74.125.127.126\r\n"
594 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
595 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
596 "generation 2\r\n"
597 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
598 "generation 2\r\n"
599 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
600 "generation 2\r\n"
601 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
602 "generation 2\r\n"
603 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
604 "raddr 192.168.1.5 rport 2346 "
605 "generation 2\r\n"
606 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
607 "raddr 192.168.1.5 rport 2348 "
608 "generation 2\r\n"
609 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
610 "a=mid:audio_content_name\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36611 "a=sendrecv\r\n"
Seth Hampson7fa6ee62018-10-17 17:25:28612 "a=msid:local_stream_1 audio_track_id_1\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36613 "a=rtcp-mux\r\n"
614 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31615 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
616 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
617 "dummy_session_params\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36618 "a=rtpmap:111 opus/48000/2\r\n"
619 "a=rtpmap:103 ISAC/16000\r\n"
620 "a=rtpmap:104 ISAC/32000\r\n"
621 "a=ssrc:1 cname:stream_1_cname\r\n"
622 "a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36623 // Audio track 2, with two stream ids.
624 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
625 "c=IN IP4 0.0.0.0\r\n"
626 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
627 "a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
628 "a=mid:audio_content_name_2\r\n"
Seth Hampson7fa6ee62018-10-17 17:25:28629 "a=sendrecv\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36630 "a=msid:local_stream_1 audio_track_id_2\r\n"
631 "a=msid:local_stream_2 audio_track_id_2\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36632 "a=rtcp-mux\r\n"
633 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31634 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
635 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
636 "dummy_session_params\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36637 "a=rtpmap:111 opus/48000/2\r\n"
638 "a=rtpmap:103 ISAC/16000\r\n"
639 "a=rtpmap:104 ISAC/32000\r\n"
640 "a=ssrc:4 cname:stream_1_cname\r\n"
641 // The support for Plan B msid signaling only includes the
642 // first media stream id "local_stream_1."
643 "a=ssrc:4 msid:local_stream_1 audio_track_id_2\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36644 // Audio track 3, with no stream ids.
645 "m=audio 9 RTP/SAVPF 111 103 104\r\n"
646 "c=IN IP4 0.0.0.0\r\n"
647 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
648 "a=ice-ufrag:ufrag_voice_3\r\na=ice-pwd:pwd_voice_3\r\n"
649 "a=mid:audio_content_name_3\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36650 "a=sendrecv\r\n"
Seth Hampson7fa6ee62018-10-17 17:25:28651 "a=msid:- audio_track_id_3\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36652 "a=rtcp-mux\r\n"
653 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31654 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
655 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
656 "dummy_session_params\r\n"
Seth Hampson5b4f0752018-04-02 23:31:36657 "a=rtpmap:111 opus/48000/2\r\n"
658 "a=rtpmap:103 ISAC/16000\r\n"
659 "a=rtpmap:104 ISAC/32000\r\n"
Seth Hampson7fa6ee62018-10-17 17:25:28660 "a=ssrc:7 cname:stream_2_cname\r\n"
Harald Alvestrand88b8dec12022-04-07 09:54:51661 "a=ssrc:7 msid:- audio_track_id_3\r\n";
Seth Hampson5b4f0752018-04-02 23:31:36662
Amit Hilbuchc57d5732018-12-11 23:30:11663// SDP string for unified plan without SSRCs
664static const char kUnifiedPlanSdpFullStringNoSsrc[] =
665 "v=0\r\n"
666 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
667 "s=-\r\n"
668 "t=0 0\r\n"
669 "a=msid-semantic: WMS local_stream_1\r\n"
670 // Audio track 1, stream 1 (with candidates).
671 "m=audio 2345 RTP/SAVPF 111 103 104\r\n"
672 "c=IN IP4 74.125.127.126\r\n"
673 "a=rtcp:2347 IN IP4 74.125.127.126\r\n"
674 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
675 "generation 2\r\n"
676 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
677 "generation 2\r\n"
678 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
679 "generation 2\r\n"
680 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
681 "generation 2\r\n"
682 "a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
683 "raddr 192.168.1.5 rport 2346 "
684 "generation 2\r\n"
685 "a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
686 "raddr 192.168.1.5 rport 2348 "
687 "generation 2\r\n"
688 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
689 "a=mid:audio_content_name\r\n"
690 "a=msid:local_stream_1 audio_track_id_1\r\n"
691 "a=sendrecv\r\n"
692 "a=rtcp-mux\r\n"
693 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31694 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
695 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
696 "dummy_session_params\r\n"
Amit Hilbuchc57d5732018-12-11 23:30:11697 "a=rtpmap:111 opus/48000/2\r\n"
698 "a=rtpmap:103 ISAC/16000\r\n"
699 "a=rtpmap:104 ISAC/32000\r\n"
700 // Video track 1, stream 1 (with candidates).
701 "m=video 3457 RTP/SAVPF 120\r\n"
702 "c=IN IP4 74.125.224.39\r\n"
703 "a=rtcp:3456 IN IP4 74.125.224.39\r\n"
704 "a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
705 "generation 2\r\n"
706 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
707 "generation 2\r\n"
708 "a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
709 "generation 2\r\n"
710 "a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
711 "generation 2\r\n"
712 "a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
713 "generation 2\r\n"
714 "a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
715 "generation 2\r\n"
716 "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
717 "a=mid:video_content_name\r\n"
718 "a=msid:local_stream_1 video_track_id_1\r\n"
719 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31720 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
721 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
Amit Hilbuchc57d5732018-12-11 23:30:11722 "a=rtpmap:120 VP8/90000\r\n"
723 // Audio track 2, stream 2.
724 "m=audio 9 RTP/SAVPF 111 103 104\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_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
728 "a=mid:audio_content_name_2\r\n"
729 "a=msid:local_stream_2 audio_track_id_2\r\n"
730 "a=sendrecv\r\n"
731 "a=rtcp-mux\r\n"
732 "a=rtcp-rsize\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31733 "a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
734 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
735 "dummy_session_params\r\n"
Amit Hilbuchc57d5732018-12-11 23:30:11736 "a=rtpmap:111 opus/48000/2\r\n"
737 "a=rtpmap:103 ISAC/16000\r\n"
738 "a=rtpmap:104 ISAC/32000\r\n"
739 // Video track 2, stream 2.
740 "m=video 9 RTP/SAVPF 120\r\n"
741 "c=IN IP4 0.0.0.0\r\n"
742 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
743 "a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
744 "a=mid:video_content_name_2\r\n"
745 "a=msid:local_stream_2 video_track_id_2\r\n"
746 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31747 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
748 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
Amit Hilbuchc57d5732018-12-11 23:30:11749 "a=rtpmap:120 VP8/90000\r\n"
750 // Video track 3, stream 2.
751 "m=video 9 RTP/SAVPF 120\r\n"
752 "c=IN IP4 0.0.0.0\r\n"
753 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
754 "a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
755 "a=mid:video_content_name_3\r\n"
756 "a=msid:local_stream_2 video_track_id_3\r\n"
757 "a=sendrecv\r\n"
Harald Alvestrand0d018412021-11-04 13:52:31758 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
759 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
Amit Hilbuchc57d5732018-12-11 23:30:11760 "a=rtpmap:120 VP8/90000\r\n";
761
henrike@webrtc.org28e20752013-07-10 00:45:36762// One candidate reference string as per W3c spec.
763// candidate:<blah> not a=candidate:<blah>CRLF
764static const char kRawCandidate[] =
765 "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
766// One candidate reference string.
767static const char kSdpOneCandidate[] =
768 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
769 "generation 2\r\n";
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15770
mallinath@webrtc.org2d60c5e2014-08-08 22:29:20771static const char kSdpTcpActiveCandidate[] =
772 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
773 "tcptype active generation 2";
774static const char kSdpTcpPassiveCandidate[] =
775 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
776 "tcptype passive generation 2";
777static const char kSdpTcpSOCandidate[] =
778 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
779 "tcptype so generation 2";
780static const char kSdpTcpInvalidCandidate[] =
781 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
782 "tcptype invalid generation 2";
783
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:15784// One candidate reference string with IPV6 address.
785static const char kRawIPV6Candidate[] =
786 "candidate:a0+B/1 1 udp 2130706432 "
ehmaldonado121cabb2017-05-05 19:04:36787 "abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd 1234 typ host generation 2";
henrike@webrtc.org28e20752013-07-10 00:45:36788
789// One candidate reference string.
honghaiza54a0802015-12-17 02:37:23790static const char kSdpOneCandidateWithUfragPwd[] =
henrike@webrtc.org28e20752013-07-10 00:45:36791 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
honghaiza54a0802015-12-17 02:37:23792 " eth0 ufrag user_rtp pwd password_rtp generation 2\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:36793
Zach Steinb336c272018-08-09 08:16:13794static const char kRawHostnameCandidate[] =
795 "candidate:a0+B/1 1 udp 2130706432 a.test 1234 typ host generation 2";
796
henrike@webrtc.org28e20752013-07-10 00:45:36797// Session id and version
798static const char kSessionId[] = "18446744069414584320";
799static const char kSessionVersion[] = "18446462598732840960";
800
deadbeef9d3584c2016-02-17 01:54:10801// ICE options.
henrike@webrtc.org28e20752013-07-10 00:45:36802static const char kIceOption1[] = "iceoption1";
803static const char kIceOption2[] = "iceoption2";
804static const char kIceOption3[] = "iceoption3";
805
deadbeef9d3584c2016-02-17 01:54:10806// ICE ufrags/passwords.
807static const char kUfragVoice[] = "ufrag_voice";
808static const char kPwdVoice[] = "pwd_voice";
809static const char kUfragVideo[] = "ufrag_video";
810static const char kPwdVideo[] = "pwd_video";
811static const char kUfragData[] = "ufrag_data";
812static const char kPwdData[] = "pwd_data";
813
814// Extra ufrags/passwords for extra unified plan m= sections.
815static const char kUfragVoice2[] = "ufrag_voice_2";
816static const char kPwdVoice2[] = "pwd_voice_2";
Seth Hampson5b4f0752018-04-02 23:31:36817static const char kUfragVoice3[] = "ufrag_voice_3";
818static const char kPwdVoice3[] = "pwd_voice_3";
deadbeef9d3584c2016-02-17 01:54:10819static const char kUfragVideo2[] = "ufrag_video_2";
820static const char kPwdVideo2[] = "pwd_video_2";
821static const char kUfragVideo3[] = "ufrag_video_3";
822static const char kPwdVideo3[] = "pwd_video_3";
823
henrike@webrtc.org28e20752013-07-10 00:45:36824// Content name
825static const char kAudioContentName[] = "audio_content_name";
826static const char kVideoContentName[] = "video_content_name";
827static const char kDataContentName[] = "data_content_name";
828
deadbeef9d3584c2016-02-17 01:54:10829// Extra content names for extra unified plan m= sections.
830static const char kAudioContentName2[] = "audio_content_name_2";
Seth Hampson5b4f0752018-04-02 23:31:36831static const char kAudioContentName3[] = "audio_content_name_3";
deadbeef9d3584c2016-02-17 01:54:10832static const char kVideoContentName2[] = "video_content_name_2";
833static const char kVideoContentName3[] = "video_content_name_3";
834
henrike@webrtc.org28e20752013-07-10 00:45:36835// MediaStream 1
Seth Hampson845e8782018-03-02 19:34:10836static const char kStreamId1[] = "local_stream_1";
henrike@webrtc.org28e20752013-07-10 00:45:36837static const char kStream1Cname[] = "stream_1_cname";
838static const char kAudioTrackId1[] = "audio_track_id_1";
Peter Boström0c4e06b2015-10-07 10:23:21839static const uint32_t kAudioTrack1Ssrc = 1;
henrike@webrtc.org28e20752013-07-10 00:45:36840static const char kVideoTrackId1[] = "video_track_id_1";
deadbeef9d3584c2016-02-17 01:54:10841static const uint32_t kVideoTrack1Ssrc1 = 2;
842static const uint32_t kVideoTrack1Ssrc2 = 3;
henrike@webrtc.org28e20752013-07-10 00:45:36843
844// MediaStream 2
Seth Hampson845e8782018-03-02 19:34:10845static const char kStreamId2[] = "local_stream_2";
henrike@webrtc.org28e20752013-07-10 00:45:36846static const char kStream2Cname[] = "stream_2_cname";
847static const char kAudioTrackId2[] = "audio_track_id_2";
Peter Boström0c4e06b2015-10-07 10:23:21848static const uint32_t kAudioTrack2Ssrc = 4;
deadbeef9d3584c2016-02-17 01:54:10849static const char kVideoTrackId2[] = "video_track_id_2";
850static const uint32_t kVideoTrack2Ssrc = 5;
henrike@webrtc.org28e20752013-07-10 00:45:36851static const char kVideoTrackId3[] = "video_track_id_3";
deadbeef9d3584c2016-02-17 01:54:10852static const uint32_t kVideoTrack3Ssrc = 6;
Seth Hampson5b4f0752018-04-02 23:31:36853static const char kAudioTrackId3[] = "audio_track_id_3";
854static const uint32_t kAudioTrack3Ssrc = 7;
henrike@webrtc.org28e20752013-07-10 00:45:36855
henrike@webrtc.org28e20752013-07-10 00:45:36856// Candidate
857static const char kDummyMid[] = "dummy_mid";
858static const int kDummyIndex = 123;
859
860// Misc
Steve Antona3a92c22017-12-07 18:27:41861static SdpType kDummyType = SdpType::kOffer;
henrike@webrtc.org28e20752013-07-10 00:45:36862
863// Helper functions
864
865static bool SdpDeserialize(const std::string& message,
866 JsepSessionDescription* jdesc) {
867 return webrtc::SdpDeserialize(message, jdesc, NULL);
868}
869
870static bool SdpDeserializeCandidate(const std::string& message,
871 JsepIceCandidate* candidate) {
872 return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
873}
874
Artem Titov880fa812021-07-30 20:30:23875// Add some extra `newlines` to the `message` after `line`.
henrike@webrtc.org28e20752013-07-10 00:45:36876static void InjectAfter(const std::string& line,
877 const std::string& newlines,
878 std::string* message) {
Steve Anton1c9c9fc2019-02-14 23:13:09879 absl::StrReplaceAll({{line, line + newlines}}, message);
henrike@webrtc.org28e20752013-07-10 00:45:36880}
881
882static void Replace(const std::string& line,
883 const std::string& newlines,
884 std::string* message) {
Steve Anton1c9c9fc2019-02-14 23:13:09885 absl::StrReplaceAll({{line, newlines}}, message);
henrike@webrtc.org28e20752013-07-10 00:45:36886}
887
Artem Titov880fa812021-07-30 20:30:23888// Expect a parse failure on the line containing `bad_part` when attempting to
889// parse `bad_sdp`.
wu@webrtc.org5e760e72014-04-02 23:19:09890static void ExpectParseFailure(const std::string& bad_sdp,
891 const std::string& bad_part) {
Steve Antona3a92c22017-12-07 18:27:41892 JsepSessionDescription desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:36893 SdpParseError error;
wu@webrtc.org5e760e72014-04-02 23:19:09894 bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
Harald Alvestrand99bcf602021-03-03 07:44:39895 ASSERT_FALSE(ret);
896 EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()))
897 << "Did not find " << bad_part << " in " << error.line;
wu@webrtc.org5e760e72014-04-02 23:19:09898}
899
Artem Titov880fa812021-07-30 20:30:23900// Expect fail to parse kSdpFullString if replace `good_part` with `bad_part`.
wu@webrtc.org5e760e72014-04-02 23:19:09901static void ExpectParseFailure(const char* good_part, const char* bad_part) {
902 std::string bad_sdp = kSdpFullString;
903 Replace(good_part, bad_part, &bad_sdp);
904 ExpectParseFailure(bad_sdp, bad_part);
905}
906
Artem Titov880fa812021-07-30 20:30:23907// Expect fail to parse kSdpFullString if add `newlines` after `injectpoint`.
wu@webrtc.org5e760e72014-04-02 23:19:09908static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
909 const std::string& newlines,
910 const std::string& bad_part) {
911 std::string bad_sdp = kSdpFullString;
912 InjectAfter(injectpoint, newlines, &bad_sdp);
913 ExpectParseFailure(bad_sdp, bad_part);
henrike@webrtc.org28e20752013-07-10 00:45:36914}
915
Steve Anton4e70a722017-11-28 22:57:10916static void ReplaceDirection(RtpTransceiverDirection direction,
henrike@webrtc.org28e20752013-07-10 00:45:36917 std::string* message) {
918 std::string new_direction;
919 switch (direction) {
Steve Anton4e70a722017-11-28 22:57:10920 case RtpTransceiverDirection::kInactive:
henrike@webrtc.org28e20752013-07-10 00:45:36921 new_direction = "a=inactive";
922 break;
Steve Anton4e70a722017-11-28 22:57:10923 case RtpTransceiverDirection::kSendOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36924 new_direction = "a=sendonly";
925 break;
Steve Anton4e70a722017-11-28 22:57:10926 case RtpTransceiverDirection::kRecvOnly:
henrike@webrtc.org28e20752013-07-10 00:45:36927 new_direction = "a=recvonly";
928 break;
Steve Anton4e70a722017-11-28 22:57:10929 case RtpTransceiverDirection::kSendRecv:
Markus Handell45c104b2020-03-11 09:51:13930 new_direction = "a=sendrecv";
931 break;
932 case RtpTransceiverDirection::kStopped:
henrike@webrtc.org28e20752013-07-10 00:45:36933 default:
Artem Titovd3251962021-11-15 15:57:07934 RTC_DCHECK_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36935 new_direction = "a=sendrecv";
936 break;
937 }
938 Replace("a=sendrecv", new_direction, message);
939}
940
Yves Gerey665174f2018-06-19 13:03:05941static void ReplaceRejected(bool audio_rejected,
942 bool video_rejected,
henrike@webrtc.org28e20752013-07-10 00:45:36943 std::string* message) {
944 if (audio_rejected) {
deadbeef3f7219b2015-12-28 23:17:14945 Replace("m=audio 9", "m=audio 0", message);
946 Replace(kAttributeIceUfragVoice, "", message);
947 Replace(kAttributeIcePwdVoice, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36948 }
949 if (video_rejected) {
deadbeef3f7219b2015-12-28 23:17:14950 Replace("m=video 9", "m=video 0", message);
951 Replace(kAttributeIceUfragVideo, "", message);
952 Replace(kAttributeIcePwdVideo, "", message);
henrike@webrtc.org28e20752013-07-10 00:45:36953 }
954}
955
956// WebRtcSdpTest
957
Mirko Bonadei6a489f22019-04-09 13:11:12958class WebRtcSdpTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36959 public:
Steve Antona3a92c22017-12-07 18:27:41960 WebRtcSdpTest() : jdesc_(kDummyType) {
phoglund37ebcf02016-01-08 13:04:57961#ifdef WEBRTC_ANDROID
962 webrtc::InitializeAndroidObjects();
963#endif
henrike@webrtc.org28e20752013-07-10 00:45:36964 // AudioContentDescription
965 audio_desc_ = CreateAudioContentDescription();
deadbeef9d3584c2016-02-17 01:54:10966 StreamParams audio_stream;
967 audio_stream.id = kAudioTrackId1;
968 audio_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 19:34:10969 audio_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-17 01:54:10970 audio_stream.ssrcs.push_back(kAudioTrack1Ssrc);
971 audio_desc_->AddStream(audio_stream);
zhihuang38989e52017-03-21 18:04:53972 rtc::SocketAddress audio_addr("74.125.127.126", 2345);
973 audio_desc_->set_connection_address(audio_addr);
Harald Alvestrand1716d392019-06-03 18:35:45974 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
975 absl::WrapUnique(audio_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36976
977 // VideoContentDescription
deadbeef9d3584c2016-02-17 01:54:10978 video_desc_ = CreateVideoContentDescription();
979 StreamParams video_stream;
980 video_stream.id = kVideoTrackId1;
981 video_stream.cname = kStream1Cname;
Seth Hampson845e8782018-03-02 19:34:10982 video_stream.set_stream_ids({kStreamId1});
deadbeef9d3584c2016-02-17 01:54:10983 video_stream.ssrcs.push_back(kVideoTrack1Ssrc1);
984 video_stream.ssrcs.push_back(kVideoTrack1Ssrc2);
985 cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream.ssrcs);
986 video_stream.ssrc_groups.push_back(ssrc_group);
987 video_desc_->AddStream(video_stream);
zhihuang38989e52017-03-21 18:04:53988 rtc::SocketAddress video_addr("74.125.224.39", 3457);
989 video_desc_->set_connection_address(video_addr);
Harald Alvestrand1716d392019-06-03 18:35:45990 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
991 absl::WrapUnique(video_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:36992
993 // TransportInfo
Steve Anton06817cd2018-12-18 23:55:30994 desc_.AddTransportInfo(TransportInfo(
995 kAudioContentName, TransportDescription(kUfragVoice, kPwdVoice)));
996 desc_.AddTransportInfo(TransportInfo(
997 kVideoContentName, TransportDescription(kUfragVideo, kPwdVideo)));
henrike@webrtc.org28e20752013-07-10 00:45:36998
999 // v4 host
1000 int port = 1234;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:521001 rtc::SocketAddress address("192.168.1.5", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071002 Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:311003 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1004 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:361005 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071006 Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:311007 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1008 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:361009 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071010 Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:311011 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1012 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:361013 address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071014 Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
guoweis@webrtc.org950c5182014-12-16 23:01:311015 kCandidatePriority, "", "", LOCAL_PORT_TYPE,
1016 kCandidateGeneration, kCandidateFoundation1);
henrike@webrtc.org28e20752013-07-10 00:45:361017
1018 // v6 host
buildbot@webrtc.orgd4e598d2014-07-29 17:36:521019 rtc::SocketAddress v6_address("::1", port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071020 cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1021 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:311022 cricket::LOCAL_PORT_TYPE,
1023 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:361024 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071025 cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1026 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:311027 cricket::LOCAL_PORT_TYPE,
1028 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:361029 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071030 cricket::Candidate candidate7(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1031 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:311032 cricket::LOCAL_PORT_TYPE,
1033 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:361034 v6_address.SetPort(port++);
guoweis@webrtc.org61c12472015-01-15 06:53:071035 cricket::Candidate candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1036 v6_address, kCandidatePriority, "", "",
guoweis@webrtc.org950c5182014-12-16 23:01:311037 cricket::LOCAL_PORT_TYPE,
1038 kCandidateGeneration, kCandidateFoundation2);
henrike@webrtc.org28e20752013-07-10 00:45:361039
1040 // stun
1041 int port_stun = 2345;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:521042 rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
1043 rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:071044 cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1045 address_stun, kCandidatePriority, "", "",
1046 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:311047 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:361048 candidate9.set_related_address(rel_address_stun);
1049
1050 address_stun.SetPort(port_stun++);
1051 rel_address_stun.SetPort(port_stun++);
guoweis@webrtc.org61c12472015-01-15 06:53:071052 cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1053 address_stun, kCandidatePriority, "", "",
1054 STUN_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:311055 kCandidateFoundation3);
henrike@webrtc.org28e20752013-07-10 00:45:361056 candidate10.set_related_address(rel_address_stun);
1057
1058 // relay
1059 int port_relay = 3456;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:521060 rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:071061 cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
1062 address_relay, kCandidatePriority, "", "",
1063 cricket::RELAY_PORT_TYPE,
guoweis@webrtc.org950c5182014-12-16 23:01:311064 kCandidateGeneration, kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:361065 address_relay.SetPort(port_relay++);
guoweis@webrtc.org61c12472015-01-15 06:53:071066 cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
1067 address_relay, kCandidatePriority, "", "",
1068 RELAY_PORT_TYPE, kCandidateGeneration,
guoweis@webrtc.org950c5182014-12-16 23:01:311069 kCandidateFoundation4);
henrike@webrtc.org28e20752013-07-10 00:45:361070
1071 // voice
1072 candidates_.push_back(candidate1);
1073 candidates_.push_back(candidate2);
1074 candidates_.push_back(candidate5);
1075 candidates_.push_back(candidate6);
1076 candidates_.push_back(candidate9);
1077 candidates_.push_back(candidate10);
1078
1079 // video
1080 candidates_.push_back(candidate3);
1081 candidates_.push_back(candidate4);
1082 candidates_.push_back(candidate7);
1083 candidates_.push_back(candidate8);
1084 candidates_.push_back(candidate11);
1085 candidates_.push_back(candidate12);
1086
Yves Gerey665174f2018-06-19 13:03:051087 jcandidate_.reset(
1088 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate1));
henrike@webrtc.org28e20752013-07-10 00:45:361089
1090 // Set up JsepSessionDescription.
Harald Alvestrand4d7160e2019-04-12 05:01:291091 jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
henrike@webrtc.org28e20752013-07-10 00:45:361092 std::string mline_id;
1093 int mline_index = 0;
Yves Gerey665174f2018-06-19 13:03:051094 for (size_t i = 0; i < candidates_.size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:361095 // In this test, the audio m line index will be 0, and the video m line
1096 // will be 1.
1097 bool is_video = (i > 5);
1098 mline_id = is_video ? "video_content_name" : "audio_content_name";
1099 mline_index = is_video ? 1 : 0;
Yves Gerey665174f2018-06-19 13:03:051100 JsepIceCandidate jice(mline_id, mline_index, candidates_.at(i));
henrike@webrtc.org28e20752013-07-10 00:45:361101 jdesc_.AddCandidate(&jice);
1102 }
1103 }
1104
Seth Hampson5b4f0752018-04-02 23:31:361105 void RemoveVideoCandidates() {
deadbeef25ed4352016-12-13 02:37:361106 const IceCandidateCollection* video_candidates_collection =
1107 jdesc_.candidates(1);
1108 ASSERT_NE(nullptr, video_candidates_collection);
1109 std::vector<cricket::Candidate> video_candidates;
1110 for (size_t i = 0; i < video_candidates_collection->count(); ++i) {
1111 cricket::Candidate c = video_candidates_collection->at(i)->candidate();
1112 c.set_transport_name("video_content_name");
1113 video_candidates.push_back(c);
1114 }
1115 jdesc_.RemoveCandidates(video_candidates);
Seth Hampson5b4f0752018-04-02 23:31:361116 }
1117
1118 // Turns the existing reference description into a description using
1119 // a=bundle-only. This means no transport attributes and a 0 port value on
1120 // the m= sections not associated with the BUNDLE-tag.
1121 void MakeBundleOnlyDescription() {
1122 RemoveVideoCandidates();
deadbeef25ed4352016-12-13 02:37:361123
1124 // And the rest of the transport attributes.
1125 desc_.transport_infos()[1].description.ice_ufrag.clear();
1126 desc_.transport_infos()[1].description.ice_pwd.clear();
1127 desc_.transport_infos()[1].description.connection_role =
1128 cricket::CONNECTIONROLE_NONE;
1129
1130 // Set bundle-only flag.
1131 desc_.contents()[1].bundle_only = true;
1132
1133 // Add BUNDLE group.
1134 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1135 group.AddContentName(kAudioContentName);
1136 group.AddContentName(kVideoContentName);
1137 desc_.AddGroup(group);
1138
Harald Alvestrand4d7160e2019-04-12 05:01:291139 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef25ed4352016-12-13 02:37:361140 jdesc_.session_version()));
1141 }
1142
deadbeef9d3584c2016-02-17 01:54:101143 // Turns the existing reference description into a plan B description,
1144 // with 2 audio tracks and 3 video tracks.
1145 void MakePlanBDescription() {
Harald Alvestrandb97d2fe2020-02-28 10:54:401146 audio_desc_ = new AudioContentDescription(*audio_desc_);
1147 video_desc_ = new VideoContentDescription(*video_desc_);
deadbeef9d3584c2016-02-17 01:54:101148
1149 StreamParams audio_track_2;
1150 audio_track_2.id = kAudioTrackId2;
1151 audio_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 19:34:101152 audio_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-17 01:54:101153 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1154 audio_desc_->AddStream(audio_track_2);
1155
1156 StreamParams video_track_2;
1157 video_track_2.id = kVideoTrackId2;
1158 video_track_2.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 19:34:101159 video_track_2.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-17 01:54:101160 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1161 video_desc_->AddStream(video_track_2);
1162
1163 StreamParams video_track_3;
1164 video_track_3.id = kVideoTrackId3;
1165 video_track_3.cname = kStream2Cname;
Seth Hampson845e8782018-03-02 19:34:101166 video_track_3.set_stream_ids({kStreamId2});
deadbeef9d3584c2016-02-17 01:54:101167 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1168 video_desc_->AddStream(video_track_3);
1169
1170 desc_.RemoveContentByName(kAudioContentName);
1171 desc_.RemoveContentByName(kVideoContentName);
Harald Alvestrand1716d392019-06-03 18:35:451172 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1173 absl::WrapUnique(audio_desc_));
1174 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1175 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-17 01:54:101176
Harald Alvestrand4d7160e2019-04-12 05:01:291177 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef9d3584c2016-02-17 01:54:101178 jdesc_.session_version()));
1179 }
1180
1181 // Turns the existing reference description into a unified plan description,
1182 // with 2 audio tracks and 3 video tracks.
Amit Hilbuchc57d5732018-12-11 23:30:111183 void MakeUnifiedPlanDescription(bool use_ssrcs = true) {
deadbeef9d3584c2016-02-17 01:54:101184 // Audio track 2.
1185 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1186 StreamParams audio_track_2;
1187 audio_track_2.id = kAudioTrackId2;
Seth Hampson845e8782018-03-02 19:34:101188 audio_track_2.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 23:30:111189 if (use_ssrcs) {
1190 audio_track_2.cname = kStream2Cname;
1191 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1192 }
deadbeef9d3584c2016-02-17 01:54:101193 audio_desc_2->AddStream(audio_track_2);
Harald Alvestrand1716d392019-06-03 18:35:451194 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
1195 absl::WrapUnique(audio_desc_2));
Steve Anton06817cd2018-12-18 23:55:301196 desc_.AddTransportInfo(TransportInfo(
1197 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
deadbeef9d3584c2016-02-17 01:54:101198 // Video track 2, in stream 2.
1199 VideoContentDescription* video_desc_2 = CreateVideoContentDescription();
1200 StreamParams video_track_2;
1201 video_track_2.id = kVideoTrackId2;
Seth Hampson845e8782018-03-02 19:34:101202 video_track_2.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 23:30:111203 if (use_ssrcs) {
1204 video_track_2.cname = kStream2Cname;
1205 video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
1206 }
deadbeef9d3584c2016-02-17 01:54:101207 video_desc_2->AddStream(video_track_2);
Harald Alvestrand1716d392019-06-03 18:35:451208 desc_.AddContent(kVideoContentName2, MediaProtocolType::kRtp,
1209 absl::WrapUnique(video_desc_2));
Steve Anton06817cd2018-12-18 23:55:301210 desc_.AddTransportInfo(TransportInfo(
1211 kVideoContentName2, TransportDescription(kUfragVideo2, kPwdVideo2)));
deadbeef9d3584c2016-02-17 01:54:101212
1213 // Video track 3, in stream 2.
1214 VideoContentDescription* video_desc_3 = CreateVideoContentDescription();
1215 StreamParams video_track_3;
1216 video_track_3.id = kVideoTrackId3;
Seth Hampson845e8782018-03-02 19:34:101217 video_track_3.set_stream_ids({kStreamId2});
Amit Hilbuchc57d5732018-12-11 23:30:111218 if (use_ssrcs) {
1219 video_track_3.cname = kStream2Cname;
1220 video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
1221 }
deadbeef9d3584c2016-02-17 01:54:101222 video_desc_3->AddStream(video_track_3);
Harald Alvestrand1716d392019-06-03 18:35:451223 desc_.AddContent(kVideoContentName3, MediaProtocolType::kRtp,
1224 absl::WrapUnique(video_desc_3));
Steve Anton06817cd2018-12-18 23:55:301225 desc_.AddTransportInfo(TransportInfo(
1226 kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3)));
Steve Antone831b8c2018-02-01 20:22:161227 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
deadbeef9d3584c2016-02-17 01:54:101228
Harald Alvestrand4d7160e2019-04-12 05:01:291229 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef9d3584c2016-02-17 01:54:101230 jdesc_.session_version()));
1231 }
1232
1233 // Creates an audio content description with no streams, and some default
1234 // configuration.
henrike@webrtc.org28e20752013-07-10 00:45:361235 AudioContentDescription* CreateAudioContentDescription() {
1236 AudioContentDescription* audio = new AudioContentDescription();
1237 audio->set_rtcp_mux(true);
deadbeef13871492015-12-09 20:37:511238 audio->set_rtcp_reduced_size(true);
Harald Alvestrand0d018412021-11-04 13:52:311239 audio->AddCrypto(CryptoParams(
1240 1, "AES_CM_128_HMAC_SHA1_32",
1241 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
1242 "dummy_session_params"));
henrike@webrtc.org28e20752013-07-10 00:45:361243 audio->set_protocol(cricket::kMediaProtocolSavpf);
Florent Castelli8c4b9ea2023-06-02 16:06:571244 audio->AddCodec(cricket::CreateAudioCodec(111, "opus", 48000, 2));
1245 audio->AddCodec(cricket::CreateAudioCodec(103, "ISAC", 16000, 1));
1246 audio->AddCodec(cricket::CreateAudioCodec(104, "ISAC", 32000, 1));
henrike@webrtc.org28e20752013-07-10 00:45:361247 return audio;
1248 }
1249
Seth Hampson5b4f0752018-04-02 23:31:361250 // Turns the existing reference description into a unified plan description,
1251 // with 3 audio MediaContentDescriptions with special StreamParams that
1252 // contain 0 or multiple stream ids: - audio track 1 has 1 media stream id -
1253 // audio track 2 has 2 media stream ids - audio track 3 has 0 media stream ids
Seth Hampson7fa6ee62018-10-17 17:25:281254 void MakeUnifiedPlanDescriptionMultipleStreamIds(const int msid_signaling) {
Seth Hampson5b4f0752018-04-02 23:31:361255 desc_.RemoveContentByName(kVideoContentName);
1256 desc_.RemoveTransportInfoByName(kVideoContentName);
1257 RemoveVideoCandidates();
1258
1259 // Audio track 2 has 2 media stream ids.
1260 AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
1261 StreamParams audio_track_2;
1262 audio_track_2.id = kAudioTrackId2;
1263 audio_track_2.cname = kStream1Cname;
1264 audio_track_2.set_stream_ids({kStreamId1, kStreamId2});
1265 audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
1266 audio_desc_2->AddStream(audio_track_2);
Harald Alvestrand1716d392019-06-03 18:35:451267 desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
1268 absl::WrapUnique(audio_desc_2));
Steve Anton06817cd2018-12-18 23:55:301269 desc_.AddTransportInfo(TransportInfo(
1270 kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
Seth Hampson5b4f0752018-04-02 23:31:361271
1272 // Audio track 3 has no stream ids.
1273 AudioContentDescription* audio_desc_3 = CreateAudioContentDescription();
1274 StreamParams audio_track_3;
1275 audio_track_3.id = kAudioTrackId3;
1276 audio_track_3.cname = kStream2Cname;
1277 audio_track_3.set_stream_ids({});
1278 audio_track_3.ssrcs.push_back(kAudioTrack3Ssrc);
1279 audio_desc_3->AddStream(audio_track_3);
Harald Alvestrand1716d392019-06-03 18:35:451280 desc_.AddContent(kAudioContentName3, MediaProtocolType::kRtp,
1281 absl::WrapUnique(audio_desc_3));
Steve Anton06817cd2018-12-18 23:55:301282 desc_.AddTransportInfo(TransportInfo(
1283 kAudioContentName3, TransportDescription(kUfragVoice3, kPwdVoice3)));
Seth Hampson7fa6ee62018-10-17 17:25:281284 desc_.set_msid_signaling(msid_signaling);
Harald Alvestrand4d7160e2019-04-12 05:01:291285 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
Seth Hampson5b4f0752018-04-02 23:31:361286 jdesc_.session_version()));
1287 }
1288
Seth Hampson5897a6e2018-04-03 18:16:331289 // Turns the existing reference description into a unified plan description
1290 // with one audio MediaContentDescription that contains one StreamParams with
1291 // 0 ssrcs.
1292 void MakeUnifiedPlanDescriptionNoSsrcSignaling() {
1293 desc_.RemoveContentByName(kVideoContentName);
1294 desc_.RemoveContentByName(kAudioContentName);
1295 desc_.RemoveTransportInfoByName(kVideoContentName);
1296 RemoveVideoCandidates();
1297
1298 AudioContentDescription* audio_desc = CreateAudioContentDescription();
1299 StreamParams audio_track;
1300 audio_track.id = kAudioTrackId1;
1301 audio_track.set_stream_ids({kStreamId1});
1302 audio_desc->AddStream(audio_track);
Harald Alvestrand1716d392019-06-03 18:35:451303 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1304 absl::WrapUnique(audio_desc));
Seth Hampson5897a6e2018-04-03 18:16:331305
1306 // Enable signaling a=msid lines.
1307 desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
Harald Alvestrand4d7160e2019-04-12 05:01:291308 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
Seth Hampson5897a6e2018-04-03 18:16:331309 jdesc_.session_version()));
1310 }
1311
deadbeef9d3584c2016-02-17 01:54:101312 // Creates a video content description with no streams, and some default
1313 // configuration.
1314 VideoContentDescription* CreateVideoContentDescription() {
1315 VideoContentDescription* video = new VideoContentDescription();
Harald Alvestrand0d018412021-11-04 13:52:311316 video->AddCrypto(CryptoParams(
1317 1, "AES_CM_128_HMAC_SHA1_80",
1318 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
deadbeef9d3584c2016-02-17 01:54:101319 video->set_protocol(cricket::kMediaProtocolSavpf);
Florent Castelli8c4b9ea2023-06-02 16:06:571320 video->AddCodec(cricket::CreateVideoCodec(120, "VP8"));
deadbeef9d3584c2016-02-17 01:54:101321 return video;
1322 }
1323
henrike@webrtc.org28e20752013-07-10 00:45:361324 template <class MCD>
Yves Gerey665174f2018-06-19 13:03:051325 void CompareMediaContentDescription(const MCD* cd1, const MCD* cd2) {
henrike@webrtc.org28e20752013-07-10 00:45:361326 // type
Harald Alvestrand1716d392019-06-03 18:35:451327 EXPECT_EQ(cd1->type(), cd2->type());
henrike@webrtc.org28e20752013-07-10 00:45:361328
1329 // content direction
1330 EXPECT_EQ(cd1->direction(), cd2->direction());
1331
1332 // rtcp_mux
1333 EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
1334
deadbeef13871492015-12-09 20:37:511335 // rtcp_reduced_size
1336 EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size());
1337
Harald Alvestrand0d018412021-11-04 13:52:311338 // cryptos
1339 EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
1340 if (cd1->cryptos().size() != cd2->cryptos().size()) {
1341 ADD_FAILURE();
1342 return;
1343 }
1344 for (size_t i = 0; i < cd1->cryptos().size(); ++i) {
1345 const CryptoParams c1 = cd1->cryptos().at(i);
1346 const CryptoParams c2 = cd2->cryptos().at(i);
1347 EXPECT_TRUE(c1.Matches(c2));
1348 EXPECT_EQ(c1.key_params, c2.key_params);
1349 EXPECT_EQ(c1.session_params, c2.session_params);
1350 }
1351
henrike@webrtc.org28e20752013-07-10 00:45:361352 // protocol
lally@webrtc.orgd7b61652015-02-24 20:18:551353 // Use an equivalence class here, for old and new versions of the
1354 // protocol description.
Yves Gerey665174f2018-06-19 13:03:051355 if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp ||
1356 cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
1357 cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
lally@webrtc.org36300852015-02-24 20:19:351358 const bool cd2_is_also_dtls_sctp =
Yves Gerey665174f2018-06-19 13:03:051359 cd2->protocol() == cricket::kMediaProtocolDtlsSctp ||
1360 cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
1361 cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
lally@webrtc.org36300852015-02-24 20:19:351362 EXPECT_TRUE(cd2_is_also_dtls_sctp);
lally@webrtc.orgd7b61652015-02-24 20:18:551363 } else {
1364 EXPECT_EQ(cd1->protocol(), cd2->protocol());
1365 }
henrike@webrtc.org28e20752013-07-10 00:45:361366
1367 // codecs
1368 EXPECT_EQ(cd1->codecs(), cd2->codecs());
1369
1370 // bandwidth
1371 EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
1372
1373 // streams
1374 EXPECT_EQ(cd1->streams(), cd2->streams());
1375
Johannes Kron0854eb62018-10-10 20:33:201376 // extmap-allow-mixed
Johannes Kron9581bc42018-10-23 08:17:391377 EXPECT_EQ(cd1->extmap_allow_mixed_enum(), cd2->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 20:33:201378
henrike@webrtc.org28e20752013-07-10 00:45:361379 // extmap
1380 ASSERT_EQ(cd1->rtp_header_extensions().size(),
1381 cd2->rtp_header_extensions().size());
Yves Gerey665174f2018-06-19 13:03:051382 for (size_t i = 0; i < cd1->rtp_header_extensions().size(); ++i) {
isheriff6f8d6862016-05-26 18:24:551383 const RtpExtension ext1 = cd1->rtp_header_extensions().at(i);
1384 const RtpExtension ext2 = cd2->rtp_header_extensions().at(i);
henrike@webrtc.org28e20752013-07-10 00:45:361385 EXPECT_EQ(ext1.uri, ext2.uri);
1386 EXPECT_EQ(ext1.id, ext2.id);
jbauch5869f502017-06-29 19:31:361387 EXPECT_EQ(ext1.encrypt, ext2.encrypt);
henrike@webrtc.org28e20752013-07-10 00:45:361388 }
henrike@webrtc.org28e20752013-07-10 00:45:361389 }
1390
Amit Hilbuchc57d5732018-12-11 23:30:111391 void CompareRidDescriptionIds(const std::vector<RidDescription>& rids,
1392 const std::vector<std::string>& ids) {
1393 // Order of elements does not matter, only equivalence of sets.
1394 EXPECT_EQ(rids.size(), ids.size());
1395 for (const std::string& id : ids) {
Steve Anton64b626b2019-01-29 01:25:261396 EXPECT_EQ(1l, absl::c_count_if(rids, [id](const RidDescription& rid) {
1397 return rid.rid == id;
1398 }));
Amit Hilbuchc57d5732018-12-11 23:30:111399 }
1400 }
1401
Amit Hilbucha2012042018-12-03 19:35:051402 void CompareSimulcastDescription(const SimulcastDescription& simulcast1,
1403 const SimulcastDescription& simulcast2) {
1404 EXPECT_EQ(simulcast1.send_layers().size(), simulcast2.send_layers().size());
1405 EXPECT_EQ(simulcast1.receive_layers().size(),
1406 simulcast2.receive_layers().size());
1407 }
1408
Harald Alvestrand5fc28b12019-05-13 11:36:161409 void CompareSctpDataContentDescription(
1410 const SctpDataContentDescription* dcd1,
1411 const SctpDataContentDescription* dcd2) {
Harald Alvestrand26bf7c42019-04-23 05:20:171412 EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap());
Harald Alvestrand5fc28b12019-05-13 11:36:161413 EXPECT_EQ(dcd1->port(), dcd2->port());
1414 EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size());
Harald Alvestrand26bf7c42019-04-23 05:20:171415 }
1416
henrike@webrtc.org28e20752013-07-10 00:45:361417 void CompareSessionDescription(const SessionDescription& desc1,
1418 const SessionDescription& desc2) {
1419 // Compare content descriptions.
1420 if (desc1.contents().size() != desc2.contents().size()) {
1421 ADD_FAILURE();
1422 return;
1423 }
Yves Gerey665174f2018-06-19 13:03:051424 for (size_t i = 0; i < desc1.contents().size(); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:361425 const cricket::ContentInfo& c1 = desc1.contents().at(i);
1426 const cricket::ContentInfo& c2 = desc2.contents().at(i);
deadbeef25ed4352016-12-13 02:37:361427 // ContentInfo properties.
henrike@webrtc.org28e20752013-07-10 00:45:361428 EXPECT_EQ(c1.name, c2.name);
deadbeef25ed4352016-12-13 02:37:361429 EXPECT_EQ(c1.type, c2.type);
1430 EXPECT_EQ(c1.rejected, c2.rejected);
1431 EXPECT_EQ(c1.bundle_only, c2.bundle_only);
henrike@webrtc.org28e20752013-07-10 00:45:361432
1433 ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
1434 if (IsAudioContent(&c1)) {
1435 const AudioContentDescription* acd1 =
Steve Antonb1c1de12017-12-21 23:14:301436 c1.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:361437 const AudioContentDescription* acd2 =
Steve Antonb1c1de12017-12-21 23:14:301438 c2.media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:361439 CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
1440 }
1441
1442 ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
1443 if (IsVideoContent(&c1)) {
1444 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 23:14:301445 c1.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:361446 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 23:14:301447 c2.media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:361448 CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
1449 }
1450
1451 ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
Harald Alvestrand5fc28b12019-05-13 11:36:161452 if (c1.media_description()->as_sctp()) {
1453 ASSERT_TRUE(c2.media_description()->as_sctp());
1454 const SctpDataContentDescription* scd1 =
1455 c1.media_description()->as_sctp();
1456 const SctpDataContentDescription* scd2 =
1457 c2.media_description()->as_sctp();
1458 CompareSctpDataContentDescription(scd1, scd2);
henrike@webrtc.org28e20752013-07-10 00:45:361459 }
Amit Hilbucha2012042018-12-03 19:35:051460
1461 CompareSimulcastDescription(
1462 c1.media_description()->simulcast_description(),
1463 c2.media_description()->simulcast_description());
henrike@webrtc.org28e20752013-07-10 00:45:361464 }
1465
1466 // group
1467 const cricket::ContentGroups groups1 = desc1.groups();
1468 const cricket::ContentGroups groups2 = desc2.groups();
1469 EXPECT_EQ(groups1.size(), groups1.size());
1470 if (groups1.size() != groups2.size()) {
1471 ADD_FAILURE();
1472 return;
1473 }
1474 for (size_t i = 0; i < groups1.size(); ++i) {
1475 const cricket::ContentGroup group1 = groups1.at(i);
1476 const cricket::ContentGroup group2 = groups2.at(i);
1477 EXPECT_EQ(group1.semantics(), group2.semantics());
1478 const cricket::ContentNames names1 = group1.content_names();
1479 const cricket::ContentNames names2 = group2.content_names();
1480 EXPECT_EQ(names1.size(), names2.size());
1481 if (names1.size() != names2.size()) {
1482 ADD_FAILURE();
1483 return;
1484 }
1485 cricket::ContentNames::const_iterator iter1 = names1.begin();
1486 cricket::ContentNames::const_iterator iter2 = names2.begin();
1487 while (iter1 != names1.end()) {
1488 EXPECT_EQ(*iter1++, *iter2++);
1489 }
1490 }
1491
1492 // transport info
1493 const cricket::TransportInfos transports1 = desc1.transport_infos();
1494 const cricket::TransportInfos transports2 = desc2.transport_infos();
1495 EXPECT_EQ(transports1.size(), transports2.size());
1496 if (transports1.size() != transports2.size()) {
1497 ADD_FAILURE();
1498 return;
1499 }
1500 for (size_t i = 0; i < transports1.size(); ++i) {
1501 const cricket::TransportInfo transport1 = transports1.at(i);
1502 const cricket::TransportInfo transport2 = transports2.at(i);
1503 EXPECT_EQ(transport1.content_name, transport2.content_name);
henrike@webrtc.org28e20752013-07-10 00:45:361504 EXPECT_EQ(transport1.description.ice_ufrag,
1505 transport2.description.ice_ufrag);
Yves Gerey665174f2018-06-19 13:03:051506 EXPECT_EQ(transport1.description.ice_pwd, transport2.description.ice_pwd);
Taylor Brandstetter2f65ec52018-05-24 18:37:281507 EXPECT_EQ(transport1.description.ice_mode,
1508 transport2.description.ice_mode);
henrike@webrtc.org28e20752013-07-10 00:45:361509 if (transport1.description.identity_fingerprint) {
1510 EXPECT_EQ(*transport1.description.identity_fingerprint,
1511 *transport2.description.identity_fingerprint);
1512 } else {
1513 EXPECT_EQ(transport1.description.identity_fingerprint.get(),
1514 transport2.description.identity_fingerprint.get());
1515 }
1516 EXPECT_EQ(transport1.description.transport_options,
1517 transport2.description.transport_options);
henrike@webrtc.org28e20752013-07-10 00:45:361518 }
deadbeefc80741f2015-10-22 20:14:451519
1520 // global attributes
1521 EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
Johannes Kron9581bc42018-10-23 08:17:391522 EXPECT_EQ(desc1.extmap_allow_mixed(), desc2.extmap_allow_mixed());
henrike@webrtc.org28e20752013-07-10 00:45:361523 }
1524
Yves Gerey665174f2018-06-19 13:03:051525 bool CompareSessionDescription(const JsepSessionDescription& desc1,
1526 const JsepSessionDescription& desc2) {
henrike@webrtc.org28e20752013-07-10 00:45:361527 EXPECT_EQ(desc1.session_id(), desc2.session_id());
1528 EXPECT_EQ(desc1.session_version(), desc2.session_version());
1529 CompareSessionDescription(*desc1.description(), *desc2.description());
1530 if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
1531 return false;
1532 for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
1533 const IceCandidateCollection* cc1 = desc1.candidates(i);
1534 const IceCandidateCollection* cc2 = desc2.candidates(i);
deadbeef25ed4352016-12-13 02:37:361535 if (cc1->count() != cc2->count()) {
1536 ADD_FAILURE();
henrike@webrtc.org28e20752013-07-10 00:45:361537 return false;
deadbeef25ed4352016-12-13 02:37:361538 }
henrike@webrtc.org28e20752013-07-10 00:45:361539 for (size_t j = 0; j < cc1->count(); ++j) {
1540 const IceCandidateInterface* c1 = cc1->at(j);
1541 const IceCandidateInterface* c2 = cc2->at(j);
1542 EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
1543 EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
1544 EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
1545 }
1546 }
1547 return true;
1548 }
1549
Artem Titov880fa812021-07-30 20:30:231550 // Disable the ice-ufrag and ice-pwd in given `sdp` message by replacing
henrike@webrtc.org28e20752013-07-10 00:45:361551 // them with invalid keywords so that the parser will just ignore them.
1552 bool RemoveCandidateUfragPwd(std::string* sdp) {
Steve Anton1c9c9fc2019-02-14 23:13:091553 absl::StrReplaceAll(
1554 {{"a=ice-ufrag", "a=xice-ufrag"}, {"a=ice-pwd", "a=xice-pwd"}}, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:361555 return true;
1556 }
1557
Artem Titov880fa812021-07-30 20:30:231558 // Update the candidates in `jdesc` to use the given `ufrag` and `pwd`.
Yves Gerey665174f2018-06-19 13:03:051559 bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc,
1560 int mline_index,
1561 const std::string& ufrag,
1562 const std::string& pwd) {
henrike@webrtc.org28e20752013-07-10 00:45:361563 std::string content_name;
1564 if (mline_index == 0) {
1565 content_name = kAudioContentName;
1566 } else if (mline_index == 1) {
1567 content_name = kVideoContentName;
1568 } else {
Artem Titovd3251962021-11-15 15:57:071569 RTC_DCHECK_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:361570 }
Yves Gerey665174f2018-06-19 13:03:051571 TransportInfo transport_info(content_name,
1572 TransportDescription(ufrag, pwd));
henrike@webrtc.org28e20752013-07-10 00:45:361573 SessionDescription* desc =
1574 const_cast<SessionDescription*>(jdesc->description());
1575 desc->RemoveTransportInfoByName(content_name);
Steve Anton06817cd2018-12-18 23:55:301576 desc->AddTransportInfo(transport_info);
henrike@webrtc.org28e20752013-07-10 00:45:361577 for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
1578 const IceCandidateCollection* cc = jdesc_.candidates(i);
1579 for (size_t j = 0; j < cc->count(); ++j) {
1580 if (cc->at(j)->sdp_mline_index() == mline_index) {
Yves Gerey665174f2018-06-19 13:03:051581 const_cast<Candidate&>(cc->at(j)->candidate()).set_username(ufrag);
1582 const_cast<Candidate&>(cc->at(j)->candidate()).set_password(pwd);
henrike@webrtc.org28e20752013-07-10 00:45:361583 }
1584 }
1585 }
1586 return true;
1587 }
1588
1589 void AddIceOptions(const std::string& content_name,
1590 const std::vector<std::string>& transport_options) {
1591 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1592 cricket::TransportInfo transport_info =
1593 *(desc_.GetTransportInfoByName(content_name));
1594 desc_.RemoveTransportInfoByName(content_name);
1595 transport_info.description.transport_options = transport_options;
1596 desc_.AddTransportInfo(transport_info);
1597 }
1598
deadbeef3f7219b2015-12-28 23:17:141599 void SetIceUfragPwd(const std::string& content_name,
1600 const std::string& ice_ufrag,
1601 const std::string& ice_pwd) {
1602 ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
1603 cricket::TransportInfo transport_info =
1604 *(desc_.GetTransportInfoByName(content_name));
1605 desc_.RemoveTransportInfoByName(content_name);
1606 transport_info.description.ice_ufrag = ice_ufrag;
1607 transport_info.description.ice_pwd = ice_pwd;
1608 desc_.AddTransportInfo(transport_info);
1609 }
1610
henrike@webrtc.org28e20752013-07-10 00:45:361611 void AddFingerprint() {
1612 desc_.RemoveTransportInfoByName(kAudioContentName);
1613 desc_.RemoveTransportInfoByName(kVideoContentName);
Steve Anton4905edb2018-10-16 02:27:441614 rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1, kIdentityDigest);
Steve Anton06817cd2018-12-18 23:55:301615 desc_.AddTransportInfo(TransportInfo(
deadbeef46eed762016-01-28 21:24:371616 kAudioContentName,
deadbeef9d3584c2016-02-17 01:54:101617 TransportDescription(std::vector<std::string>(), kUfragVoice, kPwdVoice,
1618 cricket::ICEMODE_FULL,
Steve Anton06817cd2018-12-18 23:55:301619 cricket::CONNECTIONROLE_NONE, &fingerprint)));
1620 desc_.AddTransportInfo(TransportInfo(
deadbeef46eed762016-01-28 21:24:371621 kVideoContentName,
deadbeef9d3584c2016-02-17 01:54:101622 TransportDescription(std::vector<std::string>(), kUfragVideo, kPwdVideo,
1623 cricket::ICEMODE_FULL,
Steve Anton06817cd2018-12-18 23:55:301624 cricket::CONNECTIONROLE_NONE, &fingerprint)));
henrike@webrtc.org28e20752013-07-10 00:45:361625 }
1626
jbauch5869f502017-06-29 19:31:361627 void AddExtmap(bool encrypted) {
Harald Alvestrandb97d2fe2020-02-28 10:54:401628 audio_desc_ = new AudioContentDescription(*audio_desc_);
1629 video_desc_ = new VideoContentDescription(*video_desc_);
jbauch5869f502017-06-29 19:31:361630 audio_desc_->AddRtpHeaderExtension(
1631 RtpExtension(kExtmapUri, kExtmapId, encrypted));
1632 video_desc_->AddRtpHeaderExtension(
1633 RtpExtension(kExtmapUri, kExtmapId, encrypted));
henrike@webrtc.org28e20752013-07-10 00:45:361634 desc_.RemoveContentByName(kAudioContentName);
1635 desc_.RemoveContentByName(kVideoContentName);
Harald Alvestrand1716d392019-06-03 18:35:451636 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
1637 absl::WrapUnique(audio_desc_));
1638 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
1639 absl::WrapUnique(video_desc_));
henrike@webrtc.org28e20752013-07-10 00:45:361640 }
1641
Harald Alvestrand0d018412021-11-04 13:52:311642 void RemoveCryptos() {
1643 audio_desc_->set_cryptos(std::vector<CryptoParams>());
1644 video_desc_->set_cryptos(std::vector<CryptoParams>());
1645 }
1646
Seth Hampson5897a6e2018-04-03 18:16:331647 // Removes everything in StreamParams from the session description that is
1648 // used for a=ssrc lines.
1649 void RemoveSsrcSignalingFromStreamParams() {
Harald Alvestrand1716d392019-06-03 18:35:451650 for (cricket::ContentInfo& content_info :
1651 jdesc_.description()->contents()) {
Seth Hampson5897a6e2018-04-03 18:16:331652 // With Unified Plan there should be one StreamParams per m= section.
1653 StreamParams& stream =
1654 content_info.media_description()->mutable_streams()[0];
1655 stream.ssrcs.clear();
1656 stream.ssrc_groups.clear();
1657 stream.cname.clear();
1658 }
1659 }
1660
Seth Hampson7fa6ee62018-10-17 17:25:281661 // Removes all a=ssrc lines from the SDP string, except for the
1662 // "a=ssrc:... cname:..." lines.
1663 void RemoveSsrcMsidLinesFromSdpString(std::string* sdp_string) {
1664 const char kAttributeSsrc[] = "a=ssrc";
1665 const char kAttributeCname[] = "cname";
1666 size_t ssrc_line_pos = sdp_string->find(kAttributeSsrc);
1667 while (ssrc_line_pos != std::string::npos) {
1668 size_t beg_line_pos = sdp_string->rfind('\n', ssrc_line_pos);
1669 size_t end_line_pos = sdp_string->find('\n', ssrc_line_pos);
1670 size_t cname_pos = sdp_string->find(kAttributeCname, ssrc_line_pos);
1671 if (cname_pos == std::string::npos || cname_pos > end_line_pos) {
1672 // Only erase a=ssrc lines that don't contain "cname".
1673 sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
1674 ssrc_line_pos = sdp_string->find(kAttributeSsrc, beg_line_pos);
1675 } else {
1676 // Skip the "a=ssrc:... cname" line and find the next "a=ssrc" line.
1677 ssrc_line_pos = sdp_string->find(kAttributeSsrc, end_line_pos);
1678 }
1679 }
1680 }
1681
Seth Hampson5897a6e2018-04-03 18:16:331682 // Removes all a=ssrc lines from the SDP string.
1683 void RemoveSsrcLinesFromSdpString(std::string* sdp_string) {
1684 const char kAttributeSsrc[] = "a=ssrc";
1685 while (sdp_string->find(kAttributeSsrc) != std::string::npos) {
1686 size_t pos_ssrc_attribute = sdp_string->find(kAttributeSsrc);
1687 size_t beg_line_pos = sdp_string->rfind('\n', pos_ssrc_attribute);
1688 size_t end_line_pos = sdp_string->find('\n', pos_ssrc_attribute);
1689 sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
1690 }
1691 }
1692
Steve Anton4e70a722017-11-28 22:57:101693 bool TestSerializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:361694 audio_desc_->set_direction(direction);
1695 video_desc_->set_direction(direction);
1696 std::string new_sdp = kSdpFullString;
1697 ReplaceDirection(direction, &new_sdp);
1698
Harald Alvestrand4d7160e2019-04-12 05:01:291699 if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:361700 jdesc_.session_version())) {
1701 return false;
1702 }
Steve Antone831b8c2018-02-01 20:22:161703 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:361704 EXPECT_EQ(new_sdp, message);
1705 return true;
1706 }
1707
1708 bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
Harald Alvestrandb97d2fe2020-02-28 10:54:401709 audio_desc_ = new AudioContentDescription(*audio_desc_);
1710 video_desc_ = new VideoContentDescription(*video_desc_);
zhihuang38989e52017-03-21 18:04:531711
henrike@webrtc.org28e20752013-07-10 00:45:361712 desc_.RemoveContentByName(kAudioContentName);
1713 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-21 00:34:001714 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
Harald Alvestrand1716d392019-06-03 18:35:451715 absl::WrapUnique(audio_desc_));
Steve Anton5adfafd2017-12-21 00:34:001716 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
Harald Alvestrand1716d392019-06-03 18:35:451717 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-17 01:54:101718 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1719 audio_rejected ? "" : kPwdVoice);
1720 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1721 video_rejected ? "" : kPwdVideo);
deadbeef3f7219b2015-12-28 23:17:141722
1723 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:361724 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
1725
Steve Antona3a92c22017-12-07 18:27:411726 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 18:04:531727 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 20:22:161728 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:361729 EXPECT_EQ(new_sdp, message);
1730 return true;
1731 }
1732
zstein4b2e0822017-02-18 03:48:381733 void AddSctpDataChannel(bool use_sctpmap) {
Harald Alvestrand5fc28b12019-05-13 11:36:161734 std::unique_ptr<SctpDataContentDescription> data(
1735 new SctpDataContentDescription());
1736 sctp_desc_ = data.get();
1737 sctp_desc_->set_use_sctpmap(use_sctpmap);
Guido Urdanetacecf87f2019-05-31 10:17:381738 sctp_desc_->set_protocol(cricket::kMediaProtocolUdpDtlsSctp);
Harald Alvestrand5fc28b12019-05-13 11:36:161739 sctp_desc_->set_port(kDefaultSctpPort);
Steve Anton5adfafd2017-12-21 00:34:001740 desc_.AddContent(kDataContentName, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 18:35:451741 std::move(data));
Steve Anton06817cd2018-12-18 23:55:301742 desc_.AddTransportInfo(TransportInfo(
1743 kDataContentName, TransportDescription(kUfragData, kPwdData)));
henrike@webrtc.org28e20752013-07-10 00:45:361744 }
1745
Steve Anton4e70a722017-11-28 22:57:101746 bool TestDeserializeDirection(RtpTransceiverDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:361747 std::string new_sdp = kSdpFullString;
1748 ReplaceDirection(direction, &new_sdp);
Steve Antona3a92c22017-12-07 18:27:411749 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:361750
1751 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
1752
1753 audio_desc_->set_direction(direction);
1754 video_desc_->set_direction(direction);
Harald Alvestrand4d7160e2019-04-12 05:01:291755 if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:361756 jdesc_.session_version())) {
1757 return false;
1758 }
1759 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
1760 return true;
1761 }
1762
1763 bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
deadbeef3f7219b2015-12-28 23:17:141764 std::string new_sdp = kSdpString;
henrike@webrtc.org28e20752013-07-10 00:45:361765 ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
Steve Antona3a92c22017-12-07 18:27:411766 JsepSessionDescription new_jdesc(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:361767 EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
deadbeef3f7219b2015-12-28 23:17:141768
Harald Alvestrandb97d2fe2020-02-28 10:54:401769 audio_desc_ = new AudioContentDescription(*audio_desc_);
1770 video_desc_ = new VideoContentDescription(*video_desc_);
henrike@webrtc.org28e20752013-07-10 00:45:361771 desc_.RemoveContentByName(kAudioContentName);
1772 desc_.RemoveContentByName(kVideoContentName);
Steve Anton5adfafd2017-12-21 00:34:001773 desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
Harald Alvestrand1716d392019-06-03 18:35:451774 absl::WrapUnique(audio_desc_));
Steve Anton5adfafd2017-12-21 00:34:001775 desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
Harald Alvestrand1716d392019-06-03 18:35:451776 absl::WrapUnique(video_desc_));
deadbeef9d3584c2016-02-17 01:54:101777 SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
1778 audio_rejected ? "" : kPwdVoice);
1779 SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
1780 video_rejected ? "" : kPwdVideo);
Steve Antona3a92c22017-12-07 18:27:411781 JsepSessionDescription jdesc_no_candidates(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:291782 if (!jdesc_no_candidates.Initialize(desc_.Clone(), jdesc_.session_id(),
deadbeef3f7219b2015-12-28 23:17:141783 jdesc_.session_version())) {
henrike@webrtc.org28e20752013-07-10 00:45:361784 return false;
1785 }
deadbeef3f7219b2015-12-28 23:17:141786 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
henrike@webrtc.org28e20752013-07-10 00:45:361787 return true;
1788 }
1789
Yves Gerey665174f2018-06-19 13:03:051790 void TestDeserializeExtmap(bool session_level,
1791 bool media_level,
1792 bool encrypted) {
jbauch5869f502017-06-29 19:31:361793 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 18:27:411794 JsepSessionDescription new_jdesc(SdpType::kOffer);
Harald Alvestrand4d7160e2019-04-12 05:01:291795 ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:361796 jdesc_.session_version()));
Steve Antona3a92c22017-12-07 18:27:411797 JsepSessionDescription jdesc_with_extmap(SdpType::kOffer);
henrike@webrtc.org28e20752013-07-10 00:45:361798 std::string sdp_with_extmap = kSdpString;
1799 if (session_level) {
jbauch5869f502017-06-29 19:31:361800 InjectAfter(kSessionTime,
1801 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1802 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:361803 &sdp_with_extmap);
1804 }
1805 if (media_level) {
jbauch5869f502017-06-29 19:31:361806 InjectAfter(kAttributeIcePwdVoice,
1807 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1808 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:361809 &sdp_with_extmap);
jbauch5869f502017-06-29 19:31:361810 InjectAfter(kAttributeIcePwdVideo,
1811 encrypted ? kExtmapWithDirectionAndAttributeEncrypted
1812 : kExtmapWithDirectionAndAttribute,
henrike@webrtc.org28e20752013-07-10 00:45:361813 &sdp_with_extmap);
1814 }
1815 // The extmap can't be present at the same time in both session level and
1816 // media level.
1817 if (session_level && media_level) {
1818 SdpParseError error;
Yves Gerey665174f2018-06-19 13:03:051819 EXPECT_FALSE(
1820 webrtc::SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap, &error));
henrike@webrtc.org28e20752013-07-10 00:45:361821 EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
1822 } else {
1823 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
1824 EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
1825 }
1826 }
1827
1828 void VerifyCodecParameter(const cricket::CodecParameterMap& params,
Yves Gerey665174f2018-06-19 13:03:051829 const std::string& name,
1830 int expected_value) {
henrike@webrtc.org28e20752013-07-10 00:45:361831 cricket::CodecParameterMap::const_iterator found = params.find(name);
1832 ASSERT_TRUE(found != params.end());
Jonas Olsson6b1985d2018-07-05 09:59:481833 EXPECT_EQ(found->second, rtc::ToString(expected_value));
henrike@webrtc.org28e20752013-07-10 00:45:361834 }
1835
1836 void TestDeserializeCodecParams(const CodecParams& params,
1837 JsepSessionDescription* jdesc_output) {
1838 std::string sdp =
1839 "v=0\r\n"
1840 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1841 "s=-\r\n"
1842 "t=0 0\r\n"
1843 // Include semantics for WebRTC Media Streams since it is supported by
1844 // this parser, and will be added to the SDP when serializing a session
1845 // description.
1846 "a=msid-semantic: WMS\r\n"
1847 // Pl type 111 preferred.
Philipp Hanckef2a4ec12020-07-01 19:07:321848 "m=audio 9 RTP/SAVPF 111 104 103 105\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:361849 // Pltype 111 listed before 103 and 104 in the map.
1850 "a=rtpmap:111 opus/48000/2\r\n"
1851 // Pltype 103 listed before 104.
1852 "a=rtpmap:103 ISAC/16000\r\n"
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:411853 "a=rtpmap:104 ISAC/32000\r\n"
Philipp Hanckef2a4ec12020-07-01 19:07:321854 "a=rtpmap:105 telephone-event/8000\r\n"
1855 "a=fmtp:105 0-15,66,70\r\n"
mallinath@webrtc.orga5506692013-08-12 21:18:151856 "a=fmtp:111 ";
henrike@webrtc.org28e20752013-07-10 00:45:361857 std::ostringstream os;
Donald Curtis144d0182015-05-15 20:14:241858 os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
mallinath@webrtc.orga5506692013-08-12 21:18:151859 << "; sprop-stereo=" << params.sprop_stereo
1860 << "; useinbandfec=" << params.useinband
Jonas Olssonb2b20312020-01-14 11:11:311861 << "; maxaveragebitrate=" << params.maxaveragebitrate
1862 << "\r\n"
1863 "a=ptime:"
1864 << params.ptime
1865 << "\r\n"
1866 "a=maxptime:"
1867 << params.max_ptime << "\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:361868 sdp += os.str();
1869
stefan@webrtc.org85d27942014-06-09 12:51:391870 os.clear();
1871 os.str("");
1872 // Pl type 100 preferred.
Philipp Hanckeb7bc2432021-03-11 14:28:001873 os << "m=video 9 RTP/SAVPF 99 95 96\r\n"
1874 "a=rtpmap:96 VP9/90000\r\n" // out-of-order wrt the m= line.
Jonas Olssonb2b20312020-01-14 11:11:311875 "a=rtpmap:99 VP8/90000\r\n"
1876 "a=rtpmap:95 RTX/90000\r\n"
1877 "a=fmtp:95 apt=99;\r\n";
stefan@webrtc.org85d27942014-06-09 12:51:391878 sdp += os.str();
1879
henrike@webrtc.org28e20752013-07-10 00:45:361880 // Deserialize
1881 SdpParseError error;
1882 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
1883
henrike@webrtc.org28e20752013-07-10 00:45:361884 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 23:14:301885 GetFirstAudioContentDescription(jdesc_output->description());
1886 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:361887 ASSERT_FALSE(acd->codecs().empty());
1888 cricket::AudioCodec opus = acd->codecs()[0];
1889 EXPECT_EQ("opus", opus.name);
1890 EXPECT_EQ(111, opus.id);
1891 VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
1892 VerifyCodecParameter(opus.params, "stereo", params.stereo);
1893 VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
1894 VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
henrike@webrtc.org1e09a712013-07-26 19:17:591895 VerifyCodecParameter(opus.params, "maxaveragebitrate",
1896 params.maxaveragebitrate);
henrike@webrtc.org28e20752013-07-10 00:45:361897 for (size_t i = 0; i < acd->codecs().size(); ++i) {
1898 cricket::AudioCodec codec = acd->codecs()[i];
1899 VerifyCodecParameter(codec.params, "ptime", params.ptime);
1900 VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
henrike@webrtc.org28e20752013-07-10 00:45:361901 }
stefan@webrtc.org85d27942014-06-09 12:51:391902
Philipp Hanckef2a4ec12020-07-01 19:07:321903 cricket::AudioCodec dtmf = acd->codecs()[3];
1904 EXPECT_EQ("telephone-event", dtmf.name);
1905 EXPECT_EQ(105, dtmf.id);
1906 EXPECT_EQ(3u,
1907 dtmf.params.size()); // ptime and max_ptime count as parameters.
1908 EXPECT_EQ(dtmf.params.begin()->first, "");
1909 EXPECT_EQ(dtmf.params.begin()->second, "0-15,66,70");
1910
stefan@webrtc.org85d27942014-06-09 12:51:391911 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 23:14:301912 GetFirstVideoContentDescription(jdesc_output->description());
1913 ASSERT_TRUE(vcd);
stefan@webrtc.org85d27942014-06-09 12:51:391914 ASSERT_FALSE(vcd->codecs().empty());
1915 cricket::VideoCodec vp8 = vcd->codecs()[0];
1916 EXPECT_EQ("VP8", vp8.name);
1917 EXPECT_EQ(99, vp8.id);
1918 cricket::VideoCodec rtx = vcd->codecs()[1];
1919 EXPECT_EQ("RTX", rtx.name);
1920 EXPECT_EQ(95, rtx.id);
1921 VerifyCodecParameter(rtx.params, "apt", vp8.id);
Philipp Hanckeb7bc2432021-03-11 14:28:001922 // VP9 is listed last in the m= line so should come after VP8 and RTX.
1923 cricket::VideoCodec vp9 = vcd->codecs()[2];
1924 EXPECT_EQ("VP9", vp9.name);
1925 EXPECT_EQ(96, vp9.id);
henrike@webrtc.org28e20752013-07-10 00:45:361926 }
1927
1928 void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
1929 bool use_wildcard) {
jlmiller@webrtc.orga744a282015-02-18 21:37:461930 std::string sdp_session_and_audio =
henrike@webrtc.org28e20752013-07-10 00:45:361931 "v=0\r\n"
1932 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
1933 "s=-\r\n"
1934 "t=0 0\r\n"
1935 // Include semantics for WebRTC Media Streams since it is supported by
1936 // this parser, and will be added to the SDP when serializing a session
1937 // description.
1938 "a=msid-semantic: WMS\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:221939 "m=audio 9 RTP/SAVPF 111\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:461940 "a=rtpmap:111 opus/48000/2\r\n";
1941 std::string sdp_video =
henrike@webrtc.org28e20752013-07-10 00:45:361942 "m=video 3457 RTP/SAVPF 101\r\n"
1943 "a=rtpmap:101 VP8/90000\r\n"
Elad Alonfadb1812019-05-24 11:40:021944 "a=rtcp-fb:101 goog-lntf\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:361945 "a=rtcp-fb:101 nack\r\n"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:581946 "a=rtcp-fb:101 nack pli\r\n"
jlmiller@webrtc.orga744a282015-02-18 21:37:461947 "a=rtcp-fb:101 goog-remb\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:361948 std::ostringstream os;
jlmiller@webrtc.orga744a282015-02-18 21:37:461949 os << sdp_session_and_audio;
Yves Gerey665174f2018-06-19 13:03:051950 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") << " nack\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:461951 os << sdp_video;
Yves Gerey665174f2018-06-19 13:03:051952 os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") << " ccm fir\r\n";
jlmiller@webrtc.orga744a282015-02-18 21:37:461953 std::string sdp = os.str();
henrike@webrtc.org28e20752013-07-10 00:45:361954 // Deserialize
1955 SdpParseError error;
1956 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:361957 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 23:14:301958 GetFirstAudioContentDescription(jdesc_output->description());
1959 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:361960 ASSERT_FALSE(acd->codecs().empty());
1961 cricket::AudioCodec opus = acd->codecs()[0];
1962 EXPECT_EQ(111, opus.id);
Yves Gerey665174f2018-06-19 13:03:051963 EXPECT_TRUE(opus.HasFeedbackParam(cricket::FeedbackParam(
1964 cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
henrike@webrtc.org28e20752013-07-10 00:45:361965
henrike@webrtc.org28e20752013-07-10 00:45:361966 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 23:14:301967 GetFirstVideoContentDescription(jdesc_output->description());
1968 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:361969 ASSERT_FALSE(vcd->codecs().empty());
1970 cricket::VideoCodec vp8 = vcd->codecs()[0];
Philipp Hancke7f4270d2023-02-23 12:20:251971 EXPECT_EQ(vp8.name, "VP8");
henrike@webrtc.org28e20752013-07-10 00:45:361972 EXPECT_EQ(101, vp8.id);
Yves Gerey665174f2018-06-19 13:03:051973 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
Elad Alonfadb1812019-05-24 11:40:021974 cricket::kRtcpFbParamLntf, cricket::kParamValueEmpty)));
1975 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
Yves Gerey665174f2018-06-19 13:03:051976 cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
1977 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
1978 cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)));
1979 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
1980 cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)));
1981 EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
1982 cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)));
henrike@webrtc.org28e20752013-07-10 00:45:361983 }
1984
1985 // Two SDP messages can mean the same thing but be different strings, e.g.
1986 // some of the lines can be serialized in different order.
1987 // However, a deserialized description can be compared field by field and has
1988 // no order. If deserializer has already been tested, serializing then
1989 // deserializing and comparing JsepSessionDescription will test
1990 // the serializer sufficiently.
Steve Antone831b8c2018-02-01 20:22:161991 void TestSerialize(const JsepSessionDescription& jdesc) {
1992 std::string message = webrtc::SdpSerialize(jdesc);
Steve Antona3a92c22017-12-07 18:27:411993 JsepSessionDescription jdesc_output_des(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:361994 SdpParseError error;
1995 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
1996 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
1997 }
1998
zhihuang38989e52017-03-21 18:04:531999 // Calling 'Initialize' with a copy of the inner SessionDescription will
2000 // create a copy of the JsepSessionDescription without candidates. The
2001 // 'connection address' field, previously set from the candidates, must also
2002 // be reset.
2003 void MakeDescriptionWithoutCandidates(JsepSessionDescription* jdesc) {
2004 rtc::SocketAddress audio_addr("0.0.0.0", 9);
2005 rtc::SocketAddress video_addr("0.0.0.0", 9);
2006 audio_desc_->set_connection_address(audio_addr);
2007 video_desc_->set_connection_address(video_addr);
Harald Alvestrand4d7160e2019-04-12 05:01:292008 ASSERT_TRUE(jdesc->Initialize(desc_.Clone(), kSessionId, kSessionVersion));
zhihuang38989e52017-03-21 18:04:532009 }
2010
henrike@webrtc.org28e20752013-07-10 00:45:362011 protected:
2012 SessionDescription desc_;
2013 AudioContentDescription* audio_desc_;
2014 VideoContentDescription* video_desc_;
Harald Alvestrand5fc28b12019-05-13 11:36:162015 SctpDataContentDescription* sctp_desc_;
henrike@webrtc.org28e20752013-07-10 00:45:362016 Candidates candidates_;
kwibergd1fe2812016-04-27 13:47:292017 std::unique_ptr<IceCandidateInterface> jcandidate_;
henrike@webrtc.org28e20752013-07-10 00:45:362018 JsepSessionDescription jdesc_;
2019};
2020
2021void TestMismatch(const std::string& string1, const std::string& string2) {
2022 int position = 0;
2023 for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
2024 if (string1.c_str()[i] != string2.c_str()[i]) {
henrike@webrtc.org28654cb2013-07-22 21:07:492025 position = static_cast<int>(i);
henrike@webrtc.org28e20752013-07-10 00:45:362026 break;
2027 }
2028 }
2029 EXPECT_EQ(0, position) << "Strings mismatch at the " << position
2030 << " character\n"
Jonas Olssonb2b20312020-01-14 11:11:312031 " 1: "
2032 << string1.substr(position, 20)
2033 << "\n"
2034 " 2: "
2035 << string2.substr(position, 20) << "\n";
henrike@webrtc.org28e20752013-07-10 00:45:362036}
2037
henrike@webrtc.org28e20752013-07-10 00:45:362038TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
2039 // SessionDescription with desc and candidates.
Steve Antone831b8c2018-02-01 20:22:162040 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:362041 TestMismatch(std::string(kSdpFullString), message);
2042}
2043
2044TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
Steve Antona3a92c22017-12-07 18:27:412045 JsepSessionDescription jdesc_empty(kDummyType);
Steve Antone831b8c2018-02-01 20:22:162046 EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
henrike@webrtc.org28e20752013-07-10 00:45:362047}
2048
Harald Alvestrand0d018412021-11-04 13:52:312049// This tests serialization of SDP with a=crypto and a=fingerprint, as would be
henrike@webrtc.org28e20752013-07-10 00:45:362050// the case in a DTLS offer.
2051TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
2052 AddFingerprint();
Steve Antona3a92c22017-12-07 18:27:412053 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 18:04:532054 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 20:22:162055 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:362056
2057 std::string sdp_with_fingerprint = kSdpString;
Yves Gerey665174f2018-06-19 13:03:052058 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2059 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:362060
2061 EXPECT_EQ(sdp_with_fingerprint, message);
2062}
2063
2064// This tests serialization of SDP with a=fingerprint with no a=crypto, as would
2065// be the case in a DTLS answer.
2066TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
2067 AddFingerprint();
Harald Alvestrand0d018412021-11-04 13:52:312068 RemoveCryptos();
Steve Antona3a92c22017-12-07 18:27:412069 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
zhihuang38989e52017-03-21 18:04:532070 MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
Steve Antone831b8c2018-02-01 20:22:162071 std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:362072
2073 std::string sdp_with_fingerprint = kSdpString;
2074 Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
2075 Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
Yves Gerey665174f2018-06-19 13:03:052076 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2077 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
henrike@webrtc.org28e20752013-07-10 00:45:362078
2079 EXPECT_EQ(sdp_with_fingerprint, message);
2080}
2081
2082TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
2083 // JsepSessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 18:27:412084 JsepSessionDescription jdesc_no_candidates(kDummyType);
zhihuang38989e52017-03-21 18:04:532085 MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
Steve Antone831b8c2018-02-01 20:22:162086 std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
henrike@webrtc.org28e20752013-07-10 00:45:362087 EXPECT_EQ(std::string(kSdpString), message);
2088}
2089
Henrik Boströmf8187e02021-04-26 19:04:262090TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundles) {
2091 ContentGroup group1(cricket::GROUP_TYPE_BUNDLE);
2092 group1.AddContentName(kAudioContentName);
2093 group1.AddContentName(kVideoContentName);
2094 desc_.AddGroup(group1);
2095 ContentGroup group2(cricket::GROUP_TYPE_BUNDLE);
2096 group2.AddContentName(kAudioContentName2);
2097 desc_.AddGroup(group2);
Harald Alvestrand4d7160e2019-04-12 05:01:292098 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362099 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:162100 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:362101 std::string sdp_with_bundle = kSdpFullString;
2102 InjectAfter(kSessionTime,
Henrik Boströmf8187e02021-04-26 19:04:262103 "a=group:BUNDLE audio_content_name video_content_name\r\n"
2104 "a=group:BUNDLE audio_content_name_2\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362105 &sdp_with_bundle);
2106 EXPECT_EQ(sdp_with_bundle, message);
2107}
2108
2109TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
Steve Antonb1c1de12017-12-21 23:14:302110 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
Taylor Brandstetteree8c2462020-07-27 22:52:022111 vcd->set_bandwidth(100 * 1000 + 755); // Integer division will drop the 755.
2112 vcd->set_bandwidth_type("AS");
Steve Antonb1c1de12017-12-21 23:14:302113 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
Taylor Brandstetteree8c2462020-07-27 22:52:022114 acd->set_bandwidth(555);
2115 acd->set_bandwidth_type("TIAS");
Harald Alvestrand4d7160e2019-04-12 05:01:292116 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362117 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:162118 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:362119 std::string sdp_with_bandwidth = kSdpFullString;
Yves Gerey665174f2018-06-19 13:03:052120 InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362121 &sdp_with_bandwidth);
Taylor Brandstetteree8c2462020-07-27 22:52:022122 InjectAfter("c=IN IP4 74.125.127.126\r\n", "b=TIAS:555\r\n",
2123 &sdp_with_bandwidth);
2124 EXPECT_EQ(sdp_with_bandwidth, message);
2125}
2126
2127// Should default to b=AS if bandwidth_type isn't set.
2128TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithMissingBandwidthType) {
2129 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2130 vcd->set_bandwidth(100 * 1000);
2131 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2132 jdesc_.session_version()));
2133 std::string message = webrtc::SdpSerialize(jdesc_);
2134 std::string sdp_with_bandwidth = kSdpFullString;
2135 InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362136 &sdp_with_bandwidth);
2137 EXPECT_EQ(sdp_with_bandwidth, message);
2138}
2139
2140TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
2141 std::vector<std::string> transport_options;
2142 transport_options.push_back(kIceOption1);
2143 transport_options.push_back(kIceOption3);
2144 AddIceOptions(kAudioContentName, transport_options);
2145 transport_options.clear();
2146 transport_options.push_back(kIceOption2);
2147 transport_options.push_back(kIceOption3);
2148 AddIceOptions(kVideoContentName, transport_options);
Harald Alvestrand4d7160e2019-04-12 05:01:292149 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362150 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:162151 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:362152 std::string sdp_with_ice_options = kSdpFullString;
Yves Gerey665174f2018-06-19 13:03:052153 InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1 iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362154 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 13:03:052155 InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2 iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362156 &sdp_with_ice_options);
2157 EXPECT_EQ(sdp_with_ice_options, message);
2158}
2159
2160TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 22:57:102161 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:362162}
2163
2164TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 22:57:102165 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:362166}
2167
2168TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 22:57:102169 EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:362170}
2171
2172TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
2173 EXPECT_TRUE(TestSerializeRejected(true, false));
2174}
2175
2176TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
2177 EXPECT_TRUE(TestSerializeRejected(false, true));
2178}
2179
2180TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
2181 EXPECT_TRUE(TestSerializeRejected(true, true));
2182}
2183
henrike@webrtc.org28e20752013-07-10 00:45:362184TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
zstein4b2e0822017-02-18 03:48:382185 bool use_sctpmap = true;
2186 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:412187 JsepSessionDescription jsep_desc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362188
zhihuang38989e52017-03-21 18:04:532189 MakeDescriptionWithoutCandidates(&jsep_desc);
Steve Antone831b8c2018-02-01 20:22:162190 std::string message = webrtc::SdpSerialize(jsep_desc);
henrike@webrtc.org28e20752013-07-10 00:45:362191
2192 std::string expected_sdp = kSdpString;
2193 expected_sdp.append(kSdpSctpDataChannelString);
2194 EXPECT_EQ(message, expected_sdp);
2195}
2196
Harald Alvestrand5fc28b12019-05-13 11:36:162197void MutateJsepSctpPort(JsepSessionDescription* jdesc,
2198 const SessionDescription& desc,
2199 int port) {
2200 // Take our pre-built session description and change the SCTP port.
2201 std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
2202 SctpDataContentDescription* dcdesc =
2203 mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
2204 dcdesc->set_port(port);
2205 ASSERT_TRUE(
2206 jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion));
2207}
2208
jiayl@webrtc.org9c16c392014-05-01 18:30:302209TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
zstein4b2e0822017-02-18 03:48:382210 bool use_sctpmap = true;
2211 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:412212 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 18:04:532213 MakeDescriptionWithoutCandidates(&jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:302214
2215 const int kNewPort = 1234;
Harald Alvestrand5fc28b12019-05-13 11:36:162216 MutateJsepSctpPort(&jsep_desc, desc_, kNewPort);
jiayl@webrtc.org9c16c392014-05-01 18:30:302217
Steve Antone831b8c2018-02-01 20:22:162218 std::string message = webrtc::SdpSerialize(jsep_desc);
jiayl@webrtc.org9c16c392014-05-01 18:30:302219
2220 std::string expected_sdp = kSdpString;
2221 expected_sdp.append(kSdpSctpDataChannelString);
2222
Steve Anton1c9c9fc2019-02-14 23:13:092223 absl::StrReplaceAll(
2224 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kNewPort)}},
2225 &expected_sdp);
jiayl@webrtc.org9c16c392014-05-01 18:30:302226
2227 EXPECT_EQ(expected_sdp, message);
2228}
2229
Johannes Kron0854eb62018-10-10 20:33:202230TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 08:17:392231 jdesc_.description()->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 20:33:202232 TestSerialize(jdesc_);
2233}
2234
2235TEST_F(WebRtcSdpTest, SerializeMediaContentDescriptionWithExtmapAllowMixed) {
2236 cricket::MediaContentDescription* video_desc =
2237 jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
2238 ASSERT_TRUE(video_desc);
2239 cricket::MediaContentDescription* audio_desc =
2240 jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
2241 ASSERT_TRUE(audio_desc);
Johannes Kron9581bc42018-10-23 08:17:392242 video_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 20:33:202243 cricket::MediaContentDescription::kMedia);
Johannes Kron9581bc42018-10-23 08:17:392244 audio_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 20:33:202245 cricket::MediaContentDescription::kMedia);
2246 TestSerialize(jdesc_);
2247}
2248
henrike@webrtc.org28e20752013-07-10 00:45:362249TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
jbauch5869f502017-06-29 19:31:362250 bool encrypted = false;
2251 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 18:27:412252 JsepSessionDescription desc_with_extmap(kDummyType);
zhihuang38989e52017-03-21 18:04:532253 MakeDescriptionWithoutCandidates(&desc_with_extmap);
Steve Antone831b8c2018-02-01 20:22:162254 std::string message = webrtc::SdpSerialize(desc_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:362255
2256 std::string sdp_with_extmap = kSdpString;
Yves Gerey665174f2018-06-19 13:03:052257 InjectAfter("a=mid:audio_content_name\r\n", kExtmap, &sdp_with_extmap);
2258 InjectAfter("a=mid:video_content_name\r\n", kExtmap, &sdp_with_extmap);
henrike@webrtc.org28e20752013-07-10 00:45:362259
2260 EXPECT_EQ(sdp_with_extmap, message);
2261}
2262
jbauch5869f502017-06-29 19:31:362263TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapEncrypted) {
2264 bool encrypted = true;
2265 AddExtmap(encrypted);
Steve Antona3a92c22017-12-07 18:27:412266 JsepSessionDescription desc_with_extmap(kDummyType);
Yves Gerey665174f2018-06-19 13:03:052267 ASSERT_TRUE(
Harald Alvestrand4d7160e2019-04-12 05:01:292268 desc_with_extmap.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
Steve Antone831b8c2018-02-01 20:22:162269 TestSerialize(desc_with_extmap);
jbauch5869f502017-06-29 19:31:362270}
2271
henrike@webrtc.org28e20752013-07-10 00:45:362272TEST_F(WebRtcSdpTest, SerializeCandidates) {
2273 std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
wu@webrtc.orgec9f5fb2014-06-24 17:05:102274 EXPECT_EQ(std::string(kRawCandidate), message);
honghaiza54a0802015-12-17 02:37:232275
2276 Candidate candidate_with_ufrag(candidates_.front());
2277 candidate_with_ufrag.set_username("ABC");
2278 jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0,
2279 candidate_with_ufrag));
2280 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2281 EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
honghaiza0c44ea2016-03-23 23:07:482282
2283 Candidate candidate_with_network_info(candidates_.front());
2284 candidate_with_network_info.set_network_id(1);
2285 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2286 candidate_with_network_info));
2287 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2288 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
2289 candidate_with_network_info.set_network_cost(999);
2290 jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
2291 candidate_with_network_info));
2292 message = webrtc::SdpSerializeCandidate(*jcandidate_);
2293 EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
2294 message);
henrike@webrtc.org28e20752013-07-10 00:45:362295}
2296
Zach Steinb336c272018-08-09 08:16:132297TEST_F(WebRtcSdpTest, SerializeHostnameCandidate) {
2298 rtc::SocketAddress address("a.test", 1234);
2299 cricket::Candidate candidate(
2300 cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp", address, kCandidatePriority,
2301 "", "", LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
2302 JsepIceCandidate jcandidate(std::string("audio_content_name"), 0, candidate);
2303 std::string message = webrtc::SdpSerializeCandidate(jcandidate);
2304 EXPECT_EQ(std::string(kRawHostnameCandidate), message);
2305}
2306
mallinath@webrtc.orge999bd02014-08-13 06:05:552307TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
guoweis@webrtc.org61c12472015-01-15 06:53:072308 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:312309 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2310 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2311 kCandidateFoundation1);
mallinath@webrtc.org2d60c5e2014-08-08 22:29:202312 candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
kwibergd1fe2812016-04-27 13:47:292313 std::unique_ptr<IceCandidateInterface> jcandidate(
2314 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:202315
2316 std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
2317 EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
2318}
2319
Taylor Brandstetter8206bc02020-04-02 19:36:382320// Test serializing a TCP candidate that came in with a missing tcptype. This
2321// shouldn't happen according to the spec, but our implementation has been
2322// accepting this for quite some time, treating it as a passive candidate.
2323//
2324// So, we should be able to at least convert such candidates to and from SDP.
2325// See: bugs.webrtc.org/11423
2326TEST_F(WebRtcSdpTest, ParseTcpCandidateWithoutTcptype) {
2327 std::string missing_tcptype =
2328 "candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9999 typ host";
2329 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2330 EXPECT_TRUE(SdpDeserializeCandidate(missing_tcptype, &jcandidate));
2331
2332 EXPECT_EQ(std::string(cricket::TCPTYPE_PASSIVE_STR),
2333 jcandidate.candidate().tcptype());
2334}
2335
2336TEST_F(WebRtcSdpTest, ParseSslTcpCandidate) {
2337 std::string ssltcp =
2338 "candidate:a0+B/1 1 ssltcp 2130706432 192.168.1.5 9999 typ host tcptype "
2339 "passive";
2340 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2341 EXPECT_TRUE(SdpDeserializeCandidate(ssltcp, &jcandidate));
2342
2343 EXPECT_EQ(std::string("ssltcp"), jcandidate.candidate().protocol());
2344}
2345
htaa6b99442016-04-12 17:29:172346TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithH264) {
Florent Castelli8c4b9ea2023-06-02 16:06:572347 cricket::VideoCodec h264_codec = cricket::CreateVideoCodec("H264");
magjed509e4fe2016-11-18 09:34:112348 h264_codec.SetParam("profile-level-id", "42e01f");
2349 h264_codec.SetParam("level-asymmetry-allowed", "1");
2350 h264_codec.SetParam("packetization-mode", "1");
2351 video_desc_->AddCodec(h264_codec);
2352
Harald Alvestrand4d7160e2019-04-12 05:01:292353 jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
htaa6b99442016-04-12 17:29:172354
Steve Antone831b8c2018-02-01 20:22:162355 std::string message = webrtc::SdpSerialize(jdesc_);
htaa6b99442016-04-12 17:29:172356 size_t after_pt = message.find(" H264/90000");
2357 ASSERT_NE(after_pt, std::string::npos);
2358 size_t before_pt = message.rfind("a=rtpmap:", after_pt);
2359 ASSERT_NE(before_pt, std::string::npos);
2360 before_pt += strlen("a=rtpmap:");
2361 std::string pt = message.substr(before_pt, after_pt - before_pt);
Artem Titov880fa812021-07-30 20:30:232362 // TODO(hta): Check if payload type `pt` occurs in the m=video line.
htaa6b99442016-04-12 17:29:172363 std::string to_find = "a=fmtp:" + pt + " ";
2364 size_t fmtp_pos = message.find(to_find);
2365 ASSERT_NE(std::string::npos, fmtp_pos) << "Failed to find " << to_find;
Mirko Bonadei37ec55e2019-01-28 10:43:522366 size_t fmtp_endpos = message.find('\n', fmtp_pos);
htaa6b99442016-04-12 17:29:172367 ASSERT_NE(std::string::npos, fmtp_endpos);
2368 std::string fmtp_value = message.substr(fmtp_pos, fmtp_endpos);
2369 EXPECT_NE(std::string::npos, fmtp_value.find("level-asymmetry-allowed=1"));
2370 EXPECT_NE(std::string::npos, fmtp_value.find("packetization-mode=1"));
2371 EXPECT_NE(std::string::npos, fmtp_value.find("profile-level-id=42e01f"));
hta62a216e2016-04-15 18:02:142372 // Check that there are no spaces after semicolons.
2373 // https://bugs.webrtc.org/5793
2374 EXPECT_EQ(std::string::npos, fmtp_value.find("; "));
htaa6b99442016-04-12 17:29:172375}
2376
henrike@webrtc.org28e20752013-07-10 00:45:362377TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
Steve Antona3a92c22017-12-07 18:27:412378 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362379 // Deserialize
2380 EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
2381 // Verify
2382 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2383}
2384
wu@webrtc.orgcecfd182013-10-30 05:18:122385TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
Steve Antona3a92c22017-12-07 18:27:412386 JsepSessionDescription jdesc(kDummyType);
wu@webrtc.orgcecfd182013-10-30 05:18:122387 const char kSdpWithoutMline[] =
Yves Gerey665174f2018-06-19 13:03:052388 "v=0\r\n"
2389 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
2390 "s=-\r\n"
2391 "t=0 0\r\n"
2392 "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
wu@webrtc.orgcecfd182013-10-30 05:18:122393 // Deserialize
2394 EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
2395 EXPECT_EQ(0u, jdesc.description()->contents().size());
2396}
2397
henrike@webrtc.org28e20752013-07-10 00:45:362398TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
Steve Antona3a92c22017-12-07 18:27:412399 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362400 std::string sdp_without_carriage_return = kSdpFullString;
2401 Replace("\r\n", "\n", &sdp_without_carriage_return);
2402 // Deserialize
2403 EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
2404 // Verify
2405 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
2406}
2407
2408TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
2409 // SessionDescription with desc but without candidates.
Steve Antona3a92c22017-12-07 18:27:412410 JsepSessionDescription jdesc_no_candidates(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:292411 ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Clone(), kSessionId,
Yves Gerey665174f2018-06-19 13:03:052412 kSessionVersion));
Steve Antona3a92c22017-12-07 18:27:412413 JsepSessionDescription new_jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362414 EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
2415 EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
2416}
2417
2418TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
2419 static const char kSdpNoRtpmapString[] =
2420 "v=0\r\n"
2421 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2422 "s=-\r\n"
2423 "t=0 0\r\n"
2424 "m=audio 49232 RTP/AVP 0 18 103\r\n"
2425 // Codec that doesn't appear in the m= line will be ignored.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:412426 "a=rtpmap:104 ISAC/32000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:362427 // The rtpmap line for static payload codec is optional.
Philipp Hancke32c60b82022-05-31 14:51:232428 "a=rtpmap:18 G729/8000\r\n"
henrike@webrtc.org28e20752013-07-10 00:45:362429 "a=rtpmap:103 ISAC/16000\r\n";
2430
Steve Antona3a92c22017-12-07 18:27:412431 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362432 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2433 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 23:55:302434 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org28e20752013-07-10 00:45:362435 AudioCodecs ref_codecs;
deadbeef67cf2c12016-04-13 17:07:162436 // The codecs in the AudioContentDescription should be in the same order as
2437 // the payload types (<fmt>s) on the m= line.
Florent Castelli8c4b9ea2023-06-02 16:06:572438 ref_codecs.push_back(cricket::CreateAudioCodec(0, "PCMU", 8000, 1));
2439 ref_codecs.push_back(cricket::CreateAudioCodec(18, "G729", 8000, 1));
2440 ref_codecs.push_back(cricket::CreateAudioCodec(103, "ISAC", 16000, 1));
henrike@webrtc.org28e20752013-07-10 00:45:362441 EXPECT_EQ(ref_codecs, audio->codecs());
2442}
2443
henrike@webrtc.org704bf9e2014-02-27 17:52:042444TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
2445 static const char kSdpNoRtpmapString[] =
2446 "v=0\r\n"
2447 "o=- 11 22 IN IP4 127.0.0.1\r\n"
2448 "s=-\r\n"
2449 "t=0 0\r\n"
2450 "m=audio 49232 RTP/AVP 18 103\r\n"
2451 "a=fmtp:18 annexb=yes\r\n"
2452 "a=rtpmap:103 ISAC/16000\r\n";
2453
Steve Antona3a92c22017-12-07 18:27:412454 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:042455 EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
2456 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 23:55:302457 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:042458
2459 cricket::AudioCodec g729 = audio->codecs()[0];
2460 EXPECT_EQ("G729", g729.name);
2461 EXPECT_EQ(8000, g729.clockrate);
2462 EXPECT_EQ(18, g729.id);
Yves Gerey665174f2018-06-19 13:03:052463 cricket::CodecParameterMap::iterator found = g729.params.find("annexb");
henrike@webrtc.org704bf9e2014-02-27 17:52:042464 ASSERT_TRUE(found != g729.params.end());
2465 EXPECT_EQ(found->second, "yes");
2466
2467 cricket::AudioCodec isac = audio->codecs()[1];
2468 EXPECT_EQ("ISAC", isac.name);
2469 EXPECT_EQ(103, isac.id);
2470 EXPECT_EQ(16000, isac.clockrate);
2471}
2472
henrike@webrtc.org28e20752013-07-10 00:45:362473// Ensure that we can deserialize SDP with a=fingerprint properly.
2474TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
2475 // Add a DTLS a=fingerprint attribute to our session description.
2476 AddFingerprint();
Steve Antona3a92c22017-12-07 18:27:412477 JsepSessionDescription new_jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:292478 ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362479 jdesc_.session_version()));
2480
Steve Antona3a92c22017-12-07 18:27:412481 JsepSessionDescription jdesc_with_fingerprint(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362482 std::string sdp_with_fingerprint = kSdpString;
2483 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
2484 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
2485 EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
2486 EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
2487}
2488
2489TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
Steve Antona3a92c22017-12-07 18:27:412490 JsepSessionDescription jdesc_with_bundle(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362491 std::string sdp_with_bundle = kSdpFullString;
2492 InjectAfter(kSessionTime,
2493 "a=group:BUNDLE audio_content_name video_content_name\r\n",
2494 &sdp_with_bundle);
2495 EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
2496 ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
2497 group.AddContentName(kAudioContentName);
2498 group.AddContentName(kVideoContentName);
2499 desc_.AddGroup(group);
Harald Alvestrand4d7160e2019-04-12 05:01:292500 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362501 jdesc_.session_version()));
2502 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
2503}
2504
2505TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
Steve Antona3a92c22017-12-07 18:27:412506 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362507 std::string sdp_with_bandwidth = kSdpFullString;
Yves Gerey665174f2018-06-19 13:03:052508 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=AS:100\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362509 &sdp_with_bandwidth);
Yves Gerey665174f2018-06-19 13:03:052510 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=AS:50\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362511 &sdp_with_bandwidth);
Yves Gerey665174f2018-06-19 13:03:052512 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
Steve Antonb1c1de12017-12-21 23:14:302513 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:362514 vcd->set_bandwidth(100 * 1000);
Steve Antonb1c1de12017-12-21 23:14:302515 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:362516 acd->set_bandwidth(50 * 1000);
Harald Alvestrand4d7160e2019-04-12 05:01:292517 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362518 jdesc_.session_version()));
2519 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2520}
2521
Taylor Brandstetteree8c2462020-07-27 22:52:022522TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithTiasBandwidth) {
2523 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
2524 std::string sdp_with_bandwidth = kSdpFullString;
2525 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=TIAS:100000\r\n",
2526 &sdp_with_bandwidth);
2527 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=TIAS:50000\r\n",
2528 &sdp_with_bandwidth);
2529 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2530 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2531 vcd->set_bandwidth(100 * 1000);
2532 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
2533 acd->set_bandwidth(50 * 1000);
2534 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2535 jdesc_.session_version()));
2536 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2537}
2538
Philipp Hanckefbbfc022020-07-31 06:30:502539TEST_F(WebRtcSdpTest,
2540 DeserializeSessionDescriptionWithUnknownBandwidthModifier) {
2541 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
2542 std::string sdp_with_bandwidth = kSdpFullString;
2543 InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
2544 "b=unknown:100000\r\n", &sdp_with_bandwidth);
2545 InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
2546 "b=unknown:50000\r\n", &sdp_with_bandwidth);
2547 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
2548 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
2549 vcd->set_bandwidth(-1);
2550 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
2551 acd->set_bandwidth(-1);
2552 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
2553 jdesc_.session_version()));
2554 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
2555}
2556
henrike@webrtc.org28e20752013-07-10 00:45:362557TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
Steve Antona3a92c22017-12-07 18:27:412558 JsepSessionDescription jdesc_with_ice_options(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362559 std::string sdp_with_ice_options = kSdpFullString;
Yves Gerey665174f2018-06-19 13:03:052560 InjectAfter(kSessionTime, "a=ice-options:iceoption3\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362561 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 13:03:052562 InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362563 &sdp_with_ice_options);
Yves Gerey665174f2018-06-19 13:03:052564 InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362565 &sdp_with_ice_options);
2566 EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
2567 std::vector<std::string> transport_options;
2568 transport_options.push_back(kIceOption3);
2569 transport_options.push_back(kIceOption1);
2570 AddIceOptions(kAudioContentName, transport_options);
2571 transport_options.clear();
2572 transport_options.push_back(kIceOption3);
2573 transport_options.push_back(kIceOption2);
2574 AddIceOptions(kVideoContentName, transport_options);
Harald Alvestrand4d7160e2019-04-12 05:01:292575 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:362576 jdesc_.session_version()));
2577 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
2578}
2579
2580TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
2581 // Remove the original ice-ufrag and ice-pwd
Steve Antona3a92c22017-12-07 18:27:412582 JsepSessionDescription jdesc_with_ufrag_pwd(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362583 std::string sdp_with_ufrag_pwd = kSdpFullString;
2584 EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
2585 // Add session level ufrag and pwd
2586 InjectAfter(kSessionTime,
Yves Gerey665174f2018-06-19 13:03:052587 "a=ice-pwd:session+level+icepwd\r\n"
2588 "a=ice-ufrag:session+level+iceufrag\r\n",
2589 &sdp_with_ufrag_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:362590 // Add media level ufrag and pwd for audio
Yves Gerey665174f2018-06-19 13:03:052591 InjectAfter(
2592 "a=mid:audio_content_name\r\n",
henrike@webrtc.org28e20752013-07-10 00:45:362593 "a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
2594 &sdp_with_ufrag_pwd);
2595 // Update the candidate ufrag and pwd to the expected ones.
Yves Gerey665174f2018-06-19 13:03:052596 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0, "media+level+iceufrag",
2597 "media+level+icepwd"));
2598 EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1, "session+level+iceufrag",
2599 "session+level+icepwd"));
henrike@webrtc.org28e20752013-07-10 00:45:362600 EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
2601 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
2602}
2603
henrike@webrtc.org28e20752013-07-10 00:45:362604TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
Steve Anton4e70a722017-11-28 22:57:102605 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kRecvOnly));
henrike@webrtc.org28e20752013-07-10 00:45:362606}
2607
2608TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
Steve Anton4e70a722017-11-28 22:57:102609 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kSendOnly));
henrike@webrtc.org28e20752013-07-10 00:45:362610}
2611
2612TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
Steve Anton4e70a722017-11-28 22:57:102613 EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kInactive));
henrike@webrtc.org28e20752013-07-10 00:45:362614}
2615
2616TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
2617 EXPECT_TRUE(TestDeserializeRejected(true, false));
2618}
2619
2620TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
2621 EXPECT_TRUE(TestDeserializeRejected(false, true));
2622}
2623
2624TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
2625 EXPECT_TRUE(TestDeserializeRejected(true, true));
2626}
2627
Johannes Kron0854eb62018-10-10 20:33:202628TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 08:17:392629 jdesc_.description()->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 20:33:202630 std::string sdp_with_extmap_allow_mixed = kSdpFullString;
Johannes Kron0854eb62018-10-10 20:33:202631 // Deserialize
2632 JsepSessionDescription jdesc_deserialized(kDummyType);
Emil Lundmark801c9992021-01-19 12:06:322633 ASSERT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
Johannes Kron0854eb62018-10-10 20:33:202634 // Verify
2635 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2636}
2637
2638TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutExtmapAllowMixed) {
Johannes Kron9581bc42018-10-23 08:17:392639 jdesc_.description()->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 20:33:202640 std::string sdp_without_extmap_allow_mixed = kSdpFullString;
Emil Lundmark801c9992021-01-19 12:06:322641 Replace(kExtmapAllowMixed, "", &sdp_without_extmap_allow_mixed);
Johannes Kron0854eb62018-10-10 20:33:202642 // Deserialize
2643 JsepSessionDescription jdesc_deserialized(kDummyType);
Emil Lundmark801c9992021-01-19 12:06:322644 ASSERT_TRUE(
Johannes Kron0854eb62018-10-10 20:33:202645 SdpDeserialize(sdp_without_extmap_allow_mixed, &jdesc_deserialized));
2646 // Verify
2647 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2648}
2649
2650TEST_F(WebRtcSdpTest, DeserializeMediaContentDescriptionWithExtmapAllowMixed) {
2651 cricket::MediaContentDescription* video_desc =
2652 jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
2653 ASSERT_TRUE(video_desc);
2654 cricket::MediaContentDescription* audio_desc =
2655 jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
2656 ASSERT_TRUE(audio_desc);
Johannes Kron9581bc42018-10-23 08:17:392657 video_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 20:33:202658 cricket::MediaContentDescription::kMedia);
Johannes Kron9581bc42018-10-23 08:17:392659 audio_desc->set_extmap_allow_mixed_enum(
Johannes Kron0854eb62018-10-10 20:33:202660 cricket::MediaContentDescription::kMedia);
2661
2662 std::string sdp_with_extmap_allow_mixed = kSdpFullString;
2663 InjectAfter("a=mid:audio_content_name\r\n", kExtmapAllowMixed,
2664 &sdp_with_extmap_allow_mixed);
2665 InjectAfter("a=mid:video_content_name\r\n", kExtmapAllowMixed,
2666 &sdp_with_extmap_allow_mixed);
2667
2668 // Deserialize
2669 JsepSessionDescription jdesc_deserialized(kDummyType);
2670 EXPECT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
2671 // Verify
2672 EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
2673}
2674
henrike@webrtc.org28e20752013-07-10 00:45:362675TEST_F(WebRtcSdpTest, DeserializeCandidate) {
2676 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2677
2678 std::string sdp = kSdpOneCandidate;
2679 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2680 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2681 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2682 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
honghaiza0c44ea2016-03-23 23:07:482683 EXPECT_EQ(0, jcandidate.candidate().network_cost());
henrike@webrtc.org28e20752013-07-10 00:45:362684
2685 // Candidate line without generation extension.
2686 sdp = kSdpOneCandidate;
2687 Replace(" generation 2", "", &sdp);
2688 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2689 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2690 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2691 Candidate expected = jcandidate_->candidate();
2692 expected.set_generation(0);
2693 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2694
honghaiza0c44ea2016-03-23 23:07:482695 // Candidate with network id and/or cost.
2696 sdp = kSdpOneCandidate;
2697 Replace(" generation 2", " generation 2 network-id 2", &sdp);
2698 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2699 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2700 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2701 expected = jcandidate_->candidate();
2702 expected.set_network_id(2);
2703 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2704 EXPECT_EQ(0, jcandidate.candidate().network_cost());
2705 // Add network cost
2706 Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
2707 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2708 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2709 EXPECT_EQ(9, jcandidate.candidate().network_cost());
2710
mallinath@webrtc.org2d60c5e2014-08-08 22:29:202711 sdp = kSdpTcpActiveCandidate;
2712 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2713 // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
guoweis@webrtc.org61c12472015-01-15 06:53:072714 Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
guoweis@webrtc.org950c5182014-12-16 23:01:312715 rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
2716 "", "", LOCAL_PORT_TYPE, kCandidateGeneration,
2717 kCandidateFoundation1);
kwibergd1fe2812016-04-27 13:47:292718 std::unique_ptr<IceCandidateInterface> jcandidate_template(
2719 new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
Yves Gerey665174f2018-06-19 13:03:052720 EXPECT_TRUE(
2721 jcandidate.candidate().IsEquivalent(jcandidate_template->candidate()));
mallinath@webrtc.org2d60c5e2014-08-08 22:29:202722 sdp = kSdpTcpPassiveCandidate;
2723 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
2724 sdp = kSdpTcpSOCandidate;
2725 EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:362726}
2727
2728// This test verifies the deserialization of candidate-attribute
David Sanders60c588d2022-03-19 08:43:102729// as per RFC 5245. Candidate-attribute will be of the format
henrike@webrtc.org28e20752013-07-10 00:45:362730// candidate:<blah>. This format will be used when candidates
2731// are trickled.
2732TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
2733 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
2734
2735 std::string candidate_attribute = kRawCandidate;
2736 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2737 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2738 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2739 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
2740 EXPECT_EQ(2u, jcandidate.candidate().generation());
2741
2742 // Candidate line without generation extension.
2743 candidate_attribute = kRawCandidate;
2744 Replace(" generation 2", "", &candidate_attribute);
2745 EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2746 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
2747 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
2748 Candidate expected = jcandidate_->candidate();
2749 expected.set_generation(0);
2750 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
2751
2752 // Candidate line without candidate:
2753 candidate_attribute = kRawCandidate;
2754 Replace("candidate:", "", &candidate_attribute);
2755 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2756
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:152757 // Candidate line with IPV6 address.
2758 EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
Zach Steinb336c272018-08-09 08:16:132759
2760 // Candidate line with hostname address.
2761 EXPECT_TRUE(SdpDeserializeCandidate(kRawHostnameCandidate, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:152762}
2763
2764// This test verifies that the deserialization of an invalid candidate string
2765// fails.
2766TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
Yves Gerey665174f2018-06-19 13:03:052767 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:152768
2769 std::string candidate_attribute = kRawCandidate;
2770 candidate_attribute.replace(0, 1, "x");
henrike@webrtc.org28e20752013-07-10 00:45:362771 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
jiayl@webrtc.org7ec3f9f2014-08-08 23:09:152772
2773 candidate_attribute = kSdpOneCandidate;
2774 candidate_attribute.replace(0, 1, "x");
2775 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2776
2777 candidate_attribute = kRawCandidate;
2778 candidate_attribute.append("\r\n");
2779 candidate_attribute.append(kRawCandidate);
2780 EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
2781
2782 EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:362783}
2784
henrike@webrtc.org28e20752013-07-10 00:45:362785TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
zstein4b2e0822017-02-18 03:48:382786 bool use_sctpmap = true;
2787 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:412788 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:292789 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
henrike@webrtc.org28e20752013-07-10 00:45:362790
2791 std::string sdp_with_data = kSdpString;
2792 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Antona3a92c22017-12-07 18:27:412793 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:362794
Guido Urdanetacecf87f2019-05-31 10:17:382795 // Verify with UDP/DTLS/SCTP (already in kSdpSctpDataChannelString).
lally@webrtc.org36300852015-02-24 20:19:352796 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2797 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2798
Guido Urdanetacecf87f2019-05-31 10:17:382799 // Verify with DTLS/SCTP.
2800 sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp), strlen(kUdpDtlsSctp),
2801 kDtlsSctp);
lally@webrtc.org36300852015-02-24 20:19:352802 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2803 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2804
2805 // Verify with TCP/DTLS/SCTP.
Guido Urdanetacecf87f2019-05-31 10:17:382806 sdp_with_data.replace(sdp_with_data.find(kDtlsSctp), strlen(kDtlsSctp),
Yves Gerey665174f2018-06-19 13:03:052807 kTcpDtlsSctp);
henrike@webrtc.org28e20752013-07-10 00:45:362808 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2809 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2810}
2811
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562812TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
zstein4b2e0822017-02-18 03:48:382813 bool use_sctpmap = false;
2814 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:412815 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:292816 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562817
2818 std::string sdp_with_data = kSdpString;
2819 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Antona3a92c22017-12-07 18:27:412820 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562821
lally@webrtc.orgc7848b72015-02-24 20:19:262822 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2823 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2824}
2825
lally69f57602015-10-08 17:15:042826TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) {
zstein4b2e0822017-02-18 03:48:382827 bool use_sctpmap = false;
2828 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:412829 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:292830 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
lally69f57602015-10-08 17:15:042831
2832 std::string sdp_with_data = kSdpString;
2833 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
Steve Antona3a92c22017-12-07 18:27:412834 JsepSessionDescription jdesc_output(kDummyType);
lally69f57602015-10-08 17:15:042835
lally69f57602015-10-08 17:15:042836 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2837 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2838}
2839
Philipp Hanckeefc55b02020-06-26 08:17:052840TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsButWrongMediaType) {
2841 bool use_sctpmap = true;
2842 AddSctpDataChannel(use_sctpmap);
2843 JsepSessionDescription jdesc(kDummyType);
2844 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
2845
2846 std::string sdp = kSdpSessionString;
2847 sdp += kSdpSctpDataChannelString;
2848
2849 const char needle[] = "m=application ";
2850 sdp.replace(sdp.find(needle), strlen(needle), "m=application:bogus ");
2851
2852 JsepSessionDescription jdesc_output(kDummyType);
2853 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
2854
Philipp Hancke4e8c1152020-10-13 10:43:152855 EXPECT_EQ(1u, jdesc_output.description()->contents().size());
2856 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
Philipp Hanckeefc55b02020-06-26 08:17:052857}
2858
Harald Alvestrand48cce4d2019-04-11 08:41:242859// Helper function to set the max-message-size parameter in the
2860// SCTP data codec.
2861void MutateJsepSctpMaxMessageSize(const SessionDescription& desc,
Harald Alvestrand5fc28b12019-05-13 11:36:162862 int new_value,
Harald Alvestrand48cce4d2019-04-11 08:41:242863 JsepSessionDescription* jdesc) {
Harald Alvestrand8da35a62019-05-10 07:31:042864 std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
Harald Alvestrand5fc28b12019-05-13 11:36:162865 SctpDataContentDescription* dcdesc =
2866 mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
2867 dcdesc->set_max_message_size(new_value);
Harald Alvestrand8da35a62019-05-10 07:31:042868 jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion);
Harald Alvestrand48cce4d2019-04-11 08:41:242869}
2870
2871TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithMaxMessageSize) {
2872 bool use_sctpmap = false;
2873 AddSctpDataChannel(use_sctpmap);
2874 JsepSessionDescription jdesc(kDummyType);
2875 std::string sdp_with_data = kSdpString;
2876
2877 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
2878 sdp_with_data.append("a=max-message-size:12345\r\n");
Harald Alvestrand5fc28b12019-05-13 11:36:162879 MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
Harald Alvestrand48cce4d2019-04-11 08:41:242880 JsepSessionDescription jdesc_output(kDummyType);
2881
Harald Alvestrand48cce4d2019-04-11 08:41:242882 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2883 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2884}
2885
Harald Alvestrandfbb45bd2019-05-15 06:07:472886TEST_F(WebRtcSdpTest, SerializeSdpWithSctpDataChannelWithMaxMessageSize) {
2887 bool use_sctpmap = false;
2888 AddSctpDataChannel(use_sctpmap);
2889 JsepSessionDescription jdesc(kDummyType);
2890 MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
2891 std::string message = webrtc::SdpSerialize(jdesc);
2892 EXPECT_NE(std::string::npos,
2893 message.find("\r\na=max-message-size:12345\r\n"));
2894 JsepSessionDescription jdesc_output(kDummyType);
2895 EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
2896 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2897}
2898
2899TEST_F(WebRtcSdpTest,
2900 SerializeSdpWithSctpDataChannelWithDefaultMaxMessageSize) {
2901 // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
2902 // The default max message size is 64K.
2903 bool use_sctpmap = false;
2904 AddSctpDataChannel(use_sctpmap);
2905 JsepSessionDescription jdesc(kDummyType);
2906 MutateJsepSctpMaxMessageSize(desc_, 65536, &jdesc);
2907 std::string message = webrtc::SdpSerialize(jdesc);
2908 EXPECT_EQ(std::string::npos, message.find("\r\na=max-message-size:"));
2909 JsepSessionDescription jdesc_output(kDummyType);
2910 EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
2911 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
2912}
2913
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562914// Test to check the behaviour if sctp-port is specified
2915// on the m= line and in a=sctp-port.
2916TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
zstein4b2e0822017-02-18 03:48:382917 bool use_sctpmap = true;
2918 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:412919 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand4d7160e2019-04-12 05:01:292920 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562921
2922 std::string sdp_with_data = kSdpString;
2923 // Append m= attributes
2924 sdp_with_data.append(kSdpSctpDataChannelString);
2925 // Append a=sctp-port attribute
2926 sdp_with_data.append("a=sctp-port 5000\r\n");
Steve Antona3a92c22017-12-07 18:27:412927 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562928
2929 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2930}
2931
Harald Alvestrand5fc28b12019-05-13 11:36:162932// Test behavior if a=rtpmap occurs in an SCTP section.
2933TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpmapAttribute) {
2934 std::string sdp_with_data = kSdpString;
2935 // Append m= attributes
2936 sdp_with_data.append(kSdpSctpDataChannelString);
2937 // Append a=rtpmap attribute
2938 sdp_with_data.append("a=rtpmap:111 opus/48000/2\r\n");
2939 JsepSessionDescription jdesc_output(kDummyType);
2940 // Correct behavior is to ignore the extra attribute.
2941 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2942}
2943
henrike@webrtc.org571df2d2014-02-19 23:04:262944// For crbug/344475.
2945TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
2946 std::string sdp_with_data = kSdpString;
2947 sdp_with_data.append(kSdpSctpDataChannelString);
2948 // Remove the "\n" at the end.
2949 sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
Steve Antona3a92c22017-12-07 18:27:412950 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org571df2d2014-02-19 23:04:262951
2952 EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
2953 // No crash is a pass.
2954}
2955
zstein4b2e0822017-02-18 03:48:382956TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) {
2957 bool use_sctpmap = true;
2958 AddSctpDataChannel(use_sctpmap);
2959
2960 // First setup the expected JsepSessionDescription.
Steve Antona3a92c22017-12-07 18:27:412961 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 11:36:162962 MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
wu@webrtc.org78187522013-10-07 23:32:022963
jiayl@webrtc.org9c16c392014-05-01 18:30:302964 // Then get the deserialized JsepSessionDescription.
wu@webrtc.org78187522013-10-07 23:32:022965 std::string sdp_with_data = kSdpString;
2966 sdp_with_data.append(kSdpSctpDataChannelString);
Steve Anton1c9c9fc2019-02-14 23:13:092967 absl::StrReplaceAll(
2968 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
2969 &sdp_with_data);
Steve Antona3a92c22017-12-07 18:27:412970 JsepSessionDescription jdesc_output(kDummyType);
wu@webrtc.org78187522013-10-07 23:32:022971
2972 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2973 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
zstein4b2e0822017-02-18 03:48:382974}
2975
2976TEST_F(WebRtcSdpTest,
2977 DeserializeSdpWithSctpDataChannelAndUnusualPortInAttribute) {
2978 bool use_sctpmap = false;
2979 AddSctpDataChannel(use_sctpmap);
2980
Steve Antona3a92c22017-12-07 18:27:412981 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 11:36:162982 MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562983
2984 // We need to test the deserialized JsepSessionDescription from
2985 // kSdpSctpDataChannelStringWithSctpPort for
2986 // draft-ietf-mmusic-sctp-sdp-07
2987 // a=sctp-port
zstein4b2e0822017-02-18 03:48:382988 std::string sdp_with_data = kSdpString;
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562989 sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
Steve Anton1c9c9fc2019-02-14 23:13:092990 absl::StrReplaceAll(
2991 {{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
2992 &sdp_with_data);
Steve Antona3a92c22017-12-07 18:27:412993 JsepSessionDescription jdesc_output(kDummyType);
jiayl@webrtc.orgddb85ab2014-09-05 16:31:562994
2995 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
2996 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
wu@webrtc.org78187522013-10-07 23:32:022997}
2998
Peter Thatcherc0c3a862015-06-24 22:31:252999TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
zstein4b2e0822017-02-18 03:48:383000 bool use_sctpmap = true;
3001 AddSctpDataChannel(use_sctpmap);
Steve Antona3a92c22017-12-07 18:27:413002 JsepSessionDescription jdesc(kDummyType);
Harald Alvestrand5fc28b12019-05-13 11:36:163003 SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_);
Peter Thatcherc0c3a862015-06-24 22:31:253004 dcd->set_bandwidth(100 * 1000);
Harald Alvestrand4d7160e2019-04-12 05:01:293005 ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
Peter Thatcherc0c3a862015-06-24 22:31:253006
3007 std::string sdp_with_bandwidth = kSdpString;
3008 sdp_with_bandwidth.append(kSdpSctpDataChannelString);
Yves Gerey665174f2018-06-19 13:03:053009 InjectAfter("a=mid:data_content_name\r\n", "b=AS:100\r\n",
Peter Thatcherc0c3a862015-06-24 22:31:253010 &sdp_with_bandwidth);
Steve Antona3a92c22017-12-07 18:27:413011 JsepSessionDescription jdesc_with_bandwidth(kDummyType);
Peter Thatcherc0c3a862015-06-24 22:31:253012
3013 // SCTP has congestion control, so we shouldn't limit the bandwidth
3014 // as we do for RTP.
3015 EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
wu@webrtc.orgcadf9042013-08-30 21:24:163016 EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
3017}
3018
Yves Gerey665174f2018-06-19 13:03:053019class WebRtcSdpExtmapTest : public WebRtcSdpTest,
Mirko Bonadei6a489f22019-04-09 13:11:123020 public ::testing::WithParamInterface<bool> {};
jbauch5869f502017-06-29 19:31:363021
3022TEST_P(WebRtcSdpExtmapTest,
Yves Gerey665174f2018-06-19 13:03:053023 DeserializeSessionDescriptionWithSessionLevelExtmap) {
jbauch5869f502017-06-29 19:31:363024 bool encrypted = GetParam();
3025 TestDeserializeExtmap(true, false, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:363026}
3027
Yves Gerey665174f2018-06-19 13:03:053028TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
jbauch5869f502017-06-29 19:31:363029 bool encrypted = GetParam();
3030 TestDeserializeExtmap(false, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:363031}
3032
Yves Gerey665174f2018-06-19 13:03:053033TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithInvalidExtmap) {
jbauch5869f502017-06-29 19:31:363034 bool encrypted = GetParam();
3035 TestDeserializeExtmap(true, true, encrypted);
henrike@webrtc.org28e20752013-07-10 00:45:363036}
3037
Mirko Bonadeic84f6612019-01-31 11:20:573038INSTANTIATE_TEST_SUITE_P(Encrypted,
3039 WebRtcSdpExtmapTest,
3040 ::testing::Values(false, true));
jbauch5869f502017-06-29 19:31:363041
sergeyu@chromium.org5bc25c42013-12-05 00:24:063042TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
Steve Antona3a92c22017-12-07 18:27:413043 JsepSessionDescription jdesc(kDummyType);
sergeyu@chromium.org5bc25c42013-12-05 00:24:063044 std::string sdp = kSdpFullString;
3045 sdp = sdp.substr(0, sdp.size() - 2); // Remove \r\n at the end.
3046 // Deserialize
3047 SdpParseError error;
3048 EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
Harald Alvestrand88b8dec12022-04-07 09:54:513049 const std::string lastline = "a=ssrc:3 msid:local_stream_1 video_track_id_1";
sergeyu@chromium.org5bc25c42013-12-05 00:24:063050 EXPECT_EQ(lastline, error.line);
3051 EXPECT_EQ("Invalid SDP line.", error.description);
3052}
3053
henrike@webrtc.org28e20752013-07-10 00:45:363054TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
3055 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
3056 std::string new_sdp = kSdpOneCandidate;
3057 Replace("udp", "unsupported_transport", &new_sdp);
3058 EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
3059 new_sdp = kSdpOneCandidate;
3060 Replace("udp", "uDP", &new_sdp);
3061 EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
3062 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
3063 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
3064 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
3065}
3066
honghaiza54a0802015-12-17 02:37:233067TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) {
henrike@webrtc.org28e20752013-07-10 00:45:363068 JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
honghaiza54a0802015-12-17 02:37:233069 EXPECT_TRUE(
3070 SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate));
henrike@webrtc.org28e20752013-07-10 00:45:363071 EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
3072 EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
3073 Candidate ref_candidate = jcandidate_->candidate();
3074 ref_candidate.set_username("user_rtp");
3075 ref_candidate.set_password("password_rtp");
3076 EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
3077}
3078
henrike@webrtc.org704bf9e2014-02-27 17:52:043079TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 18:27:413080 JsepSessionDescription jdesc(kDummyType);
henrike@webrtc.org704bf9e2014-02-27 17:52:043081
3082 // Deserialize
3083 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
3084
3085 // Verify
3086 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 23:55:303087 cricket::GetFirstAudioContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:043088 EXPECT_TRUE(audio->conference_mode());
3089
3090 cricket::VideoContentDescription* video =
Steve Anton06817cd2018-12-18 23:55:303091 cricket::GetFirstVideoContentDescription(jdesc.description());
henrike@webrtc.org704bf9e2014-02-27 17:52:043092 EXPECT_TRUE(video->conference_mode());
3093}
3094
deadbeefd45aea82017-09-16 08:24:293095TEST_F(WebRtcSdpTest, SerializeSdpWithConferenceFlag) {
Steve Antona3a92c22017-12-07 18:27:413096 JsepSessionDescription jdesc(kDummyType);
deadbeefd45aea82017-09-16 08:24:293097
3098 // We tested deserialization already above, so just test that if we serialize
3099 // and deserialize the flag doesn't disappear.
3100 EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
Steve Antone831b8c2018-02-01 20:22:163101 std::string reserialized = webrtc::SdpSerialize(jdesc);
deadbeefd45aea82017-09-16 08:24:293102 EXPECT_TRUE(SdpDeserialize(reserialized, &jdesc));
3103
3104 // Verify.
3105 cricket::AudioContentDescription* audio =
Steve Anton06817cd2018-12-18 23:55:303106 cricket::GetFirstAudioContentDescription(jdesc.description());
deadbeefd45aea82017-09-16 08:24:293107 EXPECT_TRUE(audio->conference_mode());
3108
3109 cricket::VideoContentDescription* video =
Steve Anton06817cd2018-12-18 23:55:303110 cricket::GetFirstVideoContentDescription(jdesc.description());
deadbeefd45aea82017-09-16 08:24:293111 EXPECT_TRUE(video->conference_mode());
3112}
3113
Sebastian Jansson97321b62019-07-24 12:01:183114TEST_F(WebRtcSdpTest, SerializeAndDeserializeRemoteNetEstimate) {
3115 {
3116 // By default remote estimates are disabled.
3117 JsepSessionDescription dst(kDummyType);
3118 SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
3119 EXPECT_FALSE(cricket::GetFirstVideoContentDescription(dst.description())
3120 ->remote_estimate());
3121 }
3122 {
3123 // When remote estimate is enabled, the setting is propagated via SDP.
3124 cricket::GetFirstVideoContentDescription(jdesc_.description())
3125 ->set_remote_estimate(true);
3126 JsepSessionDescription dst(kDummyType);
3127 SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
3128 EXPECT_TRUE(cricket::GetFirstVideoContentDescription(dst.description())
3129 ->remote_estimate());
3130 }
3131}
3132
henrike@webrtc.org28e20752013-07-10 00:45:363133TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
3134 const char kSdpDestroyer[] = "!@#$%^&";
decurtis@webrtc.org8af11042015-01-07 19:15:513135 const char kSdpEmptyType[] = " =candidate";
3136 const char kSdpEqualAsPlus[] = "a+candidate";
3137 const char kSdpSpaceAfterEqual[] = "a= candidate";
3138 const char kSdpUpperType[] = "A=candidate";
3139 const char kSdpEmptyLine[] = "";
3140 const char kSdpMissingValue[] = "a=";
3141
Yves Gerey665174f2018-06-19 13:03:053142 const char kSdpBrokenFingerprint[] =
3143 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:363144 "4AAD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
Yves Gerey665174f2018-06-19 13:03:053145 const char kSdpExtraField[] =
3146 "a=fingerprint:sha-1 "
henrike@webrtc.org28e20752013-07-10 00:45:363147 "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 13:03:053148 const char kSdpMissingSpace[] =
3149 "a=fingerprint:sha-1"
henrike@webrtc.org28e20752013-07-10 00:45:363150 "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:583151 // MD5 is not allowed in fingerprints.
Yves Gerey665174f2018-06-19 13:03:053152 const char kSdpMd5[] =
3153 "a=fingerprint:md5 "
henrika@webrtc.orgaebb1ad2014-01-14 10:00:583154 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
henrike@webrtc.org28e20752013-07-10 00:45:363155
3156 // Broken session description
wu@webrtc.org5e760e72014-04-02 23:19:093157 ExpectParseFailure("v=", kSdpDestroyer);
3158 ExpectParseFailure("o=", kSdpDestroyer);
3159 ExpectParseFailure("s=-", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:363160 // Broken time description
wu@webrtc.org5e760e72014-04-02 23:19:093161 ExpectParseFailure("t=", kSdpDestroyer);
henrike@webrtc.org28e20752013-07-10 00:45:363162
3163 // Broken media description
wu@webrtc.org5e760e72014-04-02 23:19:093164 ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
3165 ExpectParseFailure("m=video", kSdpDestroyer);
Philipp Hanckeefc55b02020-06-26 08:17:053166 ExpectParseFailure("m=", "c=IN IP4 74.125.224.39");
henrike@webrtc.org28e20752013-07-10 00:45:363167
3168 // Invalid lines
decurtis@webrtc.org8af11042015-01-07 19:15:513169 ExpectParseFailure("a=candidate", kSdpEmptyType);
3170 ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
3171 ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
3172 ExpectParseFailure("a=candidate", kSdpUpperType);
henrike@webrtc.org28e20752013-07-10 00:45:363173
3174 // Bogus fingerprint replacing a=sendrev. We selected this attribute
3175 // because it's orthogonal to what we are replacing and hence
3176 // safe.
decurtis@webrtc.org8af11042015-01-07 19:15:513177 ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
3178 ExpectParseFailure("a=sendrecv", kSdpExtraField);
3179 ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
3180 ExpectParseFailure("a=sendrecv", kSdpMd5);
3181
3182 // Empty Line
3183 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
3184 ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
wu@webrtc.org5e760e72014-04-02 23:19:093185}
3186
3187TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
3188 // ssrc
3189 ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
deadbeef9d3584c2016-02-17 01:54:103190 ExpectParseFailure("a=ssrc-group:FEC 2 3", "a=ssrc-group:FEC badvalue 3");
Harald Alvestrand0d018412021-11-04 13:52:313191 // crypto
3192 ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
wu@webrtc.org5e760e72014-04-02 23:19:093193 // rtpmap
3194 ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
3195 ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
3196 ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
3197 // candidate
3198 ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
3199 ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
3200 ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
3201 ExpectParseFailure("rport 2346", "rport badvalue");
3202 ExpectParseFailure("rport 2346 generation 2",
3203 "rport 2346 generation badvalue");
3204 // m line
3205 ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
3206 "m=audio 2345 RTP/SAVPF 111 badvalue 104");
3207
3208 // bandwidth
3209 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
Yves Gerey665174f2018-06-19 13:03:053210 "b=AS:badvalue\r\n", "b=AS:badvalue");
Philipp Hanckefbbfc022020-07-31 06:30:503211 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS\r\n",
3212 "b=AS");
3213 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS:\r\n",
3214 "b=AS:");
3215 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3216 "b=AS:12:34\r\n", "b=AS:12:34");
3217
wu@webrtc.org5e760e72014-04-02 23:19:093218 // rtcp-fb
3219 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3220 "a=rtcp-fb:badvalue nack\r\n",
3221 "a=rtcp-fb:badvalue nack");
3222 // extmap
3223 ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
3224 "a=extmap:badvalue http://example.com\r\n",
3225 "a=extmap:badvalue http://example.com");
henrike@webrtc.org28e20752013-07-10 00:45:363226}
3227
3228TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
Steve Antona3a92c22017-12-07 18:27:413229 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363230
3231 const char kSdpWithReorderedPlTypesString[] =
3232 "v=0\r\n"
3233 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3234 "s=-\r\n"
3235 "t=0 0\r\n"
pthatcher@webrtc.orgc9d6d142014-10-23 23:37:223236 "m=audio 9 RTP/SAVPF 104 103\r\n" // Pl type 104 preferred.
Yves Gerey665174f2018-06-19 13:03:053237 "a=rtpmap:111 opus/48000/2\r\n" // Pltype 111 listed before 103 and 104
3238 // in the map.
henrike@webrtc.org28e20752013-07-10 00:45:363239 "a=rtpmap:103 ISAC/16000\r\n" // Pltype 103 listed before 104 in the map.
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:413240 "a=rtpmap:104 ISAC/32000\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:363241
3242 // Deserialize
3243 EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
3244
henrike@webrtc.org28e20752013-07-10 00:45:363245 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 23:14:303246 GetFirstAudioContentDescription(jdesc_output.description());
3247 ASSERT_TRUE(acd);
henrike@webrtc.org28e20752013-07-10 00:45:363248 ASSERT_FALSE(acd->codecs().empty());
minyue@webrtc.orgf9b5c1b2015-02-17 12:36:413249 EXPECT_EQ("ISAC", acd->codecs()[0].name);
3250 EXPECT_EQ(32000, acd->codecs()[0].clockrate);
henrike@webrtc.org28e20752013-07-10 00:45:363251 EXPECT_EQ(104, acd->codecs()[0].id);
3252}
3253
3254TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
Steve Antona3a92c22017-12-07 18:27:413255 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363256 CodecParams params;
3257 params.max_ptime = 40;
3258 params.ptime = 30;
3259 params.min_ptime = 10;
3260 params.sprop_stereo = 1;
3261 params.stereo = 1;
3262 params.useinband = 1;
henrike@webrtc.org1e09a712013-07-26 19:17:593263 params.maxaveragebitrate = 128000;
henrike@webrtc.org28e20752013-07-10 00:45:363264 TestDeserializeCodecParams(params, &jdesc_output);
Steve Antone831b8c2018-02-01 20:22:163265 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:363266}
3267
3268TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
3269 const bool kUseWildcard = false;
Steve Antona3a92c22017-12-07 18:27:413270 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363271 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 20:22:163272 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:363273}
3274
3275TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
3276 const bool kUseWildcard = true;
Steve Antona3a92c22017-12-07 18:27:413277 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363278 TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
Steve Antone831b8c2018-02-01 20:22:163279 TestSerialize(jdesc_output);
henrike@webrtc.org28e20752013-07-10 00:45:363280}
3281
3282TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
Steve Antona3a92c22017-12-07 18:27:413283 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363284
3285 const char kSdpWithFmtpString[] =
3286 "v=0\r\n"
3287 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3288 "s=-\r\n"
3289 "t=0 0\r\n"
3290 "m=video 3457 RTP/SAVPF 120\r\n"
3291 "a=rtpmap:120 VP8/90000\r\n"
Donald Curtis0e07f922015-05-15 16:21:233292 "a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
3293
3294 // Deserialize
3295 SdpParseError error;
Donald Curtis144d0182015-05-15 20:14:243296 EXPECT_TRUE(
3297 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
Donald Curtis0e07f922015-05-15 16:21:233298
Donald Curtis0e07f922015-05-15 16:21:233299 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 23:14:303300 GetFirstVideoContentDescription(jdesc_output.description());
3301 ASSERT_TRUE(vcd);
Donald Curtis0e07f922015-05-15 16:21:233302 ASSERT_FALSE(vcd->codecs().empty());
3303 cricket::VideoCodec vp8 = vcd->codecs()[0];
3304 EXPECT_EQ("VP8", vp8.name);
3305 EXPECT_EQ(120, vp8.id);
3306 cricket::CodecParameterMap::iterator found =
3307 vp8.params.find("x-google-min-bitrate");
3308 ASSERT_TRUE(found != vp8.params.end());
3309 EXPECT_EQ(found->second, "10");
3310 found = vp8.params.find("x-google-max-quantization");
3311 ASSERT_TRUE(found != vp8.params.end());
3312 EXPECT_EQ(found->second, "40");
3313}
3314
johan2d8d23e2016-06-03 08:22:423315TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSprops) {
Steve Antona3a92c22017-12-07 18:27:413316 JsepSessionDescription jdesc_output(kDummyType);
johan2d8d23e2016-06-03 08:22:423317
3318 const char kSdpWithFmtpString[] =
3319 "v=0\r\n"
3320 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3321 "s=-\r\n"
3322 "t=0 0\r\n"
3323 "m=video 49170 RTP/AVP 98\r\n"
3324 "a=rtpmap:98 H264/90000\r\n"
3325 "a=fmtp:98 profile-level-id=42A01E; "
3326 "sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==\r\n";
3327
3328 // Deserialize.
3329 SdpParseError error;
3330 EXPECT_TRUE(
3331 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
3332
johan2d8d23e2016-06-03 08:22:423333 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 23:14:303334 GetFirstVideoContentDescription(jdesc_output.description());
3335 ASSERT_TRUE(vcd);
johan2d8d23e2016-06-03 08:22:423336 ASSERT_FALSE(vcd->codecs().empty());
3337 cricket::VideoCodec h264 = vcd->codecs()[0];
3338 EXPECT_EQ("H264", h264.name);
3339 EXPECT_EQ(98, h264.id);
3340 cricket::CodecParameterMap::const_iterator found =
3341 h264.params.find("profile-level-id");
3342 ASSERT_TRUE(found != h264.params.end());
3343 EXPECT_EQ(found->second, "42A01E");
3344 found = h264.params.find("sprop-parameter-sets");
3345 ASSERT_TRUE(found != h264.params.end());
3346 EXPECT_EQ(found->second, "Z0IACpZTBYmI,aMljiA==");
3347}
3348
Donald Curtis0e07f922015-05-15 16:21:233349TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
Steve Antona3a92c22017-12-07 18:27:413350 JsepSessionDescription jdesc_output(kDummyType);
Donald Curtis0e07f922015-05-15 16:21:233351
3352 const char kSdpWithFmtpString[] =
3353 "v=0\r\n"
3354 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3355 "s=-\r\n"
3356 "t=0 0\r\n"
3357 "m=video 3457 RTP/SAVPF 120\r\n"
3358 "a=rtpmap:120 VP8/90000\r\n"
3359 "a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
henrike@webrtc.org28e20752013-07-10 00:45:363360
3361 // Deserialize
3362 SdpParseError error;
Yves Gerey665174f2018-06-19 13:03:053363 EXPECT_TRUE(
3364 webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
henrike@webrtc.org28e20752013-07-10 00:45:363365
henrike@webrtc.org28e20752013-07-10 00:45:363366 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 23:14:303367 GetFirstVideoContentDescription(jdesc_output.description());
3368 ASSERT_TRUE(vcd);
henrike@webrtc.org28e20752013-07-10 00:45:363369 ASSERT_FALSE(vcd->codecs().empty());
3370 cricket::VideoCodec vp8 = vcd->codecs()[0];
3371 EXPECT_EQ("VP8", vp8.name);
3372 EXPECT_EQ(120, vp8.id);
3373 cricket::CodecParameterMap::iterator found =
3374 vp8.params.find("x-google-min-bitrate");
3375 ASSERT_TRUE(found != vp8.params.end());
3376 EXPECT_EQ(found->second, "10");
3377 found = vp8.params.find("x-google-max-quantization");
3378 ASSERT_TRUE(found != vp8.params.end());
3379 EXPECT_EQ(found->second, "40");
3380}
3381
Mirta Dvornicic479a3c02019-06-04 13:38:503382TEST_F(WebRtcSdpTest, DeserializePacketizationAttributeWithIllegalValue) {
3383 JsepSessionDescription jdesc_output(kDummyType);
3384
3385 const char kSdpWithPacketizationString[] =
3386 "v=0\r\n"
3387 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3388 "s=-\r\n"
3389 "t=0 0\r\n"
3390 "m=audio 9 RTP/SAVPF 111\r\n"
3391 "a=rtpmap:111 opus/48000/2\r\n"
3392 "a=packetization:111 unknownpacketizationattributeforaudio\r\n"
3393 "m=video 3457 RTP/SAVPF 120 121 122\r\n"
3394 "a=rtpmap:120 VP8/90000\r\n"
3395 "a=packetization:120 raw\r\n"
3396 "a=rtpmap:121 VP9/90000\r\n"
3397 "a=rtpmap:122 H264/90000\r\n"
3398 "a=packetization:122 unknownpacketizationattributevalue\r\n";
3399
3400 SdpParseError error;
3401 EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithPacketizationString, &jdesc_output,
3402 &error));
3403
3404 AudioContentDescription* acd =
3405 GetFirstAudioContentDescription(jdesc_output.description());
3406 ASSERT_TRUE(acd);
3407 ASSERT_THAT(acd->codecs(), testing::SizeIs(1));
3408 cricket::AudioCodec opus = acd->codecs()[0];
3409 EXPECT_EQ(opus.name, "opus");
3410 EXPECT_EQ(opus.id, 111);
3411
3412 const VideoContentDescription* vcd =
3413 GetFirstVideoContentDescription(jdesc_output.description());
3414 ASSERT_TRUE(vcd);
3415 ASSERT_THAT(vcd->codecs(), testing::SizeIs(3));
3416 cricket::VideoCodec vp8 = vcd->codecs()[0];
3417 EXPECT_EQ(vp8.name, "VP8");
3418 EXPECT_EQ(vp8.id, 120);
3419 EXPECT_EQ(vp8.packetization, "raw");
3420 cricket::VideoCodec vp9 = vcd->codecs()[1];
3421 EXPECT_EQ(vp9.name, "VP9");
3422 EXPECT_EQ(vp9.id, 121);
3423 EXPECT_EQ(vp9.packetization, absl::nullopt);
3424 cricket::VideoCodec h264 = vcd->codecs()[2];
3425 EXPECT_EQ(h264.name, "H264");
3426 EXPECT_EQ(h264.id, 122);
3427 EXPECT_EQ(h264.packetization, absl::nullopt);
3428}
3429
ossuaa4b0772017-01-30 15:41:183430TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithUnknownParameter) {
Steve Antonb1c1de12017-12-21 23:14:303431 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 15:41:183432
3433 cricket::AudioCodecs codecs = acd->codecs();
3434 codecs[0].params["unknown-future-parameter"] = "SomeFutureValue";
3435 acd->set_codecs(codecs);
3436
Harald Alvestrand4d7160e2019-04-12 05:01:293437 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 15:41:183438 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:163439 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 15:41:183440 std::string sdp_with_fmtp = kSdpFullString;
3441 InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
3442 "a=fmtp:111 unknown-future-parameter=SomeFutureValue\r\n",
3443 &sdp_with_fmtp);
3444 EXPECT_EQ(sdp_with_fmtp, message);
3445}
3446
3447TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithKnownFmtpParameter) {
Steve Antonb1c1de12017-12-21 23:14:303448 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 15:41:183449
3450 cricket::AudioCodecs codecs = acd->codecs();
3451 codecs[0].params["stereo"] = "1";
3452 acd->set_codecs(codecs);
3453
Harald Alvestrand4d7160e2019-04-12 05:01:293454 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 15:41:183455 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:163456 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 15:41:183457 std::string sdp_with_fmtp = kSdpFullString;
Yves Gerey665174f2018-06-19 13:03:053458 InjectAfter("a=rtpmap:111 opus/48000/2\r\n", "a=fmtp:111 stereo=1\r\n",
ossuaa4b0772017-01-30 15:41:183459 &sdp_with_fmtp);
3460 EXPECT_EQ(sdp_with_fmtp, message);
3461}
3462
3463TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithPTimeAndMaxPTime) {
Steve Antonb1c1de12017-12-21 23:14:303464 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
ossuaa4b0772017-01-30 15:41:183465
3466 cricket::AudioCodecs codecs = acd->codecs();
3467 codecs[0].params["ptime"] = "20";
3468 codecs[0].params["maxptime"] = "120";
3469 acd->set_codecs(codecs);
3470
Harald Alvestrand4d7160e2019-04-12 05:01:293471 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
ossuaa4b0772017-01-30 15:41:183472 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:163473 std::string message = webrtc::SdpSerialize(jdesc_);
ossuaa4b0772017-01-30 15:41:183474 std::string sdp_with_fmtp = kSdpFullString;
3475 InjectAfter("a=rtpmap:104 ISAC/32000\r\n",
3476 "a=maxptime:120\r\n" // No comma here. String merging!
3477 "a=ptime:20\r\n",
3478 &sdp_with_fmtp);
3479 EXPECT_EQ(sdp_with_fmtp, message);
3480}
3481
Philipp Hanckef2a4ec12020-07-01 19:07:323482TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithTelephoneEvent) {
3483 AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
3484
3485 cricket::AudioCodecs codecs = acd->codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:573486 cricket::AudioCodec dtmf =
3487 cricket::CreateAudioCodec(105, "telephone-event", 8000, 1);
Philipp Hanckef2a4ec12020-07-01 19:07:323488 dtmf.params[""] = "0-15";
3489 codecs.push_back(dtmf);
3490 acd->set_codecs(codecs);
3491
3492 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
3493 jdesc_.session_version()));
3494 std::string message = webrtc::SdpSerialize(jdesc_);
3495 std::string sdp_with_fmtp = kSdpFullString;
3496 InjectAfter("m=audio 2345 RTP/SAVPF 111 103 104", " 105", &sdp_with_fmtp);
3497 InjectAfter(
3498 "a=rtpmap:104 ISAC/32000\r\n",
3499 "a=rtpmap:105 telephone-event/8000\r\n" // No comma here. String merging!
3500 "a=fmtp:105 0-15\r\n",
3501 &sdp_with_fmtp);
3502 EXPECT_EQ(sdp_with_fmtp, message);
3503}
3504
henrike@webrtc.org28e20752013-07-10 00:45:363505TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
Steve Antonb1c1de12017-12-21 23:14:303506 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
henrike@webrtc.org28e20752013-07-10 00:45:363507
3508 cricket::VideoCodecs codecs = vcd->codecs();
3509 codecs[0].params["x-google-min-bitrate"] = "10";
3510 vcd->set_codecs(codecs);
3511
Harald Alvestrand4d7160e2019-04-12 05:01:293512 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
henrike@webrtc.org28e20752013-07-10 00:45:363513 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:163514 std::string message = webrtc::SdpSerialize(jdesc_);
henrike@webrtc.org28e20752013-07-10 00:45:363515 std::string sdp_with_fmtp = kSdpFullString;
3516 InjectAfter("a=rtpmap:120 VP8/90000\r\n",
Yves Gerey665174f2018-06-19 13:03:053517 "a=fmtp:120 x-google-min-bitrate=10\r\n", &sdp_with_fmtp);
henrike@webrtc.org28e20752013-07-10 00:45:363518 EXPECT_EQ(sdp_with_fmtp, message);
3519}
3520
Mirta Dvornicic479a3c02019-06-04 13:38:503521TEST_F(WebRtcSdpTest, SerializeVideoPacketizationAttribute) {
3522 VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
3523
3524 cricket::VideoCodecs codecs = vcd->codecs();
3525 codecs[0].packetization = "raw";
3526 vcd->set_codecs(codecs);
3527
3528 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
3529 jdesc_.session_version()));
3530 std::string message = webrtc::SdpSerialize(jdesc_);
3531 std::string sdp_with_packetization = kSdpFullString;
3532 InjectAfter("a=rtpmap:120 VP8/90000\r\n", "a=packetization:120 raw\r\n",
3533 &sdp_with_packetization);
3534 EXPECT_EQ(sdp_with_packetization, message);
3535}
3536
Taylor Brandstetter2f65ec52018-05-24 18:37:283537TEST_F(WebRtcSdpTest, DeserializeAndSerializeSdpWithIceLite) {
3538 // Deserialize the baseline description, making sure it's ICE full.
Steve Antona3a92c22017-12-07 18:27:413539 JsepSessionDescription jdesc_with_icelite(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363540 std::string sdp_with_icelite = kSdpFullString;
3541 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3542 cricket::SessionDescription* desc = jdesc_with_icelite.description();
3543 const cricket::TransportInfo* tinfo1 =
3544 desc->GetTransportInfoByName("audio_content_name");
3545 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
3546 const cricket::TransportInfo* tinfo2 =
3547 desc->GetTransportInfoByName("video_content_name");
3548 EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
Taylor Brandstetter2f65ec52018-05-24 18:37:283549
3550 // Add "a=ice-lite" and deserialize, making sure it's ICE lite.
Yves Gerey665174f2018-06-19 13:03:053551 InjectAfter(kSessionTime, "a=ice-lite\r\n", &sdp_with_icelite);
henrike@webrtc.org28e20752013-07-10 00:45:363552 EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
3553 desc = jdesc_with_icelite.description();
3554 const cricket::TransportInfo* atinfo =
3555 desc->GetTransportInfoByName("audio_content_name");
3556 EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
3557 const cricket::TransportInfo* vtinfo =
Yves Gerey665174f2018-06-19 13:03:053558 desc->GetTransportInfoByName("video_content_name");
henrike@webrtc.org28e20752013-07-10 00:45:363559 EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
Taylor Brandstetter2f65ec52018-05-24 18:37:283560
3561 // Now that we know deserialization works, we can use TestSerialize to test
3562 // serialization.
3563 TestSerialize(jdesc_with_icelite);
henrike@webrtc.org28e20752013-07-10 00:45:363564}
3565
3566// Verifies that the candidates in the input SDP are parsed and serialized
3567// correctly in the output SDP.
3568TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
3569 std::string sdp_with_data = kSdpString;
3570 sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
Steve Antona3a92c22017-12-07 18:27:413571 JsepSessionDescription jdesc_output(kDummyType);
henrike@webrtc.org28e20752013-07-10 00:45:363572
3573 EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
Steve Antone831b8c2018-02-01 20:22:163574 EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
henrike@webrtc.org28e20752013-07-10 00:45:363575}
sergeyu@chromium.org0be6aa02013-08-23 23:21:253576
3577TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
3578 AddFingerprint();
3579 TransportInfo audio_transport_info =
3580 *(desc_.GetTransportInfoByName(kAudioContentName));
3581 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3582 audio_transport_info.description.connection_role);
3583 audio_transport_info.description.connection_role =
Yves Gerey665174f2018-06-19 13:03:053584 cricket::CONNECTIONROLE_ACTIVE;
sergeyu@chromium.org0be6aa02013-08-23 23:21:253585
3586 TransportInfo video_transport_info =
3587 *(desc_.GetTransportInfoByName(kVideoContentName));
3588 EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
3589 video_transport_info.description.connection_role);
3590 video_transport_info.description.connection_role =
Yves Gerey665174f2018-06-19 13:03:053591 cricket::CONNECTIONROLE_ACTIVE;
sergeyu@chromium.org0be6aa02013-08-23 23:21:253592
3593 desc_.RemoveTransportInfoByName(kAudioContentName);
3594 desc_.RemoveTransportInfoByName(kVideoContentName);
3595
3596 desc_.AddTransportInfo(audio_transport_info);
3597 desc_.AddTransportInfo(video_transport_info);
3598
Harald Alvestrand4d7160e2019-04-12 05:01:293599 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
sergeyu@chromium.org0be6aa02013-08-23 23:21:253600 jdesc_.session_version()));
Steve Antone831b8c2018-02-01 20:22:163601 std::string message = webrtc::SdpSerialize(jdesc_);
sergeyu@chromium.org0be6aa02013-08-23 23:21:253602 std::string sdp_with_dtlssetup = kSdpFullString;
3603
3604 // Fingerprint attribute is necessary to add DTLS setup attribute.
Yves Gerey665174f2018-06-19 13:03:053605 InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_dtlssetup);
3606 InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_dtlssetup);
Artem Titov880fa812021-07-30 20:30:233607 // Now adding `setup` attribute.
Yves Gerey665174f2018-06-19 13:03:053608 InjectAfter(kFingerprint, "a=setup:active\r\n", &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:253609 EXPECT_EQ(sdp_with_dtlssetup, message);
3610}
3611
Harald Alvestrandefece422021-08-19 09:12:513612TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributeActpass) {
Steve Antona3a92c22017-12-07 18:27:413613 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
sergeyu@chromium.org0be6aa02013-08-23 23:21:253614 std::string sdp_with_dtlssetup = kSdpFullString;
Yves Gerey665174f2018-06-19 13:03:053615 InjectAfter(kSessionTime, "a=setup:actpass\r\n", &sdp_with_dtlssetup);
sergeyu@chromium.org0be6aa02013-08-23 23:21:253616 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3617 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3618 const cricket::TransportInfo* atinfo =
3619 desc->GetTransportInfoByName("audio_content_name");
3620 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3621 atinfo->description.connection_role);
3622 const cricket::TransportInfo* vtinfo =
Yves Gerey665174f2018-06-19 13:03:053623 desc->GetTransportInfoByName("video_content_name");
sergeyu@chromium.org0be6aa02013-08-23 23:21:253624 EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
3625 vtinfo->description.connection_role);
3626}
jiayl@webrtc.orge7d47a12014-08-05 19:19:053627
Harald Alvestrandefece422021-08-19 09:12:513628TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributeActive) {
3629 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
3630 std::string sdp_with_dtlssetup = kSdpFullString;
3631 InjectAfter(kSessionTime, "a=setup:active\r\n", &sdp_with_dtlssetup);
3632 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3633 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3634 const cricket::TransportInfo* atinfo =
3635 desc->GetTransportInfoByName("audio_content_name");
3636 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
3637 atinfo->description.connection_role);
3638 const cricket::TransportInfo* vtinfo =
3639 desc->GetTransportInfoByName("video_content_name");
3640 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
3641 vtinfo->description.connection_role);
3642}
3643TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributePassive) {
3644 JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
3645 std::string sdp_with_dtlssetup = kSdpFullString;
3646 InjectAfter(kSessionTime, "a=setup:passive\r\n", &sdp_with_dtlssetup);
3647 EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
3648 cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
3649 const cricket::TransportInfo* atinfo =
3650 desc->GetTransportInfoByName("audio_content_name");
3651 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
3652 atinfo->description.connection_role);
3653 const cricket::TransportInfo* vtinfo =
3654 desc->GetTransportInfoByName("video_content_name");
3655 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
3656 vtinfo->description.connection_role);
3657}
3658
jiayl@webrtc.orge7d47a12014-08-05 19:19:053659// Verifies that the order of the serialized m-lines follows the order of the
3660// ContentInfo in SessionDescription, and vise versa for deserialization.
3661TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
Steve Antona3a92c22017-12-07 18:27:413662 JsepSessionDescription jdesc(kDummyType);
Yves Gerey665174f2018-06-19 13:03:053663 const std::string media_content_sdps[3] = {kSdpAudioString, kSdpVideoString,
3664 kSdpSctpDataChannelString};
3665 const cricket::MediaType media_types[3] = {cricket::MEDIA_TYPE_AUDIO,
3666 cricket::MEDIA_TYPE_VIDEO,
3667 cricket::MEDIA_TYPE_DATA};
jiayl@webrtc.orge7d47a12014-08-05 19:19:053668
3669 // Verifies all 6 permutations.
3670 for (size_t i = 0; i < 6; ++i) {
3671 size_t media_content_in_sdp[3];
3672 // The index of the first media content.
3673 media_content_in_sdp[0] = i / 2;
3674 // The index of the second media content.
3675 media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
3676 // The index of the third media content.
3677 media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
3678
3679 std::string sdp_string = kSdpSessionString;
3680 for (size_t i = 0; i < 3; ++i)
3681 sdp_string += media_content_sdps[media_content_in_sdp[i]];
3682
3683 EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
3684 cricket::SessionDescription* desc = jdesc.description();
3685 EXPECT_EQ(3u, desc->contents().size());
3686
3687 for (size_t i = 0; i < 3; ++i) {
3688 const cricket::MediaContentDescription* mdesc =
Steve Antonb1c1de12017-12-21 23:14:303689 desc->contents()[i].media_description();
jiayl@webrtc.orge7d47a12014-08-05 19:19:053690 EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
3691 }
3692
Steve Antone831b8c2018-02-01 20:22:163693 std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
jiayl@webrtc.orge7d47a12014-08-05 19:19:053694 EXPECT_EQ(sdp_string, serialized_sdp);
3695 }
3696}
deadbeef9d3584c2016-02-17 01:54:103697
deadbeef25ed4352016-12-13 02:37:363698TEST_F(WebRtcSdpTest, DeserializeBundleOnlyAttribute) {
3699 MakeBundleOnlyDescription();
Steve Antona3a92c22017-12-07 18:27:413700 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 21:53:473701 ASSERT_TRUE(
deadbeef25ed4352016-12-13 02:37:363702 SdpDeserialize(kBundleOnlySdpFullString, &deserialized_description));
3703 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3704}
3705
deadbeef12771a12017-01-03 21:53:473706// The semantics of "a=bundle-only" are only defined when it's used in
3707// combination with a 0 port on the m= line. We should ignore it if used with a
3708// nonzero port.
3709TEST_F(WebRtcSdpTest, IgnoreBundleOnlyWithNonzeroPort) {
3710 // Make the base bundle-only description but unset the bundle-only flag.
3711 MakeBundleOnlyDescription();
3712 jdesc_.description()->contents()[1].bundle_only = false;
3713
3714 std::string modified_sdp = kBundleOnlySdpFullString;
3715 Replace("m=video 0", "m=video 9", &modified_sdp);
Steve Antona3a92c22017-12-07 18:27:413716 JsepSessionDescription deserialized_description(kDummyType);
deadbeef12771a12017-01-03 21:53:473717 ASSERT_TRUE(SdpDeserialize(modified_sdp, &deserialized_description));
3718 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
deadbeef25ed4352016-12-13 02:37:363719}
3720
3721TEST_F(WebRtcSdpTest, SerializeBundleOnlyAttribute) {
3722 MakeBundleOnlyDescription();
Steve Antone831b8c2018-02-01 20:22:163723 TestSerialize(jdesc_);
deadbeef25ed4352016-12-13 02:37:363724}
3725
deadbeef9d3584c2016-02-17 01:54:103726TEST_F(WebRtcSdpTest, DeserializePlanBSessionDescription) {
3727 MakePlanBDescription();
3728
Steve Antona3a92c22017-12-07 18:27:413729 JsepSessionDescription deserialized_description(kDummyType);
deadbeef9d3584c2016-02-17 01:54:103730 EXPECT_TRUE(SdpDeserialize(kPlanBSdpFullString, &deserialized_description));
3731
3732 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3733}
3734
3735TEST_F(WebRtcSdpTest, SerializePlanBSessionDescription) {
3736 MakePlanBDescription();
Steve Antone831b8c2018-02-01 20:22:163737 TestSerialize(jdesc_);
deadbeef9d3584c2016-02-17 01:54:103738}
3739
3740TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescription) {
3741 MakeUnifiedPlanDescription();
3742
Steve Antona3a92c22017-12-07 18:27:413743 JsepSessionDescription deserialized_description(kDummyType);
Harald Alvestrand0d018412021-11-04 13:52:313744 EXPECT_TRUE(
deadbeef9d3584c2016-02-17 01:54:103745 SdpDeserialize(kUnifiedPlanSdpFullString, &deserialized_description));
3746
3747 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3748}
3749
3750TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescription) {
3751 MakeUnifiedPlanDescription();
Steve Antone831b8c2018-02-01 20:22:163752 TestSerialize(jdesc_);
3753}
3754
Seth Hampson5b4f0752018-04-02 23:31:363755// This tests deserializing a Unified Plan SDP that is compatible with both
Seth Hampson7fa6ee62018-10-17 17:25:283756// Unified Plan and Plan B style SDP, meaning that it contains both "a=ssrc
3757// msid" lines and "a=msid " lines. It tests the case for audio/video tracks
Seth Hampson5b4f0752018-04-02 23:31:363758// with no stream ids and multiple stream ids. For parsing this, the Unified
3759// Plan a=msid lines should take priority, because the Plan B style a=ssrc msid
3760// lines do not support multiple stream ids and no stream ids.
Seth Hampson7fa6ee62018-10-17 17:25:283761TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionSpecialMsid) {
3762 // Create both msid lines for Plan B and Unified Plan support.
3763 MakeUnifiedPlanDescriptionMultipleStreamIds(
3764 cricket::kMsidSignalingMediaSection |
3765 cricket::kMsidSignalingSsrcAttribute);
Seth Hampson5b4f0752018-04-02 23:31:363766
3767 JsepSessionDescription deserialized_description(kDummyType);
3768 EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
3769 &deserialized_description));
3770
3771 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
Henrik Boström5b147782018-12-04 10:25:053772 EXPECT_EQ(cricket::kMsidSignalingMediaSection |
3773 cricket::kMsidSignalingSsrcAttribute,
3774 deserialized_description.description()->msid_signaling());
Seth Hampson5b4f0752018-04-02 23:31:363775}
3776
Seth Hampson7fa6ee62018-10-17 17:25:283777// Tests the serialization of a Unified Plan SDP that is compatible for both
3778// Unified Plan and Plan B style SDPs, meaning that it contains both "a=ssrc
3779// msid" lines and "a=msid " lines. It tests the case for no stream ids and
3780// multiple stream ids.
3781TEST_F(WebRtcSdpTest, SerializeSessionDescriptionSpecialMsid) {
3782 // Create both msid lines for Plan B and Unified Plan support.
3783 MakeUnifiedPlanDescriptionMultipleStreamIds(
3784 cricket::kMsidSignalingMediaSection |
3785 cricket::kMsidSignalingSsrcAttribute);
3786 std::string serialized_sdp = webrtc::SdpSerialize(jdesc_);
3787 // We explicitly test that the serialized SDP string is equal to the hard
3788 // coded SDP string. This is necessary, because in the parser "a=msid" lines
3789 // take priority over "a=ssrc msid" lines. This means if we just used
3790 // TestSerialize(), it could serialize an SDP that omits "a=ssrc msid" lines,
3791 // and still pass, because the deserialized version would be the same.
3792 EXPECT_EQ(kUnifiedPlanSdpFullStringWithSpecialMsid, serialized_sdp);
3793}
3794
3795// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
3796// that signal stream IDs) is deserialized appropriately. It tests the case for
3797// no stream ids and multiple stream ids.
3798TEST_F(WebRtcSdpTest, UnifiedPlanDeserializeSessionDescriptionSpecialMsid) {
3799 // Only create a=msid lines for strictly Unified Plan stream ID support.
3800 MakeUnifiedPlanDescriptionMultipleStreamIds(
3801 cricket::kMsidSignalingMediaSection);
3802
3803 JsepSessionDescription deserialized_description(kDummyType);
3804 std::string unified_plan_sdp_string =
3805 kUnifiedPlanSdpFullStringWithSpecialMsid;
3806 RemoveSsrcMsidLinesFromSdpString(&unified_plan_sdp_string);
3807 EXPECT_TRUE(
3808 SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
3809
3810 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3811}
3812
3813// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
3814// that signal stream IDs) is serialized appropriately. It tests the case for no
3815// stream ids and multiple stream ids.
3816TEST_F(WebRtcSdpTest, UnifiedPlanSerializeSessionDescriptionSpecialMsid) {
3817 // Only create a=msid lines for strictly Unified Plan stream ID support.
3818 MakeUnifiedPlanDescriptionMultipleStreamIds(
3819 cricket::kMsidSignalingMediaSection);
3820
Seth Hampson5b4f0752018-04-02 23:31:363821 TestSerialize(jdesc_);
3822}
3823
Seth Hampson5897a6e2018-04-03 18:16:333824// This tests that a Unified Plan SDP with no a=ssrc lines is
3825// serialized/deserialized appropriately. In this case the
3826// MediaContentDescription will contain a StreamParams object that doesn't have
3827// any SSRCs. Vice versa, this will be created upon deserializing an SDP with no
3828// SSRC lines.
3829TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
3830 MakeUnifiedPlanDescription();
3831 RemoveSsrcSignalingFromStreamParams();
3832 std::string unified_plan_sdp_string = kUnifiedPlanSdpFullString;
3833 RemoveSsrcLinesFromSdpString(&unified_plan_sdp_string);
3834
3835 JsepSessionDescription deserialized_description(kDummyType);
3836 EXPECT_TRUE(
3837 SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
3838 EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
3839}
3840
3841TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
3842 MakeUnifiedPlanDescription();
3843 RemoveSsrcSignalingFromStreamParams();
3844
3845 TestSerialize(jdesc_);
3846}
3847
Steve Antone831b8c2018-02-01 20:22:163848TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
3849 JsepSessionDescription jsep_desc(kDummyType);
3850 ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
3851 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
3852}
3853
3854TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
3855 JsepSessionDescription jsep_desc(kDummyType);
3856 std::string sdp = kSdpSessionString;
3857 sdp += kSdpSctpDataChannelString;
3858 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
3859 EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
3860}
3861
3862TEST_F(WebRtcSdpTest, PlanBHasSsrcAttributeMsidSignaling) {
3863 JsepSessionDescription jsep_desc(kDummyType);
3864 ASSERT_TRUE(SdpDeserialize(kPlanBSdpFullString, &jsep_desc));
3865 EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
3866 jsep_desc.description()->msid_signaling());
3867}
3868
3869TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
3870 JsepSessionDescription jsep_desc(kDummyType);
3871 ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
3872 EXPECT_EQ(cricket::kMsidSignalingMediaSection,
3873 jsep_desc.description()->msid_signaling());
3874}
3875
3876const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";
3877const char kSsrcAttributeMsidLine[] =
3878 "a=ssrc:1 msid:local_stream_1 audio_track_id_1";
3879
3880TEST_F(WebRtcSdpTest, SerializeOnlyMediaSectionMsid) {
3881 jdesc_.description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
3882 std::string sdp = webrtc::SdpSerialize(jdesc_);
3883
3884 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
3885 EXPECT_EQ(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
3886}
3887
3888TEST_F(WebRtcSdpTest, SerializeOnlySsrcAttributeMsid) {
3889 jdesc_.description()->set_msid_signaling(
3890 cricket::kMsidSignalingSsrcAttribute);
3891 std::string sdp = webrtc::SdpSerialize(jdesc_);
3892
3893 EXPECT_EQ(std::string::npos, sdp.find(kMediaSectionMsidLine));
3894 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
3895}
3896
3897TEST_F(WebRtcSdpTest, SerializeBothMediaSectionAndSsrcAttributeMsid) {
3898 jdesc_.description()->set_msid_signaling(
3899 cricket::kMsidSignalingMediaSection |
3900 cricket::kMsidSignalingSsrcAttribute);
3901 std::string sdp = webrtc::SdpSerialize(jdesc_);
3902
3903 EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
3904 EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
deadbeef9d3584c2016-02-17 01:54:103905}
deadbeef7e146cb2016-09-28 17:04:343906
deadbeefb2362572016-12-14 00:37:063907// Regression test for integer overflow bug:
3908// https://bugs.chromium.org/p/chromium/issues/detail?id=648071
3909TEST_F(WebRtcSdpTest, DeserializeLargeBandwidthLimit) {
deadbeefb2362572016-12-14 00:37:063910 // Bandwidth attribute is the max signed 32-bit int, which will get
3911 // multiplied by 1000 and cause int overflow if not careful.
deadbeef7bcdb692017-01-20 20:43:583912 static const char kSdpWithLargeBandwidth[] =
deadbeefb2362572016-12-14 00:37:063913 "v=0\r\n"
3914 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3915 "s=-\r\n"
3916 "t=0 0\r\n"
3917 "m=video 3457 RTP/SAVPF 120\r\n"
3918 "b=AS:2147483647\r\n"
3919 "foo=fail\r\n";
3920
3921 ExpectParseFailure(std::string(kSdpWithLargeBandwidth), "foo=fail");
3922}
deadbeef7bcdb692017-01-20 20:43:583923
deadbeefbc88c6b2017-08-02 18:26:343924// Similar to the above, except that negative values are illegal, not just
3925// error-prone as large values are.
3926// https://bugs.chromium.org/p/chromium/issues/detail?id=675361
3927TEST_F(WebRtcSdpTest, DeserializingNegativeBandwidthLimitFails) {
3928 static const char kSdpWithNegativeBandwidth[] =
3929 "v=0\r\n"
3930 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3931 "s=-\r\n"
3932 "t=0 0\r\n"
3933 "m=video 3457 RTP/SAVPF 120\r\n"
3934 "b=AS:-1000\r\n";
3935
3936 ExpectParseFailure(std::string(kSdpWithNegativeBandwidth), "b=AS:-1000");
3937}
3938
deadbeef3e8016e2017-08-04 00:49:303939// An exception to the above rule: a value of -1 for b=AS should just be
3940// ignored, resulting in "kAutoBandwidth" in the deserialized object.
3941// Applications historically may be using "b=AS:-1" to mean "no bandwidth
3942// limit", but this is now what ommitting the attribute entirely will do, so
3943// ignoring it will have the intended effect.
3944TEST_F(WebRtcSdpTest, BandwidthLimitOfNegativeOneIgnored) {
3945 static const char kSdpWithBandwidthOfNegativeOne[] =
3946 "v=0\r\n"
3947 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3948 "s=-\r\n"
3949 "t=0 0\r\n"
3950 "m=video 3457 RTP/SAVPF 120\r\n"
3951 "b=AS:-1\r\n";
3952
Steve Antona3a92c22017-12-07 18:27:413953 JsepSessionDescription jdesc_output(kDummyType);
deadbeef3e8016e2017-08-04 00:49:303954 EXPECT_TRUE(SdpDeserialize(kSdpWithBandwidthOfNegativeOne, &jdesc_output));
deadbeef3e8016e2017-08-04 00:49:303955 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 23:14:303956 GetFirstVideoContentDescription(jdesc_output.description());
3957 ASSERT_TRUE(vcd);
deadbeef3e8016e2017-08-04 00:49:303958 EXPECT_EQ(cricket::kAutoBandwidth, vcd->bandwidth());
3959}
3960
deadbeef7bcdb692017-01-20 20:43:583961// Test that "ufrag"/"pwd" in the candidate line itself are ignored, and only
3962// the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
3963// Regression test for:
3964// https://bugs.chromium.org/p/chromium/issues/detail?id=681286
3965TEST_F(WebRtcSdpTest, IceCredentialsInCandidateStringIgnored) {
3966 // Important piece is "ufrag foo pwd bar".
3967 static const char kSdpWithIceCredentialsInCandidateString[] =
3968 "v=0\r\n"
3969 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3970 "s=-\r\n"
3971 "t=0 0\r\n"
3972 "m=audio 9 RTP/SAVPF 111\r\n"
3973 "c=IN IP4 0.0.0.0\r\n"
3974 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
3975 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
3976 "a=rtpmap:111 opus/48000/2\r\n"
3977 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
3978 "generation 2 ufrag foo pwd bar\r\n";
3979
Steve Antona3a92c22017-12-07 18:27:413980 JsepSessionDescription jdesc_output(kDummyType);
deadbeef7bcdb692017-01-20 20:43:583981 EXPECT_TRUE(
3982 SdpDeserialize(kSdpWithIceCredentialsInCandidateString, &jdesc_output));
3983 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
3984 ASSERT_NE(nullptr, candidates);
Mirko Bonadeie12c1fe2018-07-03 10:53:233985 ASSERT_EQ(1U, candidates->count());
deadbeef7bcdb692017-01-20 20:43:583986 cricket::Candidate c = candidates->at(0)->candidate();
3987 EXPECT_EQ("ufrag_voice", c.username());
3988 EXPECT_EQ("pwd_voice", c.password());
3989}
deadbeef90f1e1e2017-02-10 20:35:053990
Johannes Kron211856b2018-09-06 10:12:283991// Test that attribute lines "a=ice-ufrag-something"/"a=ice-pwd-something" are
3992// ignored, and only the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
3993// Regression test for:
3994// https://bugs.chromium.org/p/webrtc/issues/detail?id=9712
3995TEST_F(WebRtcSdpTest, AttributeWithPartialMatchingNameIsIgnored) {
3996 static const char kSdpWithFooIceCredentials[] =
3997 "v=0\r\n"
3998 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
3999 "s=-\r\n"
4000 "t=0 0\r\n"
4001 "m=audio 9 RTP/SAVPF 111\r\n"
4002 "c=IN IP4 0.0.0.0\r\n"
4003 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
4004 "a=ice-ufrag-something:foo\r\na=ice-pwd-something:bar\r\n"
4005 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
4006 "a=rtpmap:111 opus/48000/2\r\n"
4007 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
4008 "generation 2\r\n";
4009
4010 JsepSessionDescription jdesc_output(kDummyType);
4011 EXPECT_TRUE(SdpDeserialize(kSdpWithFooIceCredentials, &jdesc_output));
4012 const IceCandidateCollection* candidates = jdesc_output.candidates(0);
4013 ASSERT_NE(nullptr, candidates);
4014 ASSERT_EQ(1U, candidates->count());
4015 cricket::Candidate c = candidates->at(0)->candidate();
4016 EXPECT_EQ("ufrag_voice", c.username());
4017 EXPECT_EQ("pwd_voice", c.password());
4018}
4019
deadbeef90f1e1e2017-02-10 20:35:054020// Test that SDP with an invalid port number in "a=candidate" lines is
4021// rejected, without crashing.
4022// Regression test for:
4023// https://bugs.chromium.org/p/chromium/issues/detail?id=677029
4024TEST_F(WebRtcSdpTest, DeserializeInvalidPortInCandidateAttribute) {
4025 static const char kSdpWithInvalidCandidatePort[] =
4026 "v=0\r\n"
4027 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4028 "s=-\r\n"
4029 "t=0 0\r\n"
4030 "m=audio 9 RTP/SAVPF 111\r\n"
4031 "c=IN IP4 0.0.0.0\r\n"
4032 "a=rtcp:9 IN IP4 0.0.0.0\r\n"
4033 "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
4034 "a=rtpmap:111 opus/48000/2\r\n"
4035 "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 12345678 typ host "
4036 "generation 2 raddr 192.168.1.1 rport 87654321\r\n";
4037
Steve Antona3a92c22017-12-07 18:27:414038 JsepSessionDescription jdesc_output(kDummyType);
deadbeef90f1e1e2017-02-10 20:35:054039 EXPECT_FALSE(SdpDeserialize(kSdpWithInvalidCandidatePort, &jdesc_output));
4040}
deadbeefa4549d62017-02-11 01:26:224041
Philipp Hancke3c529892022-12-05 18:59:104042TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithStreamIdAndTrackId) {
4043 std::string sdp =
4044 "v=0\r\n"
4045 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4046 "s=-\r\n"
4047 "t=0 0\r\n"
4048 "m=audio 9 RTP/SAVPF 111\r\n"
4049 "c=IN IP4 0.0.0.0\r\n"
4050 "a=rtpmap:111 opus/48000/2\r\n"
4051 "a=msid:stream_id track_id\r\n";
4052
4053 JsepSessionDescription jdesc_output(kDummyType);
4054 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4055 auto stream = jdesc_output.description()
4056 ->contents()[0]
4057 .media_description()
4058 ->streams()[0];
4059 ASSERT_EQ(stream.stream_ids().size(), 1u);
4060 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4061 EXPECT_EQ(stream.id, "track_id");
4062}
4063
4064TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithEmptyStreamIdAndTrackId) {
4065 std::string sdp =
4066 "v=0\r\n"
4067 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4068 "s=-\r\n"
4069 "t=0 0\r\n"
4070 "m=audio 9 RTP/SAVPF 111\r\n"
4071 "c=IN IP4 0.0.0.0\r\n"
4072 "a=rtpmap:111 opus/48000/2\r\n"
4073 "a=msid:- track_id\r\n";
4074
4075 JsepSessionDescription jdesc_output(kDummyType);
4076 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4077 auto stream = jdesc_output.description()
4078 ->contents()[0]
4079 .media_description()
4080 ->streams()[0];
4081 ASSERT_EQ(stream.stream_ids().size(), 0u);
4082 EXPECT_EQ(stream.id, "track_id");
4083}
4084
deadbeefa4549d62017-02-11 01:26:224085// Test that "a=msid" with a missing track ID is rejected and doesn't crash.
4086// Regression test for:
4087// https://bugs.chromium.org/p/chromium/issues/detail?id=686405
4088TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingTrackId) {
Philipp Hancke3c529892022-12-05 18:59:104089 std::string sdp =
deadbeefa4549d62017-02-11 01:26:224090 "v=0\r\n"
4091 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4092 "s=-\r\n"
4093 "t=0 0\r\n"
4094 "m=audio 9 RTP/SAVPF 111\r\n"
4095 "c=IN IP4 0.0.0.0\r\n"
4096 "a=rtpmap:111 opus/48000/2\r\n"
4097 "a=msid:stream_id \r\n";
4098
Steve Antona3a92c22017-12-07 18:27:414099 JsepSessionDescription jdesc_output(kDummyType);
Philipp Hancke3c529892022-12-05 18:59:104100 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
deadbeefa4549d62017-02-11 01:26:224101}
4102
Philipp Hanckeb493db92022-12-08 11:46:204103TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutColon) {
4104 std::string sdp =
4105 "v=0\r\n"
4106 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4107 "s=-\r\n"
4108 "t=0 0\r\n"
4109 "m=audio 9 RTP/SAVPF 111\r\n"
4110 "c=IN IP4 0.0.0.0\r\n"
4111 "a=rtpmap:111 opus/48000/2\r\n"
4112 "a=msid\r\n";
4113
4114 JsepSessionDescription jdesc_output(kDummyType);
4115 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
4116}
4117
4118TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAttributes) {
4119 std::string sdp =
4120 "v=0\r\n"
4121 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4122 "s=-\r\n"
4123 "t=0 0\r\n"
4124 "m=audio 9 RTP/SAVPF 111\r\n"
4125 "c=IN IP4 0.0.0.0\r\n"
4126 "a=rtpmap:111 opus/48000/2\r\n"
4127 "a=msid:\r\n";
4128
4129 JsepSessionDescription jdesc_output(kDummyType);
4130 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
4131}
4132
4133TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithTooManySpaces) {
4134 std::string sdp =
4135 "v=0\r\n"
4136 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4137 "s=-\r\n"
4138 "t=0 0\r\n"
4139 "m=audio 9 RTP/SAVPF 111\r\n"
4140 "c=IN IP4 0.0.0.0\r\n"
4141 "a=rtpmap:111 opus/48000/2\r\n"
4142 "a=msid:stream_id track_id bogus\r\n";
4143
4144 JsepSessionDescription jdesc_output(kDummyType);
4145 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
4146}
4147
4148TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithDifferentTrackIds) {
4149 std::string sdp =
4150 "v=0\r\n"
4151 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4152 "s=-\r\n"
4153 "t=0 0\r\n"
4154 "m=audio 9 RTP/SAVPF 111\r\n"
4155 "c=IN IP4 0.0.0.0\r\n"
4156 "a=rtpmap:111 opus/48000/2\r\n"
4157 "a=msid:stream_id track_id\r\n"
4158 "a=msid:stream_id2 track_id2\r\n";
4159
4160 JsepSessionDescription jdesc_output(kDummyType);
4161 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
4162}
4163
Philipp Hanckee093c482022-12-05 12:20:014164TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppData) {
Philipp Hancke3c529892022-12-05 18:59:104165 std::string sdp =
Philipp Hanckee093c482022-12-05 12:20:014166 "v=0\r\n"
4167 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4168 "s=-\r\n"
4169 "t=0 0\r\n"
4170 "m=audio 9 RTP/SAVPF 111\r\n"
4171 "c=IN IP4 0.0.0.0\r\n"
4172 "a=rtpmap:111 opus/48000/2\r\n"
4173 "a=msid:stream_id\r\n";
4174
4175 JsepSessionDescription jdesc_output(kDummyType);
Philipp Hancke3c529892022-12-05 18:59:104176 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4177 auto stream = jdesc_output.description()
4178 ->contents()[0]
4179 .media_description()
4180 ->streams()[0];
4181 ASSERT_EQ(stream.stream_ids().size(), 1u);
4182 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4183 // Track id is randomly generated.
4184 EXPECT_NE(stream.id, "");
Philipp Hanckee093c482022-12-05 12:20:014185}
4186
4187TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataTwoStreams) {
Philipp Hancke3c529892022-12-05 18:59:104188 std::string sdp =
Philipp Hanckee093c482022-12-05 12:20:014189 "v=0\r\n"
4190 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4191 "s=-\r\n"
4192 "t=0 0\r\n"
4193 "m=audio 9 RTP/SAVPF 111\r\n"
4194 "c=IN IP4 0.0.0.0\r\n"
4195 "a=rtpmap:111 opus/48000/2\r\n"
4196 "a=msid:stream_id\r\n"
4197 "a=msid:stream_id2\r\n";
4198
4199 JsepSessionDescription jdesc_output(kDummyType);
Philipp Hancke3c529892022-12-05 18:59:104200 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4201 auto stream = jdesc_output.description()
4202 ->contents()[0]
4203 .media_description()
4204 ->streams()[0];
4205 ASSERT_EQ(stream.stream_ids().size(), 2u);
4206 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4207 EXPECT_EQ(stream.stream_ids()[1], "stream_id2");
4208 // Track id is randomly generated.
4209 EXPECT_NE(stream.id, "");
Philipp Hanckee093c482022-12-05 12:20:014210}
4211
4212TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataDuplicate) {
Philipp Hancke3c529892022-12-05 18:59:104213 std::string sdp =
Philipp Hanckee093c482022-12-05 12:20:014214 "v=0\r\n"
4215 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4216 "s=-\r\n"
4217 "t=0 0\r\n"
4218 "m=audio 9 RTP/SAVPF 111\r\n"
4219 "c=IN IP4 0.0.0.0\r\n"
4220 "a=rtpmap:111 opus/48000/2\r\n"
4221 "a=msid:stream_id\r\n"
4222 "a=msid:stream_id\r\n";
4223
4224 JsepSessionDescription jdesc_output(kDummyType);
Philipp Hancke3c529892022-12-05 18:59:104225 // This is somewhat silly but accept it. Duplicates get filtered.
4226 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4227 auto stream = jdesc_output.description()
4228 ->contents()[0]
4229 .media_description()
4230 ->streams()[0];
4231 ASSERT_EQ(stream.stream_ids().size(), 1u);
4232 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4233 // Track id is randomly generated.
4234 EXPECT_NE(stream.id, "");
Philipp Hanckee093c482022-12-05 12:20:014235}
4236
4237TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataMixed) {
Philipp Hancke3c529892022-12-05 18:59:104238 std::string sdp =
Philipp Hanckee093c482022-12-05 12:20:014239 "v=0\r\n"
4240 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4241 "s=-\r\n"
4242 "t=0 0\r\n"
4243 "m=audio 9 RTP/SAVPF 111\r\n"
4244 "c=IN IP4 0.0.0.0\r\n"
4245 "a=rtpmap:111 opus/48000/2\r\n"
4246 "a=msid:stream_id\r\n"
Philipp Hancke3c529892022-12-05 18:59:104247 "a=msid:stream_id2 track_id\r\n";
Philipp Hanckee093c482022-12-05 12:20:014248
4249 JsepSessionDescription jdesc_output(kDummyType);
4250 // Mixing the syntax like this is not a good idea but we accept it
4251 // and the result is the second track_id.
Philipp Hancke3c529892022-12-05 18:59:104252 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4253 auto stream = jdesc_output.description()
4254 ->contents()[0]
4255 .media_description()
4256 ->streams()[0];
4257 ASSERT_EQ(stream.stream_ids().size(), 2u);
4258 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4259 EXPECT_EQ(stream.stream_ids()[1], "stream_id2");
4260
4261 // Track id is taken from second line.
4262 EXPECT_EQ(stream.id, "track_id");
4263}
4264
Philipp Hanckeb493db92022-12-08 11:46:204265TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataMixed2) {
4266 std::string sdp =
4267 "v=0\r\n"
4268 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4269 "s=-\r\n"
4270 "t=0 0\r\n"
4271 "m=audio 9 RTP/SAVPF 111\r\n"
4272 "c=IN IP4 0.0.0.0\r\n"
4273 "a=rtpmap:111 opus/48000/2\r\n"
4274 "a=msid:stream_id track_id\r\n"
4275 "a=msid:stream_id2\r\n";
4276
4277 JsepSessionDescription jdesc_output(kDummyType);
4278 // Mixing the syntax like this is not a good idea but we accept it
4279 // and the result is the second track_id.
4280 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4281 auto stream = jdesc_output.description()
4282 ->contents()[0]
4283 .media_description()
4284 ->streams()[0];
4285 ASSERT_EQ(stream.stream_ids().size(), 2u);
4286 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4287 EXPECT_EQ(stream.stream_ids()[1], "stream_id2");
4288
4289 // Track id is taken from first line.
4290 EXPECT_EQ(stream.id, "track_id");
4291}
4292
Philipp Hancke3c529892022-12-05 18:59:104293TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataMixedNoStream) {
4294 std::string sdp =
4295 "v=0\r\n"
4296 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4297 "s=-\r\n"
4298 "t=0 0\r\n"
4299 "m=audio 9 RTP/SAVPF 111\r\n"
4300 "c=IN IP4 0.0.0.0\r\n"
4301 "a=rtpmap:111 opus/48000/2\r\n"
4302 "a=msid:stream_id\r\n"
4303 "a=msid:- track_id\r\n";
4304
4305 JsepSessionDescription jdesc_output(kDummyType);
4306 // This is somewhat undefined behavior but accept it and expect a single
4307 // stream.
4308 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4309 auto stream = jdesc_output.description()
4310 ->contents()[0]
4311 .media_description()
4312 ->streams()[0];
4313 ASSERT_EQ(stream.stream_ids().size(), 1u);
4314 EXPECT_EQ(stream.stream_ids()[0], "stream_id");
4315 EXPECT_EQ(stream.id, "track_id");
Philipp Hanckee093c482022-12-05 12:20:014316}
4317
deadbeefa4549d62017-02-11 01:26:224318TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingStreamId) {
Philipp Hancke3c529892022-12-05 18:59:104319 std::string sdp =
deadbeefa4549d62017-02-11 01:26:224320 "v=0\r\n"
4321 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4322 "s=-\r\n"
4323 "t=0 0\r\n"
4324 "m=audio 9 RTP/SAVPF 111\r\n"
4325 "c=IN IP4 0.0.0.0\r\n"
4326 "a=rtpmap:111 opus/48000/2\r\n"
4327 "a=msid: track_id\r\n";
4328
Steve Antona3a92c22017-12-07 18:27:414329 JsepSessionDescription jdesc_output(kDummyType);
Philipp Hancke3c529892022-12-05 18:59:104330 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
deadbeefa4549d62017-02-11 01:26:224331}
zhihuang38989e52017-03-21 18:04:534332
4333// Tests that if both session-level address and media-level address exist, use
4334// the media-level address.
4335TEST_F(WebRtcSdpTest, ParseConnectionData) {
Steve Antona3a92c22017-12-07 18:27:414336 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 18:04:534337
4338 // Sesssion-level address.
4339 std::string sdp = kSdpFullString;
4340 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
4341 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4342
4343 const auto& content1 = jsep_desc.description()->contents()[0];
4344 EXPECT_EQ("74.125.127.126:2345",
Steve Antonb1c1de12017-12-21 23:14:304345 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 18:04:534346 const auto& content2 = jsep_desc.description()->contents()[1];
4347 EXPECT_EQ("74.125.224.39:3457",
Steve Antonb1c1de12017-12-21 23:14:304348 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 18:04:534349}
4350
4351// Tests that the session-level connection address will be used if the media
4352// level-addresses are not specified.
4353TEST_F(WebRtcSdpTest, ParseConnectionDataSessionLevelOnly) {
Steve Antona3a92c22017-12-07 18:27:414354 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 18:04:534355
4356 // Sesssion-level address.
4357 std::string sdp = kSdpString;
4358 InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
4359 // Remove the media level addresses.
4360 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
4361 Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
4362 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4363
4364 const auto& content1 = jsep_desc.description()->contents()[0];
4365 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 23:14:304366 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 18:04:534367 const auto& content2 = jsep_desc.description()->contents()[1];
4368 EXPECT_EQ("192.168.0.3:9",
Steve Antonb1c1de12017-12-21 23:14:304369 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 18:04:534370}
4371
4372TEST_F(WebRtcSdpTest, ParseConnectionDataIPv6) {
Steve Antona3a92c22017-12-07 18:27:414373 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 18:04:534374
4375 std::string sdp = kSdpString;
4376 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4377 Replace("m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP4 0.0.0.0\r\n",
4378 "m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP6 "
4379 "2001:0db8:85a3:0000:0000:8a2e:0370:7335\r\n",
4380 &sdp);
4381 Replace("m=video 9 RTP/SAVPF 120\r\nc=IN IP4 0.0.0.0\r\n",
4382 "m=video 9 RTP/SAVPF 120\r\nc=IN IP6 "
4383 "2001:0db8:85a3:0000:0000:8a2e:0370:7336\r\n",
4384 &sdp);
4385 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4386 const auto& content1 = jsep_desc.description()->contents()[0];
4387 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7335]:9",
Steve Antonb1c1de12017-12-21 23:14:304388 content1.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 18:04:534389 const auto& content2 = jsep_desc.description()->contents()[1];
4390 EXPECT_EQ("[2001:db8:85a3::8a2e:370:7336]:9",
Steve Antonb1c1de12017-12-21 23:14:304391 content2.media_description()->connection_address().ToString());
zhihuang38989e52017-03-21 18:04:534392}
4393
Qingsi Wang56991422019-02-08 20:53:064394// Test that a c= line that contains a hostname connection address can be
4395// parsed.
4396TEST_F(WebRtcSdpTest, ParseConnectionDataWithHostnameConnectionAddress) {
4397 JsepSessionDescription jsep_desc(kDummyType);
4398 std::string sdp = kSdpString;
4399 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4400
4401 sdp = kSdpString;
4402 Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
4403 Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
4404 ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4405
4406 ASSERT_NE(nullptr, jsep_desc.description());
4407 const auto& content1 = jsep_desc.description()->contents()[0];
4408 EXPECT_EQ("example.local:9",
4409 content1.media_description()->connection_address().ToString());
4410 const auto& content2 = jsep_desc.description()->contents()[1];
4411 EXPECT_EQ("example.local:9",
4412 content2.media_description()->connection_address().ToString());
4413}
4414
4415// Test that the invalid or unsupported connection data cannot be parsed.
zhihuang38989e52017-03-21 18:04:534416TEST_F(WebRtcSdpTest, ParseConnectionDataFailure) {
Steve Antona3a92c22017-12-07 18:27:414417 JsepSessionDescription jsep_desc(kDummyType);
zhihuang38989e52017-03-21 18:04:534418 std::string sdp = kSdpString;
4419 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4420
4421 // Unsupported multicast IPv4 address.
4422 sdp = kSdpFullString;
4423 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP4 74.125.224.39/127\r\n", &sdp);
4424 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4425
4426 // Unsupported multicast IPv6 address.
4427 sdp = kSdpFullString;
4428 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 ::1/3\r\n", &sdp);
4429 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4430
4431 // Mismatched address type.
4432 sdp = kSdpFullString;
4433 Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 74.125.224.39\r\n", &sdp);
4434 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4435
4436 sdp = kSdpFullString;
4437 Replace("c=IN IP4 74.125.224.39\r\n",
4438 "c=IN IP4 2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n", &sdp);
4439 EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
4440}
4441
4442TEST_F(WebRtcSdpTest, SerializeAndDeserializeWithConnectionAddress) {
Steve Antona3a92c22017-12-07 18:27:414443 JsepSessionDescription expected_jsep(kDummyType);
zhihuang38989e52017-03-21 18:04:534444 MakeDescriptionWithoutCandidates(&expected_jsep);
4445 // Serialization.
Steve Antone831b8c2018-02-01 20:22:164446 std::string message = webrtc::SdpSerialize(expected_jsep);
zhihuang38989e52017-03-21 18:04:534447 // Deserialization.
Steve Antona3a92c22017-12-07 18:27:414448 JsepSessionDescription jdesc(kDummyType);
zhihuang38989e52017-03-21 18:04:534449 EXPECT_TRUE(SdpDeserialize(message, &jdesc));
Steve Antonb1c1de12017-12-21 23:14:304450 auto audio_desc = jdesc.description()
4451 ->GetContentByName(kAudioContentName)
4452 ->media_description();
4453 auto video_desc = jdesc.description()
4454 ->GetContentByName(kVideoContentName)
4455 ->media_description();
zhihuang38989e52017-03-21 18:04:534456 EXPECT_EQ(audio_desc_->connection_address().ToString(),
4457 audio_desc->connection_address().ToString());
4458 EXPECT_EQ(video_desc_->connection_address().ToString(),
4459 video_desc->connection_address().ToString());
4460}
Taylor Brandstetter93a7b242018-04-16 17:45:244461
4462// RFC4566 says "If a session has no meaningful name, the value "s= " SHOULD be
4463// used (i.e., a single space as the session name)." So we should accept that.
4464TEST_F(WebRtcSdpTest, DeserializeEmptySessionName) {
4465 JsepSessionDescription jsep_desc(kDummyType);
4466 std::string sdp = kSdpString;
4467 Replace("s=-\r\n", "s= \r\n", &sdp);
4468 EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
4469}
Amit Hilbucha2012042018-12-03 19:35:054470
4471// Simulcast malformed input test for invalid format.
4472TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_EmptyAttribute) {
Harald Alvestrand88b8dec12022-04-07 09:54:514473 ExpectParseFailureWithNewLines(
4474 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n", "a=simulcast:\r\n",
4475 "a=simulcast:");
Amit Hilbucha2012042018-12-03 19:35:054476}
4477
4478// Tests that duplicate simulcast entries in the SDP triggers a parse failure.
4479TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_DuplicateAttribute) {
Harald Alvestrand88b8dec12022-04-07 09:54:514480 ExpectParseFailureWithNewLines(
4481 "a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n",
4482 "a=simulcast:send 1\r\na=simulcast:recv 2\r\n", "a=simulcast:");
Amit Hilbucha2012042018-12-03 19:35:054483}
4484
4485// Validates that deserialization uses the a=simulcast: attribute
4486TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttribute) {
Amit Hilbuchc57d5732018-12-11 23:30:114487 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4488 sdp += "a=rid:1 send\r\n";
4489 sdp += "a=rid:2 send\r\n";
4490 sdp += "a=rid:3 send\r\n";
4491 sdp += "a=rid:4 recv\r\n";
4492 sdp += "a=rid:5 recv\r\n";
4493 sdp += "a=rid:6 recv\r\n";
Amit Hilbucha2012042018-12-03 19:35:054494 sdp += "a=simulcast:send 1,2;3 recv 4;5;6\r\n";
4495 JsepSessionDescription output(kDummyType);
4496 SdpParseError error;
4497 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4498 const cricket::ContentInfos& contents = output.description()->contents();
4499 const cricket::MediaContentDescription* media =
4500 contents.back().media_description();
4501 EXPECT_TRUE(media->HasSimulcast());
4502 EXPECT_EQ(2ul, media->simulcast_description().send_layers().size());
4503 EXPECT_EQ(3ul, media->simulcast_description().receive_layers().size());
Amit Hilbuchc57d5732018-12-11 23:30:114504 EXPECT_FALSE(media->streams().empty());
4505 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4506 CompareRidDescriptionIds(rids, {"1", "2", "3"});
Amit Hilbuchc57d5732018-12-11 23:30:114507}
4508
4509// Validates that deserialization removes rids that do not appear in SDP
4510TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttributeRemovesUnknownRids) {
4511 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4512 sdp += "a=rid:1 send\r\n";
4513 sdp += "a=rid:3 send\r\n";
4514 sdp += "a=rid:4 recv\r\n";
4515 sdp += "a=simulcast:send 1,2;3 recv 4;5,6\r\n";
4516 JsepSessionDescription output(kDummyType);
4517 SdpParseError error;
4518 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4519 const cricket::ContentInfos& contents = output.description()->contents();
4520 const cricket::MediaContentDescription* media =
4521 contents.back().media_description();
4522 EXPECT_TRUE(media->HasSimulcast());
4523 const SimulcastDescription& simulcast = media->simulcast_description();
4524 EXPECT_EQ(2ul, simulcast.send_layers().size());
4525 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4526
4527 std::vector<SimulcastLayer> all_send_layers =
4528 simulcast.send_layers().GetAllLayers();
4529 EXPECT_EQ(2ul, all_send_layers.size());
Steve Anton64b626b2019-01-29 01:25:264530 EXPECT_EQ(0,
4531 absl::c_count_if(all_send_layers, [](const SimulcastLayer& layer) {
4532 return layer.rid == "2";
4533 }));
Amit Hilbuchc57d5732018-12-11 23:30:114534
4535 std::vector<SimulcastLayer> all_receive_layers =
4536 simulcast.receive_layers().GetAllLayers();
4537 ASSERT_EQ(1ul, all_receive_layers.size());
4538 EXPECT_EQ("4", all_receive_layers[0].rid);
4539
4540 EXPECT_FALSE(media->streams().empty());
4541 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4542 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbuchc57d5732018-12-11 23:30:114543}
4544
4545// Validates that Simulcast removes rids that appear in both send and receive.
4546TEST_F(WebRtcSdpTest,
4547 TestDeserializeSimulcastAttributeRemovesDuplicateSendReceive) {
4548 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4549 sdp += "a=rid:1 send\r\n";
4550 sdp += "a=rid:2 send\r\n";
4551 sdp += "a=rid:3 send\r\n";
4552 sdp += "a=rid:4 recv\r\n";
4553 sdp += "a=simulcast:send 1;2;3 recv 2;4\r\n";
4554 JsepSessionDescription output(kDummyType);
4555 SdpParseError error;
4556 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4557 const cricket::ContentInfos& contents = output.description()->contents();
4558 const cricket::MediaContentDescription* media =
4559 contents.back().media_description();
4560 EXPECT_TRUE(media->HasSimulcast());
4561 const SimulcastDescription& simulcast = media->simulcast_description();
4562 EXPECT_EQ(2ul, simulcast.send_layers().size());
4563 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4564 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4565 EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
4566
4567 EXPECT_FALSE(media->streams().empty());
4568 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4569 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbuchc57d5732018-12-11 23:30:114570}
4571
4572// Ignores empty rid line.
4573TEST_F(WebRtcSdpTest, TestDeserializeIgnoresEmptyRidLines) {
4574 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4575 sdp += "a=rid:1 send\r\n";
4576 sdp += "a=rid:2 send\r\n";
4577 sdp += "a=rid\r\n"; // Should ignore this line.
4578 sdp += "a=rid:\r\n"; // Should ignore this line.
4579 sdp += "a=simulcast:send 1;2\r\n";
4580 JsepSessionDescription output(kDummyType);
4581 SdpParseError error;
4582 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4583 const cricket::ContentInfos& contents = output.description()->contents();
4584 const cricket::MediaContentDescription* media =
4585 contents.back().media_description();
4586 EXPECT_TRUE(media->HasSimulcast());
4587 const SimulcastDescription& simulcast = media->simulcast_description();
4588 EXPECT_TRUE(simulcast.receive_layers().empty());
4589 EXPECT_EQ(2ul, simulcast.send_layers().size());
4590 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4591
4592 EXPECT_FALSE(media->streams().empty());
4593 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4594 CompareRidDescriptionIds(rids, {"1", "2"});
Amit Hilbuchc57d5732018-12-11 23:30:114595}
4596
4597// Ignores malformed rid lines.
4598TEST_F(WebRtcSdpTest, TestDeserializeIgnoresMalformedRidLines) {
4599 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4600 sdp += "a=rid:1 send pt=\r\n"; // Should ignore this line.
4601 sdp += "a=rid:2 receive\r\n"; // Should ignore this line.
4602 sdp += "a=rid:3 max-width=720;pt=120\r\n"; // Should ignore this line.
4603 sdp += "a=rid:4\r\n"; // Should ignore this line.
4604 sdp += "a=rid:5 send\r\n";
4605 sdp += "a=simulcast:send 1,2,3;4,5\r\n";
4606 JsepSessionDescription output(kDummyType);
4607 SdpParseError error;
4608 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4609 const cricket::ContentInfos& contents = output.description()->contents();
4610 const cricket::MediaContentDescription* media =
4611 contents.back().media_description();
4612 EXPECT_TRUE(media->HasSimulcast());
4613 const SimulcastDescription& simulcast = media->simulcast_description();
4614 EXPECT_TRUE(simulcast.receive_layers().empty());
4615 EXPECT_EQ(1ul, simulcast.send_layers().size());
4616 EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
4617
4618 EXPECT_FALSE(media->streams().empty());
4619 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4620 CompareRidDescriptionIds(rids, {"5"});
Amit Hilbuchc57d5732018-12-11 23:30:114621}
4622
4623// Removes RIDs that specify a different format than the m= section.
4624TEST_F(WebRtcSdpTest, TestDeserializeRemovesRidsWithInvalidCodec) {
4625 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4626 sdp += "a=rid:1 send pt=121,120\r\n"; // Should remove 121 and keep RID.
4627 sdp += "a=rid:2 send pt=121\r\n"; // Should remove RID altogether.
4628 sdp += "a=simulcast:send 1;2\r\n";
4629 JsepSessionDescription output(kDummyType);
4630 SdpParseError error;
4631 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4632 const cricket::ContentInfos& contents = output.description()->contents();
4633 const cricket::MediaContentDescription* media =
4634 contents.back().media_description();
4635 EXPECT_TRUE(media->HasSimulcast());
4636 const SimulcastDescription& simulcast = media->simulcast_description();
4637 EXPECT_TRUE(simulcast.receive_layers().empty());
4638 EXPECT_EQ(1ul, simulcast.send_layers().size());
4639 EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
4640 EXPECT_EQ("1", simulcast.send_layers()[0][0].rid);
4641 EXPECT_EQ(1ul, media->streams().size());
4642 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4643 EXPECT_EQ(1ul, rids.size());
4644 EXPECT_EQ("1", rids[0].rid);
4645 EXPECT_EQ(1ul, rids[0].payload_types.size());
4646 EXPECT_EQ(120, rids[0].payload_types[0]);
Amit Hilbuchc57d5732018-12-11 23:30:114647}
4648
4649// Ignores duplicate rid lines
4650TEST_F(WebRtcSdpTest, TestDeserializeIgnoresDuplicateRidLines) {
4651 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4652 sdp += "a=rid:1 send\r\n";
4653 sdp += "a=rid:2 send\r\n";
4654 sdp += "a=rid:2 send\r\n";
4655 sdp += "a=rid:3 send\r\n";
4656 sdp += "a=rid:4 recv\r\n";
4657 sdp += "a=simulcast:send 1,2;3 recv 4\r\n";
4658 JsepSessionDescription output(kDummyType);
4659 SdpParseError error;
4660 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4661 const cricket::ContentInfos& contents = output.description()->contents();
4662 const cricket::MediaContentDescription* media =
4663 contents.back().media_description();
4664 EXPECT_TRUE(media->HasSimulcast());
4665 const SimulcastDescription& simulcast = media->simulcast_description();
4666 EXPECT_EQ(2ul, simulcast.send_layers().size());
4667 EXPECT_EQ(1ul, simulcast.receive_layers().size());
4668 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4669 EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
4670
4671 EXPECT_FALSE(media->streams().empty());
4672 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4673 CompareRidDescriptionIds(rids, {"1", "3"});
Amit Hilbucha2012042018-12-03 19:35:054674}
4675
Florent Castellic4421972019-07-02 18:27:424676TEST_F(WebRtcSdpTest, TestDeserializeRidSendDirection) {
4677 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4678 sdp += "a=rid:1 recv\r\n";
4679 sdp += "a=rid:2 recv\r\n";
4680 sdp += "a=simulcast:send 1;2\r\n";
4681 JsepSessionDescription output(kDummyType);
4682 SdpParseError error;
4683 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4684 const cricket::ContentInfos& contents = output.description()->contents();
4685 const cricket::MediaContentDescription* media =
4686 contents.back().media_description();
4687 EXPECT_FALSE(media->HasSimulcast());
4688}
4689
4690TEST_F(WebRtcSdpTest, TestDeserializeRidRecvDirection) {
4691 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4692 sdp += "a=rid:1 send\r\n";
4693 sdp += "a=rid:2 send\r\n";
4694 sdp += "a=simulcast:recv 1;2\r\n";
4695 JsepSessionDescription output(kDummyType);
4696 SdpParseError error;
4697 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4698 const cricket::ContentInfos& contents = output.description()->contents();
4699 const cricket::MediaContentDescription* media =
4700 contents.back().media_description();
4701 EXPECT_FALSE(media->HasSimulcast());
4702}
4703
4704TEST_F(WebRtcSdpTest, TestDeserializeIgnoresWrongRidDirectionLines) {
4705 std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
4706 sdp += "a=rid:1 send\r\n";
4707 sdp += "a=rid:2 send\r\n";
4708 sdp += "a=rid:3 send\r\n";
4709 sdp += "a=rid:4 recv\r\n";
4710 sdp += "a=rid:5 recv\r\n";
4711 sdp += "a=rid:6 recv\r\n";
4712 sdp += "a=simulcast:send 1;5;3 recv 4;2;6\r\n";
4713 JsepSessionDescription output(kDummyType);
4714 SdpParseError error;
4715 EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4716 const cricket::ContentInfos& contents = output.description()->contents();
4717 const cricket::MediaContentDescription* media =
4718 contents.back().media_description();
4719 EXPECT_TRUE(media->HasSimulcast());
4720 const SimulcastDescription& simulcast = media->simulcast_description();
4721 EXPECT_EQ(2ul, simulcast.send_layers().size());
4722 EXPECT_EQ(2ul, simulcast.receive_layers().size());
4723 EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
4724 EXPECT_EQ(2ul, simulcast.receive_layers().GetAllLayers().size());
4725
4726 EXPECT_FALSE(media->streams().empty());
4727 const std::vector<RidDescription>& rids = media->streams()[0].rids();
4728 CompareRidDescriptionIds(rids, {"1", "3"});
4729}
4730
Amit Hilbucha2012042018-12-03 19:35:054731// Simulcast serialization integration test.
4732// This test will serialize and deserialize the description and compare.
4733// More detailed tests for parsing simulcast can be found in
4734// unit tests for SdpSerializer.
4735TEST_F(WebRtcSdpTest, SerializeSimulcast_ComplexSerialization) {
Amit Hilbuchc57d5732018-12-11 23:30:114736 MakeUnifiedPlanDescription(/* use_ssrcs = */ false);
Amit Hilbucha2012042018-12-03 19:35:054737 auto description = jdesc_.description();
4738 auto media = description->GetContentDescriptionByName(kVideoContentName3);
Amit Hilbuchc57d5732018-12-11 23:30:114739 ASSERT_EQ(media->streams().size(), 1ul);
4740 StreamParams& send_stream = media->mutable_streams()[0];
4741 std::vector<RidDescription> send_rids;
4742 send_rids.push_back(RidDescription("1", RidDirection::kSend));
4743 send_rids.push_back(RidDescription("2", RidDirection::kSend));
4744 send_rids.push_back(RidDescription("3", RidDirection::kSend));
4745 send_rids.push_back(RidDescription("4", RidDirection::kSend));
4746 send_stream.set_rids(send_rids);
Florent Castellib60141b2019-07-03 10:47:544747 std::vector<RidDescription> receive_rids;
4748 receive_rids.push_back(RidDescription("5", RidDirection::kReceive));
4749 receive_rids.push_back(RidDescription("6", RidDirection::kReceive));
4750 receive_rids.push_back(RidDescription("7", RidDirection::kReceive));
4751 media->set_receive_rids(receive_rids);
Amit Hilbuchc57d5732018-12-11 23:30:114752
Amit Hilbucha2012042018-12-03 19:35:054753 SimulcastDescription& simulcast = media->simulcast_description();
4754 simulcast.send_layers().AddLayerWithAlternatives(
4755 {SimulcastLayer("2", false), SimulcastLayer("1", true)});
4756 simulcast.send_layers().AddLayerWithAlternatives(
4757 {SimulcastLayer("4", false), SimulcastLayer("3", false)});
Florent Castellib60141b2019-07-03 10:47:544758 simulcast.receive_layers().AddLayer({SimulcastLayer("5", false)});
4759 simulcast.receive_layers().AddLayer({SimulcastLayer("6", false)});
4760 simulcast.receive_layers().AddLayer({SimulcastLayer("7", false)});
Amit Hilbucha2012042018-12-03 19:35:054761
Amit Hilbucha2012042018-12-03 19:35:054762 TestSerialize(jdesc_);
4763}
Steve Anton06817cd2018-12-18 23:55:304764
4765// Test that the content name is empty if the media section does not have an
4766// a=mid line.
4767TEST_F(WebRtcSdpTest, ParseNoMid) {
4768 std::string sdp = kSdpString;
4769 Replace("a=mid:audio_content_name\r\n", "", &sdp);
4770 Replace("a=mid:video_content_name\r\n", "", &sdp);
4771
4772 JsepSessionDescription output(kDummyType);
4773 SdpParseError error;
4774 ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4775
4776 EXPECT_THAT(output.description()->contents(),
4777 ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
4778 Field("name", &cricket::ContentInfo::name, "")));
4779}
Piotr (Peter) Slatala13e570f2019-02-27 19:34:264780
Guido Urdanetacecf87f2019-05-31 10:17:384781TEST_F(WebRtcSdpTest, SerializeWithDefaultSctpProtocol) {
4782 AddSctpDataChannel(false); // Don't use sctpmap
4783 JsepSessionDescription jsep_desc(kDummyType);
4784 MakeDescriptionWithoutCandidates(&jsep_desc);
4785 std::string message = webrtc::SdpSerialize(jsep_desc);
4786 EXPECT_NE(std::string::npos,
4787 message.find(cricket::kMediaProtocolUdpDtlsSctp));
4788}
4789
4790TEST_F(WebRtcSdpTest, DeserializeWithAllSctpProtocols) {
4791 AddSctpDataChannel(false);
4792 std::string protocols[] = {cricket::kMediaProtocolDtlsSctp,
4793 cricket::kMediaProtocolUdpDtlsSctp,
4794 cricket::kMediaProtocolTcpDtlsSctp};
4795 for (const auto& protocol : protocols) {
4796 sctp_desc_->set_protocol(protocol);
4797 JsepSessionDescription jsep_desc(kDummyType);
4798 MakeDescriptionWithoutCandidates(&jsep_desc);
4799 std::string message = webrtc::SdpSerialize(jsep_desc);
4800 EXPECT_NE(std::string::npos, message.find(protocol));
4801 JsepSessionDescription jsep_output(kDummyType);
4802 SdpParseError error;
4803 EXPECT_TRUE(webrtc::SdpDeserialize(message, &jsep_output, &error));
4804 }
4805}
Taylor Brandstetter4256df02020-02-18 22:05:074806
4807// According to https://tools.ietf.org/html/rfc5576#section-6.1, the CNAME
4808// attribute is mandatory, but we relax that restriction.
4809TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCname) {
4810 std::string sdp_without_cname = kSdpFullString;
4811 Replace("a=ssrc:1 cname:stream_1_cname\r\n", "", &sdp_without_cname);
4812 JsepSessionDescription new_jdesc(kDummyType);
4813 EXPECT_TRUE(SdpDeserialize(sdp_without_cname, &new_jdesc));
4814
4815 audio_desc_->mutable_streams()[0].cname = "";
4816 ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
4817 jdesc_.session_version()));
4818 EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
4819}
Philipp Hanckeefc55b02020-06-26 08:17:054820
Dor Hend1831cb2023-02-03 01:59:284821TEST_F(WebRtcSdpTest,
4822 DeserializeSdpWithUnrecognizedApplicationProtocolRejectsSection) {
4823 const char* unsupported_application_protocols[] = {
4824 "bogus/RTP/", "RTP/SAVPF", "DTLS/SCTP/RTP/", "DTLS/SCTPRTP/",
4825 "obviously-bogus", "UDP/TL/RTSP/SAVPF", "UDP/TL/RTSP/S"};
4826
4827 for (auto proto : unsupported_application_protocols) {
4828 JsepSessionDescription jdesc_output(kDummyType);
4829 std::string sdp = kSdpSessionString;
4830 sdp.append("m=application 9 ");
4831 sdp.append(proto);
4832 sdp.append(" 101\r\n");
4833
4834 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4835
4836 // Make sure we actually parsed a single media section
4837 ASSERT_EQ(1u, jdesc_output.description()->contents().size());
4838
4839 // Content is not getting parsed as sctp but instead unsupported.
4840 EXPECT_EQ(nullptr, jdesc_output.description()
4841 ->contents()[0]
4842 .media_description()
4843 ->as_sctp());
4844 EXPECT_NE(nullptr, jdesc_output.description()
4845 ->contents()[0]
4846 .media_description()
4847 ->as_unsupported());
4848
4849 // Reject the content
4850 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
4851 }
4852}
4853
Philipp Hanckeefc55b02020-06-26 08:17:054854TEST_F(WebRtcSdpTest, DeserializeSdpWithUnsupportedMediaType) {
Philipp Hanckeefc55b02020-06-26 08:17:054855 std::string sdp = kSdpSessionString;
4856 sdp +=
4857 "m=bogus 9 RTP/SAVPF 0 8\r\n"
Philipp Hancke4e8c1152020-10-13 10:43:154858 "c=IN IP4 0.0.0.0\r\n"
4859 "a=mid:bogusmid\r\n";
Philipp Hanckeefc55b02020-06-26 08:17:054860 sdp +=
4861 "m=audio/something 9 RTP/SAVPF 0 8\r\n"
Philipp Hancke4e8c1152020-10-13 10:43:154862 "c=IN IP4 0.0.0.0\r\n"
4863 "a=mid:somethingmid\r\n";
Philipp Hanckeefc55b02020-06-26 08:17:054864
4865 JsepSessionDescription jdesc_output(kDummyType);
4866 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4867
Philipp Hancke4e8c1152020-10-13 10:43:154868 ASSERT_EQ(2u, jdesc_output.description()->contents().size());
4869 ASSERT_NE(nullptr, jdesc_output.description()
4870 ->contents()[0]
4871 .media_description()
4872 ->as_unsupported());
4873 ASSERT_NE(nullptr, jdesc_output.description()
4874 ->contents()[1]
4875 .media_description()
4876 ->as_unsupported());
4877
4878 EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
4879 EXPECT_TRUE(jdesc_output.description()->contents()[1].rejected);
4880
4881 EXPECT_EQ(jdesc_output.description()->contents()[0].name, "bogusmid");
4882 EXPECT_EQ(jdesc_output.description()->contents()[1].name, "somethingmid");
Philipp Hanckeefc55b02020-06-26 08:17:054883}
Philipp Hanckeb70c9532021-01-13 09:40:064884
4885TEST_F(WebRtcSdpTest, MediaTypeProtocolMismatch) {
4886 std::string sdp =
4887 "v=0\r\n"
4888 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4889 "s=-\r\n"
4890 "t=0 0\r\n";
4891
4892 ExpectParseFailure(std::string(sdp + "m=audio 9 UDP/DTLS/SCTP 120\r\n"),
4893 "m=audio");
4894 ExpectParseFailure(std::string(sdp + "m=video 9 UDP/DTLS/SCTP 120\r\n"),
4895 "m=video");
4896 ExpectParseFailure(std::string(sdp + "m=video 9 SOMETHING 120\r\n"),
4897 "m=video");
Philipp Hanckeb70c9532021-01-13 09:40:064898}
Philipp Hanckecd467b52021-01-29 08:29:474899
4900// Regression test for:
4901// https://bugs.chromium.org/p/chromium/issues/detail?id=1171965
4902TEST_F(WebRtcSdpTest, SctpPortInUnsupportedContent) {
4903 std::string sdp =
4904 "v=0\r\n"
4905 "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
4906 "s=-\r\n"
4907 "t=0 0\r\n"
4908 "m=o 1 DTLS/SCTP 5000\r\n"
4909 "a=sctp-port\r\n";
4910
4911 JsepSessionDescription jdesc_output(kDummyType);
4912 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4913}
Harald Alvestrand99bcf602021-03-03 07:44:394914
4915TEST_F(WebRtcSdpTest, IllegalMidCharacterValue) {
4916 std::string sdp = kSdpString;
4917 // [ is an illegal token value.
4918 Replace("a=mid:", "a=mid:[]", &sdp);
4919 ExpectParseFailure(std::string(sdp), "a=mid:[]");
4920}
Philipp Hancked58ac5a2021-11-25 07:57:544921
4922TEST_F(WebRtcSdpTest, MaxChannels) {
4923 std::string sdp =
4924 "v=0\r\n"
4925 "o=- 11 22 IN IP4 127.0.0.1\r\n"
4926 "s=-\r\n"
4927 "t=0 0\r\n"
4928 "m=audio 49232 RTP/AVP 108\r\n"
4929 "a=rtpmap:108 ISAC/16000/512\r\n";
4930
4931 ExpectParseFailure(sdp, "a=rtpmap:108 ISAC/16000/512");
4932}
Harald Alvestrand88b8dec12022-04-07 09:54:514933
Philipp Hancke32c60b82022-05-31 14:51:234934TEST_F(WebRtcSdpTest, DuplicateAudioRtpmapWithConflict) {
4935 std::string sdp =
4936 "v=0\r\n"
4937 "o=- 11 22 IN IP4 127.0.0.1\r\n"
4938 "s=-\r\n"
4939 "t=0 0\r\n"
4940 "m=audio 49232 RTP/AVP 108\r\n"
Philipp Hancke32c60b82022-05-31 14:51:234941 "a=rtpmap:108 ISAC/16000\r\n"
Philipp Hancke62c20f32022-07-07 09:06:364942 "a=rtpmap:108 G711/16000\r\n";
Philipp Hancke32c60b82022-05-31 14:51:234943
Philipp Hancke62c20f32022-07-07 09:06:364944 ExpectParseFailure(sdp, "a=rtpmap:108 G711/16000");
Philipp Hancke32c60b82022-05-31 14:51:234945}
4946
4947TEST_F(WebRtcSdpTest, DuplicateVideoRtpmapWithConflict) {
4948 std::string sdp =
4949 "v=0\r\n"
4950 "o=- 11 22 IN IP4 127.0.0.1\r\n"
4951 "s=-\r\n"
4952 "t=0 0\r\n"
4953 "m=video 49232 RTP/AVP 108\r\n"
4954 "a=rtpmap:108 VP8/90000\r\n"
4955 "a=rtpmap:108 VP9/90000\r\n";
4956
4957 ExpectParseFailure(sdp, "a=rtpmap:108 VP9/90000");
4958}
4959
4960TEST_F(WebRtcSdpTest, FmtpBeforeRtpMap) {
4961 std::string sdp =
4962 "v=0\r\n"
4963 "o=- 11 22 IN IP4 127.0.0.1\r\n"
4964 "s=-\r\n"
4965 "t=0 0\r\n"
4966 "m=video 49232 RTP/AVP 108\r\n"
4967 "a=fmtp:108 profile-level=1\r\n"
4968 "a=rtpmap:108 VP9/90000\r\n";
4969
4970 JsepSessionDescription jdesc_output(kDummyType);
4971 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4972}
4973
Andrey Logvin1d848e12022-06-22 09:39:194974TEST_F(WebRtcSdpTest, StaticallyAssignedPayloadTypeWithDifferentCasing) {
4975 std::string sdp =
4976 "v=0\r\n"
4977 "o=- 11 22 IN IP4 127.0.0.1\r\n"
4978 "s=-\r\n"
4979 "t=0 0\r\n"
4980 "m=audio 49232 RTP/AVP 18\r\n"
4981 // Casing differs from statically assigned type, this should
4982 // still be accepted.
4983 "a=rtpmap:18 g729/8000\r\n";
4984
4985 JsepSessionDescription jdesc_output(kDummyType);
4986 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
4987}
4988
Harald Alvestrand88b8dec12022-04-07 09:54:514989// This tests parsing of SDP with unknown ssrc-specific attributes.
4990TEST_F(WebRtcSdpTest, ParseIgnoreUnknownSsrcSpecificAttribute) {
4991 std::string sdp = kSdpString;
4992 sdp += "a=ssrc:1 mslabel:something\r\n";
4993
4994 JsepSessionDescription output(kDummyType);
4995 SdpParseError error;
4996 ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
4997}
Philipp Hancke55615992023-02-21 09:49:184998
4999TEST_F(WebRtcSdpTest, ParseSessionLevelExtmapAttributes) {
5000 std::string sdp =
5001 "v=0\r\n"
5002 "o=- 0 3 IN IP4 127.0.0.1\r\n"
5003 "s=-\r\n"
5004 "t=0 0\r\n"
5005 "a=group:BUNDLE 0\r\n"
5006 "a=fingerprint:sha-1 "
5007 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
5008 "a=setup:actpass\r\n"
5009 "a=ice-ufrag:ETEn\r\n"
5010 "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
5011 "a=extmap:3 "
5012 "http://www.ietf.org/id/"
5013 "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
5014 "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
5015 "c=IN IP4 0.0.0.0\r\n"
5016 "a=rtcp-mux\r\n"
5017 "a=sendonly\r\n"
5018 "a=mid:0\r\n"
5019 "a=rtpmap:111 opus/48000/2\r\n";
5020 JsepSessionDescription jdesc(kDummyType);
5021 EXPECT_TRUE(SdpDeserialize(sdp, &jdesc));
5022 ASSERT_EQ(1u, jdesc.description()->contents().size());
5023 const auto content = jdesc.description()->contents()[0];
5024 const auto* audio_description = content.media_description()->as_audio();
5025 ASSERT_NE(audio_description, nullptr);
5026 const auto& extensions = audio_description->rtp_header_extensions();
5027 ASSERT_EQ(1u, extensions.size());
5028 EXPECT_EQ(extensions[0].uri,
5029 "http://www.ietf.org/id/"
5030 "draft-holmer-rmcat-transport-wide-cc-extensions-01");
5031 EXPECT_EQ(extensions[0].id, 3);
5032}
5033
5034TEST_F(WebRtcSdpTest, RejectSessionLevelMediaLevelExtmapMixedUsage) {
5035 std::string sdp =
5036 "v=0\r\n"
5037 "o=- 0 3 IN IP4 127.0.0.1\r\n"
5038 "s=-\r\n"
5039 "t=0 0\r\n"
5040 "a=group:BUNDLE 0\r\n"
5041 "a=fingerprint:sha-1 "
5042 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
5043 "a=setup:actpass\r\n"
5044 "a=ice-ufrag:ETEn\r\n"
5045 "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
5046 "a=extmap:3 "
5047 "http://www.ietf.org/id/"
5048 "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
5049 "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
5050 "a=extmap:2 "
5051 "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n"
5052 "c=IN IP4 0.0.0.0\r\n"
5053 "a=rtcp-mux\r\n"
5054 "a=sendonly\r\n"
5055 "a=mid:0\r\n"
5056 "a=rtpmap:111 opus/48000/2\r\n";
5057 JsepSessionDescription jdesc(kDummyType);
5058 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
5059}
Philipp Hancke6a38a3e2023-06-15 05:21:565060
5061TEST_F(WebRtcSdpTest, RejectDuplicateSsrcInSsrcGroup) {
5062 std::string sdp =
5063 "v=0\r\n"
5064 "o=- 0 3 IN IP4 127.0.0.1\r\n"
5065 "s=-\r\n"
5066 "t=0 0\r\n"
5067 "a=group:BUNDLE 0\r\n"
5068 "a=fingerprint:sha-1 "
5069 "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
5070 "a=setup:actpass\r\n"
5071 "a=ice-ufrag:ETEn\r\n"
5072 "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
5073 "m=video 9 UDP/TLS/RTP/SAVPF 96 97\r\n"
5074 "c=IN IP4 0.0.0.0\r\n"
5075 "a=rtcp-mux\r\n"
5076 "a=sendonly\r\n"
5077 "a=mid:0\r\n"
5078 "a=rtpmap:96 VP8/90000\r\n"
5079 "a=rtpmap:97 rtx/90000\r\n"
5080 "a=fmtp:97 apt=96\r\n"
5081 "a=ssrc-group:FID 1234 1234\r\n"
5082 "a=ssrc:1234 cname:test\r\n";
5083 JsepSessionDescription jdesc(kDummyType);
5084 EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
5085}