blob: 6ea7aeb8ab93f0b317e3b323acb88b9f39b15268 [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;
42using cricket::MediaSessionOptions;
43using cricket::MediaType;
44using cricket::SessionDescription;
45using cricket::SsrcGroup;
46using cricket::StreamParams;
47using cricket::StreamParamsVec;
48using cricket::TransportDescription;
49using cricket::TransportDescriptionFactory;
50using cricket::TransportInfo;
51using cricket::ContentInfo;
52using cricket::CryptoParamsVec;
53using cricket::AudioContentDescription;
54using cricket::VideoContentDescription;
55using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080056using cricket::GetFirstAudioContent;
57using cricket::GetFirstVideoContent;
58using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::GetFirstAudioContentDescription;
60using cricket::GetFirstVideoContentDescription;
61using cricket::GetFirstDataContentDescription;
62using cricket::kAutoBandwidth;
63using cricket::AudioCodec;
64using cricket::VideoCodec;
65using cricket::DataCodec;
66using cricket::NS_JINGLE_RTP;
67using cricket::MEDIA_TYPE_AUDIO;
68using cricket::MEDIA_TYPE_VIDEO;
69using cricket::MEDIA_TYPE_DATA;
70using cricket::RtpHeaderExtension;
71using 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;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076
77static const AudioCodec kAudioCodecs1[] = {
78 AudioCodec(103, "ISAC", 16000, -1, 1, 6),
79 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
80 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
81 AudioCodec(8, "PCMA", 8000, 64000, 1, 3),
82 AudioCodec(117, "red", 8000, 0, 1, 2),
83 AudioCodec(107, "CN", 48000, 0, 1, 1)
84};
85
86static const AudioCodec kAudioCodecs2[] = {
87 AudioCodec(126, "speex", 16000, 22000, 1, 3),
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +000088 AudioCodec(0, "PCMU", 8000, 64000, 1, 2),
89 AudioCodec(127, "iLBC", 8000, 13300, 1, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090};
91
92static const AudioCodec kAudioCodecsAnswer[] = {
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +000093 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
94 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095};
96
97static const VideoCodec kVideoCodecs1[] = {
98 VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
99 VideoCodec(97, "H264", 320, 200, 30, 1)
100};
101
102static const VideoCodec kVideoCodecs2[] = {
103 VideoCodec(126, "H264", 320, 200, 30, 2),
104 VideoCodec(127, "H263", 320, 200, 30, 1)
105};
106
107static const VideoCodec kVideoCodecsAnswer[] = {
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +0000108 VideoCodec(97, "H264", 320, 200, 30, 1)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109};
110
111static const DataCodec kDataCodecs1[] = {
112 DataCodec(98, "binary-data", 2),
113 DataCodec(99, "utf8-text", 1)
114};
115
116static const DataCodec kDataCodecs2[] = {
117 DataCodec(126, "binary-data", 2),
118 DataCodec(127, "utf8-text", 1)
119};
120
121static const DataCodec kDataCodecsAnswer[] = {
122 DataCodec(98, "binary-data", 2),
123 DataCodec(99, "utf8-text", 1)
124};
125
126static const RtpHeaderExtension kAudioRtpExtension1[] = {
127 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
128 RtpHeaderExtension("http://google.com/testing/audio_something", 10),
129};
130
131static const RtpHeaderExtension kAudioRtpExtension2[] = {
132 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
133 RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000134 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135};
136
deadbeefa5b273a2015-08-20 17:30:13 -0700137static const RtpHeaderExtension kAudioRtpExtension3[] = {
138 RtpHeaderExtension("http://google.com/testing/audio_something", 2),
139 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 3),
140};
141
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
143 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
144};
145
146static const RtpHeaderExtension kVideoRtpExtension1[] = {
147 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000148 RtpHeaderExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000149};
150
151static const RtpHeaderExtension kVideoRtpExtension2[] = {
152 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
153 RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000154 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155};
156
deadbeefa5b273a2015-08-20 17:30:13 -0700157static const RtpHeaderExtension kVideoRtpExtension3[] = {
158 RtpHeaderExtension("http://google.com/testing/video_something", 4),
159 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 5),
160};
161
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
163 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164};
165
Peter Boström0c4e06b2015-10-07 12:23:21 +0200166static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
167static const uint32_t kSimSsrc[] = {10, 20, 30};
168static const uint32_t kFec1Ssrc[] = {10, 11};
169static const uint32_t kFec2Ssrc[] = {20, 21};
170static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171
172static const char kMediaStream1[] = "stream_1";
173static const char kMediaStream2[] = "stream_2";
174static const char kVideoTrack1[] = "video_1";
175static const char kVideoTrack2[] = "video_2";
176static const char kAudioTrack1[] = "audio_1";
177static const char kAudioTrack2[] = "audio_2";
178static const char kAudioTrack3[] = "audio_3";
179static const char kDataTrack1[] = "data_1";
180static const char kDataTrack2[] = "data_2";
181static const char kDataTrack3[] = "data_3";
182
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000183static bool IsMediaContentOfType(const ContentInfo* content,
184 MediaType media_type) {
185 const MediaContentDescription* mdesc =
186 static_cast<const MediaContentDescription*>(content->description);
187 return mdesc && mdesc->type() == media_type;
188}
189
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000190static cricket::MediaContentDirection
191GetMediaDirection(const ContentInfo* content) {
192 cricket::MediaContentDescription* desc =
193 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
194 return desc->direction();
195}
196
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000197static void AddRtxCodec(const VideoCodec& rtx_codec,
198 std::vector<VideoCodec>* codecs) {
199 VideoCodec rtx;
200 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
201 codecs->push_back(rtx_codec);
202}
203
204template <class T>
205static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
206 std::vector<std::string> codec_names;
207 for (const auto& codec : codecs) {
208 codec_names.push_back(codec.name);
209 }
210 return codec_names;
211}
212
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000213class MediaSessionDescriptionFactoryTest : public testing::Test {
214 public:
215 MediaSessionDescriptionFactoryTest()
Henrik Boström3a14bf32015-08-31 09:27:58 +0200216 : f1_(&tdf1_),
217 f2_(&tdf2_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
219 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
220 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
221 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
222 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
223 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200224 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwiberg0eb15ed2015-12-17 03:04:15 -0800225 rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200226 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwiberg0eb15ed2015-12-17 03:04:15 -0800227 rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228 }
229
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000230 // Create a video StreamParamsVec object with:
231 // - one video stream with 3 simulcast streams and FEC,
232 StreamParamsVec CreateComplexVideoStreamParamsVec() {
233 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
234 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
235 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
236 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
237
238 std::vector<SsrcGroup> ssrc_groups;
239 ssrc_groups.push_back(sim_group);
240 ssrc_groups.push_back(fec_group1);
241 ssrc_groups.push_back(fec_group2);
242 ssrc_groups.push_back(fec_group3);
243
244 StreamParams simulcast_params;
245 simulcast_params.id = kVideoTrack1;
246 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
247 simulcast_params.ssrc_groups = ssrc_groups;
248 simulcast_params.cname = "Video_SIM_FEC";
249 simulcast_params.sync_label = kMediaStream1;
250
251 StreamParamsVec video_streams;
252 video_streams.push_back(simulcast_params);
253
254 return video_streams;
255 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256
257 bool CompareCryptoParams(const CryptoParamsVec& c1,
258 const CryptoParamsVec& c2) {
259 if (c1.size() != c2.size())
260 return false;
261 for (size_t i = 0; i < c1.size(); ++i)
262 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
263 c1[i].key_params != c2[i].key_params ||
264 c1[i].session_params != c2[i].session_params)
265 return false;
266 return true;
267 }
268
269 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
270 bool has_current_desc) {
271 const std::string current_audio_ufrag = "current_audio_ufrag";
272 const std::string current_audio_pwd = "current_audio_pwd";
273 const std::string current_video_ufrag = "current_video_ufrag";
274 const std::string current_video_pwd = "current_video_pwd";
275 const std::string current_data_ufrag = "current_data_ufrag";
276 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800277 std::unique_ptr<SessionDescription> current_desc;
278 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279 if (has_current_desc) {
280 current_desc.reset(new SessionDescription());
281 EXPECT_TRUE(current_desc->AddTransportInfo(
282 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700283 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000284 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 EXPECT_TRUE(current_desc->AddTransportInfo(
286 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700287 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000288 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000289 EXPECT_TRUE(current_desc->AddTransportInfo(
290 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700291 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000292 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 }
294 if (offer) {
295 desc.reset(f1_.CreateOffer(options, current_desc.get()));
296 } else {
kwiberg31022942016-03-11 14:18:21 -0800297 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 offer.reset(f1_.CreateOffer(options, NULL));
299 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
300 }
301 ASSERT_TRUE(desc.get() != NULL);
302 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000303 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304 EXPECT_TRUE(ti_audio != NULL);
305 if (has_current_desc) {
306 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
307 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
308 } else {
309 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
310 ti_audio->description.ice_ufrag.size());
311 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
312 ti_audio->description.ice_pwd.size());
313 }
314
315 } else {
316 EXPECT_TRUE(ti_audio == NULL);
317 }
318 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000319 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 EXPECT_TRUE(ti_video != NULL);
321 if (options.bundle_enabled) {
322 EXPECT_EQ(ti_audio->description.ice_ufrag,
323 ti_video->description.ice_ufrag);
324 EXPECT_EQ(ti_audio->description.ice_pwd,
325 ti_video->description.ice_pwd);
326 } else {
327 if (has_current_desc) {
328 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
329 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
330 } else {
331 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
332 ti_video->description.ice_ufrag.size());
333 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
334 ti_video->description.ice_pwd.size());
335 }
336 }
337 } else {
338 EXPECT_TRUE(ti_video == NULL);
339 }
340 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
341 if (options.has_data()) {
342 EXPECT_TRUE(ti_data != NULL);
343 if (options.bundle_enabled) {
344 EXPECT_EQ(ti_audio->description.ice_ufrag,
345 ti_data->description.ice_ufrag);
346 EXPECT_EQ(ti_audio->description.ice_pwd,
347 ti_data->description.ice_pwd);
348 } else {
349 if (has_current_desc) {
350 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
351 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
352 } else {
353 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
354 ti_data->description.ice_ufrag.size());
355 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
356 ti_data->description.ice_pwd.size());
357 }
358 }
359 } else {
360 EXPECT_TRUE(ti_video == NULL);
361 }
362 }
363
364 void TestCryptoWithBundle(bool offer) {
365 f1_.set_secure(SEC_ENABLED);
366 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000367 options.recv_audio = true;
368 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369 options.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -0800370 std::unique_ptr<SessionDescription> ref_desc;
371 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372 if (offer) {
373 options.bundle_enabled = false;
374 ref_desc.reset(f1_.CreateOffer(options, NULL));
375 options.bundle_enabled = true;
376 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
377 } else {
378 options.bundle_enabled = true;
379 ref_desc.reset(f1_.CreateOffer(options, NULL));
380 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
381 }
382 ASSERT_TRUE(desc.get() != NULL);
383 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000384 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385 desc.get()->GetContentDescriptionByName("audio"));
386 ASSERT_TRUE(audio_media_desc != NULL);
387 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000388 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389 desc.get()->GetContentDescriptionByName("video"));
390 ASSERT_TRUE(video_media_desc != NULL);
391 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
392 video_media_desc->cryptos()));
393 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
394 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
395 audio_media_desc->cryptos()[0].cipher_suite);
396
397 // Verify the selected crypto is one from the reference audio
398 // media content.
399 const cricket::MediaContentDescription* ref_audio_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 ref_desc.get()->GetContentDescriptionByName("audio"));
402 bool found = false;
403 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
404 if (ref_audio_media_desc->cryptos()[i].Matches(
405 audio_media_desc->cryptos()[0])) {
406 found = true;
407 break;
408 }
409 }
410 EXPECT_TRUE(found);
411 }
412
413 // This test that the audio and video media direction is set to
414 // |expected_direction_in_answer| in an answer if the offer direction is set
415 // to |direction_in_offer|.
416 void TestMediaDirectionInAnswer(
417 cricket::MediaContentDirection direction_in_offer,
418 cricket::MediaContentDirection expected_direction_in_answer) {
419 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000420 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800421 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 ASSERT_TRUE(offer.get() != NULL);
423 ContentInfo* ac_offer= offer->GetContentByName("audio");
424 ASSERT_TRUE(ac_offer != NULL);
425 AudioContentDescription* acd_offer =
426 static_cast<AudioContentDescription*>(ac_offer->description);
427 acd_offer->set_direction(direction_in_offer);
428 ContentInfo* vc_offer= offer->GetContentByName("video");
429 ASSERT_TRUE(vc_offer != NULL);
430 VideoContentDescription* vcd_offer =
431 static_cast<VideoContentDescription*>(vc_offer->description);
432 vcd_offer->set_direction(direction_in_offer);
433
kwiberg31022942016-03-11 14:18:21 -0800434 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 f2_.CreateAnswer(offer.get(), opts, NULL));
436 const AudioContentDescription* acd_answer =
437 GetFirstAudioContentDescription(answer.get());
438 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
439 const VideoContentDescription* vcd_answer =
440 GetFirstVideoContentDescription(answer.get());
441 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
442 }
443
444 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
445 const cricket::ContentDescription* description = content->description;
446 ASSERT(description != NULL);
447 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000448 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 ASSERT(audio_content_desc != NULL);
450 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
451 if (audio_content_desc->codecs()[i].name == "CN")
452 return false;
453 }
454 return true;
455 }
456
457 protected:
458 MediaSessionDescriptionFactory f1_;
459 MediaSessionDescriptionFactory f2_;
460 TransportDescriptionFactory tdf1_;
461 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462};
463
464// Create a typical audio offer, and ensure it matches what we expect.
465TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
466 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800467 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000468 f1_.CreateOffer(MediaSessionOptions(), NULL));
469 ASSERT_TRUE(offer.get() != NULL);
470 const ContentInfo* ac = offer->GetContentByName("audio");
471 const ContentInfo* vc = offer->GetContentByName("video");
472 ASSERT_TRUE(ac != NULL);
473 ASSERT_TRUE(vc == NULL);
474 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
475 const AudioContentDescription* acd =
476 static_cast<const AudioContentDescription*>(ac->description);
477 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
478 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
479 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
480 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
481 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
482 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
483 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
484}
485
486// Create a typical video offer, and ensure it matches what we expect.
487TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
488 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000489 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800491 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 ASSERT_TRUE(offer.get() != NULL);
493 const ContentInfo* ac = offer->GetContentByName("audio");
494 const ContentInfo* vc = offer->GetContentByName("video");
495 ASSERT_TRUE(ac != NULL);
496 ASSERT_TRUE(vc != NULL);
497 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
498 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
499 const AudioContentDescription* acd =
500 static_cast<const AudioContentDescription*>(ac->description);
501 const VideoContentDescription* vcd =
502 static_cast<const VideoContentDescription*>(vc->description);
503 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
504 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
505 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
506 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
507 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
508 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
509 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
510 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
511 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
512 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
513 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
514 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
515 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
516 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
517}
518
519// Test creating an offer with bundle where the Codecs have the same dynamic
520// RTP playlod type. The test verifies that the offer don't contain the
521// duplicate RTP payload types.
522TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
523 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
524 const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
525 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
526 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
527 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
528
529 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000530 opts.recv_audio = true;
531 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 opts.data_channel_type = cricket::DCT_RTP;
533 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800534 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 const VideoContentDescription* vcd =
536 GetFirstVideoContentDescription(offer.get());
537 const AudioContentDescription* acd =
538 GetFirstAudioContentDescription(offer.get());
539 const DataContentDescription* dcd =
540 GetFirstDataContentDescription(offer.get());
541 ASSERT_TRUE(NULL != vcd);
542 ASSERT_TRUE(NULL != acd);
543 ASSERT_TRUE(NULL != dcd);
544 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
545 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
546 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
547 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
548 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
549 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
550}
551
552// Test creating an updated offer with with bundle, audio, video and data
553// after an audio only session has been negotiated.
554TEST_F(MediaSessionDescriptionFactoryTest,
555 TestCreateUpdatedVideoOfferWithBundle) {
556 f1_.set_secure(SEC_ENABLED);
557 f2_.set_secure(SEC_ENABLED);
558 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000559 opts.recv_audio = true;
560 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 opts.data_channel_type = cricket::DCT_NONE;
562 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800563 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
564 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 f2_.CreateAnswer(offer.get(), opts, NULL));
566
567 MediaSessionOptions updated_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000568 updated_opts.recv_audio = true;
569 updated_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 updated_opts.data_channel_type = cricket::DCT_RTP;
571 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800572 std::unique_ptr<SessionDescription> updated_offer(
573 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574
575 const AudioContentDescription* acd =
576 GetFirstAudioContentDescription(updated_offer.get());
577 const VideoContentDescription* vcd =
578 GetFirstVideoContentDescription(updated_offer.get());
579 const DataContentDescription* dcd =
580 GetFirstDataContentDescription(updated_offer.get());
581 EXPECT_TRUE(NULL != vcd);
582 EXPECT_TRUE(NULL != acd);
583 EXPECT_TRUE(NULL != dcd);
584
585 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
586 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
587 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
588 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
589 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
590 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
591}
deadbeef44f08192015-12-15 16:20:09 -0800592
wu@webrtc.org78187522013-10-07 23:32:02 +0000593// Create a RTP data offer, and ensure it matches what we expect.
594TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 MediaSessionOptions opts;
596 opts.data_channel_type = cricket::DCT_RTP;
597 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800598 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 ASSERT_TRUE(offer.get() != NULL);
600 const ContentInfo* ac = offer->GetContentByName("audio");
601 const ContentInfo* dc = offer->GetContentByName("data");
602 ASSERT_TRUE(ac != NULL);
603 ASSERT_TRUE(dc != NULL);
604 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
605 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
606 const AudioContentDescription* acd =
607 static_cast<const AudioContentDescription*>(ac->description);
608 const DataContentDescription* dcd =
609 static_cast<const DataContentDescription*>(dc->description);
610 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
611 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
612 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
613 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
614 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
615 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
616 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
617 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
618 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
619 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
620 EXPECT_EQ(cricket::kDataMaxBandwidth,
621 dcd->bandwidth()); // default bandwidth (auto)
622 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
623 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
624 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
625}
626
wu@webrtc.org78187522013-10-07 23:32:02 +0000627// Create an SCTP data offer with bundle without error.
628TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
629 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000630 opts.recv_audio = false;
wu@webrtc.org78187522013-10-07 23:32:02 +0000631 opts.bundle_enabled = true;
632 opts.data_channel_type = cricket::DCT_SCTP;
633 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800634 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000635 EXPECT_TRUE(offer.get() != NULL);
636 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
637}
638
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000639// Test creating an sctp data channel from an already generated offer.
640TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
641 MediaSessionOptions opts;
642 opts.recv_audio = false;
643 opts.bundle_enabled = true;
644 opts.data_channel_type = cricket::DCT_SCTP;
645 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800646 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000647 ASSERT_TRUE(offer1.get() != NULL);
648 const ContentInfo* data = offer1->GetContentByName("data");
649 ASSERT_TRUE(data != NULL);
650 const MediaContentDescription* mdesc =
651 static_cast<const MediaContentDescription*>(data->description);
652 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
653
654 // Now set data_channel_type to 'none' (default) and make sure that the
655 // datachannel type that gets generated from the previous offer, is of the
656 // same type.
657 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800658 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000659 f1_.CreateOffer(opts, offer1.get()));
660 data = offer2->GetContentByName("data");
661 ASSERT_TRUE(data != NULL);
662 mdesc = static_cast<const MediaContentDescription*>(data->description);
663 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
664}
665
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666// Create an audio, video offer without legacy StreamParams.
667TEST_F(MediaSessionDescriptionFactoryTest,
668 TestCreateOfferWithoutLegacyStreams) {
669 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000670 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 f1_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800672 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 ASSERT_TRUE(offer.get() != NULL);
674 const ContentInfo* ac = offer->GetContentByName("audio");
675 const ContentInfo* vc = offer->GetContentByName("video");
676 ASSERT_TRUE(ac != NULL);
677 ASSERT_TRUE(vc != NULL);
678 const AudioContentDescription* acd =
679 static_cast<const AudioContentDescription*>(ac->description);
680 const VideoContentDescription* vcd =
681 static_cast<const VideoContentDescription*>(vc->description);
682
683 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
684 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
685}
686
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000687// Creates an audio+video sendonly offer.
688TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
689 MediaSessionOptions options;
690 options.recv_audio = false;
691 options.recv_video = false;
692 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
693 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
694
kwiberg31022942016-03-11 14:18:21 -0800695 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000696 ASSERT_TRUE(offer.get() != NULL);
697 EXPECT_EQ(2u, offer->contents().size());
698 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
699 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
700
701 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
702 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
703}
704
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000705// Verifies that the order of the media contents in the current
706// SessionDescription is preserved in the new SessionDescription.
707TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
708 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000709 opts.recv_audio = false;
710 opts.recv_video = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000711 opts.data_channel_type = cricket::DCT_SCTP;
712
kwiberg31022942016-03-11 14:18:21 -0800713 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000714 ASSERT_TRUE(offer1.get() != NULL);
715 EXPECT_EQ(1u, offer1->contents().size());
716 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
717
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000718 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800719 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000720 f1_.CreateOffer(opts, offer1.get()));
721 ASSERT_TRUE(offer2.get() != NULL);
722 EXPECT_EQ(2u, offer2->contents().size());
723 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
724 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
725
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000726 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800727 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000728 f1_.CreateOffer(opts, offer2.get()));
729 ASSERT_TRUE(offer3.get() != NULL);
730 EXPECT_EQ(3u, offer3->contents().size());
731 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
732 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
733 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
734
735 // Verifies the default order is audio-video-data, so that the previous checks
736 // didn't pass by accident.
kwiberg31022942016-03-11 14:18:21 -0800737 std::unique_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000738 ASSERT_TRUE(offer4.get() != NULL);
739 EXPECT_EQ(3u, offer4->contents().size());
740 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
741 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
742 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
743}
744
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745// Create a typical audio answer, and ensure it matches what we expect.
746TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
747 f1_.set_secure(SEC_ENABLED);
748 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800749 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 f1_.CreateOffer(MediaSessionOptions(), NULL));
751 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800752 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
754 const ContentInfo* ac = answer->GetContentByName("audio");
755 const ContentInfo* vc = answer->GetContentByName("video");
756 ASSERT_TRUE(ac != NULL);
757 ASSERT_TRUE(vc == NULL);
758 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
759 const AudioContentDescription* acd =
760 static_cast<const AudioContentDescription*>(ac->description);
761 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
762 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
763 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
764 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
765 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
766 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
767 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
768}
769
770// Create a typical video answer, and ensure it matches what we expect.
771TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
772 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000773 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 f1_.set_secure(SEC_ENABLED);
775 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800776 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800778 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779 f2_.CreateAnswer(offer.get(), opts, NULL));
780 const ContentInfo* ac = answer->GetContentByName("audio");
781 const ContentInfo* vc = answer->GetContentByName("video");
782 ASSERT_TRUE(ac != NULL);
783 ASSERT_TRUE(vc != NULL);
784 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
785 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
786 const AudioContentDescription* acd =
787 static_cast<const AudioContentDescription*>(ac->description);
788 const VideoContentDescription* vcd =
789 static_cast<const VideoContentDescription*>(vc->description);
790 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
791 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
792 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
793 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
794 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
795 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
796 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
797 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
798 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
799 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
800 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
801 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
802}
803
804TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
805 MediaSessionOptions opts;
806 opts.data_channel_type = cricket::DCT_RTP;
807 f1_.set_secure(SEC_ENABLED);
808 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800809 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800811 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 f2_.CreateAnswer(offer.get(), opts, NULL));
813 const ContentInfo* ac = answer->GetContentByName("audio");
814 const ContentInfo* vc = answer->GetContentByName("data");
815 ASSERT_TRUE(ac != NULL);
816 ASSERT_TRUE(vc != NULL);
817 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
818 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
819 const AudioContentDescription* acd =
820 static_cast<const AudioContentDescription*>(ac->description);
821 const DataContentDescription* vcd =
822 static_cast<const DataContentDescription*>(vc->description);
823 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
824 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
825 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
826 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
827 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
828 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
829 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
830 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
831 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
832 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
833 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
834 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
835}
836
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000837// Verifies that the order of the media contents in the offer is preserved in
838// the answer.
839TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
840 MediaSessionOptions opts;
841
842 // Creates a data only offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000843 opts.recv_audio = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000844 opts.data_channel_type = cricket::DCT_SCTP;
kwiberg31022942016-03-11 14:18:21 -0800845 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000846 ASSERT_TRUE(offer1.get() != NULL);
847
848 // Appends audio to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000849 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800850 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000851 f1_.CreateOffer(opts, offer1.get()));
852 ASSERT_TRUE(offer2.get() != NULL);
853
854 // Appends video to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000855 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800856 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000857 f1_.CreateOffer(opts, offer2.get()));
858 ASSERT_TRUE(offer3.get() != NULL);
859
kwiberg31022942016-03-11 14:18:21 -0800860 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000861 f2_.CreateAnswer(offer3.get(), opts, NULL));
862 ASSERT_TRUE(answer.get() != NULL);
863 EXPECT_EQ(3u, answer->contents().size());
864 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
865 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
866 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
867}
868
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869// This test that the media direction is set to send/receive in an answer if
870// the offer is send receive.
871TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
872 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
873}
874
875// This test that the media direction is set to receive only in an answer if
876// the offer is send only.
877TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
878 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
879}
880
881// This test that the media direction is set to send only in an answer if
882// the offer is recv only.
883TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
884 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
885}
886
887// This test that the media direction is set to inactive in an answer if
888// the offer is inactive.
889TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
890 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
891}
892
893// Test that a data content with an unknown protocol is rejected in an answer.
894TEST_F(MediaSessionDescriptionFactoryTest,
895 CreateDataAnswerToOfferWithUnknownProtocol) {
896 MediaSessionOptions opts;
897 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000898 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 f1_.set_secure(SEC_ENABLED);
900 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800901 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 ContentInfo* dc_offer= offer->GetContentByName("data");
903 ASSERT_TRUE(dc_offer != NULL);
904 DataContentDescription* dcd_offer =
905 static_cast<DataContentDescription*>(dc_offer->description);
906 ASSERT_TRUE(dcd_offer != NULL);
907 std::string protocol = "a weird unknown protocol";
908 dcd_offer->set_protocol(protocol);
909
kwiberg31022942016-03-11 14:18:21 -0800910 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 f2_.CreateAnswer(offer.get(), opts, NULL));
912
913 const ContentInfo* dc_answer = answer->GetContentByName("data");
914 ASSERT_TRUE(dc_answer != NULL);
915 EXPECT_TRUE(dc_answer->rejected);
916 const DataContentDescription* dcd_answer =
917 static_cast<const DataContentDescription*>(dc_answer->description);
918 ASSERT_TRUE(dcd_answer != NULL);
919 EXPECT_EQ(protocol, dcd_answer->protocol());
920}
921
922// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
923TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
924 MediaSessionOptions opts;
925 f1_.set_secure(SEC_DISABLED);
926 f2_.set_secure(SEC_DISABLED);
927 tdf1_.set_secure(SEC_DISABLED);
928 tdf2_.set_secure(SEC_DISABLED);
929
kwiberg31022942016-03-11 14:18:21 -0800930 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 const AudioContentDescription* offer_acd =
932 GetFirstAudioContentDescription(offer.get());
933 ASSERT_TRUE(offer_acd != NULL);
934 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
935
kwiberg31022942016-03-11 14:18:21 -0800936 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 f2_.CreateAnswer(offer.get(), opts, NULL));
938
939 const ContentInfo* ac_answer = answer->GetContentByName("audio");
940 ASSERT_TRUE(ac_answer != NULL);
941 EXPECT_FALSE(ac_answer->rejected);
942
943 const AudioContentDescription* answer_acd =
944 GetFirstAudioContentDescription(answer.get());
945 ASSERT_TRUE(answer_acd != NULL);
946 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
947}
948
949// Create a video offer and answer and ensure the RTP header extensions
950// matches what we expect.
951TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
952 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000953 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000954
955 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
956 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
957 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
958 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
959
kwiberg31022942016-03-11 14:18:21 -0800960 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800962 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000963 f2_.CreateAnswer(offer.get(), opts, NULL));
964
965 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
966 GetFirstAudioContentDescription(
967 offer.get())->rtp_header_extensions());
968 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
969 GetFirstVideoContentDescription(
970 offer.get())->rtp_header_extensions());
971 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
972 GetFirstAudioContentDescription(
973 answer.get())->rtp_header_extensions());
974 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
975 GetFirstVideoContentDescription(
976 answer.get())->rtp_header_extensions());
977}
978
979// Create an audio, video, data answer without legacy StreamParams.
980TEST_F(MediaSessionDescriptionFactoryTest,
981 TestCreateAnswerWithoutLegacyStreams) {
982 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000983 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984 opts.data_channel_type = cricket::DCT_RTP;
985 f1_.set_add_legacy_streams(false);
986 f2_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800987 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800989 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 f2_.CreateAnswer(offer.get(), opts, NULL));
991 const ContentInfo* ac = answer->GetContentByName("audio");
992 const ContentInfo* vc = answer->GetContentByName("video");
993 const ContentInfo* dc = answer->GetContentByName("data");
994 ASSERT_TRUE(ac != NULL);
995 ASSERT_TRUE(vc != NULL);
996 const AudioContentDescription* acd =
997 static_cast<const AudioContentDescription*>(ac->description);
998 const VideoContentDescription* vcd =
999 static_cast<const VideoContentDescription*>(vc->description);
1000 const DataContentDescription* dcd =
1001 static_cast<const DataContentDescription*>(dc->description);
1002
1003 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1004 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1005 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1006}
1007
1008TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1009 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001010 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001011 opts.data_channel_type = cricket::DCT_RTP;
1012 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001013 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001014 ASSERT_TRUE(offer.get() != NULL);
1015 const ContentInfo* ac = offer->GetContentByName("audio");
1016 const ContentInfo* vc = offer->GetContentByName("video");
1017 const ContentInfo* dc = offer->GetContentByName("data");
1018 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1019 static_cast<const AudioContentDescription*>(ac->description));
1020 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1021 static_cast<const VideoContentDescription*>(vc->description));
1022 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1023 static_cast<const DataContentDescription*>(dc->description));
1024
1025 EXPECT_FALSE(acd->partial()); // default is false.
1026 acd->set_partial(true);
1027 EXPECT_TRUE(acd->partial());
1028 acd->set_partial(false);
1029 EXPECT_FALSE(acd->partial());
1030
1031 EXPECT_FALSE(vcd->partial()); // default is false.
1032 vcd->set_partial(true);
1033 EXPECT_TRUE(vcd->partial());
1034 vcd->set_partial(false);
1035 EXPECT_FALSE(vcd->partial());
1036
1037 EXPECT_FALSE(dcd->partial()); // default is false.
1038 dcd->set_partial(true);
1039 EXPECT_TRUE(dcd->partial());
1040 dcd->set_partial(false);
1041 EXPECT_FALSE(dcd->partial());
1042}
1043
1044// Create a typical video answer, and ensure it matches what we expect.
1045TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1046 MediaSessionOptions offer_opts;
1047 MediaSessionOptions answer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001048 answer_opts.recv_video = true;
1049 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050 answer_opts.data_channel_type = cricket::DCT_RTP;
1051 offer_opts.data_channel_type = cricket::DCT_RTP;
1052
kwiberg31022942016-03-11 14:18:21 -08001053 std::unique_ptr<SessionDescription> offer;
1054 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055
1056 offer_opts.rtcp_mux_enabled = true;
1057 answer_opts.rtcp_mux_enabled = true;
1058
1059 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1060 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1061 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1062 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1063 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1064 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1065 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1066 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1067 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1068 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1069 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1070 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1071 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1072 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1073
1074 offer_opts.rtcp_mux_enabled = true;
1075 answer_opts.rtcp_mux_enabled = false;
1076
1077 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1078 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1079 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1080 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1081 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1082 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1083 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1084 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1085 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1086 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1087 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1088 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1089 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1090 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1091
1092 offer_opts.rtcp_mux_enabled = false;
1093 answer_opts.rtcp_mux_enabled = true;
1094
1095 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1096 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1097 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1098 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1099 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1100 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1101 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1102 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1103 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1104 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1105 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1106 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1107 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1108 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1109
1110 offer_opts.rtcp_mux_enabled = false;
1111 answer_opts.rtcp_mux_enabled = false;
1112
1113 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1114 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1115 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1116 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1117 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1118 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1119 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1120 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1121 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1122 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1123 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1124 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1125 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1126 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1127}
1128
1129// Create an audio-only answer to a video offer.
1130TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1131 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001132 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001133 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001135 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1137 const ContentInfo* ac = answer->GetContentByName("audio");
1138 const ContentInfo* vc = answer->GetContentByName("video");
1139 ASSERT_TRUE(ac != NULL);
1140 ASSERT_TRUE(vc != NULL);
1141 ASSERT_TRUE(vc->description != NULL);
1142 EXPECT_TRUE(vc->rejected);
1143}
1144
1145// Create an audio-only answer to an offer with data.
1146TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1147 MediaSessionOptions opts;
1148 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001149 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001150 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001151 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1153 const ContentInfo* ac = answer->GetContentByName("audio");
1154 const ContentInfo* dc = answer->GetContentByName("data");
1155 ASSERT_TRUE(ac != NULL);
1156 ASSERT_TRUE(dc != NULL);
1157 ASSERT_TRUE(dc->description != NULL);
1158 EXPECT_TRUE(dc->rejected);
1159}
1160
1161// Create an answer that rejects the contents which are rejected in the offer.
1162TEST_F(MediaSessionDescriptionFactoryTest,
1163 CreateAnswerToOfferWithRejectedMedia) {
1164 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001165 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001166 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001167 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001168 ASSERT_TRUE(offer.get() != NULL);
1169 ContentInfo* ac = offer->GetContentByName("audio");
1170 ContentInfo* vc = offer->GetContentByName("video");
1171 ContentInfo* dc = offer->GetContentByName("data");
1172 ASSERT_TRUE(ac != NULL);
1173 ASSERT_TRUE(vc != NULL);
1174 ASSERT_TRUE(dc != NULL);
1175 ac->rejected = true;
1176 vc->rejected = true;
1177 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001178 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001179 f2_.CreateAnswer(offer.get(), opts, NULL));
1180 ac = answer->GetContentByName("audio");
1181 vc = answer->GetContentByName("video");
1182 dc = answer->GetContentByName("data");
1183 ASSERT_TRUE(ac != NULL);
1184 ASSERT_TRUE(vc != NULL);
1185 ASSERT_TRUE(dc != NULL);
1186 EXPECT_TRUE(ac->rejected);
1187 EXPECT_TRUE(vc->rejected);
1188 EXPECT_TRUE(dc->rejected);
1189}
1190
1191// Create an audio and video offer with:
1192// - one video track
1193// - two audio tracks
1194// - two data tracks
1195// and ensure it matches what we expect. Also updates the initial offer by
1196// adding a new video track and replaces one of the audio tracks.
1197TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1198 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001199 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1200 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1201 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001203 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1204 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205
1206 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001207 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208
1209 ASSERT_TRUE(offer.get() != NULL);
1210 const ContentInfo* ac = offer->GetContentByName("audio");
1211 const ContentInfo* vc = offer->GetContentByName("video");
1212 const ContentInfo* dc = offer->GetContentByName("data");
1213 ASSERT_TRUE(ac != NULL);
1214 ASSERT_TRUE(vc != NULL);
1215 ASSERT_TRUE(dc != NULL);
1216 const AudioContentDescription* acd =
1217 static_cast<const AudioContentDescription*>(ac->description);
1218 const VideoContentDescription* vcd =
1219 static_cast<const VideoContentDescription*>(vc->description);
1220 const DataContentDescription* dcd =
1221 static_cast<const DataContentDescription*>(dc->description);
1222 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1223 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1224
1225 const StreamParamsVec& audio_streams = acd->streams();
1226 ASSERT_EQ(2U, audio_streams.size());
1227 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1228 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1229 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1230 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1231 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1232 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1233 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1234
1235 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1236 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1237 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1238
1239 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1240 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1241 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1242
1243 const StreamParamsVec& video_streams = vcd->streams();
1244 ASSERT_EQ(1U, video_streams.size());
1245 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1246 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1247 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1248 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1249
1250 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1251 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1252 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1253
1254 const StreamParamsVec& data_streams = dcd->streams();
1255 ASSERT_EQ(2U, data_streams.size());
1256 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1257 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1258 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1259 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1260 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1261 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1262 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1263
1264 EXPECT_EQ(cricket::kDataMaxBandwidth,
1265 dcd->bandwidth()); // default bandwidth (auto)
1266 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1267 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1268
1269
1270 // Update the offer. Add a new video track that is not synched to the
1271 // other tracks and replace audio track 2 with audio track 3.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001272 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1273 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1274 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1275 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1276 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
kwiberg31022942016-03-11 14:18:21 -08001277 std::unique_ptr<SessionDescription> updated_offer(
1278 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001279
1280 ASSERT_TRUE(updated_offer.get() != NULL);
1281 ac = updated_offer->GetContentByName("audio");
1282 vc = updated_offer->GetContentByName("video");
1283 dc = updated_offer->GetContentByName("data");
1284 ASSERT_TRUE(ac != NULL);
1285 ASSERT_TRUE(vc != NULL);
1286 ASSERT_TRUE(dc != NULL);
1287 const AudioContentDescription* updated_acd =
1288 static_cast<const AudioContentDescription*>(ac->description);
1289 const VideoContentDescription* updated_vcd =
1290 static_cast<const VideoContentDescription*>(vc->description);
1291 const DataContentDescription* updated_dcd =
1292 static_cast<const DataContentDescription*>(dc->description);
1293
1294 EXPECT_EQ(acd->type(), updated_acd->type());
1295 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1296 EXPECT_EQ(vcd->type(), updated_vcd->type());
1297 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1298 EXPECT_EQ(dcd->type(), updated_dcd->type());
1299 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1300 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1301 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1302 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1303 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1304 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1305 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1306
1307 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1308 ASSERT_EQ(2U, updated_audio_streams.size());
1309 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1310 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1311 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1312 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1313 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1314
1315 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1316 ASSERT_EQ(2U, updated_video_streams.size());
1317 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1318 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1319 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1320
1321 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1322 ASSERT_EQ(2U, updated_data_streams.size());
1323 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1324 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1325 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1326 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1327 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
1328}
1329
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001330// Create an offer with simulcast video stream.
1331TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1332 MediaSessionOptions opts;
1333 const int num_sim_layers = 3;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001334 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
kwiberg31022942016-03-11 14:18:21 -08001335 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001336
1337 ASSERT_TRUE(offer.get() != NULL);
1338 const ContentInfo* vc = offer->GetContentByName("video");
1339 ASSERT_TRUE(vc != NULL);
1340 const VideoContentDescription* vcd =
1341 static_cast<const VideoContentDescription*>(vc->description);
1342
1343 const StreamParamsVec& video_streams = vcd->streams();
1344 ASSERT_EQ(1U, video_streams.size());
1345 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1346 const SsrcGroup* sim_ssrc_group =
1347 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1348 ASSERT_TRUE(sim_ssrc_group != NULL);
1349 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1350}
1351
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352// Create an audio and video answer to a standard video offer with:
1353// - one video track
1354// - two audio tracks
1355// - two data tracks
1356// and ensure it matches what we expect. Also updates the initial answer by
1357// adding a new video track and removes one of the audio tracks.
1358TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1359 MediaSessionOptions offer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001360 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001361 offer_opts.data_channel_type = cricket::DCT_RTP;
1362 f1_.set_secure(SEC_ENABLED);
1363 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001364 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001365
1366 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001367 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1368 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1369 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001370 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001371 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1372 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001373
kwiberg31022942016-03-11 14:18:21 -08001374 std::unique_ptr<SessionDescription> answer(
1375 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001376
1377 ASSERT_TRUE(answer.get() != NULL);
1378 const ContentInfo* ac = answer->GetContentByName("audio");
1379 const ContentInfo* vc = answer->GetContentByName("video");
1380 const ContentInfo* dc = answer->GetContentByName("data");
1381 ASSERT_TRUE(ac != NULL);
1382 ASSERT_TRUE(vc != NULL);
1383 ASSERT_TRUE(dc != NULL);
1384 const AudioContentDescription* acd =
1385 static_cast<const AudioContentDescription*>(ac->description);
1386 const VideoContentDescription* vcd =
1387 static_cast<const VideoContentDescription*>(vc->description);
1388 const DataContentDescription* dcd =
1389 static_cast<const DataContentDescription*>(dc->description);
1390 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1391 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1392 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1393
1394 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1395 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1396
1397 const StreamParamsVec& audio_streams = acd->streams();
1398 ASSERT_EQ(2U, audio_streams.size());
1399 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1400 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1401 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1402 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1403 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1404 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1405 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1406
1407 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1408 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1409
1410 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1411 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1412
1413 const StreamParamsVec& video_streams = vcd->streams();
1414 ASSERT_EQ(1U, video_streams.size());
1415 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1416 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1417 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1418 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1419
1420 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1421 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1422
1423 const StreamParamsVec& data_streams = dcd->streams();
1424 ASSERT_EQ(2U, data_streams.size());
1425 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1426 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1427 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1428 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1429 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1430 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1431 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1432
1433 EXPECT_EQ(cricket::kDataMaxBandwidth,
1434 dcd->bandwidth()); // default bandwidth (auto)
1435 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1436
1437 // Update the answer. Add a new video track that is not synched to the
1438 // other traacks and remove 1 audio track.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001439 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1440 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1441 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
kwiberg31022942016-03-11 14:18:21 -08001442 std::unique_ptr<SessionDescription> updated_answer(
1443 f2_.CreateAnswer(offer.get(), opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001444
1445 ASSERT_TRUE(updated_answer.get() != NULL);
1446 ac = updated_answer->GetContentByName("audio");
1447 vc = updated_answer->GetContentByName("video");
1448 dc = updated_answer->GetContentByName("data");
1449 ASSERT_TRUE(ac != NULL);
1450 ASSERT_TRUE(vc != NULL);
1451 ASSERT_TRUE(dc != NULL);
1452 const AudioContentDescription* updated_acd =
1453 static_cast<const AudioContentDescription*>(ac->description);
1454 const VideoContentDescription* updated_vcd =
1455 static_cast<const VideoContentDescription*>(vc->description);
1456 const DataContentDescription* updated_dcd =
1457 static_cast<const DataContentDescription*>(dc->description);
1458
1459 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1460 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1461 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1462 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1463 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1464 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1465
1466 EXPECT_EQ(acd->type(), updated_acd->type());
1467 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1468 EXPECT_EQ(vcd->type(), updated_vcd->type());
1469 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1470 EXPECT_EQ(dcd->type(), updated_dcd->type());
1471 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1472
1473 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1474 ASSERT_EQ(1U, updated_audio_streams.size());
1475 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1476
1477 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1478 ASSERT_EQ(2U, updated_video_streams.size());
1479 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1480 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1481 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1482
1483 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1484 ASSERT_EQ(1U, updated_data_streams.size());
1485 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1486}
1487
1488
1489// Create an updated offer after creating an answer to the original offer and
1490// verify that the codecs that were part of the original answer are not changed
1491// in the updated offer.
1492TEST_F(MediaSessionDescriptionFactoryTest,
1493 RespondentCreatesOfferAfterCreatingAnswer) {
1494 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001495 opts.recv_audio = true;
1496 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001497
kwiberg31022942016-03-11 14:18:21 -08001498 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1499 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001500 f2_.CreateAnswer(offer.get(), opts, NULL));
1501
1502 const AudioContentDescription* acd =
1503 GetFirstAudioContentDescription(answer.get());
1504 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1505
1506 const VideoContentDescription* vcd =
1507 GetFirstVideoContentDescription(answer.get());
1508 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1509
kwiberg31022942016-03-11 14:18:21 -08001510 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511 f2_.CreateOffer(opts, answer.get()));
1512
1513 // The expected audio codecs are the common audio codecs from the first
1514 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1515 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001516 // TODO(wu): |updated_offer| should not include the codec
1517 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519 kAudioCodecsAnswer[0],
1520 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001521 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001522 };
1523
1524 // The expected video codecs are the common video codecs from the first
1525 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1526 // preference order.
1527 const VideoCodec kUpdatedVideoCodecOffer[] = {
1528 kVideoCodecsAnswer[0],
1529 kVideoCodecs2[1],
1530 };
1531
1532 const AudioContentDescription* updated_acd =
1533 GetFirstAudioContentDescription(updated_offer.get());
1534 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1535
1536 const VideoContentDescription* updated_vcd =
1537 GetFirstVideoContentDescription(updated_offer.get());
1538 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1539}
1540
1541// Create an updated offer after creating an answer to the original offer and
1542// verify that the codecs that were part of the original answer are not changed
1543// in the updated offer. In this test Rtx is enabled.
1544TEST_F(MediaSessionDescriptionFactoryTest,
1545 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1546 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001547 opts.recv_video = true;
1548 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001551 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001552 f1_.set_video_codecs(f1_codecs);
1553
1554 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001555 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001556 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001557 f2_.set_video_codecs(f2_codecs);
1558
kwiberg31022942016-03-11 14:18:21 -08001559 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001561 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001562 f2_.CreateAnswer(offer.get(), opts, NULL));
1563
1564 const VideoContentDescription* vcd =
1565 GetFirstVideoContentDescription(answer.get());
1566
1567 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001568 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1569 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570
1571 EXPECT_EQ(expected_codecs, vcd->codecs());
1572
1573 // Now, make sure we get same result, except for the preference order,
1574 // if |f2_| creates an updated offer even though the default payload types
1575 // are different from |f1_|.
1576 expected_codecs[0].preference = f1_codecs[1].preference;
1577
kwiberg31022942016-03-11 14:18:21 -08001578 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579 f2_.CreateOffer(opts, answer.get()));
1580 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001581 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1583
1584 const VideoContentDescription* updated_vcd =
1585 GetFirstVideoContentDescription(updated_answer.get());
1586
1587 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1588}
1589
1590// Create an updated offer that adds video after creating an audio only answer
1591// to the original offer. This test verifies that if a video codec and the RTX
1592// codec have the same default payload type as an audio codec that is already in
1593// use, the added codecs payload types are changed.
1594TEST_F(MediaSessionDescriptionFactoryTest,
1595 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1596 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001598 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599 f1_.set_video_codecs(f1_codecs);
1600
1601 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001602 opts.recv_audio = true;
1603 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604
kwiberg31022942016-03-11 14:18:21 -08001605 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1606 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607 f2_.CreateAnswer(offer.get(), opts, NULL));
1608
1609 const AudioContentDescription* acd =
1610 GetFirstAudioContentDescription(answer.get());
1611 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1612
1613 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1614 // reference be the same as an audio codec that was negotiated in the
1615 // first offer/answer exchange.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001616 opts.recv_audio = true;
1617 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618
1619 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1620 int used_pl_type = acd->codecs()[0].id;
1621 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001622 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623 f2_.set_video_codecs(f2_codecs);
1624
kwiberg31022942016-03-11 14:18:21 -08001625 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626 f2_.CreateOffer(opts, answer.get()));
1627 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001628 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001629 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1630
1631 const AudioContentDescription* updated_acd =
1632 GetFirstAudioContentDescription(answer.get());
1633 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1634
1635 const VideoContentDescription* updated_vcd =
1636 GetFirstVideoContentDescription(updated_answer.get());
1637
1638 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001639 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1641 EXPECT_NE(used_pl_type, new_h264_pl_type);
1642 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001643 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001644 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1645 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1646}
1647
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001648// Create an updated offer with RTX after creating an answer to an offer
1649// without RTX, and with different default payload types.
1650// Verify that the added RTX codec references the correct payload type.
1651TEST_F(MediaSessionDescriptionFactoryTest,
1652 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
1653 MediaSessionOptions opts;
1654 opts.recv_video = true;
1655 opts.recv_audio = true;
1656
1657 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1658 // This creates rtx for H264 with the payload type |f2_| uses.
1659 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1660 f2_.set_video_codecs(f2_codecs);
1661
kwiberg31022942016-03-11 14:18:21 -08001662 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001663 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08001664 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001665 f2_.CreateAnswer(offer.get(), opts, nullptr));
1666
1667 const VideoContentDescription* vcd =
1668 GetFirstVideoContentDescription(answer.get());
1669
1670 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1671 EXPECT_EQ(expected_codecs, vcd->codecs());
1672
1673 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
1674 // updated offer, even though the default payload types are different from
1675 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08001676 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001677 f2_.CreateOffer(opts, answer.get()));
1678 ASSERT_TRUE(updated_offer);
1679
1680 const VideoContentDescription* updated_vcd =
1681 GetFirstVideoContentDescription(updated_offer.get());
1682
1683 // New offer should attempt to add H263, and RTX for H264.
1684 expected_codecs.push_back(kVideoCodecs2[1]);
1685 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
1686 &expected_codecs);
1687 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1688}
1689
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001690// Test that RTX is ignored when there is no associated payload type parameter.
1691TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1692 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001693 opts.recv_video = true;
1694 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001695 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001696 // This creates RTX without associated payload type parameter.
1697 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName, 0, 0, 0, 0), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698 f1_.set_video_codecs(f1_codecs);
1699
1700 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001701 // This creates RTX for H264 with the payload type |f2_| uses.
1702 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001703 f2_.set_video_codecs(f2_codecs);
1704
kwiberg31022942016-03-11 14:18:21 -08001705 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706 ASSERT_TRUE(offer.get() != NULL);
1707 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1708 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1709 // is possible to test that that RTX is dropped when
1710 // kCodecParamAssociatedPayloadType is missing in the offer.
1711 VideoContentDescription* desc =
1712 static_cast<cricket::VideoContentDescription*>(
1713 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1714 ASSERT_TRUE(desc != NULL);
1715 std::vector<VideoCodec> codecs = desc->codecs();
1716 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1717 iter != codecs.end(); ++iter) {
1718 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1719 iter->params.clear();
1720 }
1721 }
1722 desc->set_codecs(codecs);
1723
kwiberg31022942016-03-11 14:18:21 -08001724 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001725 f2_.CreateAnswer(offer.get(), opts, NULL));
1726
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001727 std::vector<std::string> codec_names =
1728 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1729 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1730 cricket::kRtxCodecName));
1731}
1732
1733// Test that RTX will be filtered out in the answer if its associated payload
1734// type doesn't match the local value.
1735TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1736 MediaSessionOptions opts;
1737 opts.recv_video = true;
1738 opts.recv_audio = false;
1739 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1740 // This creates RTX for H264 in sender.
1741 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1742 f1_.set_video_codecs(f1_codecs);
1743
1744 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1745 // This creates RTX for H263 in receiver.
1746 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1747 f2_.set_video_codecs(f2_codecs);
1748
kwiberg31022942016-03-11 14:18:21 -08001749 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001750 ASSERT_TRUE(offer.get() != NULL);
1751 // Associated payload type doesn't match, therefore, RTX codec is removed in
1752 // the answer.
kwiberg31022942016-03-11 14:18:21 -08001753 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001754 f2_.CreateAnswer(offer.get(), opts, NULL));
1755
1756 std::vector<std::string> codec_names =
1757 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1758 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1759 cricket::kRtxCodecName));
1760}
1761
1762// Test that when multiple RTX codecs are offered, only the matched RTX codec
1763// is added in the answer, and the unsupported RTX codec is filtered out.
1764TEST_F(MediaSessionDescriptionFactoryTest,
1765 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1766 MediaSessionOptions opts;
1767 opts.recv_video = true;
1768 opts.recv_audio = false;
1769 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1770 // This creates RTX for H264-SVC in sender.
1771 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1772 f1_.set_video_codecs(f1_codecs);
1773
1774 // This creates RTX for H264 in sender.
1775 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1776 f1_.set_video_codecs(f1_codecs);
1777
1778 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1779 // This creates RTX for H264 in receiver.
1780 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1781 f2_.set_video_codecs(f2_codecs);
1782
1783 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1784 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08001785 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001786 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001787 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001788 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001789 const VideoContentDescription* vcd =
1790 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001791 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1792 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1793 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001794
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001795 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001796}
1797
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001798// Test that after one RTX codec has been negotiated, a new offer can attempt
1799// to add another.
1800TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
1801 MediaSessionOptions opts;
1802 opts.recv_video = true;
1803 opts.recv_audio = false;
1804 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1805 // This creates RTX for H264 for the offerer.
1806 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1807 f1_.set_video_codecs(f1_codecs);
1808
kwiberg31022942016-03-11 14:18:21 -08001809 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001810 ASSERT_TRUE(offer);
1811 const VideoContentDescription* vcd =
1812 GetFirstVideoContentDescription(offer.get());
1813
1814 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
1815 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1816 &expected_codecs);
1817 EXPECT_EQ(expected_codecs, vcd->codecs());
1818
1819 // Now, attempt to add RTX for H264-SVC.
1820 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1821 f1_.set_video_codecs(f1_codecs);
1822
kwiberg31022942016-03-11 14:18:21 -08001823 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001824 f1_.CreateOffer(opts, offer.get()));
1825 ASSERT_TRUE(updated_offer);
1826 vcd = GetFirstVideoContentDescription(updated_offer.get());
1827
1828 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
1829 &expected_codecs);
1830 EXPECT_EQ(expected_codecs, vcd->codecs());
1831}
1832
Noah Richards2e7a0982015-05-18 14:02:54 -07001833// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1834// generated for each simulcast ssrc and correctly grouped.
1835TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1836 MediaSessionOptions opts;
1837 opts.recv_video = true;
1838 opts.recv_audio = false;
1839
1840 // Add simulcast streams.
1841 opts.AddSendVideoStream("stream1", "stream1label", 3);
1842
1843 // Use a single real codec, and then add RTX for it.
1844 std::vector<VideoCodec> f1_codecs;
1845 f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30, 1));
1846 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1847 f1_.set_video_codecs(f1_codecs);
1848
1849 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1850 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08001851 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07001852 ASSERT_TRUE(offer.get() != NULL);
1853 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
1854 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1855 ASSERT_TRUE(desc != NULL);
1856 EXPECT_TRUE(desc->multistream());
1857 const StreamParamsVec& streams = desc->streams();
1858 // Single stream.
1859 ASSERT_EQ(1u, streams.size());
1860 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
1861 EXPECT_EQ(6u, streams[0].ssrcs.size());
1862 // And should have a SIM group for the simulcast.
1863 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
1864 // And a FID group for RTX.
1865 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02001866 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07001867 streams[0].GetPrimarySsrcs(&primary_ssrcs);
1868 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02001869 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07001870 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
1871 EXPECT_EQ(3u, fid_ssrcs.size());
1872}
1873
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001874// Create an updated offer after creating an answer to the original offer and
1875// verify that the RTP header extensions that were part of the original answer
1876// are not changed in the updated offer.
1877TEST_F(MediaSessionDescriptionFactoryTest,
1878 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1879 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001880 opts.recv_audio = true;
1881 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001882
1883 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1884 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1885 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1886 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1887
kwiberg31022942016-03-11 14:18:21 -08001888 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1889 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001890 f2_.CreateAnswer(offer.get(), opts, NULL));
1891
1892 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1893 GetFirstAudioContentDescription(
1894 answer.get())->rtp_header_extensions());
1895 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1896 GetFirstVideoContentDescription(
1897 answer.get())->rtp_header_extensions());
1898
kwiberg31022942016-03-11 14:18:21 -08001899 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001900 f2_.CreateOffer(opts, answer.get()));
1901
1902 // The expected RTP header extensions in the new offer are the resulting
1903 // extensions from the first offer/answer exchange plus the extensions only
1904 // |f2_| offer.
1905 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001906 // |f1_| for another extensions, it is changed to 13.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001907 const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1908 kAudioRtpExtensionAnswer[0],
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001909 RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
1910 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911 };
1912
1913 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001914 // |f1_| for another extensions, is is changed to 12.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915 const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1916 kVideoRtpExtensionAnswer[0],
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001917 RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
1918 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 };
1920
1921 const AudioContentDescription* updated_acd =
1922 GetFirstAudioContentDescription(updated_offer.get());
1923 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1924 updated_acd->rtp_header_extensions());
1925
1926 const VideoContentDescription* updated_vcd =
1927 GetFirstVideoContentDescription(updated_offer.get());
1928 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1929 updated_vcd->rtp_header_extensions());
1930}
1931
deadbeefa5b273a2015-08-20 17:30:13 -07001932// Verify that if the same RTP extension URI is used for audio and video, the
1933// same ID is used. Also verify that the ID isn't changed when creating an
1934// updated offer (this was previously a bug).
1935TEST_F(MediaSessionDescriptionFactoryTest,
1936 RtpHeaderExtensionIdReused) {
1937 MediaSessionOptions opts;
1938 opts.recv_audio = true;
1939 opts.recv_video = true;
1940
1941 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
1942 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
1943
kwiberg31022942016-03-11 14:18:21 -08001944 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07001945
1946 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
1947 // the video extensions.
1948 const RtpHeaderExtension kExpectedVideoRtpExtension[] = {
1949 kVideoRtpExtension3[0],
1950 kAudioRtpExtension3[1],
1951 };
1952
1953 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1954 GetFirstAudioContentDescription(
1955 offer.get())->rtp_header_extensions());
1956 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1957 GetFirstVideoContentDescription(
1958 offer.get())->rtp_header_extensions());
1959
1960 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08001961 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07001962 f1_.CreateOffer(opts, offer.get()));
1963
1964 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1965 GetFirstAudioContentDescription(
1966 updated_offer.get())->rtp_header_extensions());
1967 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1968 GetFirstVideoContentDescription(
1969 updated_offer.get())->rtp_header_extensions());
1970}
1971
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001972TEST(MediaSessionDescription, CopySessionDescription) {
1973 SessionDescription source;
1974 cricket::ContentGroup group(cricket::CN_AUDIO);
1975 source.AddGroup(group);
1976 AudioContentDescription* acd(new AudioContentDescription());
1977 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1978 acd->AddLegacyStream(1);
1979 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1980 VideoContentDescription* vcd(new VideoContentDescription());
1981 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1982 vcd->AddLegacyStream(2);
1983 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1984
kwiberg31022942016-03-11 14:18:21 -08001985 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001986 ASSERT_TRUE(copy.get() != NULL);
1987 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1988 const ContentInfo* ac = copy->GetContentByName("audio");
1989 const ContentInfo* vc = copy->GetContentByName("video");
1990 ASSERT_TRUE(ac != NULL);
1991 ASSERT_TRUE(vc != NULL);
1992 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1993 const AudioContentDescription* acd_copy =
1994 static_cast<const AudioContentDescription*>(ac->description);
1995 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1996 EXPECT_EQ(1u, acd->first_ssrc());
1997
1998 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1999 const VideoContentDescription* vcd_copy =
2000 static_cast<const VideoContentDescription*>(vc->description);
2001 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2002 EXPECT_EQ(2u, vcd->first_ssrc());
2003}
2004
2005// The below TestTransportInfoXXX tests create different offers/answers, and
2006// ensure the TransportInfo in the SessionDescription matches what we expect.
2007TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2008 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002009 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010 TestTransportInfo(true, options, false);
2011}
2012
2013TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2014 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002015 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002016 TestTransportInfo(true, options, true);
2017}
2018
2019TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2020 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002021 options.recv_audio = true;
2022 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002023 options.data_channel_type = cricket::DCT_RTP;
2024 TestTransportInfo(true, options, false);
2025}
2026
2027TEST_F(MediaSessionDescriptionFactoryTest,
2028 TestTransportInfoOfferMultimediaCurrent) {
2029 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002030 options.recv_audio = true;
2031 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032 options.data_channel_type = cricket::DCT_RTP;
2033 TestTransportInfo(true, options, true);
2034}
2035
2036TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2037 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002038 options.recv_audio = true;
2039 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002040 options.data_channel_type = cricket::DCT_RTP;
2041 options.bundle_enabled = true;
2042 TestTransportInfo(true, options, false);
2043}
2044
2045TEST_F(MediaSessionDescriptionFactoryTest,
2046 TestTransportInfoOfferBundleCurrent) {
2047 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002048 options.recv_audio = true;
2049 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002050 options.data_channel_type = cricket::DCT_RTP;
2051 options.bundle_enabled = true;
2052 TestTransportInfo(true, options, true);
2053}
2054
2055TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2056 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002057 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058 TestTransportInfo(false, options, false);
2059}
2060
2061TEST_F(MediaSessionDescriptionFactoryTest,
2062 TestTransportInfoAnswerAudioCurrent) {
2063 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002064 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 TestTransportInfo(false, options, true);
2066}
2067
2068TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2069 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002070 options.recv_audio = true;
2071 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072 options.data_channel_type = cricket::DCT_RTP;
2073 TestTransportInfo(false, options, false);
2074}
2075
2076TEST_F(MediaSessionDescriptionFactoryTest,
2077 TestTransportInfoAnswerMultimediaCurrent) {
2078 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002079 options.recv_audio = true;
2080 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081 options.data_channel_type = cricket::DCT_RTP;
2082 TestTransportInfo(false, options, true);
2083}
2084
2085TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2086 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002087 options.recv_audio = true;
2088 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002089 options.data_channel_type = cricket::DCT_RTP;
2090 options.bundle_enabled = true;
2091 TestTransportInfo(false, options, false);
2092}
2093
2094TEST_F(MediaSessionDescriptionFactoryTest,
2095 TestTransportInfoAnswerBundleCurrent) {
2096 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002097 options.recv_audio = true;
2098 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002099 options.data_channel_type = cricket::DCT_RTP;
2100 options.bundle_enabled = true;
2101 TestTransportInfo(false, options, true);
2102}
2103
2104// Create an offer with bundle enabled and verify the crypto parameters are
2105// the common set of the available cryptos.
2106TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2107 TestCryptoWithBundle(true);
2108}
2109
2110// Create an answer with bundle enabled and verify the crypto parameters are
2111// the common set of the available cryptos.
2112TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2113 TestCryptoWithBundle(false);
2114}
2115
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002116// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2117// DTLS is not enabled locally.
2118TEST_F(MediaSessionDescriptionFactoryTest,
2119 TestOfferDtlsSavpfWithoutDtlsFailed) {
2120 f1_.set_secure(SEC_ENABLED);
2121 f2_.set_secure(SEC_ENABLED);
2122 tdf1_.set_secure(SEC_DISABLED);
2123 tdf2_.set_secure(SEC_DISABLED);
2124
kwiberg31022942016-03-11 14:18:21 -08002125 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002126 f1_.CreateOffer(MediaSessionOptions(), NULL));
2127 ASSERT_TRUE(offer.get() != NULL);
2128 ContentInfo* offer_content = offer->GetContentByName("audio");
2129 ASSERT_TRUE(offer_content != NULL);
2130 AudioContentDescription* offer_audio_desc =
2131 static_cast<AudioContentDescription*>(offer_content->description);
2132 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2133
kwiberg31022942016-03-11 14:18:21 -08002134 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002135 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2136 ASSERT_TRUE(answer != NULL);
2137 ContentInfo* answer_content = answer->GetContentByName("audio");
2138 ASSERT_TRUE(answer_content != NULL);
2139
2140 ASSERT_TRUE(answer_content->rejected);
2141}
2142
2143// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2144// UDP/TLS/RTP/SAVPF.
2145TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2146 f1_.set_secure(SEC_ENABLED);
2147 f2_.set_secure(SEC_ENABLED);
2148 tdf1_.set_secure(SEC_ENABLED);
2149 tdf2_.set_secure(SEC_ENABLED);
2150
kwiberg31022942016-03-11 14:18:21 -08002151 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002152 f1_.CreateOffer(MediaSessionOptions(), NULL));
2153 ASSERT_TRUE(offer.get() != NULL);
2154 ContentInfo* offer_content = offer->GetContentByName("audio");
2155 ASSERT_TRUE(offer_content != NULL);
2156 AudioContentDescription* offer_audio_desc =
2157 static_cast<AudioContentDescription*>(offer_content->description);
2158 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2159
kwiberg31022942016-03-11 14:18:21 -08002160 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002161 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2162 ASSERT_TRUE(answer != NULL);
2163
2164 const ContentInfo* answer_content = answer->GetContentByName("audio");
2165 ASSERT_TRUE(answer_content != NULL);
2166 ASSERT_FALSE(answer_content->rejected);
2167
2168 const AudioContentDescription* answer_audio_desc =
2169 static_cast<const AudioContentDescription*>(answer_content->description);
2170 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2171 answer_audio_desc->protocol());
2172}
2173
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174// Test that we include both SDES and DTLS in the offer, but only include SDES
2175// in the answer if DTLS isn't negotiated.
2176TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2177 f1_.set_secure(SEC_ENABLED);
2178 f2_.set_secure(SEC_ENABLED);
2179 tdf1_.set_secure(SEC_ENABLED);
2180 tdf2_.set_secure(SEC_DISABLED);
2181 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002182 options.recv_audio = true;
2183 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002184 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185 const cricket::MediaContentDescription* audio_media_desc;
2186 const cricket::MediaContentDescription* video_media_desc;
2187 const cricket::TransportDescription* audio_trans_desc;
2188 const cricket::TransportDescription* video_trans_desc;
2189
2190 // Generate an offer with SDES and DTLS support.
2191 offer.reset(f1_.CreateOffer(options, NULL));
2192 ASSERT_TRUE(offer.get() != NULL);
2193
2194 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2195 offer->GetContentDescriptionByName("audio"));
2196 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002197 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002198 offer->GetContentDescriptionByName("video"));
2199 ASSERT_TRUE(video_media_desc != NULL);
2200 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2201 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2202
2203 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2204 ASSERT_TRUE(audio_trans_desc != NULL);
2205 video_trans_desc = offer->GetTransportDescriptionByName("video");
2206 ASSERT_TRUE(video_trans_desc != NULL);
2207 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2208 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2209
2210 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2211 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2212 ASSERT_TRUE(answer.get() != NULL);
2213
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002214 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002215 answer->GetContentDescriptionByName("audio"));
2216 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002217 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002218 answer->GetContentDescriptionByName("video"));
2219 ASSERT_TRUE(video_media_desc != NULL);
2220 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2221 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2222
2223 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2224 ASSERT_TRUE(audio_trans_desc != NULL);
2225 video_trans_desc = answer->GetTransportDescriptionByName("video");
2226 ASSERT_TRUE(video_trans_desc != NULL);
2227 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2228 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2229
2230 // Enable DTLS; the answer should now only have DTLS support.
2231 tdf2_.set_secure(SEC_ENABLED);
2232 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2233 ASSERT_TRUE(answer.get() != NULL);
2234
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002235 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002236 answer->GetContentDescriptionByName("audio"));
2237 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002238 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 answer->GetContentDescriptionByName("video"));
2240 ASSERT_TRUE(video_media_desc != NULL);
2241 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2242 EXPECT_TRUE(video_media_desc->cryptos().empty());
2243 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2244 audio_media_desc->protocol());
2245 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2246 video_media_desc->protocol());
2247
2248 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2249 ASSERT_TRUE(audio_trans_desc != NULL);
2250 video_trans_desc = answer->GetTransportDescriptionByName("video");
2251 ASSERT_TRUE(video_trans_desc != NULL);
2252 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2253 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002254
2255 // Try creating offer again. DTLS enabled now, crypto's should be empty
2256 // in new offer.
2257 offer.reset(f1_.CreateOffer(options, offer.get()));
2258 ASSERT_TRUE(offer.get() != NULL);
2259 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2260 offer->GetContentDescriptionByName("audio"));
2261 ASSERT_TRUE(audio_media_desc != NULL);
2262 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2263 offer->GetContentDescriptionByName("video"));
2264 ASSERT_TRUE(video_media_desc != NULL);
2265 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2266 EXPECT_TRUE(video_media_desc->cryptos().empty());
2267
2268 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2269 ASSERT_TRUE(audio_trans_desc != NULL);
2270 video_trans_desc = offer->GetTransportDescriptionByName("video");
2271 ASSERT_TRUE(video_trans_desc != NULL);
2272 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2273 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002274}
2275
2276// Test that an answer can't be created if cryptos are required but the offer is
2277// unsecure.
2278TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2279 MediaSessionOptions options;
2280 f1_.set_secure(SEC_DISABLED);
2281 tdf1_.set_secure(SEC_DISABLED);
2282 f2_.set_secure(SEC_REQUIRED);
2283 tdf1_.set_secure(SEC_ENABLED);
2284
kwiberg31022942016-03-11 14:18:21 -08002285 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002286 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002287 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002288 f2_.CreateAnswer(offer.get(), options, NULL));
2289 EXPECT_TRUE(answer.get() == NULL);
2290}
2291
2292// Test that we accept a DTLS offer without SDES and create an appropriate
2293// answer.
2294TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2295 f1_.set_secure(SEC_DISABLED);
2296 f2_.set_secure(SEC_ENABLED);
2297 tdf1_.set_secure(SEC_ENABLED);
2298 tdf2_.set_secure(SEC_ENABLED);
2299 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002300 options.recv_audio = true;
2301 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002302 options.data_channel_type = cricket::DCT_RTP;
2303
kwiberg31022942016-03-11 14:18:21 -08002304 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002305
2306 // Generate an offer with DTLS but without SDES.
2307 offer.reset(f1_.CreateOffer(options, NULL));
2308 ASSERT_TRUE(offer.get() != NULL);
2309
2310 const AudioContentDescription* audio_offer =
2311 GetFirstAudioContentDescription(offer.get());
2312 ASSERT_TRUE(audio_offer->cryptos().empty());
2313 const VideoContentDescription* video_offer =
2314 GetFirstVideoContentDescription(offer.get());
2315 ASSERT_TRUE(video_offer->cryptos().empty());
2316 const DataContentDescription* data_offer =
2317 GetFirstDataContentDescription(offer.get());
2318 ASSERT_TRUE(data_offer->cryptos().empty());
2319
2320 const cricket::TransportDescription* audio_offer_trans_desc =
2321 offer->GetTransportDescriptionByName("audio");
2322 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2323 const cricket::TransportDescription* video_offer_trans_desc =
2324 offer->GetTransportDescriptionByName("video");
2325 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2326 const cricket::TransportDescription* data_offer_trans_desc =
2327 offer->GetTransportDescriptionByName("data");
2328 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2329
2330 // Generate an answer with DTLS.
2331 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2332 ASSERT_TRUE(answer.get() != NULL);
2333
2334 const cricket::TransportDescription* audio_answer_trans_desc =
2335 answer->GetTransportDescriptionByName("audio");
2336 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2337 const cricket::TransportDescription* video_answer_trans_desc =
2338 answer->GetTransportDescriptionByName("video");
2339 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2340 const cricket::TransportDescription* data_answer_trans_desc =
2341 answer->GetTransportDescriptionByName("data");
2342 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2343}
2344
2345// Verifies if vad_enabled option is set to false, CN codecs are not present in
2346// offer or answer.
2347TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2348 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002349 options.recv_audio = true;
2350 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002351 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002352 ASSERT_TRUE(offer.get() != NULL);
2353 const ContentInfo* audio_content = offer->GetContentByName("audio");
2354 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2355
2356 options.vad_enabled = false;
2357 offer.reset(f1_.CreateOffer(options, NULL));
2358 ASSERT_TRUE(offer.get() != NULL);
2359 audio_content = offer->GetContentByName("audio");
2360 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002361 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362 f1_.CreateAnswer(offer.get(), options, NULL));
2363 ASSERT_TRUE(answer.get() != NULL);
2364 audio_content = answer->GetContentByName("audio");
2365 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2366}
deadbeef44f08192015-12-15 16:20:09 -08002367
2368// Test that the content name ("mid" in SDP) is unchanged when creating a
2369// new offer.
2370TEST_F(MediaSessionDescriptionFactoryTest,
2371 TestContentNameNotChangedInSubsequentOffers) {
2372 MediaSessionOptions opts;
2373 opts.recv_audio = true;
2374 opts.recv_video = true;
2375 opts.data_channel_type = cricket::DCT_SCTP;
2376 // Create offer and modify the default content names.
kwiberg31022942016-03-11 14:18:21 -08002377 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
deadbeef44f08192015-12-15 16:20:09 -08002378 for (ContentInfo& content : offer->contents()) {
2379 content.name.append("_modified");
2380 }
2381
kwiberg31022942016-03-11 14:18:21 -08002382 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002383 f1_.CreateOffer(opts, offer.get()));
2384 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2385 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2386 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2387 ASSERT_TRUE(audio_content != nullptr);
2388 ASSERT_TRUE(video_content != nullptr);
2389 ASSERT_TRUE(data_content != nullptr);
2390 EXPECT_EQ("audio_modified", audio_content->name);
2391 EXPECT_EQ("video_modified", video_content->name);
2392 EXPECT_EQ("data_modified", data_content->name);
2393}