blob: 281d306c059f7e48bf6eaf0d970f373b08681528 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000015#include "webrtc/base/fakesslidentity.h"
16#include "webrtc/base/gunit.h"
17#include "webrtc/base/messagedigest.h"
18#include "webrtc/base/ssladapter.h"
kjellandera96e2d72016-02-04 23:52:28 -080019#include "webrtc/media/base/codec.h"
20#include "webrtc/media/base/testutils.h"
kjellanderf4752772016-03-02 05:42:30 -080021#include "webrtc/p2p/base/p2pconstants.h"
kjellandera96e2d72016-02-04 23:52:28 -080022#include "webrtc/p2p/base/transportdescription.h"
23#include "webrtc/p2p/base/transportinfo.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010024#include "webrtc/pc/mediasession.h"
25#include "webrtc/pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000026
27#ifdef HAVE_SRTP
28#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000029 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000030 ASSERT_EQ(s, cd->cryptos().size()); \
31 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
32#else
33#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000034 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035 ASSERT_EQ(0U, cd->cryptos().size());
36#endif
37
38typedef std::vector<cricket::Candidate> Candidates;
39
40using cricket::MediaContentDescription;
41using cricket::MediaSessionDescriptionFactory;
ossu075af922016-06-14 03:29:38 -070042using cricket::MediaContentDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043using cricket::MediaSessionOptions;
44using cricket::MediaType;
45using cricket::SessionDescription;
46using cricket::SsrcGroup;
47using cricket::StreamParams;
48using cricket::StreamParamsVec;
49using cricket::TransportDescription;
50using cricket::TransportDescriptionFactory;
51using cricket::TransportInfo;
52using cricket::ContentInfo;
53using cricket::CryptoParamsVec;
54using cricket::AudioContentDescription;
55using cricket::VideoContentDescription;
56using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080057using cricket::GetFirstAudioContent;
58using cricket::GetFirstVideoContent;
59using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::GetFirstAudioContentDescription;
61using cricket::GetFirstVideoContentDescription;
62using cricket::GetFirstDataContentDescription;
63using cricket::kAutoBandwidth;
64using cricket::AudioCodec;
65using cricket::VideoCodec;
66using cricket::DataCodec;
67using cricket::NS_JINGLE_RTP;
68using cricket::MEDIA_TYPE_AUDIO;
69using cricket::MEDIA_TYPE_VIDEO;
70using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071using cricket::SEC_DISABLED;
72using cricket::SEC_ENABLED;
73using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070074using rtc::CS_AES_CM_128_HMAC_SHA1_32;
75using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070076using rtc::CS_AEAD_AES_128_GCM;
77using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070078using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079
80static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070081 AudioCodec(103, "ISAC", 16000, -1, 1),
82 AudioCodec(102, "iLBC", 8000, 13300, 1),
83 AudioCodec(0, "PCMU", 8000, 64000, 1),
84 AudioCodec(8, "PCMA", 8000, 64000, 1),
85 AudioCodec(117, "red", 8000, 0, 1),
86 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087
88static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070089 AudioCodec(126, "speex", 16000, 22000, 1),
90 AudioCodec(0, "PCMU", 8000, 64000, 1),
91 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092};
93
94static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070095 AudioCodec(102, "iLBC", 8000, 13300, 1),
96 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097};
98
99static const VideoCodec kVideoCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700100 VideoCodec(96, "H264-SVC", 320, 200, 30),
101 VideoCodec(97, "H264", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103static const VideoCodec kVideoCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700104 VideoCodec(126, "H264", 320, 200, 30),
105 VideoCodec(127, "H263", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
107static const VideoCodec kVideoCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700108 VideoCodec(97, "H264", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
deadbeef67cf2c12016-04-13 10:07:16 -0700110static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
111 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
deadbeef67cf2c12016-04-13 10:07:16 -0700113static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
114 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115
deadbeef67cf2c12016-04-13 10:07:16 -0700116static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
117 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118
isheriff6f8d6862016-05-26 11:24:55 -0700119static const RtpExtension kAudioRtpExtension1[] = {
120 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
121 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122};
123
isheriff6f8d6862016-05-26 11:24:55 -0700124static const RtpExtension kAudioRtpExtension2[] = {
125 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
126 RtpExtension("http://google.com/testing/audio_something_else", 8),
127 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128};
129
isheriff6f8d6862016-05-26 11:24:55 -0700130static const RtpExtension kAudioRtpExtension3[] = {
131 RtpExtension("http://google.com/testing/audio_something", 2),
132 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700133};
134
isheriff6f8d6862016-05-26 11:24:55 -0700135static const RtpExtension kAudioRtpExtensionAnswer[] = {
136 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137};
138
isheriff6f8d6862016-05-26 11:24:55 -0700139static const RtpExtension kVideoRtpExtension1[] = {
140 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
141 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142};
143
isheriff6f8d6862016-05-26 11:24:55 -0700144static const RtpExtension kVideoRtpExtension2[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
146 RtpExtension("http://google.com/testing/video_something_else", 14),
147 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148};
149
isheriff6f8d6862016-05-26 11:24:55 -0700150static const RtpExtension kVideoRtpExtension3[] = {
151 RtpExtension("http://google.com/testing/video_something", 4),
152 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kVideoRtpExtensionAnswer[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157};
158
Peter Boström0c4e06b2015-10-07 12:23:21 +0200159static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
160static const uint32_t kSimSsrc[] = {10, 20, 30};
161static const uint32_t kFec1Ssrc[] = {10, 11};
162static const uint32_t kFec2Ssrc[] = {20, 21};
163static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164
165static const char kMediaStream1[] = "stream_1";
166static const char kMediaStream2[] = "stream_2";
167static const char kVideoTrack1[] = "video_1";
168static const char kVideoTrack2[] = "video_2";
169static const char kAudioTrack1[] = "audio_1";
170static const char kAudioTrack2[] = "audio_2";
171static const char kAudioTrack3[] = "audio_3";
172static const char kDataTrack1[] = "data_1";
173static const char kDataTrack2[] = "data_2";
174static const char kDataTrack3[] = "data_3";
175
zhihuangcf5b37c2016-05-05 11:44:35 -0700176static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
177 "RTP/SAVPF"};
178static const char* kMediaProtocolsDtls[] = {
179 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
180 "UDP/TLS/RTP/SAVP"};
181
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000182static bool IsMediaContentOfType(const ContentInfo* content,
183 MediaType media_type) {
184 const MediaContentDescription* mdesc =
185 static_cast<const MediaContentDescription*>(content->description);
186 return mdesc && mdesc->type() == media_type;
187}
188
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000189static cricket::MediaContentDirection
190GetMediaDirection(const ContentInfo* content) {
191 cricket::MediaContentDescription* desc =
192 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
193 return desc->direction();
194}
195
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000196static void AddRtxCodec(const VideoCodec& rtx_codec,
197 std::vector<VideoCodec>* codecs) {
198 VideoCodec rtx;
199 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
200 codecs->push_back(rtx_codec);
201}
202
203template <class T>
204static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
205 std::vector<std::string> codec_names;
206 for (const auto& codec : codecs) {
207 codec_names.push_back(codec.name);
208 }
209 return codec_names;
210}
211
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212class MediaSessionDescriptionFactoryTest : public testing::Test {
213 public:
214 MediaSessionDescriptionFactoryTest()
Henrik Boström3a14bf32015-08-31 09:27:58 +0200215 : f1_(&tdf1_),
216 f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700217 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
218 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
220 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700221 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
222 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
224 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200225 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700226 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200227 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700228 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 }
230
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000231 // Create a video StreamParamsVec object with:
232 // - one video stream with 3 simulcast streams and FEC,
233 StreamParamsVec CreateComplexVideoStreamParamsVec() {
234 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
235 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
236 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
237 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
238
239 std::vector<SsrcGroup> ssrc_groups;
240 ssrc_groups.push_back(sim_group);
241 ssrc_groups.push_back(fec_group1);
242 ssrc_groups.push_back(fec_group2);
243 ssrc_groups.push_back(fec_group3);
244
245 StreamParams simulcast_params;
246 simulcast_params.id = kVideoTrack1;
247 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
248 simulcast_params.ssrc_groups = ssrc_groups;
249 simulcast_params.cname = "Video_SIM_FEC";
250 simulcast_params.sync_label = kMediaStream1;
251
252 StreamParamsVec video_streams;
253 video_streams.push_back(simulcast_params);
254
255 return video_streams;
256 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257
258 bool CompareCryptoParams(const CryptoParamsVec& c1,
259 const CryptoParamsVec& c2) {
260 if (c1.size() != c2.size())
261 return false;
262 for (size_t i = 0; i < c1.size(); ++i)
263 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
264 c1[i].key_params != c2[i].key_params ||
265 c1[i].session_params != c2[i].session_params)
266 return false;
267 return true;
268 }
269
270 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
271 bool has_current_desc) {
272 const std::string current_audio_ufrag = "current_audio_ufrag";
273 const std::string current_audio_pwd = "current_audio_pwd";
274 const std::string current_video_ufrag = "current_video_ufrag";
275 const std::string current_video_pwd = "current_video_pwd";
276 const std::string current_data_ufrag = "current_data_ufrag";
277 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800278 std::unique_ptr<SessionDescription> current_desc;
279 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 if (has_current_desc) {
281 current_desc.reset(new SessionDescription());
282 EXPECT_TRUE(current_desc->AddTransportInfo(
283 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700284 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000285 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 EXPECT_TRUE(current_desc->AddTransportInfo(
287 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700288 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000289 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290 EXPECT_TRUE(current_desc->AddTransportInfo(
291 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700292 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000293 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 }
295 if (offer) {
296 desc.reset(f1_.CreateOffer(options, current_desc.get()));
297 } else {
kwiberg31022942016-03-11 14:18:21 -0800298 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 offer.reset(f1_.CreateOffer(options, NULL));
300 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
301 }
302 ASSERT_TRUE(desc.get() != NULL);
303 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000304 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305 EXPECT_TRUE(ti_audio != NULL);
306 if (has_current_desc) {
307 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
308 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
309 } else {
310 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
311 ti_audio->description.ice_ufrag.size());
312 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
313 ti_audio->description.ice_pwd.size());
314 }
315
316 } else {
317 EXPECT_TRUE(ti_audio == NULL);
318 }
319 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000320 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321 EXPECT_TRUE(ti_video != NULL);
322 if (options.bundle_enabled) {
323 EXPECT_EQ(ti_audio->description.ice_ufrag,
324 ti_video->description.ice_ufrag);
325 EXPECT_EQ(ti_audio->description.ice_pwd,
326 ti_video->description.ice_pwd);
327 } else {
328 if (has_current_desc) {
329 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
330 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
331 } else {
332 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
333 ti_video->description.ice_ufrag.size());
334 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
335 ti_video->description.ice_pwd.size());
336 }
337 }
338 } else {
339 EXPECT_TRUE(ti_video == NULL);
340 }
341 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
342 if (options.has_data()) {
343 EXPECT_TRUE(ti_data != NULL);
344 if (options.bundle_enabled) {
345 EXPECT_EQ(ti_audio->description.ice_ufrag,
346 ti_data->description.ice_ufrag);
347 EXPECT_EQ(ti_audio->description.ice_pwd,
348 ti_data->description.ice_pwd);
349 } else {
350 if (has_current_desc) {
351 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
352 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
353 } else {
354 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
355 ti_data->description.ice_ufrag.size());
356 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
357 ti_data->description.ice_pwd.size());
358 }
359 }
360 } else {
361 EXPECT_TRUE(ti_video == NULL);
362 }
363 }
364
365 void TestCryptoWithBundle(bool offer) {
366 f1_.set_secure(SEC_ENABLED);
367 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000368 options.recv_audio = true;
369 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370 options.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -0800371 std::unique_ptr<SessionDescription> ref_desc;
372 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000373 if (offer) {
374 options.bundle_enabled = false;
375 ref_desc.reset(f1_.CreateOffer(options, NULL));
376 options.bundle_enabled = true;
377 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
378 } else {
379 options.bundle_enabled = true;
380 ref_desc.reset(f1_.CreateOffer(options, NULL));
381 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
382 }
383 ASSERT_TRUE(desc.get() != NULL);
384 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000385 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386 desc.get()->GetContentDescriptionByName("audio"));
387 ASSERT_TRUE(audio_media_desc != NULL);
388 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000389 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390 desc.get()->GetContentDescriptionByName("video"));
391 ASSERT_TRUE(video_media_desc != NULL);
392 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
393 video_media_desc->cryptos()));
394 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
395 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
396 audio_media_desc->cryptos()[0].cipher_suite);
397
398 // Verify the selected crypto is one from the reference audio
399 // media content.
400 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000401 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402 ref_desc.get()->GetContentDescriptionByName("audio"));
403 bool found = false;
404 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
405 if (ref_audio_media_desc->cryptos()[i].Matches(
406 audio_media_desc->cryptos()[0])) {
407 found = true;
408 break;
409 }
410 }
411 EXPECT_TRUE(found);
412 }
413
414 // This test that the audio and video media direction is set to
415 // |expected_direction_in_answer| in an answer if the offer direction is set
416 // to |direction_in_offer|.
417 void TestMediaDirectionInAnswer(
418 cricket::MediaContentDirection direction_in_offer,
419 cricket::MediaContentDirection expected_direction_in_answer) {
420 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000421 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800422 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700424 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 ASSERT_TRUE(ac_offer != NULL);
426 AudioContentDescription* acd_offer =
427 static_cast<AudioContentDescription*>(ac_offer->description);
428 acd_offer->set_direction(direction_in_offer);
terelius8c011e52016-04-26 05:28:11 -0700429 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430 ASSERT_TRUE(vc_offer != NULL);
431 VideoContentDescription* vcd_offer =
432 static_cast<VideoContentDescription*>(vc_offer->description);
433 vcd_offer->set_direction(direction_in_offer);
434
kwiberg31022942016-03-11 14:18:21 -0800435 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 f2_.CreateAnswer(offer.get(), opts, NULL));
437 const AudioContentDescription* acd_answer =
438 GetFirstAudioContentDescription(answer.get());
439 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
440 const VideoContentDescription* vcd_answer =
441 GetFirstVideoContentDescription(answer.get());
442 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
443 }
444
445 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
446 const cricket::ContentDescription* description = content->description;
447 ASSERT(description != NULL);
448 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000449 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 ASSERT(audio_content_desc != NULL);
451 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
452 if (audio_content_desc->codecs()[i].name == "CN")
453 return false;
454 }
455 return true;
456 }
457
jbauchcb560652016-08-04 05:20:32 -0700458 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
459 MediaSessionOptions offer_opts;
460 offer_opts.recv_video = true;
461 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
462 MediaSessionOptions answer_opts;
463 answer_opts.recv_video = true;
464 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
465 f1_.set_secure(SEC_ENABLED);
466 f2_.set_secure(SEC_ENABLED);
467 std::unique_ptr<SessionDescription> offer(
468 f1_.CreateOffer(offer_opts, NULL));
469 ASSERT_TRUE(offer.get() != NULL);
470 std::unique_ptr<SessionDescription> answer(
471 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
472 const ContentInfo* ac = answer->GetContentByName("audio");
473 const ContentInfo* vc = answer->GetContentByName("video");
474 ASSERT_TRUE(ac != NULL);
475 ASSERT_TRUE(vc != NULL);
476 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
477 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
478 const AudioContentDescription* acd =
479 static_cast<const AudioContentDescription*>(ac->description);
480 const VideoContentDescription* vcd =
481 static_cast<const VideoContentDescription*>(vc->description);
482 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
483 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
484 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
485 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
486 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
487 if (gcm_offer && gcm_answer) {
488 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
489 } else {
490 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
491 }
492 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
493 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
494 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
495 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
496 if (gcm_offer && gcm_answer) {
497 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
498 } else {
499 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
500 }
501 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
502 }
503
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 protected:
505 MediaSessionDescriptionFactory f1_;
506 MediaSessionDescriptionFactory f2_;
507 TransportDescriptionFactory tdf1_;
508 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509};
510
511// Create a typical audio offer, and ensure it matches what we expect.
512TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
513 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800514 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 f1_.CreateOffer(MediaSessionOptions(), NULL));
516 ASSERT_TRUE(offer.get() != NULL);
517 const ContentInfo* ac = offer->GetContentByName("audio");
518 const ContentInfo* vc = offer->GetContentByName("video");
519 ASSERT_TRUE(ac != NULL);
520 ASSERT_TRUE(vc == NULL);
521 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
522 const AudioContentDescription* acd =
523 static_cast<const AudioContentDescription*>(ac->description);
524 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700525 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
527 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
528 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
529 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
530 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
531}
532
533// Create a typical video offer, and ensure it matches what we expect.
534TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
535 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000536 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800538 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 ASSERT_TRUE(offer.get() != NULL);
540 const ContentInfo* ac = offer->GetContentByName("audio");
541 const ContentInfo* vc = offer->GetContentByName("video");
542 ASSERT_TRUE(ac != NULL);
543 ASSERT_TRUE(vc != NULL);
544 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
545 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
546 const AudioContentDescription* acd =
547 static_cast<const AudioContentDescription*>(ac->description);
548 const VideoContentDescription* vcd =
549 static_cast<const VideoContentDescription*>(vc->description);
550 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700551 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
553 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
554 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
555 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
556 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
557 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
558 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
559 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
560 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
561 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
562 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
563 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
564}
565
566// Test creating an offer with bundle where the Codecs have the same dynamic
567// RTP playlod type. The test verifies that the offer don't contain the
568// duplicate RTP payload types.
569TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
570 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700571 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
573 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
574 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
575
576 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000577 opts.recv_audio = true;
578 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 opts.data_channel_type = cricket::DCT_RTP;
580 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800581 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 const VideoContentDescription* vcd =
583 GetFirstVideoContentDescription(offer.get());
584 const AudioContentDescription* acd =
585 GetFirstAudioContentDescription(offer.get());
586 const DataContentDescription* dcd =
587 GetFirstDataContentDescription(offer.get());
588 ASSERT_TRUE(NULL != vcd);
589 ASSERT_TRUE(NULL != acd);
590 ASSERT_TRUE(NULL != dcd);
591 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
592 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
593 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
594 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
595 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
596 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
597}
598
599// Test creating an updated offer with with bundle, audio, video and data
600// after an audio only session has been negotiated.
601TEST_F(MediaSessionDescriptionFactoryTest,
602 TestCreateUpdatedVideoOfferWithBundle) {
603 f1_.set_secure(SEC_ENABLED);
604 f2_.set_secure(SEC_ENABLED);
605 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000606 opts.recv_audio = true;
607 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 opts.data_channel_type = cricket::DCT_NONE;
609 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800610 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
611 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 f2_.CreateAnswer(offer.get(), opts, NULL));
613
614 MediaSessionOptions updated_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000615 updated_opts.recv_audio = true;
616 updated_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 updated_opts.data_channel_type = cricket::DCT_RTP;
618 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800619 std::unique_ptr<SessionDescription> updated_offer(
620 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621
622 const AudioContentDescription* acd =
623 GetFirstAudioContentDescription(updated_offer.get());
624 const VideoContentDescription* vcd =
625 GetFirstVideoContentDescription(updated_offer.get());
626 const DataContentDescription* dcd =
627 GetFirstDataContentDescription(updated_offer.get());
628 EXPECT_TRUE(NULL != vcd);
629 EXPECT_TRUE(NULL != acd);
630 EXPECT_TRUE(NULL != dcd);
631
632 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
633 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
634 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
635 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
636 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
637 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
638}
deadbeef44f08192015-12-15 16:20:09 -0800639
wu@webrtc.org78187522013-10-07 23:32:02 +0000640// Create a RTP data offer, and ensure it matches what we expect.
641TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 MediaSessionOptions opts;
643 opts.data_channel_type = cricket::DCT_RTP;
644 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800645 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 ASSERT_TRUE(offer.get() != NULL);
647 const ContentInfo* ac = offer->GetContentByName("audio");
648 const ContentInfo* dc = offer->GetContentByName("data");
649 ASSERT_TRUE(ac != NULL);
650 ASSERT_TRUE(dc != NULL);
651 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
652 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
653 const AudioContentDescription* acd =
654 static_cast<const AudioContentDescription*>(ac->description);
655 const DataContentDescription* dcd =
656 static_cast<const DataContentDescription*>(dc->description);
657 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700658 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
660 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
661 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
662 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
663 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
664 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
665 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
666 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
667 EXPECT_EQ(cricket::kDataMaxBandwidth,
668 dcd->bandwidth()); // default bandwidth (auto)
669 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
670 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
671 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
672}
673
wu@webrtc.org78187522013-10-07 23:32:02 +0000674// Create an SCTP data offer with bundle without error.
675TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
676 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000677 opts.recv_audio = false;
wu@webrtc.org78187522013-10-07 23:32:02 +0000678 opts.bundle_enabled = true;
679 opts.data_channel_type = cricket::DCT_SCTP;
680 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800681 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000682 EXPECT_TRUE(offer.get() != NULL);
683 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
684}
685
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000686// Test creating an sctp data channel from an already generated offer.
687TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
688 MediaSessionOptions opts;
689 opts.recv_audio = false;
690 opts.bundle_enabled = true;
691 opts.data_channel_type = cricket::DCT_SCTP;
692 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800693 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000694 ASSERT_TRUE(offer1.get() != NULL);
695 const ContentInfo* data = offer1->GetContentByName("data");
696 ASSERT_TRUE(data != NULL);
697 const MediaContentDescription* mdesc =
698 static_cast<const MediaContentDescription*>(data->description);
699 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
700
701 // Now set data_channel_type to 'none' (default) and make sure that the
702 // datachannel type that gets generated from the previous offer, is of the
703 // same type.
704 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800705 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000706 f1_.CreateOffer(opts, offer1.get()));
707 data = offer2->GetContentByName("data");
708 ASSERT_TRUE(data != NULL);
709 mdesc = static_cast<const MediaContentDescription*>(data->description);
710 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
711}
712
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713// Create an audio, video offer without legacy StreamParams.
714TEST_F(MediaSessionDescriptionFactoryTest,
715 TestCreateOfferWithoutLegacyStreams) {
716 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000717 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718 f1_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800719 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 ASSERT_TRUE(offer.get() != NULL);
721 const ContentInfo* ac = offer->GetContentByName("audio");
722 const ContentInfo* vc = offer->GetContentByName("video");
723 ASSERT_TRUE(ac != NULL);
724 ASSERT_TRUE(vc != NULL);
725 const AudioContentDescription* acd =
726 static_cast<const AudioContentDescription*>(ac->description);
727 const VideoContentDescription* vcd =
728 static_cast<const VideoContentDescription*>(vc->description);
729
730 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
731 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
732}
733
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000734// Creates an audio+video sendonly offer.
735TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
736 MediaSessionOptions options;
737 options.recv_audio = false;
738 options.recv_video = false;
739 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
740 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
741
kwiberg31022942016-03-11 14:18:21 -0800742 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000743 ASSERT_TRUE(offer.get() != NULL);
744 EXPECT_EQ(2u, offer->contents().size());
745 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
746 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
747
748 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
749 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
750}
751
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000752// Verifies that the order of the media contents in the current
753// SessionDescription is preserved in the new SessionDescription.
754TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
755 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000756 opts.recv_audio = false;
757 opts.recv_video = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000758 opts.data_channel_type = cricket::DCT_SCTP;
759
kwiberg31022942016-03-11 14:18:21 -0800760 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000761 ASSERT_TRUE(offer1.get() != NULL);
762 EXPECT_EQ(1u, offer1->contents().size());
763 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
764
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000765 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800766 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000767 f1_.CreateOffer(opts, offer1.get()));
768 ASSERT_TRUE(offer2.get() != NULL);
769 EXPECT_EQ(2u, offer2->contents().size());
770 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
771 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
772
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000773 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800774 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000775 f1_.CreateOffer(opts, offer2.get()));
776 ASSERT_TRUE(offer3.get() != NULL);
777 EXPECT_EQ(3u, offer3->contents().size());
778 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
779 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
780 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
781
782 // Verifies the default order is audio-video-data, so that the previous checks
783 // didn't pass by accident.
kwiberg31022942016-03-11 14:18:21 -0800784 std::unique_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000785 ASSERT_TRUE(offer4.get() != NULL);
786 EXPECT_EQ(3u, offer4->contents().size());
787 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
788 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
789 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
790}
791
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792// Create a typical audio answer, and ensure it matches what we expect.
793TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
794 f1_.set_secure(SEC_ENABLED);
795 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800796 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 f1_.CreateOffer(MediaSessionOptions(), NULL));
798 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800799 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
801 const ContentInfo* ac = answer->GetContentByName("audio");
802 const ContentInfo* vc = answer->GetContentByName("video");
803 ASSERT_TRUE(ac != NULL);
804 ASSERT_TRUE(vc == NULL);
805 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
806 const AudioContentDescription* acd =
807 static_cast<const AudioContentDescription*>(ac->description);
808 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
809 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
810 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
811 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
812 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
813 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
814 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
815}
816
jbauchcb560652016-08-04 05:20:32 -0700817// Create a typical audio answer with GCM ciphers enabled, and ensure it
818// matches what we expect.
819TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
820 f1_.set_secure(SEC_ENABLED);
821 f2_.set_secure(SEC_ENABLED);
822 MediaSessionOptions options;
823 options.crypto_options.enable_gcm_crypto_suites = true;
824 std::unique_ptr<SessionDescription> offer(
825 f1_.CreateOffer(options, NULL));
826 ASSERT_TRUE(offer.get() != NULL);
827 std::unique_ptr<SessionDescription> answer(
828 f2_.CreateAnswer(offer.get(), options, NULL));
829 const ContentInfo* ac = answer->GetContentByName("audio");
830 const ContentInfo* vc = answer->GetContentByName("video");
831 ASSERT_TRUE(ac != NULL);
832 ASSERT_TRUE(vc == NULL);
833 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
834 const AudioContentDescription* acd =
835 static_cast<const AudioContentDescription*>(ac->description);
836 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
837 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
838 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
839 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
840 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
841 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
842 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
843}
844
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845// Create a typical video answer, and ensure it matches what we expect.
846TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
847 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000848 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 f1_.set_secure(SEC_ENABLED);
850 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800851 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800853 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 f2_.CreateAnswer(offer.get(), opts, NULL));
855 const ContentInfo* ac = answer->GetContentByName("audio");
856 const ContentInfo* vc = answer->GetContentByName("video");
857 ASSERT_TRUE(ac != NULL);
858 ASSERT_TRUE(vc != NULL);
859 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
860 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
861 const AudioContentDescription* acd =
862 static_cast<const AudioContentDescription*>(ac->description);
863 const VideoContentDescription* vcd =
864 static_cast<const VideoContentDescription*>(vc->description);
865 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
866 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
867 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
868 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
869 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
870 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
871 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
872 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
873 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
874 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
875 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
876 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
877}
878
jbauchcb560652016-08-04 05:20:32 -0700879// Create a typical video answer with GCM ciphers enabled, and ensure it
880// matches what we expect.
881TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
882 TestVideoGcmCipher(true, true);
883}
884
885// Create a typical video answer with GCM ciphers enabled for the offer only,
886// and ensure it matches what we expect.
887TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
888 TestVideoGcmCipher(true, false);
889}
890
891// Create a typical video answer with GCM ciphers enabled for the answer only,
892// and ensure it matches what we expect.
893TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
894 TestVideoGcmCipher(false, true);
895}
896
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
898 MediaSessionOptions opts;
899 opts.data_channel_type = cricket::DCT_RTP;
900 f1_.set_secure(SEC_ENABLED);
901 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800902 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800904 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 f2_.CreateAnswer(offer.get(), opts, NULL));
906 const ContentInfo* ac = answer->GetContentByName("audio");
907 const ContentInfo* vc = answer->GetContentByName("data");
908 ASSERT_TRUE(ac != NULL);
909 ASSERT_TRUE(vc != NULL);
910 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
911 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
912 const AudioContentDescription* acd =
913 static_cast<const AudioContentDescription*>(ac->description);
914 const DataContentDescription* vcd =
915 static_cast<const DataContentDescription*>(vc->description);
916 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
917 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
918 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
919 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
920 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
921 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
922 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
923 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
924 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
925 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
926 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
927 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
928}
929
jbauchcb560652016-08-04 05:20:32 -0700930TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
931 MediaSessionOptions opts;
932 opts.data_channel_type = cricket::DCT_RTP;
933 opts.crypto_options.enable_gcm_crypto_suites = true;
934 f1_.set_secure(SEC_ENABLED);
935 f2_.set_secure(SEC_ENABLED);
936 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
937 ASSERT_TRUE(offer.get() != NULL);
938 std::unique_ptr<SessionDescription> answer(
939 f2_.CreateAnswer(offer.get(), opts, NULL));
940 const ContentInfo* ac = answer->GetContentByName("audio");
941 const ContentInfo* vc = answer->GetContentByName("data");
942 ASSERT_TRUE(ac != NULL);
943 ASSERT_TRUE(vc != NULL);
944 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
945 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
946 const AudioContentDescription* acd =
947 static_cast<const AudioContentDescription*>(ac->description);
948 const DataContentDescription* vcd =
949 static_cast<const DataContentDescription*>(vc->description);
950 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
951 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
952 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
953 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
954 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
955 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
956 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
957 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
958 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
959 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
960 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
961 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
962}
963
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000964// Verifies that the order of the media contents in the offer is preserved in
965// the answer.
966TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
967 MediaSessionOptions opts;
968
969 // Creates a data only offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000970 opts.recv_audio = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000971 opts.data_channel_type = cricket::DCT_SCTP;
kwiberg31022942016-03-11 14:18:21 -0800972 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000973 ASSERT_TRUE(offer1.get() != NULL);
974
975 // Appends audio to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000976 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800977 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000978 f1_.CreateOffer(opts, offer1.get()));
979 ASSERT_TRUE(offer2.get() != NULL);
980
981 // Appends video to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000982 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800983 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000984 f1_.CreateOffer(opts, offer2.get()));
985 ASSERT_TRUE(offer3.get() != NULL);
986
kwiberg31022942016-03-11 14:18:21 -0800987 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000988 f2_.CreateAnswer(offer3.get(), opts, NULL));
989 ASSERT_TRUE(answer.get() != NULL);
990 EXPECT_EQ(3u, answer->contents().size());
991 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
992 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
993 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
994}
995
ossu075af922016-06-14 03:29:38 -0700996// TODO(deadbeef): Extend these tests to ensure the correct direction with other
997// answerer settings.
998
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999// This test that the media direction is set to send/receive in an answer if
1000// the offer is send receive.
1001TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1002 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1003}
1004
1005// This test that the media direction is set to receive only in an answer if
1006// the offer is send only.
1007TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1008 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1009}
1010
1011// This test that the media direction is set to send only in an answer if
1012// the offer is recv only.
1013TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1014 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1015}
1016
1017// This test that the media direction is set to inactive in an answer if
1018// the offer is inactive.
1019TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1020 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1021}
1022
1023// Test that a data content with an unknown protocol is rejected in an answer.
1024TEST_F(MediaSessionDescriptionFactoryTest,
1025 CreateDataAnswerToOfferWithUnknownProtocol) {
1026 MediaSessionOptions opts;
1027 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001028 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 f1_.set_secure(SEC_ENABLED);
1030 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001031 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001032 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 ASSERT_TRUE(dc_offer != NULL);
1034 DataContentDescription* dcd_offer =
1035 static_cast<DataContentDescription*>(dc_offer->description);
1036 ASSERT_TRUE(dcd_offer != NULL);
1037 std::string protocol = "a weird unknown protocol";
1038 dcd_offer->set_protocol(protocol);
1039
kwiberg31022942016-03-11 14:18:21 -08001040 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001041 f2_.CreateAnswer(offer.get(), opts, NULL));
1042
1043 const ContentInfo* dc_answer = answer->GetContentByName("data");
1044 ASSERT_TRUE(dc_answer != NULL);
1045 EXPECT_TRUE(dc_answer->rejected);
1046 const DataContentDescription* dcd_answer =
1047 static_cast<const DataContentDescription*>(dc_answer->description);
1048 ASSERT_TRUE(dcd_answer != NULL);
1049 EXPECT_EQ(protocol, dcd_answer->protocol());
1050}
1051
1052// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1053TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
1054 MediaSessionOptions opts;
1055 f1_.set_secure(SEC_DISABLED);
1056 f2_.set_secure(SEC_DISABLED);
1057 tdf1_.set_secure(SEC_DISABLED);
1058 tdf2_.set_secure(SEC_DISABLED);
1059
kwiberg31022942016-03-11 14:18:21 -08001060 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001061 const AudioContentDescription* offer_acd =
1062 GetFirstAudioContentDescription(offer.get());
1063 ASSERT_TRUE(offer_acd != NULL);
1064 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1065
kwiberg31022942016-03-11 14:18:21 -08001066 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067 f2_.CreateAnswer(offer.get(), opts, NULL));
1068
1069 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1070 ASSERT_TRUE(ac_answer != NULL);
1071 EXPECT_FALSE(ac_answer->rejected);
1072
1073 const AudioContentDescription* answer_acd =
1074 GetFirstAudioContentDescription(answer.get());
1075 ASSERT_TRUE(answer_acd != NULL);
1076 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1077}
1078
1079// Create a video offer and answer and ensure the RTP header extensions
1080// matches what we expect.
1081TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1082 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001083 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001084
1085 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1086 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1087 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1088 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1089
kwiberg31022942016-03-11 14:18:21 -08001090 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001091 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001092 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 f2_.CreateAnswer(offer.get(), opts, NULL));
1094
1095 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1096 GetFirstAudioContentDescription(
1097 offer.get())->rtp_header_extensions());
1098 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1099 GetFirstVideoContentDescription(
1100 offer.get())->rtp_header_extensions());
1101 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1102 GetFirstAudioContentDescription(
1103 answer.get())->rtp_header_extensions());
1104 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1105 GetFirstVideoContentDescription(
1106 answer.get())->rtp_header_extensions());
1107}
1108
1109// Create an audio, video, data answer without legacy StreamParams.
1110TEST_F(MediaSessionDescriptionFactoryTest,
1111 TestCreateAnswerWithoutLegacyStreams) {
1112 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001113 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001114 opts.data_channel_type = cricket::DCT_RTP;
1115 f1_.set_add_legacy_streams(false);
1116 f2_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -08001117 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001119 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001120 f2_.CreateAnswer(offer.get(), opts, NULL));
1121 const ContentInfo* ac = answer->GetContentByName("audio");
1122 const ContentInfo* vc = answer->GetContentByName("video");
1123 const ContentInfo* dc = answer->GetContentByName("data");
1124 ASSERT_TRUE(ac != NULL);
1125 ASSERT_TRUE(vc != NULL);
1126 const AudioContentDescription* acd =
1127 static_cast<const AudioContentDescription*>(ac->description);
1128 const VideoContentDescription* vcd =
1129 static_cast<const VideoContentDescription*>(vc->description);
1130 const DataContentDescription* dcd =
1131 static_cast<const DataContentDescription*>(dc->description);
1132
1133 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1134 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1135 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1136}
1137
1138TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1139 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001140 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001141 opts.data_channel_type = cricket::DCT_RTP;
1142 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001143 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 ASSERT_TRUE(offer.get() != NULL);
1145 const ContentInfo* ac = offer->GetContentByName("audio");
1146 const ContentInfo* vc = offer->GetContentByName("video");
1147 const ContentInfo* dc = offer->GetContentByName("data");
1148 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1149 static_cast<const AudioContentDescription*>(ac->description));
1150 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1151 static_cast<const VideoContentDescription*>(vc->description));
1152 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1153 static_cast<const DataContentDescription*>(dc->description));
1154
1155 EXPECT_FALSE(acd->partial()); // default is false.
1156 acd->set_partial(true);
1157 EXPECT_TRUE(acd->partial());
1158 acd->set_partial(false);
1159 EXPECT_FALSE(acd->partial());
1160
1161 EXPECT_FALSE(vcd->partial()); // default is false.
1162 vcd->set_partial(true);
1163 EXPECT_TRUE(vcd->partial());
1164 vcd->set_partial(false);
1165 EXPECT_FALSE(vcd->partial());
1166
1167 EXPECT_FALSE(dcd->partial()); // default is false.
1168 dcd->set_partial(true);
1169 EXPECT_TRUE(dcd->partial());
1170 dcd->set_partial(false);
1171 EXPECT_FALSE(dcd->partial());
1172}
1173
1174// Create a typical video answer, and ensure it matches what we expect.
1175TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1176 MediaSessionOptions offer_opts;
1177 MediaSessionOptions answer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001178 answer_opts.recv_video = true;
1179 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180 answer_opts.data_channel_type = cricket::DCT_RTP;
1181 offer_opts.data_channel_type = cricket::DCT_RTP;
1182
kwiberg31022942016-03-11 14:18:21 -08001183 std::unique_ptr<SessionDescription> offer;
1184 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185
1186 offer_opts.rtcp_mux_enabled = true;
1187 answer_opts.rtcp_mux_enabled = true;
1188
1189 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1190 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1191 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1192 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1193 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1194 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1195 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1196 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1197 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1198 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1199 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1200 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1201 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1202 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1203
1204 offer_opts.rtcp_mux_enabled = true;
1205 answer_opts.rtcp_mux_enabled = false;
1206
1207 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1208 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1209 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1210 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1211 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1212 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1213 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1214 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1215 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1216 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1217 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1218 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1219 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1220 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1221
1222 offer_opts.rtcp_mux_enabled = false;
1223 answer_opts.rtcp_mux_enabled = true;
1224
1225 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1226 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1227 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1228 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1229 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1230 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1231 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1232 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1233 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1234 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1235 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1236 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1237 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1238 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1239
1240 offer_opts.rtcp_mux_enabled = false;
1241 answer_opts.rtcp_mux_enabled = false;
1242
1243 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1244 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1245 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1246 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1247 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1248 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1249 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1250 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1251 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1252 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1253 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1254 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1255 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1256 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1257}
1258
1259// Create an audio-only answer to a video offer.
1260TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1261 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001262 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001263 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001265 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1267 const ContentInfo* ac = answer->GetContentByName("audio");
1268 const ContentInfo* vc = answer->GetContentByName("video");
1269 ASSERT_TRUE(ac != NULL);
1270 ASSERT_TRUE(vc != NULL);
1271 ASSERT_TRUE(vc->description != NULL);
1272 EXPECT_TRUE(vc->rejected);
1273}
1274
1275// Create an audio-only answer to an offer with data.
1276TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1277 MediaSessionOptions opts;
1278 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001279 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001281 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1283 const ContentInfo* ac = answer->GetContentByName("audio");
1284 const ContentInfo* dc = answer->GetContentByName("data");
1285 ASSERT_TRUE(ac != NULL);
1286 ASSERT_TRUE(dc != NULL);
1287 ASSERT_TRUE(dc->description != NULL);
1288 EXPECT_TRUE(dc->rejected);
1289}
1290
1291// Create an answer that rejects the contents which are rejected in the offer.
1292TEST_F(MediaSessionDescriptionFactoryTest,
1293 CreateAnswerToOfferWithRejectedMedia) {
1294 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001295 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001297 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 ASSERT_TRUE(offer.get() != NULL);
1299 ContentInfo* ac = offer->GetContentByName("audio");
1300 ContentInfo* vc = offer->GetContentByName("video");
1301 ContentInfo* dc = offer->GetContentByName("data");
1302 ASSERT_TRUE(ac != NULL);
1303 ASSERT_TRUE(vc != NULL);
1304 ASSERT_TRUE(dc != NULL);
1305 ac->rejected = true;
1306 vc->rejected = true;
1307 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001308 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 f2_.CreateAnswer(offer.get(), opts, NULL));
1310 ac = answer->GetContentByName("audio");
1311 vc = answer->GetContentByName("video");
1312 dc = answer->GetContentByName("data");
1313 ASSERT_TRUE(ac != NULL);
1314 ASSERT_TRUE(vc != NULL);
1315 ASSERT_TRUE(dc != NULL);
1316 EXPECT_TRUE(ac->rejected);
1317 EXPECT_TRUE(vc->rejected);
1318 EXPECT_TRUE(dc->rejected);
1319}
1320
1321// Create an audio and video offer with:
1322// - one video track
1323// - two audio tracks
1324// - two data tracks
1325// and ensure it matches what we expect. Also updates the initial offer by
1326// adding a new video track and replaces one of the audio tracks.
1327TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1328 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001329 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1330 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1331 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001333 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1334 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001335
1336 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001337 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001338
1339 ASSERT_TRUE(offer.get() != NULL);
1340 const ContentInfo* ac = offer->GetContentByName("audio");
1341 const ContentInfo* vc = offer->GetContentByName("video");
1342 const ContentInfo* dc = offer->GetContentByName("data");
1343 ASSERT_TRUE(ac != NULL);
1344 ASSERT_TRUE(vc != NULL);
1345 ASSERT_TRUE(dc != NULL);
1346 const AudioContentDescription* acd =
1347 static_cast<const AudioContentDescription*>(ac->description);
1348 const VideoContentDescription* vcd =
1349 static_cast<const VideoContentDescription*>(vc->description);
1350 const DataContentDescription* dcd =
1351 static_cast<const DataContentDescription*>(dc->description);
1352 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001353 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001354
1355 const StreamParamsVec& audio_streams = acd->streams();
1356 ASSERT_EQ(2U, audio_streams.size());
1357 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1358 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1359 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1360 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1361 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1362 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1363 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1364
1365 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1366 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1367 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1368
1369 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1370 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1371 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1372
1373 const StreamParamsVec& video_streams = vcd->streams();
1374 ASSERT_EQ(1U, video_streams.size());
1375 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1376 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1377 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1378 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1379
1380 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1381 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1382 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1383
1384 const StreamParamsVec& data_streams = dcd->streams();
1385 ASSERT_EQ(2U, data_streams.size());
1386 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1387 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1388 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1389 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1390 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1391 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1392 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1393
1394 EXPECT_EQ(cricket::kDataMaxBandwidth,
1395 dcd->bandwidth()); // default bandwidth (auto)
1396 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1397 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1398
1399
1400 // Update the offer. Add a new video track that is not synched to the
1401 // other tracks and replace audio track 2 with audio track 3.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001402 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1403 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1404 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1405 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1406 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
kwiberg31022942016-03-11 14:18:21 -08001407 std::unique_ptr<SessionDescription> updated_offer(
1408 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409
1410 ASSERT_TRUE(updated_offer.get() != NULL);
1411 ac = updated_offer->GetContentByName("audio");
1412 vc = updated_offer->GetContentByName("video");
1413 dc = updated_offer->GetContentByName("data");
1414 ASSERT_TRUE(ac != NULL);
1415 ASSERT_TRUE(vc != NULL);
1416 ASSERT_TRUE(dc != NULL);
1417 const AudioContentDescription* updated_acd =
1418 static_cast<const AudioContentDescription*>(ac->description);
1419 const VideoContentDescription* updated_vcd =
1420 static_cast<const VideoContentDescription*>(vc->description);
1421 const DataContentDescription* updated_dcd =
1422 static_cast<const DataContentDescription*>(dc->description);
1423
1424 EXPECT_EQ(acd->type(), updated_acd->type());
1425 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1426 EXPECT_EQ(vcd->type(), updated_vcd->type());
1427 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1428 EXPECT_EQ(dcd->type(), updated_dcd->type());
1429 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1430 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1431 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1432 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1433 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1434 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1435 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1436
1437 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1438 ASSERT_EQ(2U, updated_audio_streams.size());
1439 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1440 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1441 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1442 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1443 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1444
1445 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1446 ASSERT_EQ(2U, updated_video_streams.size());
1447 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1448 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001449 // All the media streams in one PeerConnection share one RTCP CNAME.
1450 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001451
1452 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1453 ASSERT_EQ(2U, updated_data_streams.size());
1454 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1455 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1456 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1457 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1458 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001459 // The stream correctly got the CNAME from the MediaSessionOptions.
1460 // The Expected RTCP CNAME is the default one as we are using the default
1461 // MediaSessionOptions.
1462 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001463}
1464
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001465// Create an offer with simulcast video stream.
1466TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1467 MediaSessionOptions opts;
1468 const int num_sim_layers = 3;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001469 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
kwiberg31022942016-03-11 14:18:21 -08001470 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001471
1472 ASSERT_TRUE(offer.get() != NULL);
1473 const ContentInfo* vc = offer->GetContentByName("video");
1474 ASSERT_TRUE(vc != NULL);
1475 const VideoContentDescription* vcd =
1476 static_cast<const VideoContentDescription*>(vc->description);
1477
1478 const StreamParamsVec& video_streams = vcd->streams();
1479 ASSERT_EQ(1U, video_streams.size());
1480 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1481 const SsrcGroup* sim_ssrc_group =
1482 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1483 ASSERT_TRUE(sim_ssrc_group != NULL);
1484 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1485}
1486
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001487// Create an audio and video answer to a standard video offer with:
1488// - one video track
1489// - two audio tracks
1490// - two data tracks
1491// and ensure it matches what we expect. Also updates the initial answer by
1492// adding a new video track and removes one of the audio tracks.
1493TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1494 MediaSessionOptions offer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001495 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001496 offer_opts.data_channel_type = cricket::DCT_RTP;
1497 f1_.set_secure(SEC_ENABLED);
1498 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001499 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001500
1501 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001502 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1503 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1504 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001505 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001506 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1507 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508
kwiberg31022942016-03-11 14:18:21 -08001509 std::unique_ptr<SessionDescription> answer(
1510 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511
1512 ASSERT_TRUE(answer.get() != NULL);
1513 const ContentInfo* ac = answer->GetContentByName("audio");
1514 const ContentInfo* vc = answer->GetContentByName("video");
1515 const ContentInfo* dc = answer->GetContentByName("data");
1516 ASSERT_TRUE(ac != NULL);
1517 ASSERT_TRUE(vc != NULL);
1518 ASSERT_TRUE(dc != NULL);
1519 const AudioContentDescription* acd =
1520 static_cast<const AudioContentDescription*>(ac->description);
1521 const VideoContentDescription* vcd =
1522 static_cast<const VideoContentDescription*>(vc->description);
1523 const DataContentDescription* dcd =
1524 static_cast<const DataContentDescription*>(dc->description);
1525 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1526 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1527 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1528
1529 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1530 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1531
1532 const StreamParamsVec& audio_streams = acd->streams();
1533 ASSERT_EQ(2U, audio_streams.size());
1534 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1535 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1536 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1537 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1538 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1539 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1540 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1541
1542 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1543 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1544
1545 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1546 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1547
1548 const StreamParamsVec& video_streams = vcd->streams();
1549 ASSERT_EQ(1U, video_streams.size());
1550 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1551 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1552 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1553 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1554
1555 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1556 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1557
1558 const StreamParamsVec& data_streams = dcd->streams();
1559 ASSERT_EQ(2U, data_streams.size());
1560 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1561 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1562 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1563 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1564 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1565 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1566 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1567
1568 EXPECT_EQ(cricket::kDataMaxBandwidth,
1569 dcd->bandwidth()); // default bandwidth (auto)
1570 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1571
1572 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001573 // other tracks and remove 1 audio track.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001574 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1575 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1576 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
kwiberg31022942016-03-11 14:18:21 -08001577 std::unique_ptr<SessionDescription> updated_answer(
1578 f2_.CreateAnswer(offer.get(), opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579
1580 ASSERT_TRUE(updated_answer.get() != NULL);
1581 ac = updated_answer->GetContentByName("audio");
1582 vc = updated_answer->GetContentByName("video");
1583 dc = updated_answer->GetContentByName("data");
1584 ASSERT_TRUE(ac != NULL);
1585 ASSERT_TRUE(vc != NULL);
1586 ASSERT_TRUE(dc != NULL);
1587 const AudioContentDescription* updated_acd =
1588 static_cast<const AudioContentDescription*>(ac->description);
1589 const VideoContentDescription* updated_vcd =
1590 static_cast<const VideoContentDescription*>(vc->description);
1591 const DataContentDescription* updated_dcd =
1592 static_cast<const DataContentDescription*>(dc->description);
1593
1594 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1595 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1596 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1597 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1598 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1599 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1600
1601 EXPECT_EQ(acd->type(), updated_acd->type());
1602 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1603 EXPECT_EQ(vcd->type(), updated_vcd->type());
1604 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1605 EXPECT_EQ(dcd->type(), updated_dcd->type());
1606 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1607
1608 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1609 ASSERT_EQ(1U, updated_audio_streams.size());
1610 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1611
1612 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1613 ASSERT_EQ(2U, updated_video_streams.size());
1614 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1615 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001616 // All media streams in one PeerConnection share one CNAME.
1617 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618
1619 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1620 ASSERT_EQ(1U, updated_data_streams.size());
1621 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1622}
1623
1624
1625// Create an updated offer after creating an answer to the original offer and
1626// verify that the codecs that were part of the original answer are not changed
1627// in the updated offer.
1628TEST_F(MediaSessionDescriptionFactoryTest,
1629 RespondentCreatesOfferAfterCreatingAnswer) {
1630 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001631 opts.recv_audio = true;
1632 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633
kwiberg31022942016-03-11 14:18:21 -08001634 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1635 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 f2_.CreateAnswer(offer.get(), opts, NULL));
1637
1638 const AudioContentDescription* acd =
1639 GetFirstAudioContentDescription(answer.get());
1640 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1641
1642 const VideoContentDescription* vcd =
1643 GetFirstVideoContentDescription(answer.get());
1644 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1645
kwiberg31022942016-03-11 14:18:21 -08001646 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647 f2_.CreateOffer(opts, answer.get()));
1648
1649 // The expected audio codecs are the common audio codecs from the first
1650 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1651 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001652 // TODO(wu): |updated_offer| should not include the codec
1653 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001654 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001655 kAudioCodecsAnswer[0],
1656 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001657 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001658 };
1659
1660 // The expected video codecs are the common video codecs from the first
1661 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1662 // preference order.
1663 const VideoCodec kUpdatedVideoCodecOffer[] = {
1664 kVideoCodecsAnswer[0],
1665 kVideoCodecs2[1],
1666 };
1667
1668 const AudioContentDescription* updated_acd =
1669 GetFirstAudioContentDescription(updated_offer.get());
1670 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1671
1672 const VideoContentDescription* updated_vcd =
1673 GetFirstVideoContentDescription(updated_offer.get());
1674 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1675}
1676
1677// Create an updated offer after creating an answer to the original offer and
1678// verify that the codecs that were part of the original answer are not changed
1679// in the updated offer. In this test Rtx is enabled.
1680TEST_F(MediaSessionDescriptionFactoryTest,
1681 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1682 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001683 opts.recv_video = true;
1684 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001685 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001686 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001687 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688 f1_.set_video_codecs(f1_codecs);
1689
1690 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001691 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001692 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001693 f2_.set_video_codecs(f2_codecs);
1694
kwiberg31022942016-03-11 14:18:21 -08001695 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001696 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001697 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698 f2_.CreateAnswer(offer.get(), opts, NULL));
1699
1700 const VideoContentDescription* vcd =
1701 GetFirstVideoContentDescription(answer.get());
1702
1703 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001704 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1705 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706
1707 EXPECT_EQ(expected_codecs, vcd->codecs());
1708
deadbeef67cf2c12016-04-13 10:07:16 -07001709 // Now, make sure we get same result (except for the order) if |f2_| creates
1710 // an updated offer even though the default payload types between |f1_| and
1711 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08001712 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713 f2_.CreateOffer(opts, answer.get()));
1714 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001715 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001716 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1717
1718 const VideoContentDescription* updated_vcd =
1719 GetFirstVideoContentDescription(updated_answer.get());
1720
1721 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1722}
1723
1724// Create an updated offer that adds video after creating an audio only answer
1725// to the original offer. This test verifies that if a video codec and the RTX
1726// codec have the same default payload type as an audio codec that is already in
1727// use, the added codecs payload types are changed.
1728TEST_F(MediaSessionDescriptionFactoryTest,
1729 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1730 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001732 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001733 f1_.set_video_codecs(f1_codecs);
1734
1735 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001736 opts.recv_audio = true;
1737 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001738
kwiberg31022942016-03-11 14:18:21 -08001739 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1740 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001741 f2_.CreateAnswer(offer.get(), opts, NULL));
1742
1743 const AudioContentDescription* acd =
1744 GetFirstAudioContentDescription(answer.get());
1745 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1746
1747 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1748 // reference be the same as an audio codec that was negotiated in the
1749 // first offer/answer exchange.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001750 opts.recv_audio = true;
1751 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001752
1753 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1754 int used_pl_type = acd->codecs()[0].id;
1755 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001756 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001757 f2_.set_video_codecs(f2_codecs);
1758
kwiberg31022942016-03-11 14:18:21 -08001759 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001760 f2_.CreateOffer(opts, answer.get()));
1761 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001762 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1764
1765 const AudioContentDescription* updated_acd =
1766 GetFirstAudioContentDescription(answer.get());
1767 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1768
1769 const VideoContentDescription* updated_vcd =
1770 GetFirstVideoContentDescription(updated_answer.get());
1771
1772 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001773 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1775 EXPECT_NE(used_pl_type, new_h264_pl_type);
1776 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001777 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1779 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1780}
1781
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001782// Create an updated offer with RTX after creating an answer to an offer
1783// without RTX, and with different default payload types.
1784// Verify that the added RTX codec references the correct payload type.
1785TEST_F(MediaSessionDescriptionFactoryTest,
1786 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
1787 MediaSessionOptions opts;
1788 opts.recv_video = true;
1789 opts.recv_audio = true;
1790
1791 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1792 // This creates rtx for H264 with the payload type |f2_| uses.
1793 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1794 f2_.set_video_codecs(f2_codecs);
1795
kwiberg31022942016-03-11 14:18:21 -08001796 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001797 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08001798 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001799 f2_.CreateAnswer(offer.get(), opts, nullptr));
1800
1801 const VideoContentDescription* vcd =
1802 GetFirstVideoContentDescription(answer.get());
1803
1804 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1805 EXPECT_EQ(expected_codecs, vcd->codecs());
1806
1807 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
1808 // updated offer, even though the default payload types are different from
1809 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08001810 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001811 f2_.CreateOffer(opts, answer.get()));
1812 ASSERT_TRUE(updated_offer);
1813
1814 const VideoContentDescription* updated_vcd =
1815 GetFirstVideoContentDescription(updated_offer.get());
1816
1817 // New offer should attempt to add H263, and RTX for H264.
1818 expected_codecs.push_back(kVideoCodecs2[1]);
1819 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
1820 &expected_codecs);
1821 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1822}
1823
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001824// Test that RTX is ignored when there is no associated payload type parameter.
1825TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1826 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001827 opts.recv_video = true;
1828 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001829 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001830 // This creates RTX without associated payload type parameter.
deadbeef67cf2c12016-04-13 10:07:16 -07001831 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName, 0, 0, 0), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001832 f1_.set_video_codecs(f1_codecs);
1833
1834 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001835 // This creates RTX for H264 with the payload type |f2_| uses.
1836 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837 f2_.set_video_codecs(f2_codecs);
1838
kwiberg31022942016-03-11 14:18:21 -08001839 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 ASSERT_TRUE(offer.get() != NULL);
1841 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1842 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1843 // is possible to test that that RTX is dropped when
1844 // kCodecParamAssociatedPayloadType is missing in the offer.
1845 VideoContentDescription* desc =
1846 static_cast<cricket::VideoContentDescription*>(
1847 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1848 ASSERT_TRUE(desc != NULL);
1849 std::vector<VideoCodec> codecs = desc->codecs();
1850 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1851 iter != codecs.end(); ++iter) {
1852 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1853 iter->params.clear();
1854 }
1855 }
1856 desc->set_codecs(codecs);
1857
kwiberg31022942016-03-11 14:18:21 -08001858 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001859 f2_.CreateAnswer(offer.get(), opts, NULL));
1860
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001861 std::vector<std::string> codec_names =
1862 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1863 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1864 cricket::kRtxCodecName));
1865}
1866
1867// Test that RTX will be filtered out in the answer if its associated payload
1868// type doesn't match the local value.
1869TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1870 MediaSessionOptions opts;
1871 opts.recv_video = true;
1872 opts.recv_audio = false;
1873 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1874 // This creates RTX for H264 in sender.
1875 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1876 f1_.set_video_codecs(f1_codecs);
1877
1878 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1879 // This creates RTX for H263 in receiver.
1880 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1881 f2_.set_video_codecs(f2_codecs);
1882
kwiberg31022942016-03-11 14:18:21 -08001883 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001884 ASSERT_TRUE(offer.get() != NULL);
1885 // Associated payload type doesn't match, therefore, RTX codec is removed in
1886 // the answer.
kwiberg31022942016-03-11 14:18:21 -08001887 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001888 f2_.CreateAnswer(offer.get(), opts, NULL));
1889
1890 std::vector<std::string> codec_names =
1891 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1892 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1893 cricket::kRtxCodecName));
1894}
1895
1896// Test that when multiple RTX codecs are offered, only the matched RTX codec
1897// is added in the answer, and the unsupported RTX codec is filtered out.
1898TEST_F(MediaSessionDescriptionFactoryTest,
1899 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1900 MediaSessionOptions opts;
1901 opts.recv_video = true;
1902 opts.recv_audio = false;
1903 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1904 // This creates RTX for H264-SVC in sender.
1905 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1906 f1_.set_video_codecs(f1_codecs);
1907
1908 // This creates RTX for H264 in sender.
1909 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1910 f1_.set_video_codecs(f1_codecs);
1911
1912 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1913 // This creates RTX for H264 in receiver.
1914 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1915 f2_.set_video_codecs(f2_codecs);
1916
1917 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1918 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08001919 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001920 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001921 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001922 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001923 const VideoContentDescription* vcd =
1924 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001925 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1926 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1927 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001928
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001929 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001930}
1931
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001932// Test that after one RTX codec has been negotiated, a new offer can attempt
1933// to add another.
1934TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
1935 MediaSessionOptions opts;
1936 opts.recv_video = true;
1937 opts.recv_audio = false;
1938 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1939 // This creates RTX for H264 for the offerer.
1940 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1941 f1_.set_video_codecs(f1_codecs);
1942
kwiberg31022942016-03-11 14:18:21 -08001943 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001944 ASSERT_TRUE(offer);
1945 const VideoContentDescription* vcd =
1946 GetFirstVideoContentDescription(offer.get());
1947
1948 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
1949 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1950 &expected_codecs);
1951 EXPECT_EQ(expected_codecs, vcd->codecs());
1952
1953 // Now, attempt to add RTX for H264-SVC.
1954 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1955 f1_.set_video_codecs(f1_codecs);
1956
kwiberg31022942016-03-11 14:18:21 -08001957 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001958 f1_.CreateOffer(opts, offer.get()));
1959 ASSERT_TRUE(updated_offer);
1960 vcd = GetFirstVideoContentDescription(updated_offer.get());
1961
1962 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
1963 &expected_codecs);
1964 EXPECT_EQ(expected_codecs, vcd->codecs());
1965}
1966
Noah Richards2e7a0982015-05-18 14:02:54 -07001967// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1968// generated for each simulcast ssrc and correctly grouped.
1969TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1970 MediaSessionOptions opts;
1971 opts.recv_video = true;
1972 opts.recv_audio = false;
1973
1974 // Add simulcast streams.
1975 opts.AddSendVideoStream("stream1", "stream1label", 3);
1976
1977 // Use a single real codec, and then add RTX for it.
1978 std::vector<VideoCodec> f1_codecs;
deadbeef67cf2c12016-04-13 10:07:16 -07001979 f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30));
Noah Richards2e7a0982015-05-18 14:02:54 -07001980 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1981 f1_.set_video_codecs(f1_codecs);
1982
1983 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1984 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08001985 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07001986 ASSERT_TRUE(offer.get() != NULL);
1987 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
1988 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1989 ASSERT_TRUE(desc != NULL);
1990 EXPECT_TRUE(desc->multistream());
1991 const StreamParamsVec& streams = desc->streams();
1992 // Single stream.
1993 ASSERT_EQ(1u, streams.size());
1994 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
1995 EXPECT_EQ(6u, streams[0].ssrcs.size());
1996 // And should have a SIM group for the simulcast.
1997 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
1998 // And a FID group for RTX.
1999 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002000 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002001 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2002 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002003 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002004 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2005 EXPECT_EQ(3u, fid_ssrcs.size());
2006}
2007
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008// Create an updated offer after creating an answer to the original offer and
2009// verify that the RTP header extensions that were part of the original answer
2010// are not changed in the updated offer.
2011TEST_F(MediaSessionDescriptionFactoryTest,
2012 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2013 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002014 opts.recv_audio = true;
2015 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002016
2017 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2018 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2019 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2020 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2021
kwiberg31022942016-03-11 14:18:21 -08002022 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2023 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024 f2_.CreateAnswer(offer.get(), opts, NULL));
2025
2026 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2027 GetFirstAudioContentDescription(
2028 answer.get())->rtp_header_extensions());
2029 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2030 GetFirstVideoContentDescription(
2031 answer.get())->rtp_header_extensions());
2032
kwiberg31022942016-03-11 14:18:21 -08002033 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034 f2_.CreateOffer(opts, answer.get()));
2035
2036 // The expected RTP header extensions in the new offer are the resulting
2037 // extensions from the first offer/answer exchange plus the extensions only
2038 // |f2_| offer.
2039 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002040 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002041 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2042 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2043 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044 };
2045
2046 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002047 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002048 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2049 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2050 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002051 };
2052
2053 const AudioContentDescription* updated_acd =
2054 GetFirstAudioContentDescription(updated_offer.get());
2055 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2056 updated_acd->rtp_header_extensions());
2057
2058 const VideoContentDescription* updated_vcd =
2059 GetFirstVideoContentDescription(updated_offer.get());
2060 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2061 updated_vcd->rtp_header_extensions());
2062}
2063
deadbeefa5b273a2015-08-20 17:30:13 -07002064// Verify that if the same RTP extension URI is used for audio and video, the
2065// same ID is used. Also verify that the ID isn't changed when creating an
2066// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002067TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002068 MediaSessionOptions opts;
2069 opts.recv_audio = true;
2070 opts.recv_video = true;
2071
2072 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2073 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2074
kwiberg31022942016-03-11 14:18:21 -08002075 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002076
2077 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2078 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002079 const RtpExtension kExpectedVideoRtpExtension[] = {
2080 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002081 };
2082
2083 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2084 GetFirstAudioContentDescription(
2085 offer.get())->rtp_header_extensions());
2086 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2087 GetFirstVideoContentDescription(
2088 offer.get())->rtp_header_extensions());
2089
2090 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002091 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002092 f1_.CreateOffer(opts, offer.get()));
2093
2094 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2095 GetFirstAudioContentDescription(
2096 updated_offer.get())->rtp_header_extensions());
2097 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2098 GetFirstVideoContentDescription(
2099 updated_offer.get())->rtp_header_extensions());
2100}
2101
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002102TEST(MediaSessionDescription, CopySessionDescription) {
2103 SessionDescription source;
2104 cricket::ContentGroup group(cricket::CN_AUDIO);
2105 source.AddGroup(group);
2106 AudioContentDescription* acd(new AudioContentDescription());
2107 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2108 acd->AddLegacyStream(1);
2109 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2110 VideoContentDescription* vcd(new VideoContentDescription());
2111 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2112 vcd->AddLegacyStream(2);
2113 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2114
kwiberg31022942016-03-11 14:18:21 -08002115 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116 ASSERT_TRUE(copy.get() != NULL);
2117 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2118 const ContentInfo* ac = copy->GetContentByName("audio");
2119 const ContentInfo* vc = copy->GetContentByName("video");
2120 ASSERT_TRUE(ac != NULL);
2121 ASSERT_TRUE(vc != NULL);
2122 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2123 const AudioContentDescription* acd_copy =
2124 static_cast<const AudioContentDescription*>(ac->description);
2125 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2126 EXPECT_EQ(1u, acd->first_ssrc());
2127
2128 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2129 const VideoContentDescription* vcd_copy =
2130 static_cast<const VideoContentDescription*>(vc->description);
2131 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2132 EXPECT_EQ(2u, vcd->first_ssrc());
2133}
2134
2135// The below TestTransportInfoXXX tests create different offers/answers, and
2136// ensure the TransportInfo in the SessionDescription matches what we expect.
2137TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2138 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002139 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002140 TestTransportInfo(true, options, false);
2141}
2142
2143TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2144 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002145 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002146 TestTransportInfo(true, options, true);
2147}
2148
2149TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2150 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002151 options.recv_audio = true;
2152 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002153 options.data_channel_type = cricket::DCT_RTP;
2154 TestTransportInfo(true, options, false);
2155}
2156
2157TEST_F(MediaSessionDescriptionFactoryTest,
2158 TestTransportInfoOfferMultimediaCurrent) {
2159 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002160 options.recv_audio = true;
2161 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002162 options.data_channel_type = cricket::DCT_RTP;
2163 TestTransportInfo(true, options, true);
2164}
2165
2166TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2167 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002168 options.recv_audio = true;
2169 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002170 options.data_channel_type = cricket::DCT_RTP;
2171 options.bundle_enabled = true;
2172 TestTransportInfo(true, options, false);
2173}
2174
2175TEST_F(MediaSessionDescriptionFactoryTest,
2176 TestTransportInfoOfferBundleCurrent) {
2177 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002178 options.recv_audio = true;
2179 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002180 options.data_channel_type = cricket::DCT_RTP;
2181 options.bundle_enabled = true;
2182 TestTransportInfo(true, options, true);
2183}
2184
2185TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2186 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002187 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 TestTransportInfo(false, options, false);
2189}
2190
2191TEST_F(MediaSessionDescriptionFactoryTest,
2192 TestTransportInfoAnswerAudioCurrent) {
2193 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002194 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195 TestTransportInfo(false, options, true);
2196}
2197
2198TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2199 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002200 options.recv_audio = true;
2201 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002202 options.data_channel_type = cricket::DCT_RTP;
2203 TestTransportInfo(false, options, false);
2204}
2205
2206TEST_F(MediaSessionDescriptionFactoryTest,
2207 TestTransportInfoAnswerMultimediaCurrent) {
2208 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002209 options.recv_audio = true;
2210 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002211 options.data_channel_type = cricket::DCT_RTP;
2212 TestTransportInfo(false, options, true);
2213}
2214
2215TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2216 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002217 options.recv_audio = true;
2218 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002219 options.data_channel_type = cricket::DCT_RTP;
2220 options.bundle_enabled = true;
2221 TestTransportInfo(false, options, false);
2222}
2223
2224TEST_F(MediaSessionDescriptionFactoryTest,
2225 TestTransportInfoAnswerBundleCurrent) {
2226 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002227 options.recv_audio = true;
2228 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002229 options.data_channel_type = cricket::DCT_RTP;
2230 options.bundle_enabled = true;
2231 TestTransportInfo(false, options, true);
2232}
2233
2234// Create an offer with bundle enabled and verify the crypto parameters are
2235// the common set of the available cryptos.
2236TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2237 TestCryptoWithBundle(true);
2238}
2239
2240// Create an answer with bundle enabled and verify the crypto parameters are
2241// the common set of the available cryptos.
2242TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2243 TestCryptoWithBundle(false);
2244}
2245
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002246// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2247// DTLS is not enabled locally.
2248TEST_F(MediaSessionDescriptionFactoryTest,
2249 TestOfferDtlsSavpfWithoutDtlsFailed) {
2250 f1_.set_secure(SEC_ENABLED);
2251 f2_.set_secure(SEC_ENABLED);
2252 tdf1_.set_secure(SEC_DISABLED);
2253 tdf2_.set_secure(SEC_DISABLED);
2254
kwiberg31022942016-03-11 14:18:21 -08002255 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002256 f1_.CreateOffer(MediaSessionOptions(), NULL));
2257 ASSERT_TRUE(offer.get() != NULL);
2258 ContentInfo* offer_content = offer->GetContentByName("audio");
2259 ASSERT_TRUE(offer_content != NULL);
2260 AudioContentDescription* offer_audio_desc =
2261 static_cast<AudioContentDescription*>(offer_content->description);
2262 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2263
kwiberg31022942016-03-11 14:18:21 -08002264 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002265 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2266 ASSERT_TRUE(answer != NULL);
2267 ContentInfo* answer_content = answer->GetContentByName("audio");
2268 ASSERT_TRUE(answer_content != NULL);
2269
2270 ASSERT_TRUE(answer_content->rejected);
2271}
2272
2273// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2274// UDP/TLS/RTP/SAVPF.
2275TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2276 f1_.set_secure(SEC_ENABLED);
2277 f2_.set_secure(SEC_ENABLED);
2278 tdf1_.set_secure(SEC_ENABLED);
2279 tdf2_.set_secure(SEC_ENABLED);
2280
kwiberg31022942016-03-11 14:18:21 -08002281 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002282 f1_.CreateOffer(MediaSessionOptions(), NULL));
2283 ASSERT_TRUE(offer.get() != NULL);
2284 ContentInfo* offer_content = offer->GetContentByName("audio");
2285 ASSERT_TRUE(offer_content != NULL);
2286 AudioContentDescription* offer_audio_desc =
2287 static_cast<AudioContentDescription*>(offer_content->description);
2288 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2289
kwiberg31022942016-03-11 14:18:21 -08002290 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002291 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2292 ASSERT_TRUE(answer != NULL);
2293
2294 const ContentInfo* answer_content = answer->GetContentByName("audio");
2295 ASSERT_TRUE(answer_content != NULL);
2296 ASSERT_FALSE(answer_content->rejected);
2297
2298 const AudioContentDescription* answer_audio_desc =
2299 static_cast<const AudioContentDescription*>(answer_content->description);
2300 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2301 answer_audio_desc->protocol());
2302}
2303
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002304// Test that we include both SDES and DTLS in the offer, but only include SDES
2305// in the answer if DTLS isn't negotiated.
2306TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2307 f1_.set_secure(SEC_ENABLED);
2308 f2_.set_secure(SEC_ENABLED);
2309 tdf1_.set_secure(SEC_ENABLED);
2310 tdf2_.set_secure(SEC_DISABLED);
2311 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002312 options.recv_audio = true;
2313 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002314 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002315 const cricket::MediaContentDescription* audio_media_desc;
2316 const cricket::MediaContentDescription* video_media_desc;
2317 const cricket::TransportDescription* audio_trans_desc;
2318 const cricket::TransportDescription* video_trans_desc;
2319
2320 // Generate an offer with SDES and DTLS support.
2321 offer.reset(f1_.CreateOffer(options, NULL));
2322 ASSERT_TRUE(offer.get() != NULL);
2323
2324 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2325 offer->GetContentDescriptionByName("audio"));
2326 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002327 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328 offer->GetContentDescriptionByName("video"));
2329 ASSERT_TRUE(video_media_desc != NULL);
2330 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2331 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2332
2333 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2334 ASSERT_TRUE(audio_trans_desc != NULL);
2335 video_trans_desc = offer->GetTransportDescriptionByName("video");
2336 ASSERT_TRUE(video_trans_desc != NULL);
2337 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2338 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2339
2340 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2341 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2342 ASSERT_TRUE(answer.get() != NULL);
2343
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002344 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002345 answer->GetContentDescriptionByName("audio"));
2346 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002347 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348 answer->GetContentDescriptionByName("video"));
2349 ASSERT_TRUE(video_media_desc != NULL);
2350 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2351 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2352
2353 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2354 ASSERT_TRUE(audio_trans_desc != NULL);
2355 video_trans_desc = answer->GetTransportDescriptionByName("video");
2356 ASSERT_TRUE(video_trans_desc != NULL);
2357 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2358 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2359
2360 // Enable DTLS; the answer should now only have DTLS support.
2361 tdf2_.set_secure(SEC_ENABLED);
2362 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2363 ASSERT_TRUE(answer.get() != NULL);
2364
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002365 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002366 answer->GetContentDescriptionByName("audio"));
2367 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002368 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369 answer->GetContentDescriptionByName("video"));
2370 ASSERT_TRUE(video_media_desc != NULL);
2371 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2372 EXPECT_TRUE(video_media_desc->cryptos().empty());
2373 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2374 audio_media_desc->protocol());
2375 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2376 video_media_desc->protocol());
2377
2378 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2379 ASSERT_TRUE(audio_trans_desc != NULL);
2380 video_trans_desc = answer->GetTransportDescriptionByName("video");
2381 ASSERT_TRUE(video_trans_desc != NULL);
2382 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2383 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002384
2385 // Try creating offer again. DTLS enabled now, crypto's should be empty
2386 // in new offer.
2387 offer.reset(f1_.CreateOffer(options, offer.get()));
2388 ASSERT_TRUE(offer.get() != NULL);
2389 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2390 offer->GetContentDescriptionByName("audio"));
2391 ASSERT_TRUE(audio_media_desc != NULL);
2392 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2393 offer->GetContentDescriptionByName("video"));
2394 ASSERT_TRUE(video_media_desc != NULL);
2395 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2396 EXPECT_TRUE(video_media_desc->cryptos().empty());
2397
2398 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2399 ASSERT_TRUE(audio_trans_desc != NULL);
2400 video_trans_desc = offer->GetTransportDescriptionByName("video");
2401 ASSERT_TRUE(video_trans_desc != NULL);
2402 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2403 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404}
2405
2406// Test that an answer can't be created if cryptos are required but the offer is
2407// unsecure.
2408TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2409 MediaSessionOptions options;
2410 f1_.set_secure(SEC_DISABLED);
2411 tdf1_.set_secure(SEC_DISABLED);
2412 f2_.set_secure(SEC_REQUIRED);
2413 tdf1_.set_secure(SEC_ENABLED);
2414
kwiberg31022942016-03-11 14:18:21 -08002415 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002416 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002417 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002418 f2_.CreateAnswer(offer.get(), options, NULL));
2419 EXPECT_TRUE(answer.get() == NULL);
2420}
2421
2422// Test that we accept a DTLS offer without SDES and create an appropriate
2423// answer.
2424TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2425 f1_.set_secure(SEC_DISABLED);
2426 f2_.set_secure(SEC_ENABLED);
2427 tdf1_.set_secure(SEC_ENABLED);
2428 tdf2_.set_secure(SEC_ENABLED);
2429 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002430 options.recv_audio = true;
2431 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432 options.data_channel_type = cricket::DCT_RTP;
2433
kwiberg31022942016-03-11 14:18:21 -08002434 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002435
2436 // Generate an offer with DTLS but without SDES.
2437 offer.reset(f1_.CreateOffer(options, NULL));
2438 ASSERT_TRUE(offer.get() != NULL);
2439
2440 const AudioContentDescription* audio_offer =
2441 GetFirstAudioContentDescription(offer.get());
2442 ASSERT_TRUE(audio_offer->cryptos().empty());
2443 const VideoContentDescription* video_offer =
2444 GetFirstVideoContentDescription(offer.get());
2445 ASSERT_TRUE(video_offer->cryptos().empty());
2446 const DataContentDescription* data_offer =
2447 GetFirstDataContentDescription(offer.get());
2448 ASSERT_TRUE(data_offer->cryptos().empty());
2449
2450 const cricket::TransportDescription* audio_offer_trans_desc =
2451 offer->GetTransportDescriptionByName("audio");
2452 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2453 const cricket::TransportDescription* video_offer_trans_desc =
2454 offer->GetTransportDescriptionByName("video");
2455 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2456 const cricket::TransportDescription* data_offer_trans_desc =
2457 offer->GetTransportDescriptionByName("data");
2458 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2459
2460 // Generate an answer with DTLS.
2461 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2462 ASSERT_TRUE(answer.get() != NULL);
2463
2464 const cricket::TransportDescription* audio_answer_trans_desc =
2465 answer->GetTransportDescriptionByName("audio");
2466 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2467 const cricket::TransportDescription* video_answer_trans_desc =
2468 answer->GetTransportDescriptionByName("video");
2469 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2470 const cricket::TransportDescription* data_answer_trans_desc =
2471 answer->GetTransportDescriptionByName("data");
2472 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2473}
2474
2475// Verifies if vad_enabled option is set to false, CN codecs are not present in
2476// offer or answer.
2477TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2478 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002479 options.recv_audio = true;
2480 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002481 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002482 ASSERT_TRUE(offer.get() != NULL);
2483 const ContentInfo* audio_content = offer->GetContentByName("audio");
2484 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2485
2486 options.vad_enabled = false;
2487 offer.reset(f1_.CreateOffer(options, NULL));
2488 ASSERT_TRUE(offer.get() != NULL);
2489 audio_content = offer->GetContentByName("audio");
2490 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002491 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492 f1_.CreateAnswer(offer.get(), options, NULL));
2493 ASSERT_TRUE(answer.get() != NULL);
2494 audio_content = answer->GetContentByName("audio");
2495 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2496}
deadbeef44f08192015-12-15 16:20:09 -08002497
2498// Test that the content name ("mid" in SDP) is unchanged when creating a
2499// new offer.
2500TEST_F(MediaSessionDescriptionFactoryTest,
2501 TestContentNameNotChangedInSubsequentOffers) {
2502 MediaSessionOptions opts;
2503 opts.recv_audio = true;
2504 opts.recv_video = true;
2505 opts.data_channel_type = cricket::DCT_SCTP;
2506 // Create offer and modify the default content names.
kwiberg31022942016-03-11 14:18:21 -08002507 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
deadbeef44f08192015-12-15 16:20:09 -08002508 for (ContentInfo& content : offer->contents()) {
2509 content.name.append("_modified");
2510 }
2511
kwiberg31022942016-03-11 14:18:21 -08002512 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002513 f1_.CreateOffer(opts, offer.get()));
2514 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2515 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2516 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2517 ASSERT_TRUE(audio_content != nullptr);
2518 ASSERT_TRUE(video_content != nullptr);
2519 ASSERT_TRUE(data_content != nullptr);
2520 EXPECT_EQ("audio_modified", audio_content->name);
2521 EXPECT_EQ("video_modified", video_content->name);
2522 EXPECT_EQ("data_modified", data_content->name);
2523}
zhihuangcf5b37c2016-05-05 11:44:35 -07002524
2525class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
2526 public:
2527 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07002528 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
2529 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07002530 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
2531 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07002532 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
2533 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07002534 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
2535 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
2536 f1_.set_secure(SEC_ENABLED);
2537 f2_.set_secure(SEC_ENABLED);
2538 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002539 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002540 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002541 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002542 tdf1_.set_secure(SEC_ENABLED);
2543 tdf2_.set_secure(SEC_ENABLED);
2544 }
2545
2546 protected:
2547 MediaSessionDescriptionFactory f1_;
2548 MediaSessionDescriptionFactory f2_;
2549 TransportDescriptionFactory tdf1_;
2550 TransportDescriptionFactory tdf2_;
2551};
2552
2553TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
2554 MediaSessionOptions opts;
2555 opts.recv_video = true;
2556 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2557 ASSERT_TRUE(offer.get() != nullptr);
2558 // Set the protocol for all the contents.
2559 for (auto content : offer.get()->contents()) {
2560 static_cast<MediaContentDescription*>(content.description)
2561 ->set_protocol(GetParam());
2562 }
2563 std::unique_ptr<SessionDescription> answer(
2564 f2_.CreateAnswer(offer.get(), opts, nullptr));
2565 const ContentInfo* ac = answer->GetContentByName("audio");
2566 const ContentInfo* vc = answer->GetContentByName("video");
2567 ASSERT_TRUE(ac != nullptr);
2568 ASSERT_TRUE(vc != nullptr);
2569 EXPECT_FALSE(ac->rejected); // the offer is accepted
2570 EXPECT_FALSE(vc->rejected);
2571 const AudioContentDescription* acd =
2572 static_cast<const AudioContentDescription*>(ac->description);
2573 const VideoContentDescription* vcd =
2574 static_cast<const VideoContentDescription*>(vc->description);
2575 EXPECT_EQ(GetParam(), acd->protocol());
2576 EXPECT_EQ(GetParam(), vcd->protocol());
2577}
2578
2579INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
2580 MediaProtocolTest,
2581 ::testing::ValuesIn(kMediaProtocols));
2582INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
2583 MediaProtocolTest,
2584 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07002585
2586TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
2587 TransportDescriptionFactory tdf;
2588 MediaSessionDescriptionFactory sf(&tdf);
2589 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2590 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2591
2592 // The merged list of codecs should contain any send codecs that are also
2593 // nominally in the recieve codecs list. Payload types should be picked from
2594 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
2595 // (set to 1). This equals what happens when the send codecs are used in an
2596 // offer and the receive codecs are used in the following answer.
2597 const std::vector<AudioCodec> sendrecv_codecs =
2598 MAKE_VECTOR(kAudioCodecsAnswer);
2599 const std::vector<AudioCodec> no_codecs;
2600
2601 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
2602 << "Please don't change shared test data!";
2603 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
2604 << "Please don't change shared test data!";
2605 // Alter iLBC send codec to have zero channels, to test that that is handled
2606 // properly.
2607 send_codecs[1].channels = 0;
2608
2609 // Alther iLBC receive codec to be lowercase, to test that case conversions
2610 // are handled properly.
2611 recv_codecs[2].name = "ilbc";
2612
2613 // Test proper merge
2614 sf.set_audio_codecs(send_codecs, recv_codecs);
2615 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2616 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002617 EXPECT_TRUE(sf.audio_sendrecv_codecs() == sendrecv_codecs);
ossu075af922016-06-14 03:29:38 -07002618
2619 // Test empty send codecs list
2620 sf.set_audio_codecs(no_codecs, recv_codecs);
2621 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2622 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002623 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002624
2625 // Test empty recv codecs list
2626 sf.set_audio_codecs(send_codecs, no_codecs);
2627 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2628 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002629 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002630
2631 // Test all empty codec lists
2632 sf.set_audio_codecs(no_codecs, no_codecs);
2633 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2634 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002635 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002636}
2637
2638namespace {
2639void TestAudioCodecsOffer(MediaContentDirection direction,
2640 bool add_legacy_stream) {
2641 TransportDescriptionFactory tdf;
2642 MediaSessionDescriptionFactory sf(&tdf);
2643 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2644 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2645 const std::vector<AudioCodec> sendrecv_codecs =
2646 MAKE_VECTOR(kAudioCodecsAnswer);
2647 sf.set_audio_codecs(send_codecs, recv_codecs);
2648 sf.set_add_legacy_streams(add_legacy_stream);
2649
2650 MediaSessionOptions opts;
2651 opts.recv_audio = (direction == cricket::MD_RECVONLY ||
2652 direction == cricket::MD_SENDRECV);
2653 opts.recv_video = false;
2654 if (direction == cricket::MD_SENDONLY || direction == cricket::MD_SENDRECV)
2655 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2656
2657 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
2658 ASSERT_TRUE(offer.get() != NULL);
2659 const ContentInfo* ac = offer->GetContentByName("audio");
2660
2661 // If the factory didn't add any audio content to the offer, we cannot check
2662 // that the codecs put in are right. This happens when we neither want to send
2663 // nor receive audio. The checks are still in place if at some point we'd
2664 // instead create an inactive stream.
2665 if (ac) {
2666 AudioContentDescription* acd =
2667 static_cast<AudioContentDescription*>(ac->description);
2668 // sendrecv and inactive should both present lists as if the channel was to
2669 // be used for sending and receiving. Inactive essentially means it might
2670 // eventually be used anything, but we don't know more at this moment.
2671 if (acd->direction() == cricket::MD_SENDONLY) {
2672 EXPECT_TRUE(acd->codecs() == send_codecs);
2673 } else if (acd->direction() == cricket::MD_RECVONLY) {
2674 EXPECT_TRUE(acd->codecs() == recv_codecs);
2675 } else {
2676 EXPECT_TRUE(acd->codecs() == sendrecv_codecs);
2677 }
2678 }
2679}
2680
2681static const AudioCodec kOfferAnswerCodecs[] = {
2682 AudioCodec(0, "codec0", 16000, -1, 1),
2683 AudioCodec(1, "codec1", 8000, 13300, 1),
2684 AudioCodec(2, "codec2", 8000, 64000, 1),
2685 AudioCodec(3, "codec3", 8000, 64000, 1),
2686 AudioCodec(4, "codec4", 8000, 0, 2),
2687 AudioCodec(5, "codec5", 32000, 0, 1),
2688 AudioCodec(6, "codec6", 48000, 0, 1)
2689};
2690
2691
2692/* The codecs groups below are chosen as per the matrix below. The objective is
2693 * to have different sets of codecs in the inputs, to get unique sets of codecs
2694 * after negotiation, depending on offer and answer communication directions.
2695 * One-way directions in the offer should either result in the opposite
2696 * direction in the answer, or an inactive answer. Regardless, the choice of
2697 * codecs should be as if the answer contained the opposite direction.
2698 * Inactive offers should be treated as sendrecv/sendrecv.
2699 *
2700 * | Offer | Answer | Result
2701 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
2702 * 0 | x - - | - x - | x - - - -
2703 * 1 | x x x | - x - | x - - x -
2704 * 2 | - x - | x - - | - x - - -
2705 * 3 | x x x | x - - | - x x - -
2706 * 4 | - x - | x x x | - x - - -
2707 * 5 | x - - | x x x | x - - - -
2708 * 6 | x x x | x x x | x x x x x
2709 */
2710// Codecs used by offerer in the AudioCodecsAnswerTest
2711static const int kOfferSendCodecs[] = { 0, 1, 3, 5, 6 };
2712static const int kOfferRecvCodecs[] = { 1, 2, 3, 4, 6 };
2713// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
2714// jumbled to catch the answer not following the order in the offer.
2715static const int kAnswerSendCodecs[] = { 6, 5, 2, 3, 4 };
2716static const int kAnswerRecvCodecs[] = { 6, 5, 4, 1, 0 };
2717// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
2718static const int kResultSend_RecvCodecs[] = { 0, 1, 5, 6 };
2719static const int kResultRecv_SendCodecs[] = { 2, 3, 4, 6 };
2720static const int kResultSendrecv_SendCodecs[] = { 3, 6 };
2721static const int kResultSendrecv_RecvCodecs[] = { 1, 6 };
2722static const int kResultSendrecv_SendrecvCodecs[] = { 6 };
2723
2724template <typename T, int IDXS>
2725std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
2726 std::vector<T> out;
2727 out.reserve(IDXS);
2728 for (int idx : indices)
2729 out.push_back(array[idx]);
2730
2731 return out;
2732}
2733
2734void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
2735 MediaContentDirection answer_direction,
2736 bool add_legacy_stream) {
2737 TransportDescriptionFactory offer_tdf;
2738 TransportDescriptionFactory answer_tdf;
2739 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
2740 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
2741 offer_factory.set_audio_codecs(
2742 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
2743 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
2744 answer_factory.set_audio_codecs(
2745 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
2746 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
2747
2748 // Never add a legacy stream to offer - we want to control the offer
2749 // parameters exactly.
2750 offer_factory.set_add_legacy_streams(false);
2751 answer_factory.set_add_legacy_streams(add_legacy_stream);
2752 MediaSessionOptions offer_opts;
2753 offer_opts.recv_audio = (offer_direction == cricket::MD_RECVONLY ||
2754 offer_direction == cricket::MD_SENDRECV);
2755 offer_opts.recv_video = false;
2756 if (offer_direction == cricket::MD_SENDONLY ||
2757 offer_direction == cricket::MD_SENDRECV) {
2758 offer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2759 }
2760
2761 std::unique_ptr<SessionDescription> offer(
2762 offer_factory.CreateOffer(offer_opts, NULL));
2763 ASSERT_TRUE(offer.get() != NULL);
2764
2765 MediaSessionOptions answer_opts;
2766 answer_opts.recv_audio = (answer_direction == cricket::MD_RECVONLY ||
2767 answer_direction == cricket::MD_SENDRECV);
2768 answer_opts.recv_video = false;
2769 if (answer_direction == cricket::MD_SENDONLY ||
2770 answer_direction == cricket::MD_SENDRECV) {
2771 answer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2772 }
2773 std::unique_ptr<SessionDescription> answer(
2774 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
2775 const ContentInfo* ac = answer->GetContentByName("audio");
2776
2777 // If the factory didn't add any audio content to the answer, we cannot check
2778 // that the codecs put in are right. This happens when we neither want to send
2779 // nor receive audio. The checks are still in place if at some point we'd
2780 // instead create an inactive stream.
2781 if (ac) {
2782 const AudioContentDescription* acd =
2783 static_cast<const AudioContentDescription*>(ac->description);
2784 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2785
2786
2787 std::vector<AudioCodec> target_codecs;
2788 // For offers with sendrecv or inactive, we should never reply with more
2789 // codecs than offered, with these codec sets.
2790 switch (offer_direction) {
2791 case cricket::MD_INACTIVE:
2792 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2793 kResultSendrecv_SendrecvCodecs);
2794 break;
2795 case cricket::MD_SENDONLY:
2796 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2797 kResultSend_RecvCodecs);
2798 break;
2799 case cricket::MD_RECVONLY:
2800 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2801 kResultRecv_SendCodecs);
2802 break;
2803 case cricket::MD_SENDRECV:
2804 if (acd->direction() == cricket::MD_SENDONLY) {
2805 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2806 kResultSendrecv_SendCodecs);
2807 } else if (acd->direction() == cricket::MD_RECVONLY) {
2808 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2809 kResultSendrecv_RecvCodecs);
2810 } else {
2811 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2812 kResultSendrecv_SendrecvCodecs);
2813 }
2814 break;
2815 }
2816
2817 auto format_codecs = [] (const std::vector<AudioCodec>& codecs) {
2818 std::stringstream os;
2819 bool first = true;
2820 os << "{";
2821 for (const auto& c : codecs) {
2822 os << (first ? " " : ", ") << c.id;
2823 first = false;
2824 }
2825 os << " }";
2826 return os.str();
2827 };
2828
2829 EXPECT_TRUE(acd->codecs() == target_codecs)
2830 << "Expected: " << format_codecs(target_codecs)
2831 << ", got: " << format_codecs(acd->codecs())
2832 << "; Offered: " << MediaContentDirectionToString(offer_direction)
2833 << ", answerer wants: "
2834 << MediaContentDirectionToString(answer_direction)
2835 << "; got: " << MediaContentDirectionToString(acd->direction());
2836 } else {
2837 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
2838 << "Only inactive offers are allowed to not generate any audio content";
2839 }
2840}
2841}
2842
2843class AudioCodecsOfferTest
2844 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2845 bool>> {
2846};
2847
2848TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
2849 TestAudioCodecsOffer(std::tr1::get<0>(GetParam()),
2850 std::tr1::get<1>(GetParam()));
2851}
2852
2853INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2854 AudioCodecsOfferTest,
2855 ::testing::Combine(
2856 ::testing::Values(cricket::MD_SENDONLY,
2857 cricket::MD_RECVONLY,
2858 cricket::MD_SENDRECV,
2859 cricket::MD_INACTIVE),
2860 ::testing::Bool()));
2861
2862class AudioCodecsAnswerTest
2863 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2864 MediaContentDirection,
2865 bool>> {
2866};
2867
2868TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
2869 TestAudioCodecsAnswer(std::tr1::get<0>(GetParam()),
2870 std::tr1::get<1>(GetParam()),
2871 std::tr1::get<2>(GetParam()));
2872}
2873
2874INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2875 AudioCodecsAnswerTest,
2876 ::testing::Combine(
2877 ::testing::Values(cricket::MD_SENDONLY,
2878 cricket::MD_RECVONLY,
2879 cricket::MD_SENDRECV,
2880 cricket::MD_INACTIVE),
2881 ::testing::Values(cricket::MD_SENDONLY,
2882 cricket::MD_RECVONLY,
2883 cricket::MD_SENDRECV,
2884 cricket::MD_INACTIVE),
2885 ::testing::Bool()));