blob: f23e070797bbdcd39fd9c2e60cdf94188a425648 [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
perkj26752742016-10-24 01:21:16 -070099static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
100 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101
perkj26752742016-10-24 01:21:16 -0700102static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
103 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104
perkj26752742016-10-24 01:21:16 -0700105static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
deadbeef67cf2c12016-04-13 10:07:16 -0700107static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
108 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
deadbeef67cf2c12016-04-13 10:07:16 -0700110static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
111 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
deadbeef67cf2c12016-04-13 10:07:16 -0700113static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
114 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115
isheriff6f8d6862016-05-26 11:24:55 -0700116static const RtpExtension kAudioRtpExtension1[] = {
117 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
118 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119};
120
isheriff6f8d6862016-05-26 11:24:55 -0700121static const RtpExtension kAudioRtpExtension2[] = {
122 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
123 RtpExtension("http://google.com/testing/audio_something_else", 8),
124 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125};
126
isheriff6f8d6862016-05-26 11:24:55 -0700127static const RtpExtension kAudioRtpExtension3[] = {
128 RtpExtension("http://google.com/testing/audio_something", 2),
129 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700130};
131
isheriff6f8d6862016-05-26 11:24:55 -0700132static const RtpExtension kAudioRtpExtensionAnswer[] = {
133 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134};
135
isheriff6f8d6862016-05-26 11:24:55 -0700136static const RtpExtension kVideoRtpExtension1[] = {
137 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
138 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139};
140
isheriff6f8d6862016-05-26 11:24:55 -0700141static const RtpExtension kVideoRtpExtension2[] = {
142 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
143 RtpExtension("http://google.com/testing/video_something_else", 14),
144 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145};
146
isheriff6f8d6862016-05-26 11:24:55 -0700147static const RtpExtension kVideoRtpExtension3[] = {
148 RtpExtension("http://google.com/testing/video_something", 4),
149 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700150};
151
isheriff6f8d6862016-05-26 11:24:55 -0700152static const RtpExtension kVideoRtpExtensionAnswer[] = {
153 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154};
155
Peter Boström0c4e06b2015-10-07 12:23:21 +0200156static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
157static const uint32_t kSimSsrc[] = {10, 20, 30};
158static const uint32_t kFec1Ssrc[] = {10, 11};
159static const uint32_t kFec2Ssrc[] = {20, 21};
160static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161
162static const char kMediaStream1[] = "stream_1";
163static const char kMediaStream2[] = "stream_2";
164static const char kVideoTrack1[] = "video_1";
165static const char kVideoTrack2[] = "video_2";
166static const char kAudioTrack1[] = "audio_1";
167static const char kAudioTrack2[] = "audio_2";
168static const char kAudioTrack3[] = "audio_3";
169static const char kDataTrack1[] = "data_1";
170static const char kDataTrack2[] = "data_2";
171static const char kDataTrack3[] = "data_3";
172
zhihuangcf5b37c2016-05-05 11:44:35 -0700173static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
174 "RTP/SAVPF"};
175static const char* kMediaProtocolsDtls[] = {
176 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
177 "UDP/TLS/RTP/SAVP"};
178
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000179static bool IsMediaContentOfType(const ContentInfo* content,
180 MediaType media_type) {
181 const MediaContentDescription* mdesc =
182 static_cast<const MediaContentDescription*>(content->description);
183 return mdesc && mdesc->type() == media_type;
184}
185
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000186static cricket::MediaContentDirection
187GetMediaDirection(const ContentInfo* content) {
188 cricket::MediaContentDescription* desc =
189 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
190 return desc->direction();
191}
192
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000193static void AddRtxCodec(const VideoCodec& rtx_codec,
194 std::vector<VideoCodec>* codecs) {
195 VideoCodec rtx;
196 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
197 codecs->push_back(rtx_codec);
198}
199
200template <class T>
201static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
202 std::vector<std::string> codec_names;
203 for (const auto& codec : codecs) {
204 codec_names.push_back(codec.name);
205 }
206 return codec_names;
207}
208
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209class MediaSessionDescriptionFactoryTest : public testing::Test {
210 public:
211 MediaSessionDescriptionFactoryTest()
Henrik Boström3a14bf32015-08-31 09:27:58 +0200212 : f1_(&tdf1_),
213 f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700214 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
215 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
217 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700218 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
219 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
221 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200222 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700223 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200224 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700225 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226 }
227
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000228 // Create a video StreamParamsVec object with:
229 // - one video stream with 3 simulcast streams and FEC,
230 StreamParamsVec CreateComplexVideoStreamParamsVec() {
231 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
232 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
233 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
234 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
235
236 std::vector<SsrcGroup> ssrc_groups;
237 ssrc_groups.push_back(sim_group);
238 ssrc_groups.push_back(fec_group1);
239 ssrc_groups.push_back(fec_group2);
240 ssrc_groups.push_back(fec_group3);
241
242 StreamParams simulcast_params;
243 simulcast_params.id = kVideoTrack1;
244 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
245 simulcast_params.ssrc_groups = ssrc_groups;
246 simulcast_params.cname = "Video_SIM_FEC";
247 simulcast_params.sync_label = kMediaStream1;
248
249 StreamParamsVec video_streams;
250 video_streams.push_back(simulcast_params);
251
252 return video_streams;
253 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254
255 bool CompareCryptoParams(const CryptoParamsVec& c1,
256 const CryptoParamsVec& c2) {
257 if (c1.size() != c2.size())
258 return false;
259 for (size_t i = 0; i < c1.size(); ++i)
260 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
261 c1[i].key_params != c2[i].key_params ||
262 c1[i].session_params != c2[i].session_params)
263 return false;
264 return true;
265 }
266
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700267 // Returns true if the transport info contains "renomination" as an
268 // ICE option.
269 bool GetIceRenomination(const TransportInfo* transport_info) {
270 const std::vector<std::string>& ice_options =
271 transport_info->description.transport_options;
272 auto iter = std::find(ice_options.begin(), ice_options.end(),
273 cricket::ICE_RENOMINATION_STR);
274 return iter != ice_options.end();
275 }
276
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000277 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
278 bool has_current_desc) {
279 const std::string current_audio_ufrag = "current_audio_ufrag";
280 const std::string current_audio_pwd = "current_audio_pwd";
281 const std::string current_video_ufrag = "current_video_ufrag";
282 const std::string current_video_pwd = "current_video_pwd";
283 const std::string current_data_ufrag = "current_data_ufrag";
284 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800285 std::unique_ptr<SessionDescription> current_desc;
286 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287 if (has_current_desc) {
288 current_desc.reset(new SessionDescription());
289 EXPECT_TRUE(current_desc->AddTransportInfo(
290 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700291 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000292 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 EXPECT_TRUE(current_desc->AddTransportInfo(
294 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700295 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000296 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297 EXPECT_TRUE(current_desc->AddTransportInfo(
298 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700299 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000300 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301 }
302 if (offer) {
303 desc.reset(f1_.CreateOffer(options, current_desc.get()));
304 } else {
kwiberg31022942016-03-11 14:18:21 -0800305 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000306 offer.reset(f1_.CreateOffer(options, NULL));
307 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
308 }
309 ASSERT_TRUE(desc.get() != NULL);
310 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000311 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312 EXPECT_TRUE(ti_audio != NULL);
313 if (has_current_desc) {
314 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
315 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
316 } else {
317 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
318 ti_audio->description.ice_ufrag.size());
319 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
320 ti_audio->description.ice_pwd.size());
321 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700322 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000323
324 } else {
325 EXPECT_TRUE(ti_audio == NULL);
326 }
327 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000328 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000329 EXPECT_TRUE(ti_video != NULL);
330 if (options.bundle_enabled) {
331 EXPECT_EQ(ti_audio->description.ice_ufrag,
332 ti_video->description.ice_ufrag);
333 EXPECT_EQ(ti_audio->description.ice_pwd,
334 ti_video->description.ice_pwd);
335 } else {
336 if (has_current_desc) {
337 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
338 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
339 } else {
340 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
341 ti_video->description.ice_ufrag.size());
342 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
343 ti_video->description.ice_pwd.size());
344 }
345 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700346 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347 } else {
348 EXPECT_TRUE(ti_video == NULL);
349 }
350 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
351 if (options.has_data()) {
352 EXPECT_TRUE(ti_data != NULL);
353 if (options.bundle_enabled) {
354 EXPECT_EQ(ti_audio->description.ice_ufrag,
355 ti_data->description.ice_ufrag);
356 EXPECT_EQ(ti_audio->description.ice_pwd,
357 ti_data->description.ice_pwd);
358 } else {
359 if (has_current_desc) {
360 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
361 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
362 } else {
363 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
364 ti_data->description.ice_ufrag.size());
365 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
366 ti_data->description.ice_pwd.size());
367 }
368 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700369 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_data));
370
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371 } else {
372 EXPECT_TRUE(ti_video == NULL);
373 }
374 }
375
376 void TestCryptoWithBundle(bool offer) {
377 f1_.set_secure(SEC_ENABLED);
378 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000379 options.recv_audio = true;
380 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000381 options.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -0800382 std::unique_ptr<SessionDescription> ref_desc;
383 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384 if (offer) {
385 options.bundle_enabled = false;
386 ref_desc.reset(f1_.CreateOffer(options, NULL));
387 options.bundle_enabled = true;
388 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
389 } else {
390 options.bundle_enabled = true;
391 ref_desc.reset(f1_.CreateOffer(options, NULL));
392 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
393 }
394 ASSERT_TRUE(desc.get() != NULL);
395 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000396 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000397 desc.get()->GetContentDescriptionByName("audio"));
398 ASSERT_TRUE(audio_media_desc != NULL);
399 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000400 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401 desc.get()->GetContentDescriptionByName("video"));
402 ASSERT_TRUE(video_media_desc != NULL);
403 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
404 video_media_desc->cryptos()));
405 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
406 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
407 audio_media_desc->cryptos()[0].cipher_suite);
408
409 // Verify the selected crypto is one from the reference audio
410 // media content.
411 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000412 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413 ref_desc.get()->GetContentDescriptionByName("audio"));
414 bool found = false;
415 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
416 if (ref_audio_media_desc->cryptos()[i].Matches(
417 audio_media_desc->cryptos()[0])) {
418 found = true;
419 break;
420 }
421 }
422 EXPECT_TRUE(found);
423 }
424
425 // This test that the audio and video media direction is set to
426 // |expected_direction_in_answer| in an answer if the offer direction is set
427 // to |direction_in_offer|.
428 void TestMediaDirectionInAnswer(
429 cricket::MediaContentDirection direction_in_offer,
430 cricket::MediaContentDirection expected_direction_in_answer) {
431 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000432 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800433 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700435 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 ASSERT_TRUE(ac_offer != NULL);
437 AudioContentDescription* acd_offer =
438 static_cast<AudioContentDescription*>(ac_offer->description);
439 acd_offer->set_direction(direction_in_offer);
terelius8c011e52016-04-26 05:28:11 -0700440 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 ASSERT_TRUE(vc_offer != NULL);
442 VideoContentDescription* vcd_offer =
443 static_cast<VideoContentDescription*>(vc_offer->description);
444 vcd_offer->set_direction(direction_in_offer);
445
kwiberg31022942016-03-11 14:18:21 -0800446 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000447 f2_.CreateAnswer(offer.get(), opts, NULL));
448 const AudioContentDescription* acd_answer =
449 GetFirstAudioContentDescription(answer.get());
450 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
451 const VideoContentDescription* vcd_answer =
452 GetFirstVideoContentDescription(answer.get());
453 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
454 }
455
456 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
457 const cricket::ContentDescription* description = content->description;
458 ASSERT(description != NULL);
459 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000460 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461 ASSERT(audio_content_desc != NULL);
462 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
463 if (audio_content_desc->codecs()[i].name == "CN")
464 return false;
465 }
466 return true;
467 }
468
jbauchcb560652016-08-04 05:20:32 -0700469 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
470 MediaSessionOptions offer_opts;
471 offer_opts.recv_video = true;
472 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
473 MediaSessionOptions answer_opts;
474 answer_opts.recv_video = true;
475 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
476 f1_.set_secure(SEC_ENABLED);
477 f2_.set_secure(SEC_ENABLED);
478 std::unique_ptr<SessionDescription> offer(
479 f1_.CreateOffer(offer_opts, NULL));
480 ASSERT_TRUE(offer.get() != NULL);
481 std::unique_ptr<SessionDescription> answer(
482 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
483 const ContentInfo* ac = answer->GetContentByName("audio");
484 const ContentInfo* vc = answer->GetContentByName("video");
485 ASSERT_TRUE(ac != NULL);
486 ASSERT_TRUE(vc != NULL);
487 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
488 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
489 const AudioContentDescription* acd =
490 static_cast<const AudioContentDescription*>(ac->description);
491 const VideoContentDescription* vcd =
492 static_cast<const VideoContentDescription*>(vc->description);
493 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
494 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
495 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
496 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
497 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
498 if (gcm_offer && gcm_answer) {
499 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
500 } else {
501 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
502 }
503 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
504 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
505 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
506 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
507 if (gcm_offer && gcm_answer) {
508 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
509 } else {
510 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
511 }
512 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
513 }
514
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 protected:
516 MediaSessionDescriptionFactory f1_;
517 MediaSessionDescriptionFactory f2_;
518 TransportDescriptionFactory tdf1_;
519 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520};
521
522// Create a typical audio offer, and ensure it matches what we expect.
523TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
524 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800525 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 f1_.CreateOffer(MediaSessionOptions(), NULL));
527 ASSERT_TRUE(offer.get() != NULL);
528 const ContentInfo* ac = offer->GetContentByName("audio");
529 const ContentInfo* vc = offer->GetContentByName("video");
530 ASSERT_TRUE(ac != NULL);
531 ASSERT_TRUE(vc == NULL);
532 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
533 const AudioContentDescription* acd =
534 static_cast<const AudioContentDescription*>(ac->description);
535 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700536 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
538 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
539 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
540 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
541 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
542}
543
544// Create a typical video offer, and ensure it matches what we expect.
545TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
546 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000547 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800549 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 ASSERT_TRUE(offer.get() != NULL);
551 const ContentInfo* ac = offer->GetContentByName("audio");
552 const ContentInfo* vc = offer->GetContentByName("video");
553 ASSERT_TRUE(ac != NULL);
554 ASSERT_TRUE(vc != NULL);
555 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
556 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
557 const AudioContentDescription* acd =
558 static_cast<const AudioContentDescription*>(ac->description);
559 const VideoContentDescription* vcd =
560 static_cast<const VideoContentDescription*>(vc->description);
561 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700562 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
564 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
565 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
566 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
567 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
568 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
569 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
570 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
571 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
572 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
573 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
574 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
575}
576
577// Test creating an offer with bundle where the Codecs have the same dynamic
578// RTP playlod type. The test verifies that the offer don't contain the
579// duplicate RTP payload types.
580TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
581 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700582 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
584 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
585 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
586
587 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000588 opts.recv_audio = true;
589 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 opts.data_channel_type = cricket::DCT_RTP;
591 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800592 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 const VideoContentDescription* vcd =
594 GetFirstVideoContentDescription(offer.get());
595 const AudioContentDescription* acd =
596 GetFirstAudioContentDescription(offer.get());
597 const DataContentDescription* dcd =
598 GetFirstDataContentDescription(offer.get());
599 ASSERT_TRUE(NULL != vcd);
600 ASSERT_TRUE(NULL != acd);
601 ASSERT_TRUE(NULL != dcd);
602 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
603 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
604 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
605 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
606 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
607 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
608}
609
610// Test creating an updated offer with with bundle, audio, video and data
611// after an audio only session has been negotiated.
612TEST_F(MediaSessionDescriptionFactoryTest,
613 TestCreateUpdatedVideoOfferWithBundle) {
614 f1_.set_secure(SEC_ENABLED);
615 f2_.set_secure(SEC_ENABLED);
616 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000617 opts.recv_audio = true;
618 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 opts.data_channel_type = cricket::DCT_NONE;
620 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800621 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
622 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 f2_.CreateAnswer(offer.get(), opts, NULL));
624
625 MediaSessionOptions updated_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000626 updated_opts.recv_audio = true;
627 updated_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 updated_opts.data_channel_type = cricket::DCT_RTP;
629 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800630 std::unique_ptr<SessionDescription> updated_offer(
631 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632
633 const AudioContentDescription* acd =
634 GetFirstAudioContentDescription(updated_offer.get());
635 const VideoContentDescription* vcd =
636 GetFirstVideoContentDescription(updated_offer.get());
637 const DataContentDescription* dcd =
638 GetFirstDataContentDescription(updated_offer.get());
639 EXPECT_TRUE(NULL != vcd);
640 EXPECT_TRUE(NULL != acd);
641 EXPECT_TRUE(NULL != dcd);
642
643 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
644 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
645 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
646 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
647 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
648 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
649}
deadbeef44f08192015-12-15 16:20:09 -0800650
wu@webrtc.org78187522013-10-07 23:32:02 +0000651// Create a RTP data offer, and ensure it matches what we expect.
652TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 MediaSessionOptions opts;
654 opts.data_channel_type = cricket::DCT_RTP;
655 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800656 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 ASSERT_TRUE(offer.get() != NULL);
658 const ContentInfo* ac = offer->GetContentByName("audio");
659 const ContentInfo* dc = offer->GetContentByName("data");
660 ASSERT_TRUE(ac != NULL);
661 ASSERT_TRUE(dc != NULL);
662 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
663 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
664 const AudioContentDescription* acd =
665 static_cast<const AudioContentDescription*>(ac->description);
666 const DataContentDescription* dcd =
667 static_cast<const DataContentDescription*>(dc->description);
668 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700669 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
671 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
672 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
673 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
674 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
675 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
676 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
677 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
678 EXPECT_EQ(cricket::kDataMaxBandwidth,
679 dcd->bandwidth()); // default bandwidth (auto)
680 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
681 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
682 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
683}
684
wu@webrtc.org78187522013-10-07 23:32:02 +0000685// Create an SCTP data offer with bundle without error.
686TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
687 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000688 opts.recv_audio = false;
wu@webrtc.org78187522013-10-07 23:32:02 +0000689 opts.bundle_enabled = true;
690 opts.data_channel_type = cricket::DCT_SCTP;
691 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800692 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000693 EXPECT_TRUE(offer.get() != NULL);
694 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
695}
696
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000697// Test creating an sctp data channel from an already generated offer.
698TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
699 MediaSessionOptions opts;
700 opts.recv_audio = false;
701 opts.bundle_enabled = true;
702 opts.data_channel_type = cricket::DCT_SCTP;
703 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800704 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000705 ASSERT_TRUE(offer1.get() != NULL);
706 const ContentInfo* data = offer1->GetContentByName("data");
707 ASSERT_TRUE(data != NULL);
708 const MediaContentDescription* mdesc =
709 static_cast<const MediaContentDescription*>(data->description);
710 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
711
712 // Now set data_channel_type to 'none' (default) and make sure that the
713 // datachannel type that gets generated from the previous offer, is of the
714 // same type.
715 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800716 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000717 f1_.CreateOffer(opts, offer1.get()));
718 data = offer2->GetContentByName("data");
719 ASSERT_TRUE(data != NULL);
720 mdesc = static_cast<const MediaContentDescription*>(data->description);
721 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
722}
723
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724// Create an audio, video offer without legacy StreamParams.
725TEST_F(MediaSessionDescriptionFactoryTest,
726 TestCreateOfferWithoutLegacyStreams) {
727 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000728 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 f1_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800730 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 ASSERT_TRUE(offer.get() != NULL);
732 const ContentInfo* ac = offer->GetContentByName("audio");
733 const ContentInfo* vc = offer->GetContentByName("video");
734 ASSERT_TRUE(ac != NULL);
735 ASSERT_TRUE(vc != NULL);
736 const AudioContentDescription* acd =
737 static_cast<const AudioContentDescription*>(ac->description);
738 const VideoContentDescription* vcd =
739 static_cast<const VideoContentDescription*>(vc->description);
740
741 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
742 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
743}
744
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000745// Creates an audio+video sendonly offer.
746TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
747 MediaSessionOptions options;
748 options.recv_audio = false;
749 options.recv_video = false;
750 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
751 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
752
kwiberg31022942016-03-11 14:18:21 -0800753 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000754 ASSERT_TRUE(offer.get() != NULL);
755 EXPECT_EQ(2u, offer->contents().size());
756 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
757 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
758
759 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
760 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
761}
762
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000763// Verifies that the order of the media contents in the current
764// SessionDescription is preserved in the new SessionDescription.
765TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
766 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000767 opts.recv_audio = false;
768 opts.recv_video = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000769 opts.data_channel_type = cricket::DCT_SCTP;
770
kwiberg31022942016-03-11 14:18:21 -0800771 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000772 ASSERT_TRUE(offer1.get() != NULL);
773 EXPECT_EQ(1u, offer1->contents().size());
774 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
775
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000776 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800777 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000778 f1_.CreateOffer(opts, offer1.get()));
779 ASSERT_TRUE(offer2.get() != NULL);
780 EXPECT_EQ(2u, offer2->contents().size());
781 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
782 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
783
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000784 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800785 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000786 f1_.CreateOffer(opts, offer2.get()));
787 ASSERT_TRUE(offer3.get() != NULL);
788 EXPECT_EQ(3u, offer3->contents().size());
789 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
790 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
791 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
792
793 // Verifies the default order is audio-video-data, so that the previous checks
794 // didn't pass by accident.
kwiberg31022942016-03-11 14:18:21 -0800795 std::unique_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000796 ASSERT_TRUE(offer4.get() != NULL);
797 EXPECT_EQ(3u, offer4->contents().size());
798 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
799 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
800 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
801}
802
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803// Create a typical audio answer, and ensure it matches what we expect.
804TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
805 f1_.set_secure(SEC_ENABLED);
806 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800807 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 f1_.CreateOffer(MediaSessionOptions(), NULL));
809 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800810 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
812 const ContentInfo* ac = answer->GetContentByName("audio");
813 const ContentInfo* vc = answer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc == NULL);
816 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
817 const AudioContentDescription* acd =
818 static_cast<const AudioContentDescription*>(ac->description);
819 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
820 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
821 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
822 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
823 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
824 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
825 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
826}
827
jbauchcb560652016-08-04 05:20:32 -0700828// Create a typical audio answer with GCM ciphers enabled, and ensure it
829// matches what we expect.
830TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
831 f1_.set_secure(SEC_ENABLED);
832 f2_.set_secure(SEC_ENABLED);
833 MediaSessionOptions options;
834 options.crypto_options.enable_gcm_crypto_suites = true;
835 std::unique_ptr<SessionDescription> offer(
836 f1_.CreateOffer(options, NULL));
837 ASSERT_TRUE(offer.get() != NULL);
838 std::unique_ptr<SessionDescription> answer(
839 f2_.CreateAnswer(offer.get(), options, NULL));
840 const ContentInfo* ac = answer->GetContentByName("audio");
841 const ContentInfo* vc = answer->GetContentByName("video");
842 ASSERT_TRUE(ac != NULL);
843 ASSERT_TRUE(vc == NULL);
844 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
845 const AudioContentDescription* acd =
846 static_cast<const AudioContentDescription*>(ac->description);
847 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
848 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
849 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
850 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
851 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
852 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
853 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
854}
855
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856// Create a typical video answer, and ensure it matches what we expect.
857TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
858 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000859 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 f1_.set_secure(SEC_ENABLED);
861 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800862 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800864 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 f2_.CreateAnswer(offer.get(), opts, NULL));
866 const ContentInfo* ac = answer->GetContentByName("audio");
867 const ContentInfo* vc = answer->GetContentByName("video");
868 ASSERT_TRUE(ac != NULL);
869 ASSERT_TRUE(vc != NULL);
870 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
871 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
872 const AudioContentDescription* acd =
873 static_cast<const AudioContentDescription*>(ac->description);
874 const VideoContentDescription* vcd =
875 static_cast<const VideoContentDescription*>(vc->description);
876 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
877 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
878 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
879 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
880 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
881 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
882 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
883 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
884 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
885 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
886 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
887 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
888}
889
jbauchcb560652016-08-04 05:20:32 -0700890// Create a typical video answer with GCM ciphers enabled, and ensure it
891// matches what we expect.
892TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
893 TestVideoGcmCipher(true, true);
894}
895
896// Create a typical video answer with GCM ciphers enabled for the offer only,
897// and ensure it matches what we expect.
898TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
899 TestVideoGcmCipher(true, false);
900}
901
902// Create a typical video answer with GCM ciphers enabled for the answer only,
903// and ensure it matches what we expect.
904TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
905 TestVideoGcmCipher(false, true);
906}
907
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
909 MediaSessionOptions opts;
910 opts.data_channel_type = cricket::DCT_RTP;
911 f1_.set_secure(SEC_ENABLED);
912 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800913 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800915 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916 f2_.CreateAnswer(offer.get(), opts, NULL));
917 const ContentInfo* ac = answer->GetContentByName("audio");
918 const ContentInfo* vc = answer->GetContentByName("data");
919 ASSERT_TRUE(ac != NULL);
920 ASSERT_TRUE(vc != NULL);
921 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
922 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
923 const AudioContentDescription* acd =
924 static_cast<const AudioContentDescription*>(ac->description);
925 const DataContentDescription* vcd =
926 static_cast<const DataContentDescription*>(vc->description);
927 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
928 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
929 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
930 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
931 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
932 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
933 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
934 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
935 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
936 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
937 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
938 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
939}
940
jbauchcb560652016-08-04 05:20:32 -0700941TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
942 MediaSessionOptions opts;
943 opts.data_channel_type = cricket::DCT_RTP;
944 opts.crypto_options.enable_gcm_crypto_suites = true;
945 f1_.set_secure(SEC_ENABLED);
946 f2_.set_secure(SEC_ENABLED);
947 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
948 ASSERT_TRUE(offer.get() != NULL);
949 std::unique_ptr<SessionDescription> answer(
950 f2_.CreateAnswer(offer.get(), opts, NULL));
951 const ContentInfo* ac = answer->GetContentByName("audio");
952 const ContentInfo* vc = answer->GetContentByName("data");
953 ASSERT_TRUE(ac != NULL);
954 ASSERT_TRUE(vc != NULL);
955 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
956 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
957 const AudioContentDescription* acd =
958 static_cast<const AudioContentDescription*>(ac->description);
959 const DataContentDescription* vcd =
960 static_cast<const DataContentDescription*>(vc->description);
961 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
962 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
963 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
964 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
965 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
966 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
967 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
968 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
969 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
970 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
971 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
972 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
973}
974
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000975// Verifies that the order of the media contents in the offer is preserved in
976// the answer.
977TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
978 MediaSessionOptions opts;
979
980 // Creates a data only offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000981 opts.recv_audio = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000982 opts.data_channel_type = cricket::DCT_SCTP;
kwiberg31022942016-03-11 14:18:21 -0800983 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000984 ASSERT_TRUE(offer1.get() != NULL);
985
986 // Appends audio to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000987 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800988 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000989 f1_.CreateOffer(opts, offer1.get()));
990 ASSERT_TRUE(offer2.get() != NULL);
991
992 // Appends video to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000993 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800994 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000995 f1_.CreateOffer(opts, offer2.get()));
996 ASSERT_TRUE(offer3.get() != NULL);
997
kwiberg31022942016-03-11 14:18:21 -0800998 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000999 f2_.CreateAnswer(offer3.get(), opts, NULL));
1000 ASSERT_TRUE(answer.get() != NULL);
1001 EXPECT_EQ(3u, answer->contents().size());
1002 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1003 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1004 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1005}
1006
ossu075af922016-06-14 03:29:38 -07001007// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1008// answerer settings.
1009
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010// This test that the media direction is set to send/receive in an answer if
1011// the offer is send receive.
1012TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1013 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1014}
1015
1016// This test that the media direction is set to receive only in an answer if
1017// the offer is send only.
1018TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1019 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1020}
1021
1022// This test that the media direction is set to send only in an answer if
1023// the offer is recv only.
1024TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1025 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1026}
1027
1028// This test that the media direction is set to inactive in an answer if
1029// the offer is inactive.
1030TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1031 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1032}
1033
1034// Test that a data content with an unknown protocol is rejected in an answer.
1035TEST_F(MediaSessionDescriptionFactoryTest,
1036 CreateDataAnswerToOfferWithUnknownProtocol) {
1037 MediaSessionOptions opts;
1038 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001039 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 f1_.set_secure(SEC_ENABLED);
1041 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001042 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001043 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001044 ASSERT_TRUE(dc_offer != NULL);
1045 DataContentDescription* dcd_offer =
1046 static_cast<DataContentDescription*>(dc_offer->description);
1047 ASSERT_TRUE(dcd_offer != NULL);
1048 std::string protocol = "a weird unknown protocol";
1049 dcd_offer->set_protocol(protocol);
1050
kwiberg31022942016-03-11 14:18:21 -08001051 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 f2_.CreateAnswer(offer.get(), opts, NULL));
1053
1054 const ContentInfo* dc_answer = answer->GetContentByName("data");
1055 ASSERT_TRUE(dc_answer != NULL);
1056 EXPECT_TRUE(dc_answer->rejected);
1057 const DataContentDescription* dcd_answer =
1058 static_cast<const DataContentDescription*>(dc_answer->description);
1059 ASSERT_TRUE(dcd_answer != NULL);
1060 EXPECT_EQ(protocol, dcd_answer->protocol());
1061}
1062
1063// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1064TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
1065 MediaSessionOptions opts;
1066 f1_.set_secure(SEC_DISABLED);
1067 f2_.set_secure(SEC_DISABLED);
1068 tdf1_.set_secure(SEC_DISABLED);
1069 tdf2_.set_secure(SEC_DISABLED);
1070
kwiberg31022942016-03-11 14:18:21 -08001071 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 const AudioContentDescription* offer_acd =
1073 GetFirstAudioContentDescription(offer.get());
1074 ASSERT_TRUE(offer_acd != NULL);
1075 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1076
kwiberg31022942016-03-11 14:18:21 -08001077 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001078 f2_.CreateAnswer(offer.get(), opts, NULL));
1079
1080 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1081 ASSERT_TRUE(ac_answer != NULL);
1082 EXPECT_FALSE(ac_answer->rejected);
1083
1084 const AudioContentDescription* answer_acd =
1085 GetFirstAudioContentDescription(answer.get());
1086 ASSERT_TRUE(answer_acd != NULL);
1087 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1088}
1089
1090// Create a video offer and answer and ensure the RTP header extensions
1091// matches what we expect.
1092TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1093 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001094 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001095
1096 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1097 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1098 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1099 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1100
kwiberg31022942016-03-11 14:18:21 -08001101 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001102 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001103 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001104 f2_.CreateAnswer(offer.get(), opts, NULL));
1105
1106 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1107 GetFirstAudioContentDescription(
1108 offer.get())->rtp_header_extensions());
1109 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1110 GetFirstVideoContentDescription(
1111 offer.get())->rtp_header_extensions());
1112 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1113 GetFirstAudioContentDescription(
1114 answer.get())->rtp_header_extensions());
1115 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1116 GetFirstVideoContentDescription(
1117 answer.get())->rtp_header_extensions());
1118}
1119
1120// Create an audio, video, data answer without legacy StreamParams.
1121TEST_F(MediaSessionDescriptionFactoryTest,
1122 TestCreateAnswerWithoutLegacyStreams) {
1123 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001124 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001125 opts.data_channel_type = cricket::DCT_RTP;
1126 f1_.set_add_legacy_streams(false);
1127 f2_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -08001128 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001130 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 f2_.CreateAnswer(offer.get(), opts, NULL));
1132 const ContentInfo* ac = answer->GetContentByName("audio");
1133 const ContentInfo* vc = answer->GetContentByName("video");
1134 const ContentInfo* dc = answer->GetContentByName("data");
1135 ASSERT_TRUE(ac != NULL);
1136 ASSERT_TRUE(vc != NULL);
1137 const AudioContentDescription* acd =
1138 static_cast<const AudioContentDescription*>(ac->description);
1139 const VideoContentDescription* vcd =
1140 static_cast<const VideoContentDescription*>(vc->description);
1141 const DataContentDescription* dcd =
1142 static_cast<const DataContentDescription*>(dc->description);
1143
1144 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1145 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1146 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1147}
1148
1149TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1150 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001151 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 opts.data_channel_type = cricket::DCT_RTP;
1153 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001154 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 ASSERT_TRUE(offer.get() != NULL);
1156 const ContentInfo* ac = offer->GetContentByName("audio");
1157 const ContentInfo* vc = offer->GetContentByName("video");
1158 const ContentInfo* dc = offer->GetContentByName("data");
1159 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1160 static_cast<const AudioContentDescription*>(ac->description));
1161 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1162 static_cast<const VideoContentDescription*>(vc->description));
1163 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1164 static_cast<const DataContentDescription*>(dc->description));
1165
1166 EXPECT_FALSE(acd->partial()); // default is false.
1167 acd->set_partial(true);
1168 EXPECT_TRUE(acd->partial());
1169 acd->set_partial(false);
1170 EXPECT_FALSE(acd->partial());
1171
1172 EXPECT_FALSE(vcd->partial()); // default is false.
1173 vcd->set_partial(true);
1174 EXPECT_TRUE(vcd->partial());
1175 vcd->set_partial(false);
1176 EXPECT_FALSE(vcd->partial());
1177
1178 EXPECT_FALSE(dcd->partial()); // default is false.
1179 dcd->set_partial(true);
1180 EXPECT_TRUE(dcd->partial());
1181 dcd->set_partial(false);
1182 EXPECT_FALSE(dcd->partial());
1183}
1184
1185// Create a typical video answer, and ensure it matches what we expect.
1186TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1187 MediaSessionOptions offer_opts;
1188 MediaSessionOptions answer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001189 answer_opts.recv_video = true;
1190 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 answer_opts.data_channel_type = cricket::DCT_RTP;
1192 offer_opts.data_channel_type = cricket::DCT_RTP;
1193
kwiberg31022942016-03-11 14:18:21 -08001194 std::unique_ptr<SessionDescription> offer;
1195 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196
1197 offer_opts.rtcp_mux_enabled = true;
1198 answer_opts.rtcp_mux_enabled = true;
1199
1200 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1201 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1202 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1203 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1204 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1205 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1206 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1207 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1208 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1209 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1210 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1211 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1212 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1213 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1214
1215 offer_opts.rtcp_mux_enabled = true;
1216 answer_opts.rtcp_mux_enabled = false;
1217
1218 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1219 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1220 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1221 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1222 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1223 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1224 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1225 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1226 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1227 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1228 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1229 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1230 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1231 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1232
1233 offer_opts.rtcp_mux_enabled = false;
1234 answer_opts.rtcp_mux_enabled = true;
1235
1236 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1237 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1238 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1239 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1240 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1241 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1242 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1243 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1244 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1245 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1246 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1247 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1248 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1249 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1250
1251 offer_opts.rtcp_mux_enabled = false;
1252 answer_opts.rtcp_mux_enabled = false;
1253
1254 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1255 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1256 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1257 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1258 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1259 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1260 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1261 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1262 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1263 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1264 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1265 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1266 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1267 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1268}
1269
1270// Create an audio-only answer to a video offer.
1271TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1272 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001273 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001274 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001276 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1278 const ContentInfo* ac = answer->GetContentByName("audio");
1279 const ContentInfo* vc = answer->GetContentByName("video");
1280 ASSERT_TRUE(ac != NULL);
1281 ASSERT_TRUE(vc != NULL);
1282 ASSERT_TRUE(vc->description != NULL);
1283 EXPECT_TRUE(vc->rejected);
1284}
1285
1286// Create an audio-only answer to an offer with data.
1287TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1288 MediaSessionOptions opts;
1289 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001290 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001291 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001292 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1294 const ContentInfo* ac = answer->GetContentByName("audio");
1295 const ContentInfo* dc = answer->GetContentByName("data");
1296 ASSERT_TRUE(ac != NULL);
1297 ASSERT_TRUE(dc != NULL);
1298 ASSERT_TRUE(dc->description != NULL);
1299 EXPECT_TRUE(dc->rejected);
1300}
1301
1302// Create an answer that rejects the contents which are rejected in the offer.
1303TEST_F(MediaSessionDescriptionFactoryTest,
1304 CreateAnswerToOfferWithRejectedMedia) {
1305 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001306 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001308 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 ASSERT_TRUE(offer.get() != NULL);
1310 ContentInfo* ac = offer->GetContentByName("audio");
1311 ContentInfo* vc = offer->GetContentByName("video");
1312 ContentInfo* dc = offer->GetContentByName("data");
1313 ASSERT_TRUE(ac != NULL);
1314 ASSERT_TRUE(vc != NULL);
1315 ASSERT_TRUE(dc != NULL);
1316 ac->rejected = true;
1317 vc->rejected = true;
1318 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001319 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320 f2_.CreateAnswer(offer.get(), opts, NULL));
1321 ac = answer->GetContentByName("audio");
1322 vc = answer->GetContentByName("video");
1323 dc = answer->GetContentByName("data");
1324 ASSERT_TRUE(ac != NULL);
1325 ASSERT_TRUE(vc != NULL);
1326 ASSERT_TRUE(dc != NULL);
1327 EXPECT_TRUE(ac->rejected);
1328 EXPECT_TRUE(vc->rejected);
1329 EXPECT_TRUE(dc->rejected);
1330}
1331
1332// Create an audio and video offer with:
1333// - one video track
1334// - two audio tracks
1335// - two data tracks
1336// and ensure it matches what we expect. Also updates the initial offer by
1337// adding a new video track and replaces one of the audio tracks.
1338TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1339 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001340 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1341 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1342 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001343 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001344 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1345 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001346
1347 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001348 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349
1350 ASSERT_TRUE(offer.get() != NULL);
1351 const ContentInfo* ac = offer->GetContentByName("audio");
1352 const ContentInfo* vc = offer->GetContentByName("video");
1353 const ContentInfo* dc = offer->GetContentByName("data");
1354 ASSERT_TRUE(ac != NULL);
1355 ASSERT_TRUE(vc != NULL);
1356 ASSERT_TRUE(dc != NULL);
1357 const AudioContentDescription* acd =
1358 static_cast<const AudioContentDescription*>(ac->description);
1359 const VideoContentDescription* vcd =
1360 static_cast<const VideoContentDescription*>(vc->description);
1361 const DataContentDescription* dcd =
1362 static_cast<const DataContentDescription*>(dc->description);
1363 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001364 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001365
1366 const StreamParamsVec& audio_streams = acd->streams();
1367 ASSERT_EQ(2U, audio_streams.size());
1368 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1369 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1370 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1371 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1372 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1373 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1374 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1375
1376 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1377 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1378 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1379
1380 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1381 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1382 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1383
1384 const StreamParamsVec& video_streams = vcd->streams();
1385 ASSERT_EQ(1U, video_streams.size());
1386 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1387 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1388 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1389 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1390
1391 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1392 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1393 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1394
1395 const StreamParamsVec& data_streams = dcd->streams();
1396 ASSERT_EQ(2U, data_streams.size());
1397 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1398 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1399 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1400 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1401 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1402 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1403 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1404
1405 EXPECT_EQ(cricket::kDataMaxBandwidth,
1406 dcd->bandwidth()); // default bandwidth (auto)
1407 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1408 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1409
1410
1411 // Update the offer. Add a new video track that is not synched to the
1412 // other tracks and replace audio track 2 with audio track 3.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001413 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1414 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1415 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1416 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1417 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
kwiberg31022942016-03-11 14:18:21 -08001418 std::unique_ptr<SessionDescription> updated_offer(
1419 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420
1421 ASSERT_TRUE(updated_offer.get() != NULL);
1422 ac = updated_offer->GetContentByName("audio");
1423 vc = updated_offer->GetContentByName("video");
1424 dc = updated_offer->GetContentByName("data");
1425 ASSERT_TRUE(ac != NULL);
1426 ASSERT_TRUE(vc != NULL);
1427 ASSERT_TRUE(dc != NULL);
1428 const AudioContentDescription* updated_acd =
1429 static_cast<const AudioContentDescription*>(ac->description);
1430 const VideoContentDescription* updated_vcd =
1431 static_cast<const VideoContentDescription*>(vc->description);
1432 const DataContentDescription* updated_dcd =
1433 static_cast<const DataContentDescription*>(dc->description);
1434
1435 EXPECT_EQ(acd->type(), updated_acd->type());
1436 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1437 EXPECT_EQ(vcd->type(), updated_vcd->type());
1438 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1439 EXPECT_EQ(dcd->type(), updated_dcd->type());
1440 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1441 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1442 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1443 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1444 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1445 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1446 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1447
1448 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1449 ASSERT_EQ(2U, updated_audio_streams.size());
1450 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1451 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1452 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1453 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1454 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1455
1456 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1457 ASSERT_EQ(2U, updated_video_streams.size());
1458 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1459 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001460 // All the media streams in one PeerConnection share one RTCP CNAME.
1461 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001462
1463 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1464 ASSERT_EQ(2U, updated_data_streams.size());
1465 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1466 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1467 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1468 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1469 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001470 // The stream correctly got the CNAME from the MediaSessionOptions.
1471 // The Expected RTCP CNAME is the default one as we are using the default
1472 // MediaSessionOptions.
1473 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001474}
1475
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001476// Create an offer with simulcast video stream.
1477TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1478 MediaSessionOptions opts;
1479 const int num_sim_layers = 3;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001480 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
kwiberg31022942016-03-11 14:18:21 -08001481 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001482
1483 ASSERT_TRUE(offer.get() != NULL);
1484 const ContentInfo* vc = offer->GetContentByName("video");
1485 ASSERT_TRUE(vc != NULL);
1486 const VideoContentDescription* vcd =
1487 static_cast<const VideoContentDescription*>(vc->description);
1488
1489 const StreamParamsVec& video_streams = vcd->streams();
1490 ASSERT_EQ(1U, video_streams.size());
1491 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1492 const SsrcGroup* sim_ssrc_group =
1493 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1494 ASSERT_TRUE(sim_ssrc_group != NULL);
1495 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1496}
1497
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001498// Create an audio and video answer to a standard video offer with:
1499// - one video track
1500// - two audio tracks
1501// - two data tracks
1502// and ensure it matches what we expect. Also updates the initial answer by
1503// adding a new video track and removes one of the audio tracks.
1504TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1505 MediaSessionOptions offer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001506 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 offer_opts.data_channel_type = cricket::DCT_RTP;
1508 f1_.set_secure(SEC_ENABLED);
1509 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001510 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511
1512 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001513 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1514 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1515 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001516 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001517 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1518 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519
kwiberg31022942016-03-11 14:18:21 -08001520 std::unique_ptr<SessionDescription> answer(
1521 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001522
1523 ASSERT_TRUE(answer.get() != NULL);
1524 const ContentInfo* ac = answer->GetContentByName("audio");
1525 const ContentInfo* vc = answer->GetContentByName("video");
1526 const ContentInfo* dc = answer->GetContentByName("data");
1527 ASSERT_TRUE(ac != NULL);
1528 ASSERT_TRUE(vc != NULL);
1529 ASSERT_TRUE(dc != NULL);
1530 const AudioContentDescription* acd =
1531 static_cast<const AudioContentDescription*>(ac->description);
1532 const VideoContentDescription* vcd =
1533 static_cast<const VideoContentDescription*>(vc->description);
1534 const DataContentDescription* dcd =
1535 static_cast<const DataContentDescription*>(dc->description);
1536 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1537 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1538 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1539
1540 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1541 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1542
1543 const StreamParamsVec& audio_streams = acd->streams();
1544 ASSERT_EQ(2U, audio_streams.size());
1545 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1546 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1547 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1548 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1549 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1550 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1551 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1552
1553 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1554 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1555
1556 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1557 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1558
1559 const StreamParamsVec& video_streams = vcd->streams();
1560 ASSERT_EQ(1U, video_streams.size());
1561 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1562 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1563 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1564 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1565
1566 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1567 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1568
1569 const StreamParamsVec& data_streams = dcd->streams();
1570 ASSERT_EQ(2U, data_streams.size());
1571 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1572 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1573 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1574 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1575 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1576 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1577 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1578
1579 EXPECT_EQ(cricket::kDataMaxBandwidth,
1580 dcd->bandwidth()); // default bandwidth (auto)
1581 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1582
1583 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001584 // other tracks and remove 1 audio track.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001585 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1586 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1587 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
kwiberg31022942016-03-11 14:18:21 -08001588 std::unique_ptr<SessionDescription> updated_answer(
1589 f2_.CreateAnswer(offer.get(), opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001590
1591 ASSERT_TRUE(updated_answer.get() != NULL);
1592 ac = updated_answer->GetContentByName("audio");
1593 vc = updated_answer->GetContentByName("video");
1594 dc = updated_answer->GetContentByName("data");
1595 ASSERT_TRUE(ac != NULL);
1596 ASSERT_TRUE(vc != NULL);
1597 ASSERT_TRUE(dc != NULL);
1598 const AudioContentDescription* updated_acd =
1599 static_cast<const AudioContentDescription*>(ac->description);
1600 const VideoContentDescription* updated_vcd =
1601 static_cast<const VideoContentDescription*>(vc->description);
1602 const DataContentDescription* updated_dcd =
1603 static_cast<const DataContentDescription*>(dc->description);
1604
1605 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1606 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1607 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1608 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1609 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1610 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1611
1612 EXPECT_EQ(acd->type(), updated_acd->type());
1613 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1614 EXPECT_EQ(vcd->type(), updated_vcd->type());
1615 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1616 EXPECT_EQ(dcd->type(), updated_dcd->type());
1617 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1618
1619 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1620 ASSERT_EQ(1U, updated_audio_streams.size());
1621 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1622
1623 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1624 ASSERT_EQ(2U, updated_video_streams.size());
1625 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1626 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001627 // All media streams in one PeerConnection share one CNAME.
1628 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001629
1630 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1631 ASSERT_EQ(1U, updated_data_streams.size());
1632 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1633}
1634
1635
1636// Create an updated offer after creating an answer to the original offer and
1637// verify that the codecs that were part of the original answer are not changed
1638// in the updated offer.
1639TEST_F(MediaSessionDescriptionFactoryTest,
1640 RespondentCreatesOfferAfterCreatingAnswer) {
1641 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001642 opts.recv_audio = true;
1643 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001644
kwiberg31022942016-03-11 14:18:21 -08001645 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1646 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647 f2_.CreateAnswer(offer.get(), opts, NULL));
1648
1649 const AudioContentDescription* acd =
1650 GetFirstAudioContentDescription(answer.get());
1651 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1652
1653 const VideoContentDescription* vcd =
1654 GetFirstVideoContentDescription(answer.get());
1655 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1656
kwiberg31022942016-03-11 14:18:21 -08001657 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001658 f2_.CreateOffer(opts, answer.get()));
1659
1660 // The expected audio codecs are the common audio codecs from the first
1661 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1662 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001663 // TODO(wu): |updated_offer| should not include the codec
1664 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001665 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001666 kAudioCodecsAnswer[0],
1667 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001668 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001669 };
1670
1671 // The expected video codecs are the common video codecs from the first
1672 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1673 // preference order.
1674 const VideoCodec kUpdatedVideoCodecOffer[] = {
1675 kVideoCodecsAnswer[0],
1676 kVideoCodecs2[1],
1677 };
1678
1679 const AudioContentDescription* updated_acd =
1680 GetFirstAudioContentDescription(updated_offer.get());
1681 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1682
1683 const VideoContentDescription* updated_vcd =
1684 GetFirstVideoContentDescription(updated_offer.get());
1685 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1686}
1687
1688// Create an updated offer after creating an answer to the original offer and
1689// verify that the codecs that were part of the original answer are not changed
1690// in the updated offer. In this test Rtx is enabled.
1691TEST_F(MediaSessionDescriptionFactoryTest,
1692 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1693 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001694 opts.recv_video = true;
1695 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001696 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001697 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001698 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001699 f1_.set_video_codecs(f1_codecs);
1700
1701 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001703 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001704 f2_.set_video_codecs(f2_codecs);
1705
kwiberg31022942016-03-11 14:18:21 -08001706 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001708 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001709 f2_.CreateAnswer(offer.get(), opts, NULL));
1710
1711 const VideoContentDescription* vcd =
1712 GetFirstVideoContentDescription(answer.get());
1713
1714 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001715 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1716 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717
1718 EXPECT_EQ(expected_codecs, vcd->codecs());
1719
deadbeef67cf2c12016-04-13 10:07:16 -07001720 // Now, make sure we get same result (except for the order) if |f2_| creates
1721 // an updated offer even though the default payload types between |f1_| and
1722 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08001723 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001724 f2_.CreateOffer(opts, answer.get()));
1725 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001726 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1728
1729 const VideoContentDescription* updated_vcd =
1730 GetFirstVideoContentDescription(updated_answer.get());
1731
1732 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1733}
1734
1735// Create an updated offer that adds video after creating an audio only answer
1736// to the original offer. This test verifies that if a video codec and the RTX
1737// codec have the same default payload type as an audio codec that is already in
1738// use, the added codecs payload types are changed.
1739TEST_F(MediaSessionDescriptionFactoryTest,
1740 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1741 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001742 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001743 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744 f1_.set_video_codecs(f1_codecs);
1745
1746 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001747 opts.recv_audio = true;
1748 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001749
kwiberg31022942016-03-11 14:18:21 -08001750 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1751 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001752 f2_.CreateAnswer(offer.get(), opts, NULL));
1753
1754 const AudioContentDescription* acd =
1755 GetFirstAudioContentDescription(answer.get());
1756 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1757
1758 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1759 // reference be the same as an audio codec that was negotiated in the
1760 // first offer/answer exchange.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001761 opts.recv_audio = true;
1762 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763
1764 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1765 int used_pl_type = acd->codecs()[0].id;
1766 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001767 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768 f2_.set_video_codecs(f2_codecs);
1769
kwiberg31022942016-03-11 14:18:21 -08001770 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001771 f2_.CreateOffer(opts, answer.get()));
1772 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001773 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1775
1776 const AudioContentDescription* updated_acd =
1777 GetFirstAudioContentDescription(answer.get());
1778 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1779
1780 const VideoContentDescription* updated_vcd =
1781 GetFirstVideoContentDescription(updated_answer.get());
1782
1783 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001784 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1786 EXPECT_NE(used_pl_type, new_h264_pl_type);
1787 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001788 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001789 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1790 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1791}
1792
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001793// Create an updated offer with RTX after creating an answer to an offer
1794// without RTX, and with different default payload types.
1795// Verify that the added RTX codec references the correct payload type.
1796TEST_F(MediaSessionDescriptionFactoryTest,
1797 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
1798 MediaSessionOptions opts;
1799 opts.recv_video = true;
1800 opts.recv_audio = true;
1801
1802 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1803 // This creates rtx for H264 with the payload type |f2_| uses.
1804 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1805 f2_.set_video_codecs(f2_codecs);
1806
kwiberg31022942016-03-11 14:18:21 -08001807 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001808 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08001809 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001810 f2_.CreateAnswer(offer.get(), opts, nullptr));
1811
1812 const VideoContentDescription* vcd =
1813 GetFirstVideoContentDescription(answer.get());
1814
1815 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1816 EXPECT_EQ(expected_codecs, vcd->codecs());
1817
1818 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
1819 // updated offer, even though the default payload types are different from
1820 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08001821 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001822 f2_.CreateOffer(opts, answer.get()));
1823 ASSERT_TRUE(updated_offer);
1824
1825 const VideoContentDescription* updated_vcd =
1826 GetFirstVideoContentDescription(updated_offer.get());
1827
1828 // New offer should attempt to add H263, and RTX for H264.
1829 expected_codecs.push_back(kVideoCodecs2[1]);
1830 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
1831 &expected_codecs);
1832 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1833}
1834
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001835// Test that RTX is ignored when there is no associated payload type parameter.
1836TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1837 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001838 opts.recv_video = true;
1839 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001841 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07001842 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843 f1_.set_video_codecs(f1_codecs);
1844
1845 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001846 // This creates RTX for H264 with the payload type |f2_| uses.
1847 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848 f2_.set_video_codecs(f2_codecs);
1849
kwiberg31022942016-03-11 14:18:21 -08001850 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001851 ASSERT_TRUE(offer.get() != NULL);
1852 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1853 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1854 // is possible to test that that RTX is dropped when
1855 // kCodecParamAssociatedPayloadType is missing in the offer.
1856 VideoContentDescription* desc =
1857 static_cast<cricket::VideoContentDescription*>(
1858 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1859 ASSERT_TRUE(desc != NULL);
1860 std::vector<VideoCodec> codecs = desc->codecs();
1861 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1862 iter != codecs.end(); ++iter) {
1863 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1864 iter->params.clear();
1865 }
1866 }
1867 desc->set_codecs(codecs);
1868
kwiberg31022942016-03-11 14:18:21 -08001869 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001870 f2_.CreateAnswer(offer.get(), opts, NULL));
1871
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001872 std::vector<std::string> codec_names =
1873 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1874 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1875 cricket::kRtxCodecName));
1876}
1877
1878// Test that RTX will be filtered out in the answer if its associated payload
1879// type doesn't match the local value.
1880TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1881 MediaSessionOptions opts;
1882 opts.recv_video = true;
1883 opts.recv_audio = false;
1884 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1885 // This creates RTX for H264 in sender.
1886 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1887 f1_.set_video_codecs(f1_codecs);
1888
1889 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1890 // This creates RTX for H263 in receiver.
1891 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1892 f2_.set_video_codecs(f2_codecs);
1893
kwiberg31022942016-03-11 14:18:21 -08001894 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001895 ASSERT_TRUE(offer.get() != NULL);
1896 // Associated payload type doesn't match, therefore, RTX codec is removed in
1897 // the answer.
kwiberg31022942016-03-11 14:18:21 -08001898 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001899 f2_.CreateAnswer(offer.get(), opts, NULL));
1900
1901 std::vector<std::string> codec_names =
1902 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1903 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1904 cricket::kRtxCodecName));
1905}
1906
1907// Test that when multiple RTX codecs are offered, only the matched RTX codec
1908// is added in the answer, and the unsupported RTX codec is filtered out.
1909TEST_F(MediaSessionDescriptionFactoryTest,
1910 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1911 MediaSessionOptions opts;
1912 opts.recv_video = true;
1913 opts.recv_audio = false;
1914 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1915 // This creates RTX for H264-SVC in sender.
1916 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1917 f1_.set_video_codecs(f1_codecs);
1918
1919 // This creates RTX for H264 in sender.
1920 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1921 f1_.set_video_codecs(f1_codecs);
1922
1923 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1924 // This creates RTX for H264 in receiver.
1925 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1926 f2_.set_video_codecs(f2_codecs);
1927
1928 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1929 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08001930 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001931 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001932 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001933 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001934 const VideoContentDescription* vcd =
1935 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001936 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1937 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1938 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001940 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941}
1942
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001943// Test that after one RTX codec has been negotiated, a new offer can attempt
1944// to add another.
1945TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
1946 MediaSessionOptions opts;
1947 opts.recv_video = true;
1948 opts.recv_audio = false;
1949 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1950 // This creates RTX for H264 for the offerer.
1951 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1952 f1_.set_video_codecs(f1_codecs);
1953
kwiberg31022942016-03-11 14:18:21 -08001954 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001955 ASSERT_TRUE(offer);
1956 const VideoContentDescription* vcd =
1957 GetFirstVideoContentDescription(offer.get());
1958
1959 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
1960 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1961 &expected_codecs);
1962 EXPECT_EQ(expected_codecs, vcd->codecs());
1963
1964 // Now, attempt to add RTX for H264-SVC.
1965 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1966 f1_.set_video_codecs(f1_codecs);
1967
kwiberg31022942016-03-11 14:18:21 -08001968 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001969 f1_.CreateOffer(opts, offer.get()));
1970 ASSERT_TRUE(updated_offer);
1971 vcd = GetFirstVideoContentDescription(updated_offer.get());
1972
1973 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
1974 &expected_codecs);
1975 EXPECT_EQ(expected_codecs, vcd->codecs());
1976}
1977
Noah Richards2e7a0982015-05-18 14:02:54 -07001978// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1979// generated for each simulcast ssrc and correctly grouped.
1980TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1981 MediaSessionOptions opts;
1982 opts.recv_video = true;
1983 opts.recv_audio = false;
1984
1985 // Add simulcast streams.
1986 opts.AddSendVideoStream("stream1", "stream1label", 3);
1987
1988 // Use a single real codec, and then add RTX for it.
1989 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07001990 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07001991 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1992 f1_.set_video_codecs(f1_codecs);
1993
1994 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1995 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08001996 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07001997 ASSERT_TRUE(offer.get() != NULL);
1998 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
1999 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2000 ASSERT_TRUE(desc != NULL);
2001 EXPECT_TRUE(desc->multistream());
2002 const StreamParamsVec& streams = desc->streams();
2003 // Single stream.
2004 ASSERT_EQ(1u, streams.size());
2005 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2006 EXPECT_EQ(6u, streams[0].ssrcs.size());
2007 // And should have a SIM group for the simulcast.
2008 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2009 // And a FID group for RTX.
2010 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002011 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002012 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2013 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002014 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002015 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2016 EXPECT_EQ(3u, fid_ssrcs.size());
2017}
2018
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019// Create an updated offer after creating an answer to the original offer and
2020// verify that the RTP header extensions that were part of the original answer
2021// are not changed in the updated offer.
2022TEST_F(MediaSessionDescriptionFactoryTest,
2023 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2024 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002025 opts.recv_audio = true;
2026 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002027
2028 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2029 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2030 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2031 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2032
kwiberg31022942016-03-11 14:18:21 -08002033 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2034 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002035 f2_.CreateAnswer(offer.get(), opts, NULL));
2036
2037 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2038 GetFirstAudioContentDescription(
2039 answer.get())->rtp_header_extensions());
2040 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2041 GetFirstVideoContentDescription(
2042 answer.get())->rtp_header_extensions());
2043
kwiberg31022942016-03-11 14:18:21 -08002044 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045 f2_.CreateOffer(opts, answer.get()));
2046
2047 // The expected RTP header extensions in the new offer are the resulting
2048 // extensions from the first offer/answer exchange plus the extensions only
2049 // |f2_| offer.
2050 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002051 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002052 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2053 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2054 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002055 };
2056
2057 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002058 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002059 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2060 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2061 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062 };
2063
2064 const AudioContentDescription* updated_acd =
2065 GetFirstAudioContentDescription(updated_offer.get());
2066 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2067 updated_acd->rtp_header_extensions());
2068
2069 const VideoContentDescription* updated_vcd =
2070 GetFirstVideoContentDescription(updated_offer.get());
2071 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2072 updated_vcd->rtp_header_extensions());
2073}
2074
deadbeefa5b273a2015-08-20 17:30:13 -07002075// Verify that if the same RTP extension URI is used for audio and video, the
2076// same ID is used. Also verify that the ID isn't changed when creating an
2077// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002078TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002079 MediaSessionOptions opts;
2080 opts.recv_audio = true;
2081 opts.recv_video = true;
2082
2083 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2084 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2085
kwiberg31022942016-03-11 14:18:21 -08002086 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002087
2088 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2089 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002090 const RtpExtension kExpectedVideoRtpExtension[] = {
2091 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002092 };
2093
2094 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2095 GetFirstAudioContentDescription(
2096 offer.get())->rtp_header_extensions());
2097 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2098 GetFirstVideoContentDescription(
2099 offer.get())->rtp_header_extensions());
2100
2101 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002102 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002103 f1_.CreateOffer(opts, offer.get()));
2104
2105 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2106 GetFirstAudioContentDescription(
2107 updated_offer.get())->rtp_header_extensions());
2108 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2109 GetFirstVideoContentDescription(
2110 updated_offer.get())->rtp_header_extensions());
2111}
2112
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002113TEST(MediaSessionDescription, CopySessionDescription) {
2114 SessionDescription source;
2115 cricket::ContentGroup group(cricket::CN_AUDIO);
2116 source.AddGroup(group);
2117 AudioContentDescription* acd(new AudioContentDescription());
2118 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2119 acd->AddLegacyStream(1);
2120 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2121 VideoContentDescription* vcd(new VideoContentDescription());
2122 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2123 vcd->AddLegacyStream(2);
2124 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2125
kwiberg31022942016-03-11 14:18:21 -08002126 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127 ASSERT_TRUE(copy.get() != NULL);
2128 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2129 const ContentInfo* ac = copy->GetContentByName("audio");
2130 const ContentInfo* vc = copy->GetContentByName("video");
2131 ASSERT_TRUE(ac != NULL);
2132 ASSERT_TRUE(vc != NULL);
2133 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2134 const AudioContentDescription* acd_copy =
2135 static_cast<const AudioContentDescription*>(ac->description);
2136 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2137 EXPECT_EQ(1u, acd->first_ssrc());
2138
2139 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2140 const VideoContentDescription* vcd_copy =
2141 static_cast<const VideoContentDescription*>(vc->description);
2142 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2143 EXPECT_EQ(2u, vcd->first_ssrc());
2144}
2145
2146// The below TestTransportInfoXXX tests create different offers/answers, and
2147// ensure the TransportInfo in the SessionDescription matches what we expect.
2148TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2149 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002150 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 TestTransportInfo(true, options, false);
2152}
2153
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002154TEST_F(MediaSessionDescriptionFactoryTest,
2155 TestTransportInfoOfferIceRenomination) {
2156 MediaSessionOptions options;
2157 options.enable_ice_renomination = true;
2158 TestTransportInfo(true, options, false);
2159}
2160
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002161TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2162 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002163 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164 TestTransportInfo(true, options, true);
2165}
2166
2167TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2168 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002169 options.recv_audio = true;
2170 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171 options.data_channel_type = cricket::DCT_RTP;
2172 TestTransportInfo(true, options, false);
2173}
2174
2175TEST_F(MediaSessionDescriptionFactoryTest,
2176 TestTransportInfoOfferMultimediaCurrent) {
2177 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002178 options.recv_audio = true;
2179 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002180 options.data_channel_type = cricket::DCT_RTP;
2181 TestTransportInfo(true, options, true);
2182}
2183
2184TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2185 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002186 options.recv_audio = true;
2187 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 options.data_channel_type = cricket::DCT_RTP;
2189 options.bundle_enabled = true;
2190 TestTransportInfo(true, options, false);
2191}
2192
2193TEST_F(MediaSessionDescriptionFactoryTest,
2194 TestTransportInfoOfferBundleCurrent) {
2195 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002196 options.recv_audio = true;
2197 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002198 options.data_channel_type = cricket::DCT_RTP;
2199 options.bundle_enabled = true;
2200 TestTransportInfo(true, options, true);
2201}
2202
2203TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2204 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002205 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002206 TestTransportInfo(false, options, false);
2207}
2208
2209TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002210 TestTransportInfoAnswerIceRenomination) {
2211 MediaSessionOptions options;
2212 options.enable_ice_renomination = true;
2213 TestTransportInfo(false, options, false);
2214}
2215
2216TEST_F(MediaSessionDescriptionFactoryTest,
2217 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002218 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002219 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002220 TestTransportInfo(false, options, true);
2221}
2222
2223TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2224 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002225 options.recv_audio = true;
2226 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002227 options.data_channel_type = cricket::DCT_RTP;
2228 TestTransportInfo(false, options, false);
2229}
2230
2231TEST_F(MediaSessionDescriptionFactoryTest,
2232 TestTransportInfoAnswerMultimediaCurrent) {
2233 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002234 options.recv_audio = true;
2235 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002236 options.data_channel_type = cricket::DCT_RTP;
2237 TestTransportInfo(false, options, true);
2238}
2239
2240TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2241 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002242 options.recv_audio = true;
2243 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244 options.data_channel_type = cricket::DCT_RTP;
2245 options.bundle_enabled = true;
2246 TestTransportInfo(false, options, false);
2247}
2248
2249TEST_F(MediaSessionDescriptionFactoryTest,
2250 TestTransportInfoAnswerBundleCurrent) {
2251 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002252 options.recv_audio = true;
2253 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254 options.data_channel_type = cricket::DCT_RTP;
2255 options.bundle_enabled = true;
2256 TestTransportInfo(false, options, true);
2257}
2258
2259// Create an offer with bundle enabled and verify the crypto parameters are
2260// the common set of the available cryptos.
2261TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2262 TestCryptoWithBundle(true);
2263}
2264
2265// Create an answer with bundle enabled and verify the crypto parameters are
2266// the common set of the available cryptos.
2267TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2268 TestCryptoWithBundle(false);
2269}
2270
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002271// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2272// DTLS is not enabled locally.
2273TEST_F(MediaSessionDescriptionFactoryTest,
2274 TestOfferDtlsSavpfWithoutDtlsFailed) {
2275 f1_.set_secure(SEC_ENABLED);
2276 f2_.set_secure(SEC_ENABLED);
2277 tdf1_.set_secure(SEC_DISABLED);
2278 tdf2_.set_secure(SEC_DISABLED);
2279
kwiberg31022942016-03-11 14:18:21 -08002280 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002281 f1_.CreateOffer(MediaSessionOptions(), NULL));
2282 ASSERT_TRUE(offer.get() != NULL);
2283 ContentInfo* offer_content = offer->GetContentByName("audio");
2284 ASSERT_TRUE(offer_content != NULL);
2285 AudioContentDescription* offer_audio_desc =
2286 static_cast<AudioContentDescription*>(offer_content->description);
2287 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2288
kwiberg31022942016-03-11 14:18:21 -08002289 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002290 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2291 ASSERT_TRUE(answer != NULL);
2292 ContentInfo* answer_content = answer->GetContentByName("audio");
2293 ASSERT_TRUE(answer_content != NULL);
2294
2295 ASSERT_TRUE(answer_content->rejected);
2296}
2297
2298// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2299// UDP/TLS/RTP/SAVPF.
2300TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2301 f1_.set_secure(SEC_ENABLED);
2302 f2_.set_secure(SEC_ENABLED);
2303 tdf1_.set_secure(SEC_ENABLED);
2304 tdf2_.set_secure(SEC_ENABLED);
2305
kwiberg31022942016-03-11 14:18:21 -08002306 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002307 f1_.CreateOffer(MediaSessionOptions(), NULL));
2308 ASSERT_TRUE(offer.get() != NULL);
2309 ContentInfo* offer_content = offer->GetContentByName("audio");
2310 ASSERT_TRUE(offer_content != NULL);
2311 AudioContentDescription* offer_audio_desc =
2312 static_cast<AudioContentDescription*>(offer_content->description);
2313 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2314
kwiberg31022942016-03-11 14:18:21 -08002315 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002316 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2317 ASSERT_TRUE(answer != NULL);
2318
2319 const ContentInfo* answer_content = answer->GetContentByName("audio");
2320 ASSERT_TRUE(answer_content != NULL);
2321 ASSERT_FALSE(answer_content->rejected);
2322
2323 const AudioContentDescription* answer_audio_desc =
2324 static_cast<const AudioContentDescription*>(answer_content->description);
2325 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2326 answer_audio_desc->protocol());
2327}
2328
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002329// Test that we include both SDES and DTLS in the offer, but only include SDES
2330// in the answer if DTLS isn't negotiated.
2331TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2332 f1_.set_secure(SEC_ENABLED);
2333 f2_.set_secure(SEC_ENABLED);
2334 tdf1_.set_secure(SEC_ENABLED);
2335 tdf2_.set_secure(SEC_DISABLED);
2336 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002337 options.recv_audio = true;
2338 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002339 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340 const cricket::MediaContentDescription* audio_media_desc;
2341 const cricket::MediaContentDescription* video_media_desc;
2342 const cricket::TransportDescription* audio_trans_desc;
2343 const cricket::TransportDescription* video_trans_desc;
2344
2345 // Generate an offer with SDES and DTLS support.
2346 offer.reset(f1_.CreateOffer(options, NULL));
2347 ASSERT_TRUE(offer.get() != NULL);
2348
2349 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2350 offer->GetContentDescriptionByName("audio"));
2351 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002352 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002353 offer->GetContentDescriptionByName("video"));
2354 ASSERT_TRUE(video_media_desc != NULL);
2355 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2356 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2357
2358 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2359 ASSERT_TRUE(audio_trans_desc != NULL);
2360 video_trans_desc = offer->GetTransportDescriptionByName("video");
2361 ASSERT_TRUE(video_trans_desc != NULL);
2362 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2363 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2364
2365 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2366 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2367 ASSERT_TRUE(answer.get() != NULL);
2368
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002369 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370 answer->GetContentDescriptionByName("audio"));
2371 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002372 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373 answer->GetContentDescriptionByName("video"));
2374 ASSERT_TRUE(video_media_desc != NULL);
2375 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2376 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2377
2378 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2379 ASSERT_TRUE(audio_trans_desc != NULL);
2380 video_trans_desc = answer->GetTransportDescriptionByName("video");
2381 ASSERT_TRUE(video_trans_desc != NULL);
2382 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2383 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2384
2385 // Enable DTLS; the answer should now only have DTLS support.
2386 tdf2_.set_secure(SEC_ENABLED);
2387 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2388 ASSERT_TRUE(answer.get() != NULL);
2389
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002390 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002391 answer->GetContentDescriptionByName("audio"));
2392 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002393 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002394 answer->GetContentDescriptionByName("video"));
2395 ASSERT_TRUE(video_media_desc != NULL);
2396 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2397 EXPECT_TRUE(video_media_desc->cryptos().empty());
2398 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2399 audio_media_desc->protocol());
2400 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2401 video_media_desc->protocol());
2402
2403 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2404 ASSERT_TRUE(audio_trans_desc != NULL);
2405 video_trans_desc = answer->GetTransportDescriptionByName("video");
2406 ASSERT_TRUE(video_trans_desc != NULL);
2407 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2408 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002409
2410 // Try creating offer again. DTLS enabled now, crypto's should be empty
2411 // in new offer.
2412 offer.reset(f1_.CreateOffer(options, offer.get()));
2413 ASSERT_TRUE(offer.get() != NULL);
2414 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2415 offer->GetContentDescriptionByName("audio"));
2416 ASSERT_TRUE(audio_media_desc != NULL);
2417 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2418 offer->GetContentDescriptionByName("video"));
2419 ASSERT_TRUE(video_media_desc != NULL);
2420 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2421 EXPECT_TRUE(video_media_desc->cryptos().empty());
2422
2423 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2424 ASSERT_TRUE(audio_trans_desc != NULL);
2425 video_trans_desc = offer->GetTransportDescriptionByName("video");
2426 ASSERT_TRUE(video_trans_desc != NULL);
2427 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2428 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002429}
2430
2431// Test that an answer can't be created if cryptos are required but the offer is
2432// unsecure.
2433TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2434 MediaSessionOptions options;
2435 f1_.set_secure(SEC_DISABLED);
2436 tdf1_.set_secure(SEC_DISABLED);
2437 f2_.set_secure(SEC_REQUIRED);
2438 tdf1_.set_secure(SEC_ENABLED);
2439
kwiberg31022942016-03-11 14:18:21 -08002440 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002442 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002443 f2_.CreateAnswer(offer.get(), options, NULL));
2444 EXPECT_TRUE(answer.get() == NULL);
2445}
2446
2447// Test that we accept a DTLS offer without SDES and create an appropriate
2448// answer.
2449TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2450 f1_.set_secure(SEC_DISABLED);
2451 f2_.set_secure(SEC_ENABLED);
2452 tdf1_.set_secure(SEC_ENABLED);
2453 tdf2_.set_secure(SEC_ENABLED);
2454 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002455 options.recv_audio = true;
2456 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002457 options.data_channel_type = cricket::DCT_RTP;
2458
kwiberg31022942016-03-11 14:18:21 -08002459 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460
2461 // Generate an offer with DTLS but without SDES.
2462 offer.reset(f1_.CreateOffer(options, NULL));
2463 ASSERT_TRUE(offer.get() != NULL);
2464
2465 const AudioContentDescription* audio_offer =
2466 GetFirstAudioContentDescription(offer.get());
2467 ASSERT_TRUE(audio_offer->cryptos().empty());
2468 const VideoContentDescription* video_offer =
2469 GetFirstVideoContentDescription(offer.get());
2470 ASSERT_TRUE(video_offer->cryptos().empty());
2471 const DataContentDescription* data_offer =
2472 GetFirstDataContentDescription(offer.get());
2473 ASSERT_TRUE(data_offer->cryptos().empty());
2474
2475 const cricket::TransportDescription* audio_offer_trans_desc =
2476 offer->GetTransportDescriptionByName("audio");
2477 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2478 const cricket::TransportDescription* video_offer_trans_desc =
2479 offer->GetTransportDescriptionByName("video");
2480 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2481 const cricket::TransportDescription* data_offer_trans_desc =
2482 offer->GetTransportDescriptionByName("data");
2483 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2484
2485 // Generate an answer with DTLS.
2486 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2487 ASSERT_TRUE(answer.get() != NULL);
2488
2489 const cricket::TransportDescription* audio_answer_trans_desc =
2490 answer->GetTransportDescriptionByName("audio");
2491 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2492 const cricket::TransportDescription* video_answer_trans_desc =
2493 answer->GetTransportDescriptionByName("video");
2494 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2495 const cricket::TransportDescription* data_answer_trans_desc =
2496 answer->GetTransportDescriptionByName("data");
2497 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2498}
2499
2500// Verifies if vad_enabled option is set to false, CN codecs are not present in
2501// offer or answer.
2502TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2503 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002504 options.recv_audio = true;
2505 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002506 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002507 ASSERT_TRUE(offer.get() != NULL);
2508 const ContentInfo* audio_content = offer->GetContentByName("audio");
2509 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2510
2511 options.vad_enabled = false;
2512 offer.reset(f1_.CreateOffer(options, NULL));
2513 ASSERT_TRUE(offer.get() != NULL);
2514 audio_content = offer->GetContentByName("audio");
2515 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002516 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517 f1_.CreateAnswer(offer.get(), options, NULL));
2518 ASSERT_TRUE(answer.get() != NULL);
2519 audio_content = answer->GetContentByName("audio");
2520 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2521}
deadbeef44f08192015-12-15 16:20:09 -08002522
2523// Test that the content name ("mid" in SDP) is unchanged when creating a
2524// new offer.
2525TEST_F(MediaSessionDescriptionFactoryTest,
2526 TestContentNameNotChangedInSubsequentOffers) {
2527 MediaSessionOptions opts;
2528 opts.recv_audio = true;
2529 opts.recv_video = true;
2530 opts.data_channel_type = cricket::DCT_SCTP;
2531 // Create offer and modify the default content names.
kwiberg31022942016-03-11 14:18:21 -08002532 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
deadbeef44f08192015-12-15 16:20:09 -08002533 for (ContentInfo& content : offer->contents()) {
2534 content.name.append("_modified");
2535 }
2536
kwiberg31022942016-03-11 14:18:21 -08002537 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002538 f1_.CreateOffer(opts, offer.get()));
2539 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2540 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2541 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2542 ASSERT_TRUE(audio_content != nullptr);
2543 ASSERT_TRUE(video_content != nullptr);
2544 ASSERT_TRUE(data_content != nullptr);
2545 EXPECT_EQ("audio_modified", audio_content->name);
2546 EXPECT_EQ("video_modified", video_content->name);
2547 EXPECT_EQ("data_modified", data_content->name);
2548}
zhihuangcf5b37c2016-05-05 11:44:35 -07002549
2550class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
2551 public:
2552 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07002553 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
2554 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07002555 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
2556 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07002557 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
2558 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07002559 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
2560 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
2561 f1_.set_secure(SEC_ENABLED);
2562 f2_.set_secure(SEC_ENABLED);
2563 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002564 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002565 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002566 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002567 tdf1_.set_secure(SEC_ENABLED);
2568 tdf2_.set_secure(SEC_ENABLED);
2569 }
2570
2571 protected:
2572 MediaSessionDescriptionFactory f1_;
2573 MediaSessionDescriptionFactory f2_;
2574 TransportDescriptionFactory tdf1_;
2575 TransportDescriptionFactory tdf2_;
2576};
2577
2578TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
2579 MediaSessionOptions opts;
2580 opts.recv_video = true;
2581 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2582 ASSERT_TRUE(offer.get() != nullptr);
2583 // Set the protocol for all the contents.
2584 for (auto content : offer.get()->contents()) {
2585 static_cast<MediaContentDescription*>(content.description)
2586 ->set_protocol(GetParam());
2587 }
2588 std::unique_ptr<SessionDescription> answer(
2589 f2_.CreateAnswer(offer.get(), opts, nullptr));
2590 const ContentInfo* ac = answer->GetContentByName("audio");
2591 const ContentInfo* vc = answer->GetContentByName("video");
2592 ASSERT_TRUE(ac != nullptr);
2593 ASSERT_TRUE(vc != nullptr);
2594 EXPECT_FALSE(ac->rejected); // the offer is accepted
2595 EXPECT_FALSE(vc->rejected);
2596 const AudioContentDescription* acd =
2597 static_cast<const AudioContentDescription*>(ac->description);
2598 const VideoContentDescription* vcd =
2599 static_cast<const VideoContentDescription*>(vc->description);
2600 EXPECT_EQ(GetParam(), acd->protocol());
2601 EXPECT_EQ(GetParam(), vcd->protocol());
2602}
2603
2604INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
2605 MediaProtocolTest,
2606 ::testing::ValuesIn(kMediaProtocols));
2607INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
2608 MediaProtocolTest,
2609 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07002610
2611TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
2612 TransportDescriptionFactory tdf;
2613 MediaSessionDescriptionFactory sf(&tdf);
2614 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2615 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2616
2617 // The merged list of codecs should contain any send codecs that are also
2618 // nominally in the recieve codecs list. Payload types should be picked from
2619 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
2620 // (set to 1). This equals what happens when the send codecs are used in an
2621 // offer and the receive codecs are used in the following answer.
2622 const std::vector<AudioCodec> sendrecv_codecs =
2623 MAKE_VECTOR(kAudioCodecsAnswer);
2624 const std::vector<AudioCodec> no_codecs;
2625
2626 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
2627 << "Please don't change shared test data!";
2628 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
2629 << "Please don't change shared test data!";
2630 // Alter iLBC send codec to have zero channels, to test that that is handled
2631 // properly.
2632 send_codecs[1].channels = 0;
2633
2634 // Alther iLBC receive codec to be lowercase, to test that case conversions
2635 // are handled properly.
2636 recv_codecs[2].name = "ilbc";
2637
2638 // Test proper merge
2639 sf.set_audio_codecs(send_codecs, recv_codecs);
2640 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2641 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002642 EXPECT_TRUE(sf.audio_sendrecv_codecs() == sendrecv_codecs);
ossu075af922016-06-14 03:29:38 -07002643
2644 // Test empty send codecs list
2645 sf.set_audio_codecs(no_codecs, recv_codecs);
2646 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2647 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002648 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002649
2650 // Test empty recv codecs list
2651 sf.set_audio_codecs(send_codecs, no_codecs);
2652 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2653 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002654 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002655
2656 // Test all empty codec lists
2657 sf.set_audio_codecs(no_codecs, no_codecs);
2658 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2659 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002660 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002661}
2662
2663namespace {
2664void TestAudioCodecsOffer(MediaContentDirection direction,
2665 bool add_legacy_stream) {
2666 TransportDescriptionFactory tdf;
2667 MediaSessionDescriptionFactory sf(&tdf);
2668 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2669 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2670 const std::vector<AudioCodec> sendrecv_codecs =
2671 MAKE_VECTOR(kAudioCodecsAnswer);
2672 sf.set_audio_codecs(send_codecs, recv_codecs);
2673 sf.set_add_legacy_streams(add_legacy_stream);
2674
2675 MediaSessionOptions opts;
2676 opts.recv_audio = (direction == cricket::MD_RECVONLY ||
2677 direction == cricket::MD_SENDRECV);
2678 opts.recv_video = false;
2679 if (direction == cricket::MD_SENDONLY || direction == cricket::MD_SENDRECV)
2680 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2681
2682 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
2683 ASSERT_TRUE(offer.get() != NULL);
2684 const ContentInfo* ac = offer->GetContentByName("audio");
2685
2686 // If the factory didn't add any audio content to the offer, we cannot check
2687 // that the codecs put in are right. This happens when we neither want to send
2688 // nor receive audio. The checks are still in place if at some point we'd
2689 // instead create an inactive stream.
2690 if (ac) {
2691 AudioContentDescription* acd =
2692 static_cast<AudioContentDescription*>(ac->description);
2693 // sendrecv and inactive should both present lists as if the channel was to
2694 // be used for sending and receiving. Inactive essentially means it might
2695 // eventually be used anything, but we don't know more at this moment.
2696 if (acd->direction() == cricket::MD_SENDONLY) {
2697 EXPECT_TRUE(acd->codecs() == send_codecs);
2698 } else if (acd->direction() == cricket::MD_RECVONLY) {
2699 EXPECT_TRUE(acd->codecs() == recv_codecs);
2700 } else {
2701 EXPECT_TRUE(acd->codecs() == sendrecv_codecs);
2702 }
2703 }
2704}
2705
2706static const AudioCodec kOfferAnswerCodecs[] = {
2707 AudioCodec(0, "codec0", 16000, -1, 1),
2708 AudioCodec(1, "codec1", 8000, 13300, 1),
2709 AudioCodec(2, "codec2", 8000, 64000, 1),
2710 AudioCodec(3, "codec3", 8000, 64000, 1),
2711 AudioCodec(4, "codec4", 8000, 0, 2),
2712 AudioCodec(5, "codec5", 32000, 0, 1),
2713 AudioCodec(6, "codec6", 48000, 0, 1)
2714};
2715
2716
2717/* The codecs groups below are chosen as per the matrix below. The objective is
2718 * to have different sets of codecs in the inputs, to get unique sets of codecs
2719 * after negotiation, depending on offer and answer communication directions.
2720 * One-way directions in the offer should either result in the opposite
2721 * direction in the answer, or an inactive answer. Regardless, the choice of
2722 * codecs should be as if the answer contained the opposite direction.
2723 * Inactive offers should be treated as sendrecv/sendrecv.
2724 *
2725 * | Offer | Answer | Result
2726 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
2727 * 0 | x - - | - x - | x - - - -
2728 * 1 | x x x | - x - | x - - x -
2729 * 2 | - x - | x - - | - x - - -
2730 * 3 | x x x | x - - | - x x - -
2731 * 4 | - x - | x x x | - x - - -
2732 * 5 | x - - | x x x | x - - - -
2733 * 6 | x x x | x x x | x x x x x
2734 */
2735// Codecs used by offerer in the AudioCodecsAnswerTest
2736static const int kOfferSendCodecs[] = { 0, 1, 3, 5, 6 };
2737static const int kOfferRecvCodecs[] = { 1, 2, 3, 4, 6 };
2738// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
2739// jumbled to catch the answer not following the order in the offer.
2740static const int kAnswerSendCodecs[] = { 6, 5, 2, 3, 4 };
2741static const int kAnswerRecvCodecs[] = { 6, 5, 4, 1, 0 };
2742// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
2743static const int kResultSend_RecvCodecs[] = { 0, 1, 5, 6 };
2744static const int kResultRecv_SendCodecs[] = { 2, 3, 4, 6 };
2745static const int kResultSendrecv_SendCodecs[] = { 3, 6 };
2746static const int kResultSendrecv_RecvCodecs[] = { 1, 6 };
2747static const int kResultSendrecv_SendrecvCodecs[] = { 6 };
2748
2749template <typename T, int IDXS>
2750std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
2751 std::vector<T> out;
2752 out.reserve(IDXS);
2753 for (int idx : indices)
2754 out.push_back(array[idx]);
2755
2756 return out;
2757}
2758
2759void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
2760 MediaContentDirection answer_direction,
2761 bool add_legacy_stream) {
2762 TransportDescriptionFactory offer_tdf;
2763 TransportDescriptionFactory answer_tdf;
2764 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
2765 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
2766 offer_factory.set_audio_codecs(
2767 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
2768 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
2769 answer_factory.set_audio_codecs(
2770 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
2771 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
2772
2773 // Never add a legacy stream to offer - we want to control the offer
2774 // parameters exactly.
2775 offer_factory.set_add_legacy_streams(false);
2776 answer_factory.set_add_legacy_streams(add_legacy_stream);
2777 MediaSessionOptions offer_opts;
2778 offer_opts.recv_audio = (offer_direction == cricket::MD_RECVONLY ||
2779 offer_direction == cricket::MD_SENDRECV);
2780 offer_opts.recv_video = false;
2781 if (offer_direction == cricket::MD_SENDONLY ||
2782 offer_direction == cricket::MD_SENDRECV) {
2783 offer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2784 }
2785
2786 std::unique_ptr<SessionDescription> offer(
2787 offer_factory.CreateOffer(offer_opts, NULL));
2788 ASSERT_TRUE(offer.get() != NULL);
2789
2790 MediaSessionOptions answer_opts;
2791 answer_opts.recv_audio = (answer_direction == cricket::MD_RECVONLY ||
2792 answer_direction == cricket::MD_SENDRECV);
2793 answer_opts.recv_video = false;
2794 if (answer_direction == cricket::MD_SENDONLY ||
2795 answer_direction == cricket::MD_SENDRECV) {
2796 answer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2797 }
2798 std::unique_ptr<SessionDescription> answer(
2799 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
2800 const ContentInfo* ac = answer->GetContentByName("audio");
2801
2802 // If the factory didn't add any audio content to the answer, we cannot check
2803 // that the codecs put in are right. This happens when we neither want to send
2804 // nor receive audio. The checks are still in place if at some point we'd
2805 // instead create an inactive stream.
2806 if (ac) {
2807 const AudioContentDescription* acd =
2808 static_cast<const AudioContentDescription*>(ac->description);
2809 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2810
2811
2812 std::vector<AudioCodec> target_codecs;
2813 // For offers with sendrecv or inactive, we should never reply with more
2814 // codecs than offered, with these codec sets.
2815 switch (offer_direction) {
2816 case cricket::MD_INACTIVE:
2817 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2818 kResultSendrecv_SendrecvCodecs);
2819 break;
2820 case cricket::MD_SENDONLY:
2821 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2822 kResultSend_RecvCodecs);
2823 break;
2824 case cricket::MD_RECVONLY:
2825 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2826 kResultRecv_SendCodecs);
2827 break;
2828 case cricket::MD_SENDRECV:
2829 if (acd->direction() == cricket::MD_SENDONLY) {
2830 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2831 kResultSendrecv_SendCodecs);
2832 } else if (acd->direction() == cricket::MD_RECVONLY) {
2833 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2834 kResultSendrecv_RecvCodecs);
2835 } else {
2836 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2837 kResultSendrecv_SendrecvCodecs);
2838 }
2839 break;
2840 }
2841
2842 auto format_codecs = [] (const std::vector<AudioCodec>& codecs) {
2843 std::stringstream os;
2844 bool first = true;
2845 os << "{";
2846 for (const auto& c : codecs) {
2847 os << (first ? " " : ", ") << c.id;
2848 first = false;
2849 }
2850 os << " }";
2851 return os.str();
2852 };
2853
2854 EXPECT_TRUE(acd->codecs() == target_codecs)
2855 << "Expected: " << format_codecs(target_codecs)
2856 << ", got: " << format_codecs(acd->codecs())
2857 << "; Offered: " << MediaContentDirectionToString(offer_direction)
2858 << ", answerer wants: "
2859 << MediaContentDirectionToString(answer_direction)
2860 << "; got: " << MediaContentDirectionToString(acd->direction());
2861 } else {
2862 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
2863 << "Only inactive offers are allowed to not generate any audio content";
2864 }
2865}
2866}
2867
2868class AudioCodecsOfferTest
2869 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2870 bool>> {
2871};
2872
2873TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
2874 TestAudioCodecsOffer(std::tr1::get<0>(GetParam()),
2875 std::tr1::get<1>(GetParam()));
2876}
2877
2878INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2879 AudioCodecsOfferTest,
2880 ::testing::Combine(
2881 ::testing::Values(cricket::MD_SENDONLY,
2882 cricket::MD_RECVONLY,
2883 cricket::MD_SENDRECV,
2884 cricket::MD_INACTIVE),
2885 ::testing::Bool()));
2886
2887class AudioCodecsAnswerTest
2888 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2889 MediaContentDirection,
2890 bool>> {
2891};
2892
2893TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
2894 TestAudioCodecsAnswer(std::tr1::get<0>(GetParam()),
2895 std::tr1::get<1>(GetParam()),
2896 std::tr1::get<2>(GetParam()));
2897}
2898
2899INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2900 AudioCodecsAnswerTest,
2901 ::testing::Combine(
2902 ::testing::Values(cricket::MD_SENDONLY,
2903 cricket::MD_RECVONLY,
2904 cricket::MD_SENDRECV,
2905 cricket::MD_INACTIVE),
2906 ::testing::Values(cricket::MD_SENDONLY,
2907 cricket::MD_RECVONLY,
2908 cricket::MD_SENDRECV,
2909 cricket::MD_INACTIVE),
2910 ::testing::Bool()));