blob: 6125d5f90ec395f6d0ebe7104f12e11c8357b26a [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000015#include "webrtc/base/fakesslidentity.h"
16#include "webrtc/base/gunit.h"
17#include "webrtc/base/messagedigest.h"
18#include "webrtc/base/ssladapter.h"
kjellandera96e2d72016-02-04 23:52:28 -080019#include "webrtc/media/base/codec.h"
20#include "webrtc/media/base/testutils.h"
kjellanderf4752772016-03-02 05:42:30 -080021#include "webrtc/p2p/base/p2pconstants.h"
kjellandera96e2d72016-02-04 23:52:28 -080022#include "webrtc/p2p/base/transportdescription.h"
23#include "webrtc/p2p/base/transportinfo.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010024#include "webrtc/pc/mediasession.h"
25#include "webrtc/pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000026
27#ifdef HAVE_SRTP
28#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000029 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000030 ASSERT_EQ(s, cd->cryptos().size()); \
31 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
32#else
33#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000034 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035 ASSERT_EQ(0U, cd->cryptos().size());
36#endif
37
38typedef std::vector<cricket::Candidate> Candidates;
39
40using cricket::MediaContentDescription;
41using cricket::MediaSessionDescriptionFactory;
ossu075af922016-06-14 03:29:38 -070042using cricket::MediaContentDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043using cricket::MediaSessionOptions;
44using cricket::MediaType;
45using cricket::SessionDescription;
46using cricket::SsrcGroup;
47using cricket::StreamParams;
48using cricket::StreamParamsVec;
49using cricket::TransportDescription;
50using cricket::TransportDescriptionFactory;
51using cricket::TransportInfo;
52using cricket::ContentInfo;
53using cricket::CryptoParamsVec;
54using cricket::AudioContentDescription;
55using cricket::VideoContentDescription;
56using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080057using cricket::GetFirstAudioContent;
58using cricket::GetFirstVideoContent;
59using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::GetFirstAudioContentDescription;
61using cricket::GetFirstVideoContentDescription;
62using cricket::GetFirstDataContentDescription;
63using cricket::kAutoBandwidth;
64using cricket::AudioCodec;
65using cricket::VideoCodec;
66using cricket::DataCodec;
67using cricket::NS_JINGLE_RTP;
68using cricket::MEDIA_TYPE_AUDIO;
69using cricket::MEDIA_TYPE_VIDEO;
70using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071using cricket::SEC_DISABLED;
72using cricket::SEC_ENABLED;
73using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070074using rtc::CS_AES_CM_128_HMAC_SHA1_32;
75using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070076using rtc::CS_AEAD_AES_128_GCM;
77using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070078using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079
80static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070081 AudioCodec(103, "ISAC", 16000, -1, 1),
82 AudioCodec(102, "iLBC", 8000, 13300, 1),
83 AudioCodec(0, "PCMU", 8000, 64000, 1),
84 AudioCodec(8, "PCMA", 8000, 64000, 1),
85 AudioCodec(117, "red", 8000, 0, 1),
86 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087
88static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070089 AudioCodec(126, "speex", 16000, 22000, 1),
90 AudioCodec(0, "PCMU", 8000, 64000, 1),
91 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092};
93
94static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070095 AudioCodec(102, "iLBC", 8000, 13300, 1),
96 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097};
98
99static const VideoCodec kVideoCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700100 VideoCodec(96, "H264-SVC", 320, 200, 30),
101 VideoCodec(97, "H264", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103static const VideoCodec kVideoCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700104 VideoCodec(126, "H264", 320, 200, 30),
105 VideoCodec(127, "H263", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
107static const VideoCodec kVideoCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700108 VideoCodec(97, "H264", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
deadbeef67cf2c12016-04-13 10:07:16 -0700110static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
111 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
deadbeef67cf2c12016-04-13 10:07:16 -0700113static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
114 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115
deadbeef67cf2c12016-04-13 10:07:16 -0700116static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
117 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118
isheriff6f8d6862016-05-26 11:24:55 -0700119static const RtpExtension kAudioRtpExtension1[] = {
120 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
121 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122};
123
isheriff6f8d6862016-05-26 11:24:55 -0700124static const RtpExtension kAudioRtpExtension2[] = {
125 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
126 RtpExtension("http://google.com/testing/audio_something_else", 8),
127 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128};
129
isheriff6f8d6862016-05-26 11:24:55 -0700130static const RtpExtension kAudioRtpExtension3[] = {
131 RtpExtension("http://google.com/testing/audio_something", 2),
132 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700133};
134
isheriff6f8d6862016-05-26 11:24:55 -0700135static const RtpExtension kAudioRtpExtensionAnswer[] = {
136 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137};
138
isheriff6f8d6862016-05-26 11:24:55 -0700139static const RtpExtension kVideoRtpExtension1[] = {
140 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
141 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142};
143
isheriff6f8d6862016-05-26 11:24:55 -0700144static const RtpExtension kVideoRtpExtension2[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
146 RtpExtension("http://google.com/testing/video_something_else", 14),
147 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148};
149
isheriff6f8d6862016-05-26 11:24:55 -0700150static const RtpExtension kVideoRtpExtension3[] = {
151 RtpExtension("http://google.com/testing/video_something", 4),
152 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kVideoRtpExtensionAnswer[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157};
158
Peter Boström0c4e06b2015-10-07 12:23:21 +0200159static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
160static const uint32_t kSimSsrc[] = {10, 20, 30};
161static const uint32_t kFec1Ssrc[] = {10, 11};
162static const uint32_t kFec2Ssrc[] = {20, 21};
163static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164
165static const char kMediaStream1[] = "stream_1";
166static const char kMediaStream2[] = "stream_2";
167static const char kVideoTrack1[] = "video_1";
168static const char kVideoTrack2[] = "video_2";
169static const char kAudioTrack1[] = "audio_1";
170static const char kAudioTrack2[] = "audio_2";
171static const char kAudioTrack3[] = "audio_3";
172static const char kDataTrack1[] = "data_1";
173static const char kDataTrack2[] = "data_2";
174static const char kDataTrack3[] = "data_3";
175
zhihuangcf5b37c2016-05-05 11:44:35 -0700176static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
177 "RTP/SAVPF"};
178static const char* kMediaProtocolsDtls[] = {
179 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
180 "UDP/TLS/RTP/SAVP"};
181
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000182static bool IsMediaContentOfType(const ContentInfo* content,
183 MediaType media_type) {
184 const MediaContentDescription* mdesc =
185 static_cast<const MediaContentDescription*>(content->description);
186 return mdesc && mdesc->type() == media_type;
187}
188
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000189static cricket::MediaContentDirection
190GetMediaDirection(const ContentInfo* content) {
191 cricket::MediaContentDescription* desc =
192 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
193 return desc->direction();
194}
195
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000196static void AddRtxCodec(const VideoCodec& rtx_codec,
197 std::vector<VideoCodec>* codecs) {
198 VideoCodec rtx;
199 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
200 codecs->push_back(rtx_codec);
201}
202
203template <class T>
204static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
205 std::vector<std::string> codec_names;
206 for (const auto& codec : codecs) {
207 codec_names.push_back(codec.name);
208 }
209 return codec_names;
210}
211
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212class MediaSessionDescriptionFactoryTest : public testing::Test {
213 public:
214 MediaSessionDescriptionFactoryTest()
Henrik Boström3a14bf32015-08-31 09:27:58 +0200215 : f1_(&tdf1_),
216 f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700217 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
218 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
220 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700221 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
222 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
224 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200225 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700226 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200227 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700228 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 }
230
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000231 // Create a video StreamParamsVec object with:
232 // - one video stream with 3 simulcast streams and FEC,
233 StreamParamsVec CreateComplexVideoStreamParamsVec() {
234 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
235 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
236 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
237 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
238
239 std::vector<SsrcGroup> ssrc_groups;
240 ssrc_groups.push_back(sim_group);
241 ssrc_groups.push_back(fec_group1);
242 ssrc_groups.push_back(fec_group2);
243 ssrc_groups.push_back(fec_group3);
244
245 StreamParams simulcast_params;
246 simulcast_params.id = kVideoTrack1;
247 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
248 simulcast_params.ssrc_groups = ssrc_groups;
249 simulcast_params.cname = "Video_SIM_FEC";
250 simulcast_params.sync_label = kMediaStream1;
251
252 StreamParamsVec video_streams;
253 video_streams.push_back(simulcast_params);
254
255 return video_streams;
256 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257
258 bool CompareCryptoParams(const CryptoParamsVec& c1,
259 const CryptoParamsVec& c2) {
260 if (c1.size() != c2.size())
261 return false;
262 for (size_t i = 0; i < c1.size(); ++i)
263 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
264 c1[i].key_params != c2[i].key_params ||
265 c1[i].session_params != c2[i].session_params)
266 return false;
267 return true;
268 }
269
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700270 // Returns true if the transport info contains "renomination" as an
271 // ICE option.
272 bool GetIceRenomination(const TransportInfo* transport_info) {
273 const std::vector<std::string>& ice_options =
274 transport_info->description.transport_options;
275 auto iter = std::find(ice_options.begin(), ice_options.end(),
276 cricket::ICE_RENOMINATION_STR);
277 return iter != ice_options.end();
278 }
279
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
281 bool has_current_desc) {
282 const std::string current_audio_ufrag = "current_audio_ufrag";
283 const std::string current_audio_pwd = "current_audio_pwd";
284 const std::string current_video_ufrag = "current_video_ufrag";
285 const std::string current_video_pwd = "current_video_pwd";
286 const std::string current_data_ufrag = "current_data_ufrag";
287 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800288 std::unique_ptr<SessionDescription> current_desc;
289 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290 if (has_current_desc) {
291 current_desc.reset(new SessionDescription());
292 EXPECT_TRUE(current_desc->AddTransportInfo(
293 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700294 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000295 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 EXPECT_TRUE(current_desc->AddTransportInfo(
297 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700298 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000299 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000300 EXPECT_TRUE(current_desc->AddTransportInfo(
301 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700302 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000303 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304 }
305 if (offer) {
306 desc.reset(f1_.CreateOffer(options, current_desc.get()));
307 } else {
kwiberg31022942016-03-11 14:18:21 -0800308 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309 offer.reset(f1_.CreateOffer(options, NULL));
310 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
311 }
312 ASSERT_TRUE(desc.get() != NULL);
313 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000314 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000315 EXPECT_TRUE(ti_audio != NULL);
316 if (has_current_desc) {
317 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
318 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
319 } else {
320 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
321 ti_audio->description.ice_ufrag.size());
322 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
323 ti_audio->description.ice_pwd.size());
324 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700325 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000326
327 } else {
328 EXPECT_TRUE(ti_audio == NULL);
329 }
330 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000331 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 EXPECT_TRUE(ti_video != NULL);
333 if (options.bundle_enabled) {
334 EXPECT_EQ(ti_audio->description.ice_ufrag,
335 ti_video->description.ice_ufrag);
336 EXPECT_EQ(ti_audio->description.ice_pwd,
337 ti_video->description.ice_pwd);
338 } else {
339 if (has_current_desc) {
340 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
341 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
342 } else {
343 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
344 ti_video->description.ice_ufrag.size());
345 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
346 ti_video->description.ice_pwd.size());
347 }
348 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700349 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 } else {
351 EXPECT_TRUE(ti_video == NULL);
352 }
353 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
354 if (options.has_data()) {
355 EXPECT_TRUE(ti_data != NULL);
356 if (options.bundle_enabled) {
357 EXPECT_EQ(ti_audio->description.ice_ufrag,
358 ti_data->description.ice_ufrag);
359 EXPECT_EQ(ti_audio->description.ice_pwd,
360 ti_data->description.ice_pwd);
361 } else {
362 if (has_current_desc) {
363 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
364 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
365 } else {
366 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
367 ti_data->description.ice_ufrag.size());
368 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
369 ti_data->description.ice_pwd.size());
370 }
371 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700372 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_data));
373
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000374 } else {
375 EXPECT_TRUE(ti_video == NULL);
376 }
377 }
378
379 void TestCryptoWithBundle(bool offer) {
380 f1_.set_secure(SEC_ENABLED);
381 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000382 options.recv_audio = true;
383 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384 options.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -0800385 std::unique_ptr<SessionDescription> ref_desc;
386 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 if (offer) {
388 options.bundle_enabled = false;
389 ref_desc.reset(f1_.CreateOffer(options, NULL));
390 options.bundle_enabled = true;
391 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
392 } else {
393 options.bundle_enabled = true;
394 ref_desc.reset(f1_.CreateOffer(options, NULL));
395 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
396 }
397 ASSERT_TRUE(desc.get() != NULL);
398 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000399 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000400 desc.get()->GetContentDescriptionByName("audio"));
401 ASSERT_TRUE(audio_media_desc != NULL);
402 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000403 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000404 desc.get()->GetContentDescriptionByName("video"));
405 ASSERT_TRUE(video_media_desc != NULL);
406 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
407 video_media_desc->cryptos()));
408 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
409 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
410 audio_media_desc->cryptos()[0].cipher_suite);
411
412 // Verify the selected crypto is one from the reference audio
413 // media content.
414 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000415 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 ref_desc.get()->GetContentDescriptionByName("audio"));
417 bool found = false;
418 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
419 if (ref_audio_media_desc->cryptos()[i].Matches(
420 audio_media_desc->cryptos()[0])) {
421 found = true;
422 break;
423 }
424 }
425 EXPECT_TRUE(found);
426 }
427
428 // This test that the audio and video media direction is set to
429 // |expected_direction_in_answer| in an answer if the offer direction is set
430 // to |direction_in_offer|.
431 void TestMediaDirectionInAnswer(
432 cricket::MediaContentDirection direction_in_offer,
433 cricket::MediaContentDirection expected_direction_in_answer) {
434 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000435 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800436 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700438 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439 ASSERT_TRUE(ac_offer != NULL);
440 AudioContentDescription* acd_offer =
441 static_cast<AudioContentDescription*>(ac_offer->description);
442 acd_offer->set_direction(direction_in_offer);
terelius8c011e52016-04-26 05:28:11 -0700443 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 ASSERT_TRUE(vc_offer != NULL);
445 VideoContentDescription* vcd_offer =
446 static_cast<VideoContentDescription*>(vc_offer->description);
447 vcd_offer->set_direction(direction_in_offer);
448
kwiberg31022942016-03-11 14:18:21 -0800449 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 f2_.CreateAnswer(offer.get(), opts, NULL));
451 const AudioContentDescription* acd_answer =
452 GetFirstAudioContentDescription(answer.get());
453 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
454 const VideoContentDescription* vcd_answer =
455 GetFirstVideoContentDescription(answer.get());
456 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
457 }
458
459 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
460 const cricket::ContentDescription* description = content->description;
461 ASSERT(description != NULL);
462 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000463 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 ASSERT(audio_content_desc != NULL);
465 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
466 if (audio_content_desc->codecs()[i].name == "CN")
467 return false;
468 }
469 return true;
470 }
471
jbauchcb560652016-08-04 05:20:32 -0700472 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
473 MediaSessionOptions offer_opts;
474 offer_opts.recv_video = true;
475 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
476 MediaSessionOptions answer_opts;
477 answer_opts.recv_video = true;
478 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
479 f1_.set_secure(SEC_ENABLED);
480 f2_.set_secure(SEC_ENABLED);
481 std::unique_ptr<SessionDescription> offer(
482 f1_.CreateOffer(offer_opts, NULL));
483 ASSERT_TRUE(offer.get() != NULL);
484 std::unique_ptr<SessionDescription> answer(
485 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
486 const ContentInfo* ac = answer->GetContentByName("audio");
487 const ContentInfo* vc = answer->GetContentByName("video");
488 ASSERT_TRUE(ac != NULL);
489 ASSERT_TRUE(vc != NULL);
490 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
491 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
492 const AudioContentDescription* acd =
493 static_cast<const AudioContentDescription*>(ac->description);
494 const VideoContentDescription* vcd =
495 static_cast<const VideoContentDescription*>(vc->description);
496 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
497 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
498 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
499 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
500 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
501 if (gcm_offer && gcm_answer) {
502 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
503 } else {
504 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
505 }
506 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
507 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
508 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
509 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
510 if (gcm_offer && gcm_answer) {
511 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
512 } else {
513 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
514 }
515 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
516 }
517
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 protected:
519 MediaSessionDescriptionFactory f1_;
520 MediaSessionDescriptionFactory f2_;
521 TransportDescriptionFactory tdf1_;
522 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523};
524
525// Create a typical audio offer, and ensure it matches what we expect.
526TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
527 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800528 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000529 f1_.CreateOffer(MediaSessionOptions(), NULL));
530 ASSERT_TRUE(offer.get() != NULL);
531 const ContentInfo* ac = offer->GetContentByName("audio");
532 const ContentInfo* vc = offer->GetContentByName("video");
533 ASSERT_TRUE(ac != NULL);
534 ASSERT_TRUE(vc == NULL);
535 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
536 const AudioContentDescription* acd =
537 static_cast<const AudioContentDescription*>(ac->description);
538 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700539 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
541 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
542 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
543 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
544 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
545}
546
547// Create a typical video offer, and ensure it matches what we expect.
548TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
549 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000550 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800552 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 ASSERT_TRUE(offer.get() != NULL);
554 const ContentInfo* ac = offer->GetContentByName("audio");
555 const ContentInfo* vc = offer->GetContentByName("video");
556 ASSERT_TRUE(ac != NULL);
557 ASSERT_TRUE(vc != NULL);
558 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
559 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
560 const AudioContentDescription* acd =
561 static_cast<const AudioContentDescription*>(ac->description);
562 const VideoContentDescription* vcd =
563 static_cast<const VideoContentDescription*>(vc->description);
564 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700565 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
567 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
568 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
569 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
570 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
571 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
572 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
573 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
574 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
575 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
576 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
577 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
578}
579
580// Test creating an offer with bundle where the Codecs have the same dynamic
581// RTP playlod type. The test verifies that the offer don't contain the
582// duplicate RTP payload types.
583TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
584 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700585 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
587 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
588 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
589
590 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000591 opts.recv_audio = true;
592 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 opts.data_channel_type = cricket::DCT_RTP;
594 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800595 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 const VideoContentDescription* vcd =
597 GetFirstVideoContentDescription(offer.get());
598 const AudioContentDescription* acd =
599 GetFirstAudioContentDescription(offer.get());
600 const DataContentDescription* dcd =
601 GetFirstDataContentDescription(offer.get());
602 ASSERT_TRUE(NULL != vcd);
603 ASSERT_TRUE(NULL != acd);
604 ASSERT_TRUE(NULL != dcd);
605 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
606 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
607 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
608 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
609 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
610 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
611}
612
613// Test creating an updated offer with with bundle, audio, video and data
614// after an audio only session has been negotiated.
615TEST_F(MediaSessionDescriptionFactoryTest,
616 TestCreateUpdatedVideoOfferWithBundle) {
617 f1_.set_secure(SEC_ENABLED);
618 f2_.set_secure(SEC_ENABLED);
619 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000620 opts.recv_audio = true;
621 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 opts.data_channel_type = cricket::DCT_NONE;
623 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800624 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
625 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 f2_.CreateAnswer(offer.get(), opts, NULL));
627
628 MediaSessionOptions updated_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000629 updated_opts.recv_audio = true;
630 updated_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 updated_opts.data_channel_type = cricket::DCT_RTP;
632 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800633 std::unique_ptr<SessionDescription> updated_offer(
634 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000635
636 const AudioContentDescription* acd =
637 GetFirstAudioContentDescription(updated_offer.get());
638 const VideoContentDescription* vcd =
639 GetFirstVideoContentDescription(updated_offer.get());
640 const DataContentDescription* dcd =
641 GetFirstDataContentDescription(updated_offer.get());
642 EXPECT_TRUE(NULL != vcd);
643 EXPECT_TRUE(NULL != acd);
644 EXPECT_TRUE(NULL != dcd);
645
646 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
647 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
648 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
649 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
650 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
651 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
652}
deadbeef44f08192015-12-15 16:20:09 -0800653
wu@webrtc.org78187522013-10-07 23:32:02 +0000654// Create a RTP data offer, and ensure it matches what we expect.
655TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 MediaSessionOptions opts;
657 opts.data_channel_type = cricket::DCT_RTP;
658 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800659 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 ASSERT_TRUE(offer.get() != NULL);
661 const ContentInfo* ac = offer->GetContentByName("audio");
662 const ContentInfo* dc = offer->GetContentByName("data");
663 ASSERT_TRUE(ac != NULL);
664 ASSERT_TRUE(dc != NULL);
665 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
666 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
667 const AudioContentDescription* acd =
668 static_cast<const AudioContentDescription*>(ac->description);
669 const DataContentDescription* dcd =
670 static_cast<const DataContentDescription*>(dc->description);
671 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700672 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
674 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
675 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
676 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
677 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
678 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
679 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
680 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
681 EXPECT_EQ(cricket::kDataMaxBandwidth,
682 dcd->bandwidth()); // default bandwidth (auto)
683 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
684 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
685 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
686}
687
wu@webrtc.org78187522013-10-07 23:32:02 +0000688// Create an SCTP data offer with bundle without error.
689TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
690 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000691 opts.recv_audio = false;
wu@webrtc.org78187522013-10-07 23:32:02 +0000692 opts.bundle_enabled = true;
693 opts.data_channel_type = cricket::DCT_SCTP;
694 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800695 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000696 EXPECT_TRUE(offer.get() != NULL);
697 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
698}
699
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000700// Test creating an sctp data channel from an already generated offer.
701TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
702 MediaSessionOptions opts;
703 opts.recv_audio = false;
704 opts.bundle_enabled = true;
705 opts.data_channel_type = cricket::DCT_SCTP;
706 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800707 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000708 ASSERT_TRUE(offer1.get() != NULL);
709 const ContentInfo* data = offer1->GetContentByName("data");
710 ASSERT_TRUE(data != NULL);
711 const MediaContentDescription* mdesc =
712 static_cast<const MediaContentDescription*>(data->description);
713 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
714
715 // Now set data_channel_type to 'none' (default) and make sure that the
716 // datachannel type that gets generated from the previous offer, is of the
717 // same type.
718 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800719 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000720 f1_.CreateOffer(opts, offer1.get()));
721 data = offer2->GetContentByName("data");
722 ASSERT_TRUE(data != NULL);
723 mdesc = static_cast<const MediaContentDescription*>(data->description);
724 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
725}
726
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727// Create an audio, video offer without legacy StreamParams.
728TEST_F(MediaSessionDescriptionFactoryTest,
729 TestCreateOfferWithoutLegacyStreams) {
730 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000731 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 f1_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800733 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734 ASSERT_TRUE(offer.get() != NULL);
735 const ContentInfo* ac = offer->GetContentByName("audio");
736 const ContentInfo* vc = offer->GetContentByName("video");
737 ASSERT_TRUE(ac != NULL);
738 ASSERT_TRUE(vc != NULL);
739 const AudioContentDescription* acd =
740 static_cast<const AudioContentDescription*>(ac->description);
741 const VideoContentDescription* vcd =
742 static_cast<const VideoContentDescription*>(vc->description);
743
744 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
745 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
746}
747
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000748// Creates an audio+video sendonly offer.
749TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
750 MediaSessionOptions options;
751 options.recv_audio = false;
752 options.recv_video = false;
753 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
754 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
755
kwiberg31022942016-03-11 14:18:21 -0800756 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000757 ASSERT_TRUE(offer.get() != NULL);
758 EXPECT_EQ(2u, offer->contents().size());
759 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
760 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
761
762 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
763 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
764}
765
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000766// Verifies that the order of the media contents in the current
767// SessionDescription is preserved in the new SessionDescription.
768TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
769 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000770 opts.recv_audio = false;
771 opts.recv_video = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000772 opts.data_channel_type = cricket::DCT_SCTP;
773
kwiberg31022942016-03-11 14:18:21 -0800774 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000775 ASSERT_TRUE(offer1.get() != NULL);
776 EXPECT_EQ(1u, offer1->contents().size());
777 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
778
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000779 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800780 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000781 f1_.CreateOffer(opts, offer1.get()));
782 ASSERT_TRUE(offer2.get() != NULL);
783 EXPECT_EQ(2u, offer2->contents().size());
784 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
785 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
786
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000787 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800788 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000789 f1_.CreateOffer(opts, offer2.get()));
790 ASSERT_TRUE(offer3.get() != NULL);
791 EXPECT_EQ(3u, offer3->contents().size());
792 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
793 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
794 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
795
796 // Verifies the default order is audio-video-data, so that the previous checks
797 // didn't pass by accident.
kwiberg31022942016-03-11 14:18:21 -0800798 std::unique_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000799 ASSERT_TRUE(offer4.get() != NULL);
800 EXPECT_EQ(3u, offer4->contents().size());
801 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
802 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
803 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
804}
805
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806// Create a typical audio answer, and ensure it matches what we expect.
807TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
808 f1_.set_secure(SEC_ENABLED);
809 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800810 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 f1_.CreateOffer(MediaSessionOptions(), NULL));
812 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800813 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
815 const ContentInfo* ac = answer->GetContentByName("audio");
816 const ContentInfo* vc = answer->GetContentByName("video");
817 ASSERT_TRUE(ac != NULL);
818 ASSERT_TRUE(vc == NULL);
819 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
820 const AudioContentDescription* acd =
821 static_cast<const AudioContentDescription*>(ac->description);
822 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
823 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
824 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
825 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
826 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
827 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
828 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
829}
830
jbauchcb560652016-08-04 05:20:32 -0700831// Create a typical audio answer with GCM ciphers enabled, and ensure it
832// matches what we expect.
833TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
834 f1_.set_secure(SEC_ENABLED);
835 f2_.set_secure(SEC_ENABLED);
836 MediaSessionOptions options;
837 options.crypto_options.enable_gcm_crypto_suites = true;
838 std::unique_ptr<SessionDescription> offer(
839 f1_.CreateOffer(options, NULL));
840 ASSERT_TRUE(offer.get() != NULL);
841 std::unique_ptr<SessionDescription> answer(
842 f2_.CreateAnswer(offer.get(), options, NULL));
843 const ContentInfo* ac = answer->GetContentByName("audio");
844 const ContentInfo* vc = answer->GetContentByName("video");
845 ASSERT_TRUE(ac != NULL);
846 ASSERT_TRUE(vc == NULL);
847 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
848 const AudioContentDescription* acd =
849 static_cast<const AudioContentDescription*>(ac->description);
850 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
851 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
852 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
853 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
854 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
855 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
856 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
857}
858
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859// Create a typical video answer, and ensure it matches what we expect.
860TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
861 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000862 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 f1_.set_secure(SEC_ENABLED);
864 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800865 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800867 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 f2_.CreateAnswer(offer.get(), opts, NULL));
869 const ContentInfo* ac = answer->GetContentByName("audio");
870 const ContentInfo* vc = answer->GetContentByName("video");
871 ASSERT_TRUE(ac != NULL);
872 ASSERT_TRUE(vc != NULL);
873 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
874 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
875 const AudioContentDescription* acd =
876 static_cast<const AudioContentDescription*>(ac->description);
877 const VideoContentDescription* vcd =
878 static_cast<const VideoContentDescription*>(vc->description);
879 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
880 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
881 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
882 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
883 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
884 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
885 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
886 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
887 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
888 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
889 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
890 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
891}
892
jbauchcb560652016-08-04 05:20:32 -0700893// Create a typical video answer with GCM ciphers enabled, and ensure it
894// matches what we expect.
895TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
896 TestVideoGcmCipher(true, true);
897}
898
899// Create a typical video answer with GCM ciphers enabled for the offer only,
900// and ensure it matches what we expect.
901TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
902 TestVideoGcmCipher(true, false);
903}
904
905// Create a typical video answer with GCM ciphers enabled for the answer only,
906// and ensure it matches what we expect.
907TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
908 TestVideoGcmCipher(false, true);
909}
910
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
912 MediaSessionOptions opts;
913 opts.data_channel_type = cricket::DCT_RTP;
914 f1_.set_secure(SEC_ENABLED);
915 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800916 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800918 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919 f2_.CreateAnswer(offer.get(), opts, NULL));
920 const ContentInfo* ac = answer->GetContentByName("audio");
921 const ContentInfo* vc = answer->GetContentByName("data");
922 ASSERT_TRUE(ac != NULL);
923 ASSERT_TRUE(vc != NULL);
924 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
925 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
926 const AudioContentDescription* acd =
927 static_cast<const AudioContentDescription*>(ac->description);
928 const DataContentDescription* vcd =
929 static_cast<const DataContentDescription*>(vc->description);
930 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
931 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
932 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
933 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
934 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
935 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
936 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
937 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
938 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
939 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
940 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
941 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
942}
943
jbauchcb560652016-08-04 05:20:32 -0700944TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
945 MediaSessionOptions opts;
946 opts.data_channel_type = cricket::DCT_RTP;
947 opts.crypto_options.enable_gcm_crypto_suites = true;
948 f1_.set_secure(SEC_ENABLED);
949 f2_.set_secure(SEC_ENABLED);
950 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
951 ASSERT_TRUE(offer.get() != NULL);
952 std::unique_ptr<SessionDescription> answer(
953 f2_.CreateAnswer(offer.get(), opts, NULL));
954 const ContentInfo* ac = answer->GetContentByName("audio");
955 const ContentInfo* vc = answer->GetContentByName("data");
956 ASSERT_TRUE(ac != NULL);
957 ASSERT_TRUE(vc != NULL);
958 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
959 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
960 const AudioContentDescription* acd =
961 static_cast<const AudioContentDescription*>(ac->description);
962 const DataContentDescription* vcd =
963 static_cast<const DataContentDescription*>(vc->description);
964 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
965 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
966 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
967 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
968 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
969 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
970 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
971 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
972 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
973 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
974 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
975 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
976}
977
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000978// Verifies that the order of the media contents in the offer is preserved in
979// the answer.
980TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
981 MediaSessionOptions opts;
982
983 // Creates a data only offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000984 opts.recv_audio = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000985 opts.data_channel_type = cricket::DCT_SCTP;
kwiberg31022942016-03-11 14:18:21 -0800986 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000987 ASSERT_TRUE(offer1.get() != NULL);
988
989 // Appends audio to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000990 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800991 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000992 f1_.CreateOffer(opts, offer1.get()));
993 ASSERT_TRUE(offer2.get() != NULL);
994
995 // Appends video to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000996 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800997 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000998 f1_.CreateOffer(opts, offer2.get()));
999 ASSERT_TRUE(offer3.get() != NULL);
1000
kwiberg31022942016-03-11 14:18:21 -08001001 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001002 f2_.CreateAnswer(offer3.get(), opts, NULL));
1003 ASSERT_TRUE(answer.get() != NULL);
1004 EXPECT_EQ(3u, answer->contents().size());
1005 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1006 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1007 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1008}
1009
ossu075af922016-06-14 03:29:38 -07001010// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1011// answerer settings.
1012
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013// This test that the media direction is set to send/receive in an answer if
1014// the offer is send receive.
1015TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1016 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1017}
1018
1019// This test that the media direction is set to receive only in an answer if
1020// the offer is send only.
1021TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1022 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1023}
1024
1025// This test that the media direction is set to send only in an answer if
1026// the offer is recv only.
1027TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1028 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1029}
1030
1031// This test that the media direction is set to inactive in an answer if
1032// the offer is inactive.
1033TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1034 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1035}
1036
1037// Test that a data content with an unknown protocol is rejected in an answer.
1038TEST_F(MediaSessionDescriptionFactoryTest,
1039 CreateDataAnswerToOfferWithUnknownProtocol) {
1040 MediaSessionOptions opts;
1041 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001042 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001043 f1_.set_secure(SEC_ENABLED);
1044 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001045 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001046 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 ASSERT_TRUE(dc_offer != NULL);
1048 DataContentDescription* dcd_offer =
1049 static_cast<DataContentDescription*>(dc_offer->description);
1050 ASSERT_TRUE(dcd_offer != NULL);
1051 std::string protocol = "a weird unknown protocol";
1052 dcd_offer->set_protocol(protocol);
1053
kwiberg31022942016-03-11 14:18:21 -08001054 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055 f2_.CreateAnswer(offer.get(), opts, NULL));
1056
1057 const ContentInfo* dc_answer = answer->GetContentByName("data");
1058 ASSERT_TRUE(dc_answer != NULL);
1059 EXPECT_TRUE(dc_answer->rejected);
1060 const DataContentDescription* dcd_answer =
1061 static_cast<const DataContentDescription*>(dc_answer->description);
1062 ASSERT_TRUE(dcd_answer != NULL);
1063 EXPECT_EQ(protocol, dcd_answer->protocol());
1064}
1065
1066// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1067TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
1068 MediaSessionOptions opts;
1069 f1_.set_secure(SEC_DISABLED);
1070 f2_.set_secure(SEC_DISABLED);
1071 tdf1_.set_secure(SEC_DISABLED);
1072 tdf2_.set_secure(SEC_DISABLED);
1073
kwiberg31022942016-03-11 14:18:21 -08001074 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001075 const AudioContentDescription* offer_acd =
1076 GetFirstAudioContentDescription(offer.get());
1077 ASSERT_TRUE(offer_acd != NULL);
1078 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1079
kwiberg31022942016-03-11 14:18:21 -08001080 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081 f2_.CreateAnswer(offer.get(), opts, NULL));
1082
1083 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1084 ASSERT_TRUE(ac_answer != NULL);
1085 EXPECT_FALSE(ac_answer->rejected);
1086
1087 const AudioContentDescription* answer_acd =
1088 GetFirstAudioContentDescription(answer.get());
1089 ASSERT_TRUE(answer_acd != NULL);
1090 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1091}
1092
1093// Create a video offer and answer and ensure the RTP header extensions
1094// matches what we expect.
1095TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1096 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001097 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098
1099 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1100 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1101 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1102 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1103
kwiberg31022942016-03-11 14:18:21 -08001104 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001106 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001107 f2_.CreateAnswer(offer.get(), opts, NULL));
1108
1109 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1110 GetFirstAudioContentDescription(
1111 offer.get())->rtp_header_extensions());
1112 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1113 GetFirstVideoContentDescription(
1114 offer.get())->rtp_header_extensions());
1115 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1116 GetFirstAudioContentDescription(
1117 answer.get())->rtp_header_extensions());
1118 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1119 GetFirstVideoContentDescription(
1120 answer.get())->rtp_header_extensions());
1121}
1122
1123// Create an audio, video, data answer without legacy StreamParams.
1124TEST_F(MediaSessionDescriptionFactoryTest,
1125 TestCreateAnswerWithoutLegacyStreams) {
1126 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001127 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128 opts.data_channel_type = cricket::DCT_RTP;
1129 f1_.set_add_legacy_streams(false);
1130 f2_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -08001131 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001133 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134 f2_.CreateAnswer(offer.get(), opts, NULL));
1135 const ContentInfo* ac = answer->GetContentByName("audio");
1136 const ContentInfo* vc = answer->GetContentByName("video");
1137 const ContentInfo* dc = answer->GetContentByName("data");
1138 ASSERT_TRUE(ac != NULL);
1139 ASSERT_TRUE(vc != NULL);
1140 const AudioContentDescription* acd =
1141 static_cast<const AudioContentDescription*>(ac->description);
1142 const VideoContentDescription* vcd =
1143 static_cast<const VideoContentDescription*>(vc->description);
1144 const DataContentDescription* dcd =
1145 static_cast<const DataContentDescription*>(dc->description);
1146
1147 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1148 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1149 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1150}
1151
1152TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1153 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001154 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 opts.data_channel_type = cricket::DCT_RTP;
1156 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001157 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001158 ASSERT_TRUE(offer.get() != NULL);
1159 const ContentInfo* ac = offer->GetContentByName("audio");
1160 const ContentInfo* vc = offer->GetContentByName("video");
1161 const ContentInfo* dc = offer->GetContentByName("data");
1162 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1163 static_cast<const AudioContentDescription*>(ac->description));
1164 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1165 static_cast<const VideoContentDescription*>(vc->description));
1166 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1167 static_cast<const DataContentDescription*>(dc->description));
1168
1169 EXPECT_FALSE(acd->partial()); // default is false.
1170 acd->set_partial(true);
1171 EXPECT_TRUE(acd->partial());
1172 acd->set_partial(false);
1173 EXPECT_FALSE(acd->partial());
1174
1175 EXPECT_FALSE(vcd->partial()); // default is false.
1176 vcd->set_partial(true);
1177 EXPECT_TRUE(vcd->partial());
1178 vcd->set_partial(false);
1179 EXPECT_FALSE(vcd->partial());
1180
1181 EXPECT_FALSE(dcd->partial()); // default is false.
1182 dcd->set_partial(true);
1183 EXPECT_TRUE(dcd->partial());
1184 dcd->set_partial(false);
1185 EXPECT_FALSE(dcd->partial());
1186}
1187
1188// Create a typical video answer, and ensure it matches what we expect.
1189TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1190 MediaSessionOptions offer_opts;
1191 MediaSessionOptions answer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001192 answer_opts.recv_video = true;
1193 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 answer_opts.data_channel_type = cricket::DCT_RTP;
1195 offer_opts.data_channel_type = cricket::DCT_RTP;
1196
kwiberg31022942016-03-11 14:18:21 -08001197 std::unique_ptr<SessionDescription> offer;
1198 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001199
1200 offer_opts.rtcp_mux_enabled = true;
1201 answer_opts.rtcp_mux_enabled = true;
1202
1203 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1204 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1205 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1206 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1207 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1208 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1209 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1210 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1211 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1212 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1213 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1214 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1215 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1216 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1217
1218 offer_opts.rtcp_mux_enabled = true;
1219 answer_opts.rtcp_mux_enabled = false;
1220
1221 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1222 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1223 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1224 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1225 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1226 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1227 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1228 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1229 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1230 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1231 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1232 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1233 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1234 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1235
1236 offer_opts.rtcp_mux_enabled = false;
1237 answer_opts.rtcp_mux_enabled = true;
1238
1239 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1240 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1241 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1242 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1243 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1244 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1245 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1246 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1247 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1248 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1249 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1250 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1251 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1252 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1253
1254 offer_opts.rtcp_mux_enabled = false;
1255 answer_opts.rtcp_mux_enabled = false;
1256
1257 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1258 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1259 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1260 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1261 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1262 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1263 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1264 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1265 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1266 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1267 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1268 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1269 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1270 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1271}
1272
1273// Create an audio-only answer to a video offer.
1274TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1275 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001276 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001277 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001279 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1281 const ContentInfo* ac = answer->GetContentByName("audio");
1282 const ContentInfo* vc = answer->GetContentByName("video");
1283 ASSERT_TRUE(ac != NULL);
1284 ASSERT_TRUE(vc != NULL);
1285 ASSERT_TRUE(vc->description != NULL);
1286 EXPECT_TRUE(vc->rejected);
1287}
1288
1289// Create an audio-only answer to an offer with data.
1290TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1291 MediaSessionOptions opts;
1292 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001293 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001294 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001295 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1297 const ContentInfo* ac = answer->GetContentByName("audio");
1298 const ContentInfo* dc = answer->GetContentByName("data");
1299 ASSERT_TRUE(ac != NULL);
1300 ASSERT_TRUE(dc != NULL);
1301 ASSERT_TRUE(dc->description != NULL);
1302 EXPECT_TRUE(dc->rejected);
1303}
1304
1305// Create an answer that rejects the contents which are rejected in the offer.
1306TEST_F(MediaSessionDescriptionFactoryTest,
1307 CreateAnswerToOfferWithRejectedMedia) {
1308 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001309 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001311 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 ASSERT_TRUE(offer.get() != NULL);
1313 ContentInfo* ac = offer->GetContentByName("audio");
1314 ContentInfo* vc = offer->GetContentByName("video");
1315 ContentInfo* dc = offer->GetContentByName("data");
1316 ASSERT_TRUE(ac != NULL);
1317 ASSERT_TRUE(vc != NULL);
1318 ASSERT_TRUE(dc != NULL);
1319 ac->rejected = true;
1320 vc->rejected = true;
1321 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001322 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323 f2_.CreateAnswer(offer.get(), opts, NULL));
1324 ac = answer->GetContentByName("audio");
1325 vc = answer->GetContentByName("video");
1326 dc = answer->GetContentByName("data");
1327 ASSERT_TRUE(ac != NULL);
1328 ASSERT_TRUE(vc != NULL);
1329 ASSERT_TRUE(dc != NULL);
1330 EXPECT_TRUE(ac->rejected);
1331 EXPECT_TRUE(vc->rejected);
1332 EXPECT_TRUE(dc->rejected);
1333}
1334
1335// Create an audio and video offer with:
1336// - one video track
1337// - two audio tracks
1338// - two data tracks
1339// and ensure it matches what we expect. Also updates the initial offer by
1340// adding a new video track and replaces one of the audio tracks.
1341TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1342 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001343 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1344 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1345 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001346 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001347 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1348 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349
1350 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001351 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352
1353 ASSERT_TRUE(offer.get() != NULL);
1354 const ContentInfo* ac = offer->GetContentByName("audio");
1355 const ContentInfo* vc = offer->GetContentByName("video");
1356 const ContentInfo* dc = offer->GetContentByName("data");
1357 ASSERT_TRUE(ac != NULL);
1358 ASSERT_TRUE(vc != NULL);
1359 ASSERT_TRUE(dc != NULL);
1360 const AudioContentDescription* acd =
1361 static_cast<const AudioContentDescription*>(ac->description);
1362 const VideoContentDescription* vcd =
1363 static_cast<const VideoContentDescription*>(vc->description);
1364 const DataContentDescription* dcd =
1365 static_cast<const DataContentDescription*>(dc->description);
1366 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001367 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001368
1369 const StreamParamsVec& audio_streams = acd->streams();
1370 ASSERT_EQ(2U, audio_streams.size());
1371 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1372 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1373 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1374 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1375 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1376 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1377 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1378
1379 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1380 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1381 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1382
1383 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1384 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1385 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1386
1387 const StreamParamsVec& video_streams = vcd->streams();
1388 ASSERT_EQ(1U, video_streams.size());
1389 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1390 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1391 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1392 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1393
1394 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1395 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1396 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1397
1398 const StreamParamsVec& data_streams = dcd->streams();
1399 ASSERT_EQ(2U, data_streams.size());
1400 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1401 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1402 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1403 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1404 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1405 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1406 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1407
1408 EXPECT_EQ(cricket::kDataMaxBandwidth,
1409 dcd->bandwidth()); // default bandwidth (auto)
1410 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1411 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1412
1413
1414 // Update the offer. Add a new video track that is not synched to the
1415 // other tracks and replace audio track 2 with audio track 3.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001416 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1417 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1418 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1419 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1420 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
kwiberg31022942016-03-11 14:18:21 -08001421 std::unique_ptr<SessionDescription> updated_offer(
1422 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001423
1424 ASSERT_TRUE(updated_offer.get() != NULL);
1425 ac = updated_offer->GetContentByName("audio");
1426 vc = updated_offer->GetContentByName("video");
1427 dc = updated_offer->GetContentByName("data");
1428 ASSERT_TRUE(ac != NULL);
1429 ASSERT_TRUE(vc != NULL);
1430 ASSERT_TRUE(dc != NULL);
1431 const AudioContentDescription* updated_acd =
1432 static_cast<const AudioContentDescription*>(ac->description);
1433 const VideoContentDescription* updated_vcd =
1434 static_cast<const VideoContentDescription*>(vc->description);
1435 const DataContentDescription* updated_dcd =
1436 static_cast<const DataContentDescription*>(dc->description);
1437
1438 EXPECT_EQ(acd->type(), updated_acd->type());
1439 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1440 EXPECT_EQ(vcd->type(), updated_vcd->type());
1441 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1442 EXPECT_EQ(dcd->type(), updated_dcd->type());
1443 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1444 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1445 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1446 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1447 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1448 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1449 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1450
1451 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1452 ASSERT_EQ(2U, updated_audio_streams.size());
1453 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1454 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1455 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1456 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1457 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1458
1459 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1460 ASSERT_EQ(2U, updated_video_streams.size());
1461 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1462 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001463 // All the media streams in one PeerConnection share one RTCP CNAME.
1464 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001465
1466 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1467 ASSERT_EQ(2U, updated_data_streams.size());
1468 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1469 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1470 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1471 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1472 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001473 // The stream correctly got the CNAME from the MediaSessionOptions.
1474 // The Expected RTCP CNAME is the default one as we are using the default
1475 // MediaSessionOptions.
1476 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001477}
1478
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001479// Create an offer with simulcast video stream.
1480TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1481 MediaSessionOptions opts;
1482 const int num_sim_layers = 3;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001483 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
kwiberg31022942016-03-11 14:18:21 -08001484 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001485
1486 ASSERT_TRUE(offer.get() != NULL);
1487 const ContentInfo* vc = offer->GetContentByName("video");
1488 ASSERT_TRUE(vc != NULL);
1489 const VideoContentDescription* vcd =
1490 static_cast<const VideoContentDescription*>(vc->description);
1491
1492 const StreamParamsVec& video_streams = vcd->streams();
1493 ASSERT_EQ(1U, video_streams.size());
1494 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1495 const SsrcGroup* sim_ssrc_group =
1496 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1497 ASSERT_TRUE(sim_ssrc_group != NULL);
1498 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1499}
1500
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001501// Create an audio and video answer to a standard video offer with:
1502// - one video track
1503// - two audio tracks
1504// - two data tracks
1505// and ensure it matches what we expect. Also updates the initial answer by
1506// adding a new video track and removes one of the audio tracks.
1507TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1508 MediaSessionOptions offer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001509 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001510 offer_opts.data_channel_type = cricket::DCT_RTP;
1511 f1_.set_secure(SEC_ENABLED);
1512 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001513 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001514
1515 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001516 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1517 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1518 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001520 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1521 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001522
kwiberg31022942016-03-11 14:18:21 -08001523 std::unique_ptr<SessionDescription> answer(
1524 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001525
1526 ASSERT_TRUE(answer.get() != NULL);
1527 const ContentInfo* ac = answer->GetContentByName("audio");
1528 const ContentInfo* vc = answer->GetContentByName("video");
1529 const ContentInfo* dc = answer->GetContentByName("data");
1530 ASSERT_TRUE(ac != NULL);
1531 ASSERT_TRUE(vc != NULL);
1532 ASSERT_TRUE(dc != NULL);
1533 const AudioContentDescription* acd =
1534 static_cast<const AudioContentDescription*>(ac->description);
1535 const VideoContentDescription* vcd =
1536 static_cast<const VideoContentDescription*>(vc->description);
1537 const DataContentDescription* dcd =
1538 static_cast<const DataContentDescription*>(dc->description);
1539 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1540 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1541 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1542
1543 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1544 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1545
1546 const StreamParamsVec& audio_streams = acd->streams();
1547 ASSERT_EQ(2U, audio_streams.size());
1548 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1549 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1550 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1551 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1552 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1553 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1554 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1555
1556 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1557 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1558
1559 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1560 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1561
1562 const StreamParamsVec& video_streams = vcd->streams();
1563 ASSERT_EQ(1U, video_streams.size());
1564 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1565 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1566 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1567 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1568
1569 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1570 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1571
1572 const StreamParamsVec& data_streams = dcd->streams();
1573 ASSERT_EQ(2U, data_streams.size());
1574 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1575 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1576 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1577 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1578 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1579 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1580 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1581
1582 EXPECT_EQ(cricket::kDataMaxBandwidth,
1583 dcd->bandwidth()); // default bandwidth (auto)
1584 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1585
1586 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001587 // other tracks and remove 1 audio track.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001588 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1589 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1590 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
kwiberg31022942016-03-11 14:18:21 -08001591 std::unique_ptr<SessionDescription> updated_answer(
1592 f2_.CreateAnswer(offer.get(), opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593
1594 ASSERT_TRUE(updated_answer.get() != NULL);
1595 ac = updated_answer->GetContentByName("audio");
1596 vc = updated_answer->GetContentByName("video");
1597 dc = updated_answer->GetContentByName("data");
1598 ASSERT_TRUE(ac != NULL);
1599 ASSERT_TRUE(vc != NULL);
1600 ASSERT_TRUE(dc != NULL);
1601 const AudioContentDescription* updated_acd =
1602 static_cast<const AudioContentDescription*>(ac->description);
1603 const VideoContentDescription* updated_vcd =
1604 static_cast<const VideoContentDescription*>(vc->description);
1605 const DataContentDescription* updated_dcd =
1606 static_cast<const DataContentDescription*>(dc->description);
1607
1608 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1609 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1610 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1611 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1612 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1613 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1614
1615 EXPECT_EQ(acd->type(), updated_acd->type());
1616 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1617 EXPECT_EQ(vcd->type(), updated_vcd->type());
1618 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1619 EXPECT_EQ(dcd->type(), updated_dcd->type());
1620 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1621
1622 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1623 ASSERT_EQ(1U, updated_audio_streams.size());
1624 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1625
1626 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1627 ASSERT_EQ(2U, updated_video_streams.size());
1628 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1629 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001630 // All media streams in one PeerConnection share one CNAME.
1631 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001632
1633 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1634 ASSERT_EQ(1U, updated_data_streams.size());
1635 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1636}
1637
1638
1639// Create an updated offer after creating an answer to the original offer and
1640// verify that the codecs that were part of the original answer are not changed
1641// in the updated offer.
1642TEST_F(MediaSessionDescriptionFactoryTest,
1643 RespondentCreatesOfferAfterCreatingAnswer) {
1644 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001645 opts.recv_audio = true;
1646 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647
kwiberg31022942016-03-11 14:18:21 -08001648 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1649 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 f2_.CreateAnswer(offer.get(), opts, NULL));
1651
1652 const AudioContentDescription* acd =
1653 GetFirstAudioContentDescription(answer.get());
1654 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1655
1656 const VideoContentDescription* vcd =
1657 GetFirstVideoContentDescription(answer.get());
1658 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1659
kwiberg31022942016-03-11 14:18:21 -08001660 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661 f2_.CreateOffer(opts, answer.get()));
1662
1663 // The expected audio codecs are the common audio codecs from the first
1664 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1665 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001666 // TODO(wu): |updated_offer| should not include the codec
1667 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001669 kAudioCodecsAnswer[0],
1670 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001671 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001672 };
1673
1674 // The expected video codecs are the common video codecs from the first
1675 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1676 // preference order.
1677 const VideoCodec kUpdatedVideoCodecOffer[] = {
1678 kVideoCodecsAnswer[0],
1679 kVideoCodecs2[1],
1680 };
1681
1682 const AudioContentDescription* updated_acd =
1683 GetFirstAudioContentDescription(updated_offer.get());
1684 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1685
1686 const VideoContentDescription* updated_vcd =
1687 GetFirstVideoContentDescription(updated_offer.get());
1688 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1689}
1690
1691// Create an updated offer after creating an answer to the original offer and
1692// verify that the codecs that were part of the original answer are not changed
1693// in the updated offer. In this test Rtx is enabled.
1694TEST_F(MediaSessionDescriptionFactoryTest,
1695 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1696 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001697 opts.recv_video = true;
1698 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001699 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001700 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001701 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702 f1_.set_video_codecs(f1_codecs);
1703
1704 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001705 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001706 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707 f2_.set_video_codecs(f2_codecs);
1708
kwiberg31022942016-03-11 14:18:21 -08001709 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001710 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001711 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712 f2_.CreateAnswer(offer.get(), opts, NULL));
1713
1714 const VideoContentDescription* vcd =
1715 GetFirstVideoContentDescription(answer.get());
1716
1717 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001718 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1719 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720
1721 EXPECT_EQ(expected_codecs, vcd->codecs());
1722
deadbeef67cf2c12016-04-13 10:07:16 -07001723 // Now, make sure we get same result (except for the order) if |f2_| creates
1724 // an updated offer even though the default payload types between |f1_| and
1725 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08001726 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 f2_.CreateOffer(opts, answer.get()));
1728 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001729 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1731
1732 const VideoContentDescription* updated_vcd =
1733 GetFirstVideoContentDescription(updated_answer.get());
1734
1735 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1736}
1737
1738// Create an updated offer that adds video after creating an audio only answer
1739// to the original offer. This test verifies that if a video codec and the RTX
1740// codec have the same default payload type as an audio codec that is already in
1741// use, the added codecs payload types are changed.
1742TEST_F(MediaSessionDescriptionFactoryTest,
1743 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1744 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001745 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001746 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 f1_.set_video_codecs(f1_codecs);
1748
1749 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001750 opts.recv_audio = true;
1751 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001752
kwiberg31022942016-03-11 14:18:21 -08001753 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1754 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001755 f2_.CreateAnswer(offer.get(), opts, NULL));
1756
1757 const AudioContentDescription* acd =
1758 GetFirstAudioContentDescription(answer.get());
1759 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1760
1761 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1762 // reference be the same as an audio codec that was negotiated in the
1763 // first offer/answer exchange.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001764 opts.recv_audio = true;
1765 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001766
1767 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1768 int used_pl_type = acd->codecs()[0].id;
1769 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001770 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001771 f2_.set_video_codecs(f2_codecs);
1772
kwiberg31022942016-03-11 14:18:21 -08001773 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 f2_.CreateOffer(opts, answer.get()));
1775 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001776 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1778
1779 const AudioContentDescription* updated_acd =
1780 GetFirstAudioContentDescription(answer.get());
1781 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1782
1783 const VideoContentDescription* updated_vcd =
1784 GetFirstVideoContentDescription(updated_answer.get());
1785
1786 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001787 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001788 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1789 EXPECT_NE(used_pl_type, new_h264_pl_type);
1790 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001791 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1793 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1794}
1795
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001796// Create an updated offer with RTX after creating an answer to an offer
1797// without RTX, and with different default payload types.
1798// Verify that the added RTX codec references the correct payload type.
1799TEST_F(MediaSessionDescriptionFactoryTest,
1800 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
1801 MediaSessionOptions opts;
1802 opts.recv_video = true;
1803 opts.recv_audio = true;
1804
1805 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1806 // This creates rtx for H264 with the payload type |f2_| uses.
1807 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1808 f2_.set_video_codecs(f2_codecs);
1809
kwiberg31022942016-03-11 14:18:21 -08001810 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001811 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08001812 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001813 f2_.CreateAnswer(offer.get(), opts, nullptr));
1814
1815 const VideoContentDescription* vcd =
1816 GetFirstVideoContentDescription(answer.get());
1817
1818 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1819 EXPECT_EQ(expected_codecs, vcd->codecs());
1820
1821 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
1822 // updated offer, even though the default payload types are different from
1823 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08001824 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001825 f2_.CreateOffer(opts, answer.get()));
1826 ASSERT_TRUE(updated_offer);
1827
1828 const VideoContentDescription* updated_vcd =
1829 GetFirstVideoContentDescription(updated_offer.get());
1830
1831 // New offer should attempt to add H263, and RTX for H264.
1832 expected_codecs.push_back(kVideoCodecs2[1]);
1833 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
1834 &expected_codecs);
1835 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1836}
1837
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001838// Test that RTX is ignored when there is no associated payload type parameter.
1839TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1840 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001841 opts.recv_video = true;
1842 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001844 // This creates RTX without associated payload type parameter.
deadbeef67cf2c12016-04-13 10:07:16 -07001845 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName, 0, 0, 0), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001846 f1_.set_video_codecs(f1_codecs);
1847
1848 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001849 // This creates RTX for H264 with the payload type |f2_| uses.
1850 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001851 f2_.set_video_codecs(f2_codecs);
1852
kwiberg31022942016-03-11 14:18:21 -08001853 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001854 ASSERT_TRUE(offer.get() != NULL);
1855 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1856 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1857 // is possible to test that that RTX is dropped when
1858 // kCodecParamAssociatedPayloadType is missing in the offer.
1859 VideoContentDescription* desc =
1860 static_cast<cricket::VideoContentDescription*>(
1861 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1862 ASSERT_TRUE(desc != NULL);
1863 std::vector<VideoCodec> codecs = desc->codecs();
1864 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1865 iter != codecs.end(); ++iter) {
1866 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1867 iter->params.clear();
1868 }
1869 }
1870 desc->set_codecs(codecs);
1871
kwiberg31022942016-03-11 14:18:21 -08001872 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001873 f2_.CreateAnswer(offer.get(), opts, NULL));
1874
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001875 std::vector<std::string> codec_names =
1876 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1877 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1878 cricket::kRtxCodecName));
1879}
1880
1881// Test that RTX will be filtered out in the answer if its associated payload
1882// type doesn't match the local value.
1883TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1884 MediaSessionOptions opts;
1885 opts.recv_video = true;
1886 opts.recv_audio = false;
1887 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1888 // This creates RTX for H264 in sender.
1889 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1890 f1_.set_video_codecs(f1_codecs);
1891
1892 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1893 // This creates RTX for H263 in receiver.
1894 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1895 f2_.set_video_codecs(f2_codecs);
1896
kwiberg31022942016-03-11 14:18:21 -08001897 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001898 ASSERT_TRUE(offer.get() != NULL);
1899 // Associated payload type doesn't match, therefore, RTX codec is removed in
1900 // the answer.
kwiberg31022942016-03-11 14:18:21 -08001901 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001902 f2_.CreateAnswer(offer.get(), opts, NULL));
1903
1904 std::vector<std::string> codec_names =
1905 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1906 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1907 cricket::kRtxCodecName));
1908}
1909
1910// Test that when multiple RTX codecs are offered, only the matched RTX codec
1911// is added in the answer, and the unsupported RTX codec is filtered out.
1912TEST_F(MediaSessionDescriptionFactoryTest,
1913 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1914 MediaSessionOptions opts;
1915 opts.recv_video = true;
1916 opts.recv_audio = false;
1917 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1918 // This creates RTX for H264-SVC in sender.
1919 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1920 f1_.set_video_codecs(f1_codecs);
1921
1922 // This creates RTX for H264 in sender.
1923 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1924 f1_.set_video_codecs(f1_codecs);
1925
1926 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1927 // This creates RTX for H264 in receiver.
1928 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1929 f2_.set_video_codecs(f2_codecs);
1930
1931 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1932 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08001933 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001934 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001935 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001936 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937 const VideoContentDescription* vcd =
1938 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001939 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1940 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1941 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001943 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944}
1945
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001946// Test that after one RTX codec has been negotiated, a new offer can attempt
1947// to add another.
1948TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
1949 MediaSessionOptions opts;
1950 opts.recv_video = true;
1951 opts.recv_audio = false;
1952 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1953 // This creates RTX for H264 for the offerer.
1954 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1955 f1_.set_video_codecs(f1_codecs);
1956
kwiberg31022942016-03-11 14:18:21 -08001957 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001958 ASSERT_TRUE(offer);
1959 const VideoContentDescription* vcd =
1960 GetFirstVideoContentDescription(offer.get());
1961
1962 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
1963 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1964 &expected_codecs);
1965 EXPECT_EQ(expected_codecs, vcd->codecs());
1966
1967 // Now, attempt to add RTX for H264-SVC.
1968 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1969 f1_.set_video_codecs(f1_codecs);
1970
kwiberg31022942016-03-11 14:18:21 -08001971 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001972 f1_.CreateOffer(opts, offer.get()));
1973 ASSERT_TRUE(updated_offer);
1974 vcd = GetFirstVideoContentDescription(updated_offer.get());
1975
1976 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
1977 &expected_codecs);
1978 EXPECT_EQ(expected_codecs, vcd->codecs());
1979}
1980
Noah Richards2e7a0982015-05-18 14:02:54 -07001981// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1982// generated for each simulcast ssrc and correctly grouped.
1983TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1984 MediaSessionOptions opts;
1985 opts.recv_video = true;
1986 opts.recv_audio = false;
1987
1988 // Add simulcast streams.
1989 opts.AddSendVideoStream("stream1", "stream1label", 3);
1990
1991 // Use a single real codec, and then add RTX for it.
1992 std::vector<VideoCodec> f1_codecs;
deadbeef67cf2c12016-04-13 10:07:16 -07001993 f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30));
Noah Richards2e7a0982015-05-18 14:02:54 -07001994 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1995 f1_.set_video_codecs(f1_codecs);
1996
1997 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1998 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08001999 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002000 ASSERT_TRUE(offer.get() != NULL);
2001 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2002 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2003 ASSERT_TRUE(desc != NULL);
2004 EXPECT_TRUE(desc->multistream());
2005 const StreamParamsVec& streams = desc->streams();
2006 // Single stream.
2007 ASSERT_EQ(1u, streams.size());
2008 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2009 EXPECT_EQ(6u, streams[0].ssrcs.size());
2010 // And should have a SIM group for the simulcast.
2011 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2012 // And a FID group for RTX.
2013 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002014 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002015 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2016 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002017 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002018 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2019 EXPECT_EQ(3u, fid_ssrcs.size());
2020}
2021
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002022// Create an updated offer after creating an answer to the original offer and
2023// verify that the RTP header extensions that were part of the original answer
2024// are not changed in the updated offer.
2025TEST_F(MediaSessionDescriptionFactoryTest,
2026 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2027 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002028 opts.recv_audio = true;
2029 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030
2031 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2032 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2033 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2034 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2035
kwiberg31022942016-03-11 14:18:21 -08002036 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2037 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038 f2_.CreateAnswer(offer.get(), opts, NULL));
2039
2040 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2041 GetFirstAudioContentDescription(
2042 answer.get())->rtp_header_extensions());
2043 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2044 GetFirstVideoContentDescription(
2045 answer.get())->rtp_header_extensions());
2046
kwiberg31022942016-03-11 14:18:21 -08002047 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002048 f2_.CreateOffer(opts, answer.get()));
2049
2050 // The expected RTP header extensions in the new offer are the resulting
2051 // extensions from the first offer/answer exchange plus the extensions only
2052 // |f2_| offer.
2053 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002054 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002055 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2056 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2057 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058 };
2059
2060 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002061 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002062 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2063 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2064 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 };
2066
2067 const AudioContentDescription* updated_acd =
2068 GetFirstAudioContentDescription(updated_offer.get());
2069 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2070 updated_acd->rtp_header_extensions());
2071
2072 const VideoContentDescription* updated_vcd =
2073 GetFirstVideoContentDescription(updated_offer.get());
2074 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2075 updated_vcd->rtp_header_extensions());
2076}
2077
deadbeefa5b273a2015-08-20 17:30:13 -07002078// Verify that if the same RTP extension URI is used for audio and video, the
2079// same ID is used. Also verify that the ID isn't changed when creating an
2080// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002081TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002082 MediaSessionOptions opts;
2083 opts.recv_audio = true;
2084 opts.recv_video = true;
2085
2086 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2087 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2088
kwiberg31022942016-03-11 14:18:21 -08002089 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002090
2091 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2092 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002093 const RtpExtension kExpectedVideoRtpExtension[] = {
2094 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002095 };
2096
2097 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2098 GetFirstAudioContentDescription(
2099 offer.get())->rtp_header_extensions());
2100 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2101 GetFirstVideoContentDescription(
2102 offer.get())->rtp_header_extensions());
2103
2104 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002105 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002106 f1_.CreateOffer(opts, offer.get()));
2107
2108 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2109 GetFirstAudioContentDescription(
2110 updated_offer.get())->rtp_header_extensions());
2111 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2112 GetFirstVideoContentDescription(
2113 updated_offer.get())->rtp_header_extensions());
2114}
2115
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116TEST(MediaSessionDescription, CopySessionDescription) {
2117 SessionDescription source;
2118 cricket::ContentGroup group(cricket::CN_AUDIO);
2119 source.AddGroup(group);
2120 AudioContentDescription* acd(new AudioContentDescription());
2121 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2122 acd->AddLegacyStream(1);
2123 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2124 VideoContentDescription* vcd(new VideoContentDescription());
2125 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2126 vcd->AddLegacyStream(2);
2127 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2128
kwiberg31022942016-03-11 14:18:21 -08002129 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130 ASSERT_TRUE(copy.get() != NULL);
2131 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2132 const ContentInfo* ac = copy->GetContentByName("audio");
2133 const ContentInfo* vc = copy->GetContentByName("video");
2134 ASSERT_TRUE(ac != NULL);
2135 ASSERT_TRUE(vc != NULL);
2136 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2137 const AudioContentDescription* acd_copy =
2138 static_cast<const AudioContentDescription*>(ac->description);
2139 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2140 EXPECT_EQ(1u, acd->first_ssrc());
2141
2142 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2143 const VideoContentDescription* vcd_copy =
2144 static_cast<const VideoContentDescription*>(vc->description);
2145 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2146 EXPECT_EQ(2u, vcd->first_ssrc());
2147}
2148
2149// The below TestTransportInfoXXX tests create different offers/answers, and
2150// ensure the TransportInfo in the SessionDescription matches what we expect.
2151TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2152 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002153 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002154 TestTransportInfo(true, options, false);
2155}
2156
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002157TEST_F(MediaSessionDescriptionFactoryTest,
2158 TestTransportInfoOfferIceRenomination) {
2159 MediaSessionOptions options;
2160 options.enable_ice_renomination = true;
2161 TestTransportInfo(true, options, false);
2162}
2163
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2165 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002166 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002167 TestTransportInfo(true, options, true);
2168}
2169
2170TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2171 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002172 options.recv_audio = true;
2173 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 options.data_channel_type = cricket::DCT_RTP;
2175 TestTransportInfo(true, options, false);
2176}
2177
2178TEST_F(MediaSessionDescriptionFactoryTest,
2179 TestTransportInfoOfferMultimediaCurrent) {
2180 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002181 options.recv_audio = true;
2182 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183 options.data_channel_type = cricket::DCT_RTP;
2184 TestTransportInfo(true, options, true);
2185}
2186
2187TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2188 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002189 options.recv_audio = true;
2190 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002191 options.data_channel_type = cricket::DCT_RTP;
2192 options.bundle_enabled = true;
2193 TestTransportInfo(true, options, false);
2194}
2195
2196TEST_F(MediaSessionDescriptionFactoryTest,
2197 TestTransportInfoOfferBundleCurrent) {
2198 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002199 options.recv_audio = true;
2200 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002201 options.data_channel_type = cricket::DCT_RTP;
2202 options.bundle_enabled = true;
2203 TestTransportInfo(true, options, true);
2204}
2205
2206TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2207 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002208 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209 TestTransportInfo(false, options, false);
2210}
2211
2212TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002213 TestTransportInfoAnswerIceRenomination) {
2214 MediaSessionOptions options;
2215 options.enable_ice_renomination = true;
2216 TestTransportInfo(false, options, false);
2217}
2218
2219TEST_F(MediaSessionDescriptionFactoryTest,
2220 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002221 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002222 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002223 TestTransportInfo(false, options, true);
2224}
2225
2226TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2227 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002228 options.recv_audio = true;
2229 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230 options.data_channel_type = cricket::DCT_RTP;
2231 TestTransportInfo(false, options, false);
2232}
2233
2234TEST_F(MediaSessionDescriptionFactoryTest,
2235 TestTransportInfoAnswerMultimediaCurrent) {
2236 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002237 options.recv_audio = true;
2238 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 options.data_channel_type = cricket::DCT_RTP;
2240 TestTransportInfo(false, options, true);
2241}
2242
2243TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2244 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002245 options.recv_audio = true;
2246 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002247 options.data_channel_type = cricket::DCT_RTP;
2248 options.bundle_enabled = true;
2249 TestTransportInfo(false, options, false);
2250}
2251
2252TEST_F(MediaSessionDescriptionFactoryTest,
2253 TestTransportInfoAnswerBundleCurrent) {
2254 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002255 options.recv_audio = true;
2256 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257 options.data_channel_type = cricket::DCT_RTP;
2258 options.bundle_enabled = true;
2259 TestTransportInfo(false, options, true);
2260}
2261
2262// Create an offer with bundle enabled and verify the crypto parameters are
2263// the common set of the available cryptos.
2264TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2265 TestCryptoWithBundle(true);
2266}
2267
2268// Create an answer with bundle enabled and verify the crypto parameters are
2269// the common set of the available cryptos.
2270TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2271 TestCryptoWithBundle(false);
2272}
2273
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002274// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2275// DTLS is not enabled locally.
2276TEST_F(MediaSessionDescriptionFactoryTest,
2277 TestOfferDtlsSavpfWithoutDtlsFailed) {
2278 f1_.set_secure(SEC_ENABLED);
2279 f2_.set_secure(SEC_ENABLED);
2280 tdf1_.set_secure(SEC_DISABLED);
2281 tdf2_.set_secure(SEC_DISABLED);
2282
kwiberg31022942016-03-11 14:18:21 -08002283 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002284 f1_.CreateOffer(MediaSessionOptions(), NULL));
2285 ASSERT_TRUE(offer.get() != NULL);
2286 ContentInfo* offer_content = offer->GetContentByName("audio");
2287 ASSERT_TRUE(offer_content != NULL);
2288 AudioContentDescription* offer_audio_desc =
2289 static_cast<AudioContentDescription*>(offer_content->description);
2290 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2291
kwiberg31022942016-03-11 14:18:21 -08002292 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002293 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2294 ASSERT_TRUE(answer != NULL);
2295 ContentInfo* answer_content = answer->GetContentByName("audio");
2296 ASSERT_TRUE(answer_content != NULL);
2297
2298 ASSERT_TRUE(answer_content->rejected);
2299}
2300
2301// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2302// UDP/TLS/RTP/SAVPF.
2303TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2304 f1_.set_secure(SEC_ENABLED);
2305 f2_.set_secure(SEC_ENABLED);
2306 tdf1_.set_secure(SEC_ENABLED);
2307 tdf2_.set_secure(SEC_ENABLED);
2308
kwiberg31022942016-03-11 14:18:21 -08002309 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002310 f1_.CreateOffer(MediaSessionOptions(), NULL));
2311 ASSERT_TRUE(offer.get() != NULL);
2312 ContentInfo* offer_content = offer->GetContentByName("audio");
2313 ASSERT_TRUE(offer_content != NULL);
2314 AudioContentDescription* offer_audio_desc =
2315 static_cast<AudioContentDescription*>(offer_content->description);
2316 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2317
kwiberg31022942016-03-11 14:18:21 -08002318 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002319 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2320 ASSERT_TRUE(answer != NULL);
2321
2322 const ContentInfo* answer_content = answer->GetContentByName("audio");
2323 ASSERT_TRUE(answer_content != NULL);
2324 ASSERT_FALSE(answer_content->rejected);
2325
2326 const AudioContentDescription* answer_audio_desc =
2327 static_cast<const AudioContentDescription*>(answer_content->description);
2328 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2329 answer_audio_desc->protocol());
2330}
2331
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002332// Test that we include both SDES and DTLS in the offer, but only include SDES
2333// in the answer if DTLS isn't negotiated.
2334TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2335 f1_.set_secure(SEC_ENABLED);
2336 f2_.set_secure(SEC_ENABLED);
2337 tdf1_.set_secure(SEC_ENABLED);
2338 tdf2_.set_secure(SEC_DISABLED);
2339 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002340 options.recv_audio = true;
2341 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002342 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343 const cricket::MediaContentDescription* audio_media_desc;
2344 const cricket::MediaContentDescription* video_media_desc;
2345 const cricket::TransportDescription* audio_trans_desc;
2346 const cricket::TransportDescription* video_trans_desc;
2347
2348 // Generate an offer with SDES and DTLS support.
2349 offer.reset(f1_.CreateOffer(options, NULL));
2350 ASSERT_TRUE(offer.get() != NULL);
2351
2352 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2353 offer->GetContentDescriptionByName("audio"));
2354 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002355 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002356 offer->GetContentDescriptionByName("video"));
2357 ASSERT_TRUE(video_media_desc != NULL);
2358 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2359 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2360
2361 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2362 ASSERT_TRUE(audio_trans_desc != NULL);
2363 video_trans_desc = offer->GetTransportDescriptionByName("video");
2364 ASSERT_TRUE(video_trans_desc != NULL);
2365 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2366 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2367
2368 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2369 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2370 ASSERT_TRUE(answer.get() != NULL);
2371
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002372 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373 answer->GetContentDescriptionByName("audio"));
2374 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002375 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002376 answer->GetContentDescriptionByName("video"));
2377 ASSERT_TRUE(video_media_desc != NULL);
2378 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2379 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2380
2381 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2382 ASSERT_TRUE(audio_trans_desc != NULL);
2383 video_trans_desc = answer->GetTransportDescriptionByName("video");
2384 ASSERT_TRUE(video_trans_desc != NULL);
2385 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2386 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2387
2388 // Enable DTLS; the answer should now only have DTLS support.
2389 tdf2_.set_secure(SEC_ENABLED);
2390 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2391 ASSERT_TRUE(answer.get() != NULL);
2392
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002393 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002394 answer->GetContentDescriptionByName("audio"));
2395 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002396 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002397 answer->GetContentDescriptionByName("video"));
2398 ASSERT_TRUE(video_media_desc != NULL);
2399 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2400 EXPECT_TRUE(video_media_desc->cryptos().empty());
2401 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2402 audio_media_desc->protocol());
2403 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2404 video_media_desc->protocol());
2405
2406 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2407 ASSERT_TRUE(audio_trans_desc != NULL);
2408 video_trans_desc = answer->GetTransportDescriptionByName("video");
2409 ASSERT_TRUE(video_trans_desc != NULL);
2410 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2411 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002412
2413 // Try creating offer again. DTLS enabled now, crypto's should be empty
2414 // in new offer.
2415 offer.reset(f1_.CreateOffer(options, offer.get()));
2416 ASSERT_TRUE(offer.get() != NULL);
2417 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2418 offer->GetContentDescriptionByName("audio"));
2419 ASSERT_TRUE(audio_media_desc != NULL);
2420 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2421 offer->GetContentDescriptionByName("video"));
2422 ASSERT_TRUE(video_media_desc != NULL);
2423 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2424 EXPECT_TRUE(video_media_desc->cryptos().empty());
2425
2426 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2427 ASSERT_TRUE(audio_trans_desc != NULL);
2428 video_trans_desc = offer->GetTransportDescriptionByName("video");
2429 ASSERT_TRUE(video_trans_desc != NULL);
2430 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2431 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432}
2433
2434// Test that an answer can't be created if cryptos are required but the offer is
2435// unsecure.
2436TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2437 MediaSessionOptions options;
2438 f1_.set_secure(SEC_DISABLED);
2439 tdf1_.set_secure(SEC_DISABLED);
2440 f2_.set_secure(SEC_REQUIRED);
2441 tdf1_.set_secure(SEC_ENABLED);
2442
kwiberg31022942016-03-11 14:18:21 -08002443 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002444 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002445 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446 f2_.CreateAnswer(offer.get(), options, NULL));
2447 EXPECT_TRUE(answer.get() == NULL);
2448}
2449
2450// Test that we accept a DTLS offer without SDES and create an appropriate
2451// answer.
2452TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2453 f1_.set_secure(SEC_DISABLED);
2454 f2_.set_secure(SEC_ENABLED);
2455 tdf1_.set_secure(SEC_ENABLED);
2456 tdf2_.set_secure(SEC_ENABLED);
2457 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002458 options.recv_audio = true;
2459 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460 options.data_channel_type = cricket::DCT_RTP;
2461
kwiberg31022942016-03-11 14:18:21 -08002462 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002463
2464 // Generate an offer with DTLS but without SDES.
2465 offer.reset(f1_.CreateOffer(options, NULL));
2466 ASSERT_TRUE(offer.get() != NULL);
2467
2468 const AudioContentDescription* audio_offer =
2469 GetFirstAudioContentDescription(offer.get());
2470 ASSERT_TRUE(audio_offer->cryptos().empty());
2471 const VideoContentDescription* video_offer =
2472 GetFirstVideoContentDescription(offer.get());
2473 ASSERT_TRUE(video_offer->cryptos().empty());
2474 const DataContentDescription* data_offer =
2475 GetFirstDataContentDescription(offer.get());
2476 ASSERT_TRUE(data_offer->cryptos().empty());
2477
2478 const cricket::TransportDescription* audio_offer_trans_desc =
2479 offer->GetTransportDescriptionByName("audio");
2480 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2481 const cricket::TransportDescription* video_offer_trans_desc =
2482 offer->GetTransportDescriptionByName("video");
2483 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2484 const cricket::TransportDescription* data_offer_trans_desc =
2485 offer->GetTransportDescriptionByName("data");
2486 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2487
2488 // Generate an answer with DTLS.
2489 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2490 ASSERT_TRUE(answer.get() != NULL);
2491
2492 const cricket::TransportDescription* audio_answer_trans_desc =
2493 answer->GetTransportDescriptionByName("audio");
2494 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2495 const cricket::TransportDescription* video_answer_trans_desc =
2496 answer->GetTransportDescriptionByName("video");
2497 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2498 const cricket::TransportDescription* data_answer_trans_desc =
2499 answer->GetTransportDescriptionByName("data");
2500 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2501}
2502
2503// Verifies if vad_enabled option is set to false, CN codecs are not present in
2504// offer or answer.
2505TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2506 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002507 options.recv_audio = true;
2508 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002509 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002510 ASSERT_TRUE(offer.get() != NULL);
2511 const ContentInfo* audio_content = offer->GetContentByName("audio");
2512 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2513
2514 options.vad_enabled = false;
2515 offer.reset(f1_.CreateOffer(options, NULL));
2516 ASSERT_TRUE(offer.get() != NULL);
2517 audio_content = offer->GetContentByName("audio");
2518 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002519 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002520 f1_.CreateAnswer(offer.get(), options, NULL));
2521 ASSERT_TRUE(answer.get() != NULL);
2522 audio_content = answer->GetContentByName("audio");
2523 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2524}
deadbeef44f08192015-12-15 16:20:09 -08002525
2526// Test that the content name ("mid" in SDP) is unchanged when creating a
2527// new offer.
2528TEST_F(MediaSessionDescriptionFactoryTest,
2529 TestContentNameNotChangedInSubsequentOffers) {
2530 MediaSessionOptions opts;
2531 opts.recv_audio = true;
2532 opts.recv_video = true;
2533 opts.data_channel_type = cricket::DCT_SCTP;
2534 // Create offer and modify the default content names.
kwiberg31022942016-03-11 14:18:21 -08002535 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
deadbeef44f08192015-12-15 16:20:09 -08002536 for (ContentInfo& content : offer->contents()) {
2537 content.name.append("_modified");
2538 }
2539
kwiberg31022942016-03-11 14:18:21 -08002540 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002541 f1_.CreateOffer(opts, offer.get()));
2542 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2543 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2544 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2545 ASSERT_TRUE(audio_content != nullptr);
2546 ASSERT_TRUE(video_content != nullptr);
2547 ASSERT_TRUE(data_content != nullptr);
2548 EXPECT_EQ("audio_modified", audio_content->name);
2549 EXPECT_EQ("video_modified", video_content->name);
2550 EXPECT_EQ("data_modified", data_content->name);
2551}
zhihuangcf5b37c2016-05-05 11:44:35 -07002552
2553class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
2554 public:
2555 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07002556 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
2557 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07002558 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
2559 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07002560 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
2561 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07002562 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
2563 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
2564 f1_.set_secure(SEC_ENABLED);
2565 f2_.set_secure(SEC_ENABLED);
2566 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002567 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002568 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002569 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002570 tdf1_.set_secure(SEC_ENABLED);
2571 tdf2_.set_secure(SEC_ENABLED);
2572 }
2573
2574 protected:
2575 MediaSessionDescriptionFactory f1_;
2576 MediaSessionDescriptionFactory f2_;
2577 TransportDescriptionFactory tdf1_;
2578 TransportDescriptionFactory tdf2_;
2579};
2580
2581TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
2582 MediaSessionOptions opts;
2583 opts.recv_video = true;
2584 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2585 ASSERT_TRUE(offer.get() != nullptr);
2586 // Set the protocol for all the contents.
2587 for (auto content : offer.get()->contents()) {
2588 static_cast<MediaContentDescription*>(content.description)
2589 ->set_protocol(GetParam());
2590 }
2591 std::unique_ptr<SessionDescription> answer(
2592 f2_.CreateAnswer(offer.get(), opts, nullptr));
2593 const ContentInfo* ac = answer->GetContentByName("audio");
2594 const ContentInfo* vc = answer->GetContentByName("video");
2595 ASSERT_TRUE(ac != nullptr);
2596 ASSERT_TRUE(vc != nullptr);
2597 EXPECT_FALSE(ac->rejected); // the offer is accepted
2598 EXPECT_FALSE(vc->rejected);
2599 const AudioContentDescription* acd =
2600 static_cast<const AudioContentDescription*>(ac->description);
2601 const VideoContentDescription* vcd =
2602 static_cast<const VideoContentDescription*>(vc->description);
2603 EXPECT_EQ(GetParam(), acd->protocol());
2604 EXPECT_EQ(GetParam(), vcd->protocol());
2605}
2606
2607INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
2608 MediaProtocolTest,
2609 ::testing::ValuesIn(kMediaProtocols));
2610INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
2611 MediaProtocolTest,
2612 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07002613
2614TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
2615 TransportDescriptionFactory tdf;
2616 MediaSessionDescriptionFactory sf(&tdf);
2617 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2618 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2619
2620 // The merged list of codecs should contain any send codecs that are also
2621 // nominally in the recieve codecs list. Payload types should be picked from
2622 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
2623 // (set to 1). This equals what happens when the send codecs are used in an
2624 // offer and the receive codecs are used in the following answer.
2625 const std::vector<AudioCodec> sendrecv_codecs =
2626 MAKE_VECTOR(kAudioCodecsAnswer);
2627 const std::vector<AudioCodec> no_codecs;
2628
2629 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
2630 << "Please don't change shared test data!";
2631 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
2632 << "Please don't change shared test data!";
2633 // Alter iLBC send codec to have zero channels, to test that that is handled
2634 // properly.
2635 send_codecs[1].channels = 0;
2636
2637 // Alther iLBC receive codec to be lowercase, to test that case conversions
2638 // are handled properly.
2639 recv_codecs[2].name = "ilbc";
2640
2641 // Test proper merge
2642 sf.set_audio_codecs(send_codecs, recv_codecs);
2643 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2644 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002645 EXPECT_TRUE(sf.audio_sendrecv_codecs() == sendrecv_codecs);
ossu075af922016-06-14 03:29:38 -07002646
2647 // Test empty send codecs list
2648 sf.set_audio_codecs(no_codecs, recv_codecs);
2649 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2650 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002651 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002652
2653 // Test empty recv codecs list
2654 sf.set_audio_codecs(send_codecs, no_codecs);
2655 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2656 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002657 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002658
2659 // Test all empty codec lists
2660 sf.set_audio_codecs(no_codecs, no_codecs);
2661 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2662 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002663 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002664}
2665
2666namespace {
2667void TestAudioCodecsOffer(MediaContentDirection direction,
2668 bool add_legacy_stream) {
2669 TransportDescriptionFactory tdf;
2670 MediaSessionDescriptionFactory sf(&tdf);
2671 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2672 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2673 const std::vector<AudioCodec> sendrecv_codecs =
2674 MAKE_VECTOR(kAudioCodecsAnswer);
2675 sf.set_audio_codecs(send_codecs, recv_codecs);
2676 sf.set_add_legacy_streams(add_legacy_stream);
2677
2678 MediaSessionOptions opts;
2679 opts.recv_audio = (direction == cricket::MD_RECVONLY ||
2680 direction == cricket::MD_SENDRECV);
2681 opts.recv_video = false;
2682 if (direction == cricket::MD_SENDONLY || direction == cricket::MD_SENDRECV)
2683 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2684
2685 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
2686 ASSERT_TRUE(offer.get() != NULL);
2687 const ContentInfo* ac = offer->GetContentByName("audio");
2688
2689 // If the factory didn't add any audio content to the offer, we cannot check
2690 // that the codecs put in are right. This happens when we neither want to send
2691 // nor receive audio. The checks are still in place if at some point we'd
2692 // instead create an inactive stream.
2693 if (ac) {
2694 AudioContentDescription* acd =
2695 static_cast<AudioContentDescription*>(ac->description);
2696 // sendrecv and inactive should both present lists as if the channel was to
2697 // be used for sending and receiving. Inactive essentially means it might
2698 // eventually be used anything, but we don't know more at this moment.
2699 if (acd->direction() == cricket::MD_SENDONLY) {
2700 EXPECT_TRUE(acd->codecs() == send_codecs);
2701 } else if (acd->direction() == cricket::MD_RECVONLY) {
2702 EXPECT_TRUE(acd->codecs() == recv_codecs);
2703 } else {
2704 EXPECT_TRUE(acd->codecs() == sendrecv_codecs);
2705 }
2706 }
2707}
2708
2709static const AudioCodec kOfferAnswerCodecs[] = {
2710 AudioCodec(0, "codec0", 16000, -1, 1),
2711 AudioCodec(1, "codec1", 8000, 13300, 1),
2712 AudioCodec(2, "codec2", 8000, 64000, 1),
2713 AudioCodec(3, "codec3", 8000, 64000, 1),
2714 AudioCodec(4, "codec4", 8000, 0, 2),
2715 AudioCodec(5, "codec5", 32000, 0, 1),
2716 AudioCodec(6, "codec6", 48000, 0, 1)
2717};
2718
2719
2720/* The codecs groups below are chosen as per the matrix below. The objective is
2721 * to have different sets of codecs in the inputs, to get unique sets of codecs
2722 * after negotiation, depending on offer and answer communication directions.
2723 * One-way directions in the offer should either result in the opposite
2724 * direction in the answer, or an inactive answer. Regardless, the choice of
2725 * codecs should be as if the answer contained the opposite direction.
2726 * Inactive offers should be treated as sendrecv/sendrecv.
2727 *
2728 * | Offer | Answer | Result
2729 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
2730 * 0 | x - - | - x - | x - - - -
2731 * 1 | x x x | - x - | x - - x -
2732 * 2 | - x - | x - - | - x - - -
2733 * 3 | x x x | x - - | - x x - -
2734 * 4 | - x - | x x x | - x - - -
2735 * 5 | x - - | x x x | x - - - -
2736 * 6 | x x x | x x x | x x x x x
2737 */
2738// Codecs used by offerer in the AudioCodecsAnswerTest
2739static const int kOfferSendCodecs[] = { 0, 1, 3, 5, 6 };
2740static const int kOfferRecvCodecs[] = { 1, 2, 3, 4, 6 };
2741// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
2742// jumbled to catch the answer not following the order in the offer.
2743static const int kAnswerSendCodecs[] = { 6, 5, 2, 3, 4 };
2744static const int kAnswerRecvCodecs[] = { 6, 5, 4, 1, 0 };
2745// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
2746static const int kResultSend_RecvCodecs[] = { 0, 1, 5, 6 };
2747static const int kResultRecv_SendCodecs[] = { 2, 3, 4, 6 };
2748static const int kResultSendrecv_SendCodecs[] = { 3, 6 };
2749static const int kResultSendrecv_RecvCodecs[] = { 1, 6 };
2750static const int kResultSendrecv_SendrecvCodecs[] = { 6 };
2751
2752template <typename T, int IDXS>
2753std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
2754 std::vector<T> out;
2755 out.reserve(IDXS);
2756 for (int idx : indices)
2757 out.push_back(array[idx]);
2758
2759 return out;
2760}
2761
2762void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
2763 MediaContentDirection answer_direction,
2764 bool add_legacy_stream) {
2765 TransportDescriptionFactory offer_tdf;
2766 TransportDescriptionFactory answer_tdf;
2767 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
2768 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
2769 offer_factory.set_audio_codecs(
2770 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
2771 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
2772 answer_factory.set_audio_codecs(
2773 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
2774 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
2775
2776 // Never add a legacy stream to offer - we want to control the offer
2777 // parameters exactly.
2778 offer_factory.set_add_legacy_streams(false);
2779 answer_factory.set_add_legacy_streams(add_legacy_stream);
2780 MediaSessionOptions offer_opts;
2781 offer_opts.recv_audio = (offer_direction == cricket::MD_RECVONLY ||
2782 offer_direction == cricket::MD_SENDRECV);
2783 offer_opts.recv_video = false;
2784 if (offer_direction == cricket::MD_SENDONLY ||
2785 offer_direction == cricket::MD_SENDRECV) {
2786 offer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2787 }
2788
2789 std::unique_ptr<SessionDescription> offer(
2790 offer_factory.CreateOffer(offer_opts, NULL));
2791 ASSERT_TRUE(offer.get() != NULL);
2792
2793 MediaSessionOptions answer_opts;
2794 answer_opts.recv_audio = (answer_direction == cricket::MD_RECVONLY ||
2795 answer_direction == cricket::MD_SENDRECV);
2796 answer_opts.recv_video = false;
2797 if (answer_direction == cricket::MD_SENDONLY ||
2798 answer_direction == cricket::MD_SENDRECV) {
2799 answer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2800 }
2801 std::unique_ptr<SessionDescription> answer(
2802 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
2803 const ContentInfo* ac = answer->GetContentByName("audio");
2804
2805 // If the factory didn't add any audio content to the answer, we cannot check
2806 // that the codecs put in are right. This happens when we neither want to send
2807 // nor receive audio. The checks are still in place if at some point we'd
2808 // instead create an inactive stream.
2809 if (ac) {
2810 const AudioContentDescription* acd =
2811 static_cast<const AudioContentDescription*>(ac->description);
2812 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2813
2814
2815 std::vector<AudioCodec> target_codecs;
2816 // For offers with sendrecv or inactive, we should never reply with more
2817 // codecs than offered, with these codec sets.
2818 switch (offer_direction) {
2819 case cricket::MD_INACTIVE:
2820 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2821 kResultSendrecv_SendrecvCodecs);
2822 break;
2823 case cricket::MD_SENDONLY:
2824 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2825 kResultSend_RecvCodecs);
2826 break;
2827 case cricket::MD_RECVONLY:
2828 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2829 kResultRecv_SendCodecs);
2830 break;
2831 case cricket::MD_SENDRECV:
2832 if (acd->direction() == cricket::MD_SENDONLY) {
2833 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2834 kResultSendrecv_SendCodecs);
2835 } else if (acd->direction() == cricket::MD_RECVONLY) {
2836 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2837 kResultSendrecv_RecvCodecs);
2838 } else {
2839 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2840 kResultSendrecv_SendrecvCodecs);
2841 }
2842 break;
2843 }
2844
2845 auto format_codecs = [] (const std::vector<AudioCodec>& codecs) {
2846 std::stringstream os;
2847 bool first = true;
2848 os << "{";
2849 for (const auto& c : codecs) {
2850 os << (first ? " " : ", ") << c.id;
2851 first = false;
2852 }
2853 os << " }";
2854 return os.str();
2855 };
2856
2857 EXPECT_TRUE(acd->codecs() == target_codecs)
2858 << "Expected: " << format_codecs(target_codecs)
2859 << ", got: " << format_codecs(acd->codecs())
2860 << "; Offered: " << MediaContentDirectionToString(offer_direction)
2861 << ", answerer wants: "
2862 << MediaContentDirectionToString(answer_direction)
2863 << "; got: " << MediaContentDirectionToString(acd->direction());
2864 } else {
2865 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
2866 << "Only inactive offers are allowed to not generate any audio content";
2867 }
2868}
2869}
2870
2871class AudioCodecsOfferTest
2872 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2873 bool>> {
2874};
2875
2876TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
2877 TestAudioCodecsOffer(std::tr1::get<0>(GetParam()),
2878 std::tr1::get<1>(GetParam()));
2879}
2880
2881INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2882 AudioCodecsOfferTest,
2883 ::testing::Combine(
2884 ::testing::Values(cricket::MD_SENDONLY,
2885 cricket::MD_RECVONLY,
2886 cricket::MD_SENDRECV,
2887 cricket::MD_INACTIVE),
2888 ::testing::Bool()));
2889
2890class AudioCodecsAnswerTest
2891 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2892 MediaContentDirection,
2893 bool>> {
2894};
2895
2896TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
2897 TestAudioCodecsAnswer(std::tr1::get<0>(GetParam()),
2898 std::tr1::get<1>(GetParam()),
2899 std::tr1::get<2>(GetParam()));
2900}
2901
2902INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2903 AudioCodecsAnswerTest,
2904 ::testing::Combine(
2905 ::testing::Values(cricket::MD_SENDONLY,
2906 cricket::MD_RECVONLY,
2907 cricket::MD_SENDRECV,
2908 cricket::MD_INACTIVE),
2909 ::testing::Values(cricket::MD_SENDONLY,
2910 cricket::MD_RECVONLY,
2911 cricket::MD_SENDRECV,
2912 cricket::MD_INACTIVE),
2913 ::testing::Bool()));