blob: c898315b1ad33d8967018cc4ab9f425115dc5615 [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;
isheriff6f8d6862016-05-26 11:24:55 -070076using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077
78static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070079 AudioCodec(103, "ISAC", 16000, -1, 1),
80 AudioCodec(102, "iLBC", 8000, 13300, 1),
81 AudioCodec(0, "PCMU", 8000, 64000, 1),
82 AudioCodec(8, "PCMA", 8000, 64000, 1),
83 AudioCodec(117, "red", 8000, 0, 1),
84 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085
86static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070087 AudioCodec(126, "speex", 16000, 22000, 1),
88 AudioCodec(0, "PCMU", 8000, 64000, 1),
89 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090};
91
92static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070093 AudioCodec(102, "iLBC", 8000, 13300, 1),
94 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095};
96
97static const VideoCodec kVideoCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070098 VideoCodec(96, "H264-SVC", 320, 200, 30),
99 VideoCodec(97, "H264", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100
101static const VideoCodec kVideoCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700102 VideoCodec(126, "H264", 320, 200, 30),
103 VideoCodec(127, "H263", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104
105static const VideoCodec kVideoCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700106 VideoCodec(97, "H264", 320, 200, 30)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107
deadbeef67cf2c12016-04-13 10:07:16 -0700108static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
109 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110
deadbeef67cf2c12016-04-13 10:07:16 -0700111static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
112 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113
deadbeef67cf2c12016-04-13 10:07:16 -0700114static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
115 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116
isheriff6f8d6862016-05-26 11:24:55 -0700117static const RtpExtension kAudioRtpExtension1[] = {
118 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
119 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120};
121
isheriff6f8d6862016-05-26 11:24:55 -0700122static const RtpExtension kAudioRtpExtension2[] = {
123 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
124 RtpExtension("http://google.com/testing/audio_something_else", 8),
125 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126};
127
isheriff6f8d6862016-05-26 11:24:55 -0700128static const RtpExtension kAudioRtpExtension3[] = {
129 RtpExtension("http://google.com/testing/audio_something", 2),
130 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700131};
132
isheriff6f8d6862016-05-26 11:24:55 -0700133static const RtpExtension kAudioRtpExtensionAnswer[] = {
134 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135};
136
isheriff6f8d6862016-05-26 11:24:55 -0700137static const RtpExtension kVideoRtpExtension1[] = {
138 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
139 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140};
141
isheriff6f8d6862016-05-26 11:24:55 -0700142static const RtpExtension kVideoRtpExtension2[] = {
143 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
144 RtpExtension("http://google.com/testing/video_something_else", 14),
145 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146};
147
isheriff6f8d6862016-05-26 11:24:55 -0700148static const RtpExtension kVideoRtpExtension3[] = {
149 RtpExtension("http://google.com/testing/video_something", 4),
150 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700151};
152
isheriff6f8d6862016-05-26 11:24:55 -0700153static const RtpExtension kVideoRtpExtensionAnswer[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155};
156
Peter Boström0c4e06b2015-10-07 12:23:21 +0200157static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
158static const uint32_t kSimSsrc[] = {10, 20, 30};
159static const uint32_t kFec1Ssrc[] = {10, 11};
160static const uint32_t kFec2Ssrc[] = {20, 21};
161static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162
163static const char kMediaStream1[] = "stream_1";
164static const char kMediaStream2[] = "stream_2";
165static const char kVideoTrack1[] = "video_1";
166static const char kVideoTrack2[] = "video_2";
167static const char kAudioTrack1[] = "audio_1";
168static const char kAudioTrack2[] = "audio_2";
169static const char kAudioTrack3[] = "audio_3";
170static const char kDataTrack1[] = "data_1";
171static const char kDataTrack2[] = "data_2";
172static const char kDataTrack3[] = "data_3";
173
zhihuangcf5b37c2016-05-05 11:44:35 -0700174static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
175 "RTP/SAVPF"};
176static const char* kMediaProtocolsDtls[] = {
177 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
178 "UDP/TLS/RTP/SAVP"};
179
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000180static bool IsMediaContentOfType(const ContentInfo* content,
181 MediaType media_type) {
182 const MediaContentDescription* mdesc =
183 static_cast<const MediaContentDescription*>(content->description);
184 return mdesc && mdesc->type() == media_type;
185}
186
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000187static cricket::MediaContentDirection
188GetMediaDirection(const ContentInfo* content) {
189 cricket::MediaContentDescription* desc =
190 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
191 return desc->direction();
192}
193
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000194static void AddRtxCodec(const VideoCodec& rtx_codec,
195 std::vector<VideoCodec>* codecs) {
196 VideoCodec rtx;
197 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
198 codecs->push_back(rtx_codec);
199}
200
201template <class T>
202static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
203 std::vector<std::string> codec_names;
204 for (const auto& codec : codecs) {
205 codec_names.push_back(codec.name);
206 }
207 return codec_names;
208}
209
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210class MediaSessionDescriptionFactoryTest : public testing::Test {
211 public:
212 MediaSessionDescriptionFactoryTest()
Henrik Boström3a14bf32015-08-31 09:27:58 +0200213 : f1_(&tdf1_),
214 f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700215 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
216 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
218 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700219 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
220 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
222 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200223 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700224 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200225 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700226 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227 }
228
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000229 // Create a video StreamParamsVec object with:
230 // - one video stream with 3 simulcast streams and FEC,
231 StreamParamsVec CreateComplexVideoStreamParamsVec() {
232 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
233 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
234 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
235 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
236
237 std::vector<SsrcGroup> ssrc_groups;
238 ssrc_groups.push_back(sim_group);
239 ssrc_groups.push_back(fec_group1);
240 ssrc_groups.push_back(fec_group2);
241 ssrc_groups.push_back(fec_group3);
242
243 StreamParams simulcast_params;
244 simulcast_params.id = kVideoTrack1;
245 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
246 simulcast_params.ssrc_groups = ssrc_groups;
247 simulcast_params.cname = "Video_SIM_FEC";
248 simulcast_params.sync_label = kMediaStream1;
249
250 StreamParamsVec video_streams;
251 video_streams.push_back(simulcast_params);
252
253 return video_streams;
254 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255
256 bool CompareCryptoParams(const CryptoParamsVec& c1,
257 const CryptoParamsVec& c2) {
258 if (c1.size() != c2.size())
259 return false;
260 for (size_t i = 0; i < c1.size(); ++i)
261 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
262 c1[i].key_params != c2[i].key_params ||
263 c1[i].session_params != c2[i].session_params)
264 return false;
265 return true;
266 }
267
268 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
269 bool has_current_desc) {
270 const std::string current_audio_ufrag = "current_audio_ufrag";
271 const std::string current_audio_pwd = "current_audio_pwd";
272 const std::string current_video_ufrag = "current_video_ufrag";
273 const std::string current_video_pwd = "current_video_pwd";
274 const std::string current_data_ufrag = "current_data_ufrag";
275 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800276 std::unique_ptr<SessionDescription> current_desc;
277 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000278 if (has_current_desc) {
279 current_desc.reset(new SessionDescription());
280 EXPECT_TRUE(current_desc->AddTransportInfo(
281 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700282 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000283 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284 EXPECT_TRUE(current_desc->AddTransportInfo(
285 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700286 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000287 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288 EXPECT_TRUE(current_desc->AddTransportInfo(
289 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700290 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000291 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000292 }
293 if (offer) {
294 desc.reset(f1_.CreateOffer(options, current_desc.get()));
295 } else {
kwiberg31022942016-03-11 14:18:21 -0800296 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297 offer.reset(f1_.CreateOffer(options, NULL));
298 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
299 }
300 ASSERT_TRUE(desc.get() != NULL);
301 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000302 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000303 EXPECT_TRUE(ti_audio != NULL);
304 if (has_current_desc) {
305 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
306 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
307 } else {
308 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
309 ti_audio->description.ice_ufrag.size());
310 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
311 ti_audio->description.ice_pwd.size());
312 }
313
314 } else {
315 EXPECT_TRUE(ti_audio == NULL);
316 }
317 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000318 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319 EXPECT_TRUE(ti_video != NULL);
320 if (options.bundle_enabled) {
321 EXPECT_EQ(ti_audio->description.ice_ufrag,
322 ti_video->description.ice_ufrag);
323 EXPECT_EQ(ti_audio->description.ice_pwd,
324 ti_video->description.ice_pwd);
325 } else {
326 if (has_current_desc) {
327 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
328 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
329 } else {
330 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
331 ti_video->description.ice_ufrag.size());
332 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
333 ti_video->description.ice_pwd.size());
334 }
335 }
336 } else {
337 EXPECT_TRUE(ti_video == NULL);
338 }
339 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
340 if (options.has_data()) {
341 EXPECT_TRUE(ti_data != NULL);
342 if (options.bundle_enabled) {
343 EXPECT_EQ(ti_audio->description.ice_ufrag,
344 ti_data->description.ice_ufrag);
345 EXPECT_EQ(ti_audio->description.ice_pwd,
346 ti_data->description.ice_pwd);
347 } else {
348 if (has_current_desc) {
349 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
350 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
351 } else {
352 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
353 ti_data->description.ice_ufrag.size());
354 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
355 ti_data->description.ice_pwd.size());
356 }
357 }
358 } else {
359 EXPECT_TRUE(ti_video == NULL);
360 }
361 }
362
363 void TestCryptoWithBundle(bool offer) {
364 f1_.set_secure(SEC_ENABLED);
365 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000366 options.recv_audio = true;
367 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368 options.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -0800369 std::unique_ptr<SessionDescription> ref_desc;
370 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371 if (offer) {
372 options.bundle_enabled = false;
373 ref_desc.reset(f1_.CreateOffer(options, NULL));
374 options.bundle_enabled = true;
375 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
376 } else {
377 options.bundle_enabled = true;
378 ref_desc.reset(f1_.CreateOffer(options, NULL));
379 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
380 }
381 ASSERT_TRUE(desc.get() != NULL);
382 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000383 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384 desc.get()->GetContentDescriptionByName("audio"));
385 ASSERT_TRUE(audio_media_desc != NULL);
386 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000387 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388 desc.get()->GetContentDescriptionByName("video"));
389 ASSERT_TRUE(video_media_desc != NULL);
390 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
391 video_media_desc->cryptos()));
392 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
393 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
394 audio_media_desc->cryptos()[0].cipher_suite);
395
396 // Verify the selected crypto is one from the reference audio
397 // media content.
398 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000399 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000400 ref_desc.get()->GetContentDescriptionByName("audio"));
401 bool found = false;
402 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
403 if (ref_audio_media_desc->cryptos()[i].Matches(
404 audio_media_desc->cryptos()[0])) {
405 found = true;
406 break;
407 }
408 }
409 EXPECT_TRUE(found);
410 }
411
412 // This test that the audio and video media direction is set to
413 // |expected_direction_in_answer| in an answer if the offer direction is set
414 // to |direction_in_offer|.
415 void TestMediaDirectionInAnswer(
416 cricket::MediaContentDirection direction_in_offer,
417 cricket::MediaContentDirection expected_direction_in_answer) {
418 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000419 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800420 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700422 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 ASSERT_TRUE(ac_offer != NULL);
424 AudioContentDescription* acd_offer =
425 static_cast<AudioContentDescription*>(ac_offer->description);
426 acd_offer->set_direction(direction_in_offer);
terelius8c011e52016-04-26 05:28:11 -0700427 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000428 ASSERT_TRUE(vc_offer != NULL);
429 VideoContentDescription* vcd_offer =
430 static_cast<VideoContentDescription*>(vc_offer->description);
431 vcd_offer->set_direction(direction_in_offer);
432
kwiberg31022942016-03-11 14:18:21 -0800433 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 f2_.CreateAnswer(offer.get(), opts, NULL));
435 const AudioContentDescription* acd_answer =
436 GetFirstAudioContentDescription(answer.get());
437 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
438 const VideoContentDescription* vcd_answer =
439 GetFirstVideoContentDescription(answer.get());
440 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
441 }
442
443 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
444 const cricket::ContentDescription* description = content->description;
445 ASSERT(description != NULL);
446 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000447 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 ASSERT(audio_content_desc != NULL);
449 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
450 if (audio_content_desc->codecs()[i].name == "CN")
451 return false;
452 }
453 return true;
454 }
455
456 protected:
457 MediaSessionDescriptionFactory f1_;
458 MediaSessionDescriptionFactory f2_;
459 TransportDescriptionFactory tdf1_;
460 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461};
462
463// Create a typical audio offer, and ensure it matches what we expect.
464TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
465 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800466 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000467 f1_.CreateOffer(MediaSessionOptions(), NULL));
468 ASSERT_TRUE(offer.get() != NULL);
469 const ContentInfo* ac = offer->GetContentByName("audio");
470 const ContentInfo* vc = offer->GetContentByName("video");
471 ASSERT_TRUE(ac != NULL);
472 ASSERT_TRUE(vc == NULL);
473 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
474 const AudioContentDescription* acd =
475 static_cast<const AudioContentDescription*>(ac->description);
476 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
477 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
478 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
479 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
480 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
481 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
482 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
483}
484
485// Create a typical video offer, and ensure it matches what we expect.
486TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
487 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000488 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000489 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800490 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000491 ASSERT_TRUE(offer.get() != NULL);
492 const ContentInfo* ac = offer->GetContentByName("audio");
493 const ContentInfo* vc = offer->GetContentByName("video");
494 ASSERT_TRUE(ac != NULL);
495 ASSERT_TRUE(vc != NULL);
496 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
497 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
498 const AudioContentDescription* acd =
499 static_cast<const AudioContentDescription*>(ac->description);
500 const VideoContentDescription* vcd =
501 static_cast<const VideoContentDescription*>(vc->description);
502 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
503 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
504 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
505 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
506 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
507 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
508 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
509 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
510 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
511 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
512 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
513 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
514 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
515 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
516}
517
518// Test creating an offer with bundle where the Codecs have the same dynamic
519// RTP playlod type. The test verifies that the offer don't contain the
520// duplicate RTP payload types.
521TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
522 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
523 const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
524 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
525 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
526 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
527
528 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000529 opts.recv_audio = true;
530 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 opts.data_channel_type = cricket::DCT_RTP;
532 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800533 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 const VideoContentDescription* vcd =
535 GetFirstVideoContentDescription(offer.get());
536 const AudioContentDescription* acd =
537 GetFirstAudioContentDescription(offer.get());
538 const DataContentDescription* dcd =
539 GetFirstDataContentDescription(offer.get());
540 ASSERT_TRUE(NULL != vcd);
541 ASSERT_TRUE(NULL != acd);
542 ASSERT_TRUE(NULL != dcd);
543 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
544 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
545 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
546 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
547 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
548 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
549}
550
551// Test creating an updated offer with with bundle, audio, video and data
552// after an audio only session has been negotiated.
553TEST_F(MediaSessionDescriptionFactoryTest,
554 TestCreateUpdatedVideoOfferWithBundle) {
555 f1_.set_secure(SEC_ENABLED);
556 f2_.set_secure(SEC_ENABLED);
557 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000558 opts.recv_audio = true;
559 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 opts.data_channel_type = cricket::DCT_NONE;
561 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800562 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
563 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 f2_.CreateAnswer(offer.get(), opts, NULL));
565
566 MediaSessionOptions updated_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000567 updated_opts.recv_audio = true;
568 updated_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 updated_opts.data_channel_type = cricket::DCT_RTP;
570 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800571 std::unique_ptr<SessionDescription> updated_offer(
572 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573
574 const AudioContentDescription* acd =
575 GetFirstAudioContentDescription(updated_offer.get());
576 const VideoContentDescription* vcd =
577 GetFirstVideoContentDescription(updated_offer.get());
578 const DataContentDescription* dcd =
579 GetFirstDataContentDescription(updated_offer.get());
580 EXPECT_TRUE(NULL != vcd);
581 EXPECT_TRUE(NULL != acd);
582 EXPECT_TRUE(NULL != dcd);
583
584 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
585 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
586 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
587 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
588 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
589 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
590}
deadbeef44f08192015-12-15 16:20:09 -0800591
wu@webrtc.org78187522013-10-07 23:32:02 +0000592// Create a RTP data offer, and ensure it matches what we expect.
593TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 MediaSessionOptions opts;
595 opts.data_channel_type = cricket::DCT_RTP;
596 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800597 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 ASSERT_TRUE(offer.get() != NULL);
599 const ContentInfo* ac = offer->GetContentByName("audio");
600 const ContentInfo* dc = offer->GetContentByName("data");
601 ASSERT_TRUE(ac != NULL);
602 ASSERT_TRUE(dc != NULL);
603 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
604 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
605 const AudioContentDescription* acd =
606 static_cast<const AudioContentDescription*>(ac->description);
607 const DataContentDescription* dcd =
608 static_cast<const DataContentDescription*>(dc->description);
609 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
610 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
611 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
612 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
613 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
614 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
615 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
616 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
617 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
618 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
619 EXPECT_EQ(cricket::kDataMaxBandwidth,
620 dcd->bandwidth()); // default bandwidth (auto)
621 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
622 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
623 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
624}
625
wu@webrtc.org78187522013-10-07 23:32:02 +0000626// Create an SCTP data offer with bundle without error.
627TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
628 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000629 opts.recv_audio = false;
wu@webrtc.org78187522013-10-07 23:32:02 +0000630 opts.bundle_enabled = true;
631 opts.data_channel_type = cricket::DCT_SCTP;
632 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800633 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000634 EXPECT_TRUE(offer.get() != NULL);
635 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
636}
637
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000638// Test creating an sctp data channel from an already generated offer.
639TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
640 MediaSessionOptions opts;
641 opts.recv_audio = false;
642 opts.bundle_enabled = true;
643 opts.data_channel_type = cricket::DCT_SCTP;
644 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800645 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000646 ASSERT_TRUE(offer1.get() != NULL);
647 const ContentInfo* data = offer1->GetContentByName("data");
648 ASSERT_TRUE(data != NULL);
649 const MediaContentDescription* mdesc =
650 static_cast<const MediaContentDescription*>(data->description);
651 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
652
653 // Now set data_channel_type to 'none' (default) and make sure that the
654 // datachannel type that gets generated from the previous offer, is of the
655 // same type.
656 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800657 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000658 f1_.CreateOffer(opts, offer1.get()));
659 data = offer2->GetContentByName("data");
660 ASSERT_TRUE(data != NULL);
661 mdesc = static_cast<const MediaContentDescription*>(data->description);
662 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
663}
664
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665// Create an audio, video offer without legacy StreamParams.
666TEST_F(MediaSessionDescriptionFactoryTest,
667 TestCreateOfferWithoutLegacyStreams) {
668 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000669 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 f1_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800671 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 ASSERT_TRUE(offer.get() != NULL);
673 const ContentInfo* ac = offer->GetContentByName("audio");
674 const ContentInfo* vc = offer->GetContentByName("video");
675 ASSERT_TRUE(ac != NULL);
676 ASSERT_TRUE(vc != NULL);
677 const AudioContentDescription* acd =
678 static_cast<const AudioContentDescription*>(ac->description);
679 const VideoContentDescription* vcd =
680 static_cast<const VideoContentDescription*>(vc->description);
681
682 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
683 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
684}
685
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000686// Creates an audio+video sendonly offer.
687TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
688 MediaSessionOptions options;
689 options.recv_audio = false;
690 options.recv_video = false;
691 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
692 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
693
kwiberg31022942016-03-11 14:18:21 -0800694 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000695 ASSERT_TRUE(offer.get() != NULL);
696 EXPECT_EQ(2u, offer->contents().size());
697 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
698 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
699
700 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
701 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
702}
703
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000704// Verifies that the order of the media contents in the current
705// SessionDescription is preserved in the new SessionDescription.
706TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
707 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000708 opts.recv_audio = false;
709 opts.recv_video = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000710 opts.data_channel_type = cricket::DCT_SCTP;
711
kwiberg31022942016-03-11 14:18:21 -0800712 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000713 ASSERT_TRUE(offer1.get() != NULL);
714 EXPECT_EQ(1u, offer1->contents().size());
715 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
716
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000717 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800718 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000719 f1_.CreateOffer(opts, offer1.get()));
720 ASSERT_TRUE(offer2.get() != NULL);
721 EXPECT_EQ(2u, offer2->contents().size());
722 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
723 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
724
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000725 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800726 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000727 f1_.CreateOffer(opts, offer2.get()));
728 ASSERT_TRUE(offer3.get() != NULL);
729 EXPECT_EQ(3u, offer3->contents().size());
730 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
731 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
732 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
733
734 // Verifies the default order is audio-video-data, so that the previous checks
735 // didn't pass by accident.
kwiberg31022942016-03-11 14:18:21 -0800736 std::unique_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000737 ASSERT_TRUE(offer4.get() != NULL);
738 EXPECT_EQ(3u, offer4->contents().size());
739 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
740 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
741 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
742}
743
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744// Create a typical audio answer, and ensure it matches what we expect.
745TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
746 f1_.set_secure(SEC_ENABLED);
747 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800748 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 f1_.CreateOffer(MediaSessionOptions(), NULL));
750 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800751 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
753 const ContentInfo* ac = answer->GetContentByName("audio");
754 const ContentInfo* vc = answer->GetContentByName("video");
755 ASSERT_TRUE(ac != NULL);
756 ASSERT_TRUE(vc == NULL);
757 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
758 const AudioContentDescription* acd =
759 static_cast<const AudioContentDescription*>(ac->description);
760 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
761 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
762 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
763 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
764 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
765 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
766 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
767}
768
769// Create a typical video answer, and ensure it matches what we expect.
770TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
771 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000772 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 f1_.set_secure(SEC_ENABLED);
774 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800775 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000776 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800777 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 f2_.CreateAnswer(offer.get(), opts, NULL));
779 const ContentInfo* ac = answer->GetContentByName("audio");
780 const ContentInfo* vc = answer->GetContentByName("video");
781 ASSERT_TRUE(ac != NULL);
782 ASSERT_TRUE(vc != NULL);
783 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
784 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
785 const AudioContentDescription* acd =
786 static_cast<const AudioContentDescription*>(ac->description);
787 const VideoContentDescription* vcd =
788 static_cast<const VideoContentDescription*>(vc->description);
789 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
790 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
791 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
792 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
793 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
794 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
795 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
796 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
797 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
798 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
799 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
800 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
801}
802
803TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
804 MediaSessionOptions opts;
805 opts.data_channel_type = cricket::DCT_RTP;
806 f1_.set_secure(SEC_ENABLED);
807 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800808 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800810 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 f2_.CreateAnswer(offer.get(), opts, NULL));
812 const ContentInfo* ac = answer->GetContentByName("audio");
813 const ContentInfo* vc = answer->GetContentByName("data");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc != NULL);
816 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
817 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
818 const AudioContentDescription* acd =
819 static_cast<const AudioContentDescription*>(ac->description);
820 const DataContentDescription* vcd =
821 static_cast<const DataContentDescription*>(vc->description);
822 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
823 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
824 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
825 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
826 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
827 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
828 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
829 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
830 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
831 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
832 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
833 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
834}
835
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000836// Verifies that the order of the media contents in the offer is preserved in
837// the answer.
838TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
839 MediaSessionOptions opts;
840
841 // Creates a data only offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000842 opts.recv_audio = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000843 opts.data_channel_type = cricket::DCT_SCTP;
kwiberg31022942016-03-11 14:18:21 -0800844 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000845 ASSERT_TRUE(offer1.get() != NULL);
846
847 // Appends audio to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000848 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800849 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000850 f1_.CreateOffer(opts, offer1.get()));
851 ASSERT_TRUE(offer2.get() != NULL);
852
853 // Appends video to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000854 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800855 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000856 f1_.CreateOffer(opts, offer2.get()));
857 ASSERT_TRUE(offer3.get() != NULL);
858
kwiberg31022942016-03-11 14:18:21 -0800859 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000860 f2_.CreateAnswer(offer3.get(), opts, NULL));
861 ASSERT_TRUE(answer.get() != NULL);
862 EXPECT_EQ(3u, answer->contents().size());
863 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
864 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
865 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
866}
867
ossu075af922016-06-14 03:29:38 -0700868// TODO(deadbeef): Extend these tests to ensure the correct direction with other
869// answerer settings.
870
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871// This test that the media direction is set to send/receive in an answer if
872// the offer is send receive.
873TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
874 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
875}
876
877// This test that the media direction is set to receive only in an answer if
878// the offer is send only.
879TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
880 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
881}
882
883// This test that the media direction is set to send only in an answer if
884// the offer is recv only.
885TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
886 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
887}
888
889// This test that the media direction is set to inactive in an answer if
890// the offer is inactive.
891TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
892 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
893}
894
895// Test that a data content with an unknown protocol is rejected in an answer.
896TEST_F(MediaSessionDescriptionFactoryTest,
897 CreateDataAnswerToOfferWithUnknownProtocol) {
898 MediaSessionOptions opts;
899 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000900 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 f1_.set_secure(SEC_ENABLED);
902 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800903 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -0700904 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 ASSERT_TRUE(dc_offer != NULL);
906 DataContentDescription* dcd_offer =
907 static_cast<DataContentDescription*>(dc_offer->description);
908 ASSERT_TRUE(dcd_offer != NULL);
909 std::string protocol = "a weird unknown protocol";
910 dcd_offer->set_protocol(protocol);
911
kwiberg31022942016-03-11 14:18:21 -0800912 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000913 f2_.CreateAnswer(offer.get(), opts, NULL));
914
915 const ContentInfo* dc_answer = answer->GetContentByName("data");
916 ASSERT_TRUE(dc_answer != NULL);
917 EXPECT_TRUE(dc_answer->rejected);
918 const DataContentDescription* dcd_answer =
919 static_cast<const DataContentDescription*>(dc_answer->description);
920 ASSERT_TRUE(dcd_answer != NULL);
921 EXPECT_EQ(protocol, dcd_answer->protocol());
922}
923
924// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
925TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
926 MediaSessionOptions opts;
927 f1_.set_secure(SEC_DISABLED);
928 f2_.set_secure(SEC_DISABLED);
929 tdf1_.set_secure(SEC_DISABLED);
930 tdf2_.set_secure(SEC_DISABLED);
931
kwiberg31022942016-03-11 14:18:21 -0800932 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000933 const AudioContentDescription* offer_acd =
934 GetFirstAudioContentDescription(offer.get());
935 ASSERT_TRUE(offer_acd != NULL);
936 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
937
kwiberg31022942016-03-11 14:18:21 -0800938 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939 f2_.CreateAnswer(offer.get(), opts, NULL));
940
941 const ContentInfo* ac_answer = answer->GetContentByName("audio");
942 ASSERT_TRUE(ac_answer != NULL);
943 EXPECT_FALSE(ac_answer->rejected);
944
945 const AudioContentDescription* answer_acd =
946 GetFirstAudioContentDescription(answer.get());
947 ASSERT_TRUE(answer_acd != NULL);
948 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
949}
950
951// Create a video offer and answer and ensure the RTP header extensions
952// matches what we expect.
953TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
954 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000955 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956
957 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
958 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
959 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
960 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
961
kwiberg31022942016-03-11 14:18:21 -0800962 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000963 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800964 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 f2_.CreateAnswer(offer.get(), opts, NULL));
966
967 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
968 GetFirstAudioContentDescription(
969 offer.get())->rtp_header_extensions());
970 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
971 GetFirstVideoContentDescription(
972 offer.get())->rtp_header_extensions());
973 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
974 GetFirstAudioContentDescription(
975 answer.get())->rtp_header_extensions());
976 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
977 GetFirstVideoContentDescription(
978 answer.get())->rtp_header_extensions());
979}
980
981// Create an audio, video, data answer without legacy StreamParams.
982TEST_F(MediaSessionDescriptionFactoryTest,
983 TestCreateAnswerWithoutLegacyStreams) {
984 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000985 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 opts.data_channel_type = cricket::DCT_RTP;
987 f1_.set_add_legacy_streams(false);
988 f2_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800989 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800991 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000992 f2_.CreateAnswer(offer.get(), opts, NULL));
993 const ContentInfo* ac = answer->GetContentByName("audio");
994 const ContentInfo* vc = answer->GetContentByName("video");
995 const ContentInfo* dc = answer->GetContentByName("data");
996 ASSERT_TRUE(ac != NULL);
997 ASSERT_TRUE(vc != NULL);
998 const AudioContentDescription* acd =
999 static_cast<const AudioContentDescription*>(ac->description);
1000 const VideoContentDescription* vcd =
1001 static_cast<const VideoContentDescription*>(vc->description);
1002 const DataContentDescription* dcd =
1003 static_cast<const DataContentDescription*>(dc->description);
1004
1005 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1006 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1007 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1008}
1009
1010TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1011 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001012 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 opts.data_channel_type = cricket::DCT_RTP;
1014 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001015 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016 ASSERT_TRUE(offer.get() != NULL);
1017 const ContentInfo* ac = offer->GetContentByName("audio");
1018 const ContentInfo* vc = offer->GetContentByName("video");
1019 const ContentInfo* dc = offer->GetContentByName("data");
1020 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1021 static_cast<const AudioContentDescription*>(ac->description));
1022 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1023 static_cast<const VideoContentDescription*>(vc->description));
1024 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1025 static_cast<const DataContentDescription*>(dc->description));
1026
1027 EXPECT_FALSE(acd->partial()); // default is false.
1028 acd->set_partial(true);
1029 EXPECT_TRUE(acd->partial());
1030 acd->set_partial(false);
1031 EXPECT_FALSE(acd->partial());
1032
1033 EXPECT_FALSE(vcd->partial()); // default is false.
1034 vcd->set_partial(true);
1035 EXPECT_TRUE(vcd->partial());
1036 vcd->set_partial(false);
1037 EXPECT_FALSE(vcd->partial());
1038
1039 EXPECT_FALSE(dcd->partial()); // default is false.
1040 dcd->set_partial(true);
1041 EXPECT_TRUE(dcd->partial());
1042 dcd->set_partial(false);
1043 EXPECT_FALSE(dcd->partial());
1044}
1045
1046// Create a typical video answer, and ensure it matches what we expect.
1047TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1048 MediaSessionOptions offer_opts;
1049 MediaSessionOptions answer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001050 answer_opts.recv_video = true;
1051 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 answer_opts.data_channel_type = cricket::DCT_RTP;
1053 offer_opts.data_channel_type = cricket::DCT_RTP;
1054
kwiberg31022942016-03-11 14:18:21 -08001055 std::unique_ptr<SessionDescription> offer;
1056 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057
1058 offer_opts.rtcp_mux_enabled = true;
1059 answer_opts.rtcp_mux_enabled = true;
1060
1061 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1062 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1063 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1064 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1065 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1066 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1067 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1068 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1069 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1070 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1071 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1072 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1073 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1074 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1075
1076 offer_opts.rtcp_mux_enabled = true;
1077 answer_opts.rtcp_mux_enabled = false;
1078
1079 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1080 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1081 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1082 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1083 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1084 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1085 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1086 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1087 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1088 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1089 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1090 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1091 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1092 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1093
1094 offer_opts.rtcp_mux_enabled = false;
1095 answer_opts.rtcp_mux_enabled = true;
1096
1097 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1098 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1099 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1100 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1101 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1102 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1103 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1104 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1105 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1106 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1107 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1108 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1109 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1110 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1111
1112 offer_opts.rtcp_mux_enabled = false;
1113 answer_opts.rtcp_mux_enabled = false;
1114
1115 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1116 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1117 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1118 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1119 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1120 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1121 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1122 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1123 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1124 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1125 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1126 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1127 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1128 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1129}
1130
1131// Create an audio-only answer to a video offer.
1132TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1133 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001134 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001135 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001137 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1139 const ContentInfo* ac = answer->GetContentByName("audio");
1140 const ContentInfo* vc = answer->GetContentByName("video");
1141 ASSERT_TRUE(ac != NULL);
1142 ASSERT_TRUE(vc != NULL);
1143 ASSERT_TRUE(vc->description != NULL);
1144 EXPECT_TRUE(vc->rejected);
1145}
1146
1147// Create an audio-only answer to an offer with data.
1148TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1149 MediaSessionOptions opts;
1150 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001151 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001153 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001154 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1155 const ContentInfo* ac = answer->GetContentByName("audio");
1156 const ContentInfo* dc = answer->GetContentByName("data");
1157 ASSERT_TRUE(ac != NULL);
1158 ASSERT_TRUE(dc != NULL);
1159 ASSERT_TRUE(dc->description != NULL);
1160 EXPECT_TRUE(dc->rejected);
1161}
1162
1163// Create an answer that rejects the contents which are rejected in the offer.
1164TEST_F(MediaSessionDescriptionFactoryTest,
1165 CreateAnswerToOfferWithRejectedMedia) {
1166 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001167 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001168 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001169 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001170 ASSERT_TRUE(offer.get() != NULL);
1171 ContentInfo* ac = offer->GetContentByName("audio");
1172 ContentInfo* vc = offer->GetContentByName("video");
1173 ContentInfo* dc = offer->GetContentByName("data");
1174 ASSERT_TRUE(ac != NULL);
1175 ASSERT_TRUE(vc != NULL);
1176 ASSERT_TRUE(dc != NULL);
1177 ac->rejected = true;
1178 vc->rejected = true;
1179 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001180 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 f2_.CreateAnswer(offer.get(), opts, NULL));
1182 ac = answer->GetContentByName("audio");
1183 vc = answer->GetContentByName("video");
1184 dc = answer->GetContentByName("data");
1185 ASSERT_TRUE(ac != NULL);
1186 ASSERT_TRUE(vc != NULL);
1187 ASSERT_TRUE(dc != NULL);
1188 EXPECT_TRUE(ac->rejected);
1189 EXPECT_TRUE(vc->rejected);
1190 EXPECT_TRUE(dc->rejected);
1191}
1192
1193// Create an audio and video offer with:
1194// - one video track
1195// - two audio tracks
1196// - two data tracks
1197// and ensure it matches what we expect. Also updates the initial offer by
1198// adding a new video track and replaces one of the audio tracks.
1199TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1200 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001201 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1202 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1203 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001205 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1206 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207
1208 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001209 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210
1211 ASSERT_TRUE(offer.get() != NULL);
1212 const ContentInfo* ac = offer->GetContentByName("audio");
1213 const ContentInfo* vc = offer->GetContentByName("video");
1214 const ContentInfo* dc = offer->GetContentByName("data");
1215 ASSERT_TRUE(ac != NULL);
1216 ASSERT_TRUE(vc != NULL);
1217 ASSERT_TRUE(dc != NULL);
1218 const AudioContentDescription* acd =
1219 static_cast<const AudioContentDescription*>(ac->description);
1220 const VideoContentDescription* vcd =
1221 static_cast<const VideoContentDescription*>(vc->description);
1222 const DataContentDescription* dcd =
1223 static_cast<const DataContentDescription*>(dc->description);
1224 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1225 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1226
1227 const StreamParamsVec& audio_streams = acd->streams();
1228 ASSERT_EQ(2U, audio_streams.size());
1229 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1230 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1231 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1232 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1233 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1234 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1235 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1236
1237 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1238 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1239 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1240
1241 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1242 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1243 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1244
1245 const StreamParamsVec& video_streams = vcd->streams();
1246 ASSERT_EQ(1U, video_streams.size());
1247 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1248 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1249 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1250 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1251
1252 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1253 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1254 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1255
1256 const StreamParamsVec& data_streams = dcd->streams();
1257 ASSERT_EQ(2U, data_streams.size());
1258 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1259 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1260 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1261 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1262 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1263 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1264 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1265
1266 EXPECT_EQ(cricket::kDataMaxBandwidth,
1267 dcd->bandwidth()); // default bandwidth (auto)
1268 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1269 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1270
1271
1272 // Update the offer. Add a new video track that is not synched to the
1273 // other tracks and replace audio track 2 with audio track 3.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001274 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1275 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1276 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1277 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1278 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
kwiberg31022942016-03-11 14:18:21 -08001279 std::unique_ptr<SessionDescription> updated_offer(
1280 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001281
1282 ASSERT_TRUE(updated_offer.get() != NULL);
1283 ac = updated_offer->GetContentByName("audio");
1284 vc = updated_offer->GetContentByName("video");
1285 dc = updated_offer->GetContentByName("data");
1286 ASSERT_TRUE(ac != NULL);
1287 ASSERT_TRUE(vc != NULL);
1288 ASSERT_TRUE(dc != NULL);
1289 const AudioContentDescription* updated_acd =
1290 static_cast<const AudioContentDescription*>(ac->description);
1291 const VideoContentDescription* updated_vcd =
1292 static_cast<const VideoContentDescription*>(vc->description);
1293 const DataContentDescription* updated_dcd =
1294 static_cast<const DataContentDescription*>(dc->description);
1295
1296 EXPECT_EQ(acd->type(), updated_acd->type());
1297 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1298 EXPECT_EQ(vcd->type(), updated_vcd->type());
1299 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1300 EXPECT_EQ(dcd->type(), updated_dcd->type());
1301 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1302 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1303 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1304 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1305 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1306 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1307 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1308
1309 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1310 ASSERT_EQ(2U, updated_audio_streams.size());
1311 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1312 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1313 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1314 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1315 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1316
1317 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1318 ASSERT_EQ(2U, updated_video_streams.size());
1319 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1320 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001321 // All the media streams in one PeerConnection share one RTCP CNAME.
1322 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323
1324 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1325 ASSERT_EQ(2U, updated_data_streams.size());
1326 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1327 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1328 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1329 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1330 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001331 // The stream correctly got the CNAME from the MediaSessionOptions.
1332 // The Expected RTCP CNAME is the default one as we are using the default
1333 // MediaSessionOptions.
1334 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001335}
1336
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001337// Create an offer with simulcast video stream.
1338TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1339 MediaSessionOptions opts;
1340 const int num_sim_layers = 3;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001341 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
kwiberg31022942016-03-11 14:18:21 -08001342 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001343
1344 ASSERT_TRUE(offer.get() != NULL);
1345 const ContentInfo* vc = offer->GetContentByName("video");
1346 ASSERT_TRUE(vc != NULL);
1347 const VideoContentDescription* vcd =
1348 static_cast<const VideoContentDescription*>(vc->description);
1349
1350 const StreamParamsVec& video_streams = vcd->streams();
1351 ASSERT_EQ(1U, video_streams.size());
1352 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1353 const SsrcGroup* sim_ssrc_group =
1354 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1355 ASSERT_TRUE(sim_ssrc_group != NULL);
1356 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1357}
1358
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001359// Create an audio and video answer to a standard video offer with:
1360// - one video track
1361// - two audio tracks
1362// - two data tracks
1363// and ensure it matches what we expect. Also updates the initial answer by
1364// adding a new video track and removes one of the audio tracks.
1365TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1366 MediaSessionOptions offer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001367 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001368 offer_opts.data_channel_type = cricket::DCT_RTP;
1369 f1_.set_secure(SEC_ENABLED);
1370 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001371 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001372
1373 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001374 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1375 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1376 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001377 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001378 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1379 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001380
kwiberg31022942016-03-11 14:18:21 -08001381 std::unique_ptr<SessionDescription> answer(
1382 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001383
1384 ASSERT_TRUE(answer.get() != NULL);
1385 const ContentInfo* ac = answer->GetContentByName("audio");
1386 const ContentInfo* vc = answer->GetContentByName("video");
1387 const ContentInfo* dc = answer->GetContentByName("data");
1388 ASSERT_TRUE(ac != NULL);
1389 ASSERT_TRUE(vc != NULL);
1390 ASSERT_TRUE(dc != NULL);
1391 const AudioContentDescription* acd =
1392 static_cast<const AudioContentDescription*>(ac->description);
1393 const VideoContentDescription* vcd =
1394 static_cast<const VideoContentDescription*>(vc->description);
1395 const DataContentDescription* dcd =
1396 static_cast<const DataContentDescription*>(dc->description);
1397 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1398 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1399 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1400
1401 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1402 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1403
1404 const StreamParamsVec& audio_streams = acd->streams();
1405 ASSERT_EQ(2U, audio_streams.size());
1406 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1407 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1408 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1409 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1410 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1411 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1412 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1413
1414 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1415 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1416
1417 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1418 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1419
1420 const StreamParamsVec& video_streams = vcd->streams();
1421 ASSERT_EQ(1U, video_streams.size());
1422 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1423 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1424 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1425 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1426
1427 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1428 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1429
1430 const StreamParamsVec& data_streams = dcd->streams();
1431 ASSERT_EQ(2U, data_streams.size());
1432 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1433 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1434 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1435 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1436 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1437 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1438 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1439
1440 EXPECT_EQ(cricket::kDataMaxBandwidth,
1441 dcd->bandwidth()); // default bandwidth (auto)
1442 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1443
1444 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001445 // other tracks and remove 1 audio track.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001446 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1447 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1448 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
kwiberg31022942016-03-11 14:18:21 -08001449 std::unique_ptr<SessionDescription> updated_answer(
1450 f2_.CreateAnswer(offer.get(), opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001451
1452 ASSERT_TRUE(updated_answer.get() != NULL);
1453 ac = updated_answer->GetContentByName("audio");
1454 vc = updated_answer->GetContentByName("video");
1455 dc = updated_answer->GetContentByName("data");
1456 ASSERT_TRUE(ac != NULL);
1457 ASSERT_TRUE(vc != NULL);
1458 ASSERT_TRUE(dc != NULL);
1459 const AudioContentDescription* updated_acd =
1460 static_cast<const AudioContentDescription*>(ac->description);
1461 const VideoContentDescription* updated_vcd =
1462 static_cast<const VideoContentDescription*>(vc->description);
1463 const DataContentDescription* updated_dcd =
1464 static_cast<const DataContentDescription*>(dc->description);
1465
1466 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1467 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1468 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1469 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1470 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1471 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1472
1473 EXPECT_EQ(acd->type(), updated_acd->type());
1474 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1475 EXPECT_EQ(vcd->type(), updated_vcd->type());
1476 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1477 EXPECT_EQ(dcd->type(), updated_dcd->type());
1478 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1479
1480 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1481 ASSERT_EQ(1U, updated_audio_streams.size());
1482 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1483
1484 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1485 ASSERT_EQ(2U, updated_video_streams.size());
1486 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1487 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001488 // All media streams in one PeerConnection share one CNAME.
1489 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001490
1491 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1492 ASSERT_EQ(1U, updated_data_streams.size());
1493 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1494}
1495
1496
1497// Create an updated offer after creating an answer to the original offer and
1498// verify that the codecs that were part of the original answer are not changed
1499// in the updated offer.
1500TEST_F(MediaSessionDescriptionFactoryTest,
1501 RespondentCreatesOfferAfterCreatingAnswer) {
1502 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001503 opts.recv_audio = true;
1504 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001505
kwiberg31022942016-03-11 14:18:21 -08001506 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1507 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508 f2_.CreateAnswer(offer.get(), opts, NULL));
1509
1510 const AudioContentDescription* acd =
1511 GetFirstAudioContentDescription(answer.get());
1512 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1513
1514 const VideoContentDescription* vcd =
1515 GetFirstVideoContentDescription(answer.get());
1516 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1517
kwiberg31022942016-03-11 14:18:21 -08001518 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519 f2_.CreateOffer(opts, answer.get()));
1520
1521 // The expected audio codecs are the common audio codecs from the first
1522 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1523 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001524 // TODO(wu): |updated_offer| should not include the codec
1525 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001527 kAudioCodecsAnswer[0],
1528 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001529 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001530 };
1531
1532 // The expected video codecs are the common video codecs from the first
1533 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1534 // preference order.
1535 const VideoCodec kUpdatedVideoCodecOffer[] = {
1536 kVideoCodecsAnswer[0],
1537 kVideoCodecs2[1],
1538 };
1539
1540 const AudioContentDescription* updated_acd =
1541 GetFirstAudioContentDescription(updated_offer.get());
1542 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1543
1544 const VideoContentDescription* updated_vcd =
1545 GetFirstVideoContentDescription(updated_offer.get());
1546 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1547}
1548
1549// Create an updated offer after creating an answer to the original offer and
1550// verify that the codecs that were part of the original answer are not changed
1551// in the updated offer. In this test Rtx is enabled.
1552TEST_F(MediaSessionDescriptionFactoryTest,
1553 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1554 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001555 opts.recv_video = true;
1556 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001557 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001558 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001559 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 f1_.set_video_codecs(f1_codecs);
1561
1562 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001564 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001565 f2_.set_video_codecs(f2_codecs);
1566
kwiberg31022942016-03-11 14:18:21 -08001567 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001569 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570 f2_.CreateAnswer(offer.get(), opts, NULL));
1571
1572 const VideoContentDescription* vcd =
1573 GetFirstVideoContentDescription(answer.get());
1574
1575 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001576 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1577 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578
1579 EXPECT_EQ(expected_codecs, vcd->codecs());
1580
deadbeef67cf2c12016-04-13 10:07:16 -07001581 // Now, make sure we get same result (except for the order) if |f2_| creates
1582 // an updated offer even though the default payload types between |f1_| and
1583 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08001584 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001585 f2_.CreateOffer(opts, answer.get()));
1586 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001587 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1589
1590 const VideoContentDescription* updated_vcd =
1591 GetFirstVideoContentDescription(updated_answer.get());
1592
1593 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1594}
1595
1596// Create an updated offer that adds video after creating an audio only answer
1597// to the original offer. This test verifies that if a video codec and the RTX
1598// codec have the same default payload type as an audio codec that is already in
1599// use, the added codecs payload types are changed.
1600TEST_F(MediaSessionDescriptionFactoryTest,
1601 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1602 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001603 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001604 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605 f1_.set_video_codecs(f1_codecs);
1606
1607 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001608 opts.recv_audio = true;
1609 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610
kwiberg31022942016-03-11 14:18:21 -08001611 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1612 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001613 f2_.CreateAnswer(offer.get(), opts, NULL));
1614
1615 const AudioContentDescription* acd =
1616 GetFirstAudioContentDescription(answer.get());
1617 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1618
1619 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1620 // reference be the same as an audio codec that was negotiated in the
1621 // first offer/answer exchange.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001622 opts.recv_audio = true;
1623 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001624
1625 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1626 int used_pl_type = acd->codecs()[0].id;
1627 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001628 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001629 f2_.set_video_codecs(f2_codecs);
1630
kwiberg31022942016-03-11 14:18:21 -08001631 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001632 f2_.CreateOffer(opts, answer.get()));
1633 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001634 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1636
1637 const AudioContentDescription* updated_acd =
1638 GetFirstAudioContentDescription(answer.get());
1639 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1640
1641 const VideoContentDescription* updated_vcd =
1642 GetFirstVideoContentDescription(updated_answer.get());
1643
1644 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001645 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1647 EXPECT_NE(used_pl_type, new_h264_pl_type);
1648 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001649 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1651 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1652}
1653
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001654// Create an updated offer with RTX after creating an answer to an offer
1655// without RTX, and with different default payload types.
1656// Verify that the added RTX codec references the correct payload type.
1657TEST_F(MediaSessionDescriptionFactoryTest,
1658 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
1659 MediaSessionOptions opts;
1660 opts.recv_video = true;
1661 opts.recv_audio = true;
1662
1663 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1664 // This creates rtx for H264 with the payload type |f2_| uses.
1665 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1666 f2_.set_video_codecs(f2_codecs);
1667
kwiberg31022942016-03-11 14:18:21 -08001668 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001669 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08001670 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001671 f2_.CreateAnswer(offer.get(), opts, nullptr));
1672
1673 const VideoContentDescription* vcd =
1674 GetFirstVideoContentDescription(answer.get());
1675
1676 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1677 EXPECT_EQ(expected_codecs, vcd->codecs());
1678
1679 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
1680 // updated offer, even though the default payload types are different from
1681 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08001682 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001683 f2_.CreateOffer(opts, answer.get()));
1684 ASSERT_TRUE(updated_offer);
1685
1686 const VideoContentDescription* updated_vcd =
1687 GetFirstVideoContentDescription(updated_offer.get());
1688
1689 // New offer should attempt to add H263, and RTX for H264.
1690 expected_codecs.push_back(kVideoCodecs2[1]);
1691 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
1692 &expected_codecs);
1693 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1694}
1695
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001696// Test that RTX is ignored when there is no associated payload type parameter.
1697TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1698 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001699 opts.recv_video = true;
1700 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001701 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001702 // This creates RTX without associated payload type parameter.
deadbeef67cf2c12016-04-13 10:07:16 -07001703 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName, 0, 0, 0), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001704 f1_.set_video_codecs(f1_codecs);
1705
1706 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001707 // This creates RTX for H264 with the payload type |f2_| uses.
1708 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001709 f2_.set_video_codecs(f2_codecs);
1710
kwiberg31022942016-03-11 14:18:21 -08001711 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712 ASSERT_TRUE(offer.get() != NULL);
1713 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1714 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1715 // is possible to test that that RTX is dropped when
1716 // kCodecParamAssociatedPayloadType is missing in the offer.
1717 VideoContentDescription* desc =
1718 static_cast<cricket::VideoContentDescription*>(
1719 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1720 ASSERT_TRUE(desc != NULL);
1721 std::vector<VideoCodec> codecs = desc->codecs();
1722 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1723 iter != codecs.end(); ++iter) {
1724 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1725 iter->params.clear();
1726 }
1727 }
1728 desc->set_codecs(codecs);
1729
kwiberg31022942016-03-11 14:18:21 -08001730 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 f2_.CreateAnswer(offer.get(), opts, NULL));
1732
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001733 std::vector<std::string> codec_names =
1734 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1735 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1736 cricket::kRtxCodecName));
1737}
1738
1739// Test that RTX will be filtered out in the answer if its associated payload
1740// type doesn't match the local value.
1741TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1742 MediaSessionOptions opts;
1743 opts.recv_video = true;
1744 opts.recv_audio = false;
1745 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1746 // This creates RTX for H264 in sender.
1747 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1748 f1_.set_video_codecs(f1_codecs);
1749
1750 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1751 // This creates RTX for H263 in receiver.
1752 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1753 f2_.set_video_codecs(f2_codecs);
1754
kwiberg31022942016-03-11 14:18:21 -08001755 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001756 ASSERT_TRUE(offer.get() != NULL);
1757 // Associated payload type doesn't match, therefore, RTX codec is removed in
1758 // the answer.
kwiberg31022942016-03-11 14:18:21 -08001759 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001760 f2_.CreateAnswer(offer.get(), opts, NULL));
1761
1762 std::vector<std::string> codec_names =
1763 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1764 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1765 cricket::kRtxCodecName));
1766}
1767
1768// Test that when multiple RTX codecs are offered, only the matched RTX codec
1769// is added in the answer, and the unsupported RTX codec is filtered out.
1770TEST_F(MediaSessionDescriptionFactoryTest,
1771 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1772 MediaSessionOptions opts;
1773 opts.recv_video = true;
1774 opts.recv_audio = false;
1775 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1776 // This creates RTX for H264-SVC in sender.
1777 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1778 f1_.set_video_codecs(f1_codecs);
1779
1780 // This creates RTX for H264 in sender.
1781 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1782 f1_.set_video_codecs(f1_codecs);
1783
1784 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1785 // This creates RTX for H264 in receiver.
1786 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1787 f2_.set_video_codecs(f2_codecs);
1788
1789 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1790 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08001791 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001792 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001793 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001794 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795 const VideoContentDescription* vcd =
1796 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001797 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1798 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1799 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001800
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001801 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802}
1803
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001804// Test that after one RTX codec has been negotiated, a new offer can attempt
1805// to add another.
1806TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
1807 MediaSessionOptions opts;
1808 opts.recv_video = true;
1809 opts.recv_audio = false;
1810 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1811 // This creates RTX for H264 for the offerer.
1812 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1813 f1_.set_video_codecs(f1_codecs);
1814
kwiberg31022942016-03-11 14:18:21 -08001815 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001816 ASSERT_TRUE(offer);
1817 const VideoContentDescription* vcd =
1818 GetFirstVideoContentDescription(offer.get());
1819
1820 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
1821 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1822 &expected_codecs);
1823 EXPECT_EQ(expected_codecs, vcd->codecs());
1824
1825 // Now, attempt to add RTX for H264-SVC.
1826 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1827 f1_.set_video_codecs(f1_codecs);
1828
kwiberg31022942016-03-11 14:18:21 -08001829 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001830 f1_.CreateOffer(opts, offer.get()));
1831 ASSERT_TRUE(updated_offer);
1832 vcd = GetFirstVideoContentDescription(updated_offer.get());
1833
1834 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
1835 &expected_codecs);
1836 EXPECT_EQ(expected_codecs, vcd->codecs());
1837}
1838
Noah Richards2e7a0982015-05-18 14:02:54 -07001839// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1840// generated for each simulcast ssrc and correctly grouped.
1841TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1842 MediaSessionOptions opts;
1843 opts.recv_video = true;
1844 opts.recv_audio = false;
1845
1846 // Add simulcast streams.
1847 opts.AddSendVideoStream("stream1", "stream1label", 3);
1848
1849 // Use a single real codec, and then add RTX for it.
1850 std::vector<VideoCodec> f1_codecs;
deadbeef67cf2c12016-04-13 10:07:16 -07001851 f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30));
Noah Richards2e7a0982015-05-18 14:02:54 -07001852 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1853 f1_.set_video_codecs(f1_codecs);
1854
1855 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1856 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08001857 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07001858 ASSERT_TRUE(offer.get() != NULL);
1859 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
1860 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1861 ASSERT_TRUE(desc != NULL);
1862 EXPECT_TRUE(desc->multistream());
1863 const StreamParamsVec& streams = desc->streams();
1864 // Single stream.
1865 ASSERT_EQ(1u, streams.size());
1866 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
1867 EXPECT_EQ(6u, streams[0].ssrcs.size());
1868 // And should have a SIM group for the simulcast.
1869 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
1870 // And a FID group for RTX.
1871 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02001872 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07001873 streams[0].GetPrimarySsrcs(&primary_ssrcs);
1874 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02001875 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07001876 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
1877 EXPECT_EQ(3u, fid_ssrcs.size());
1878}
1879
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001880// Create an updated offer after creating an answer to the original offer and
1881// verify that the RTP header extensions that were part of the original answer
1882// are not changed in the updated offer.
1883TEST_F(MediaSessionDescriptionFactoryTest,
1884 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1885 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001886 opts.recv_audio = true;
1887 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888
1889 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1890 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1891 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1892 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1893
kwiberg31022942016-03-11 14:18:21 -08001894 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1895 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001896 f2_.CreateAnswer(offer.get(), opts, NULL));
1897
1898 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1899 GetFirstAudioContentDescription(
1900 answer.get())->rtp_header_extensions());
1901 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1902 GetFirstVideoContentDescription(
1903 answer.get())->rtp_header_extensions());
1904
kwiberg31022942016-03-11 14:18:21 -08001905 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001906 f2_.CreateOffer(opts, answer.get()));
1907
1908 // The expected RTP header extensions in the new offer are the resulting
1909 // extensions from the first offer/answer exchange plus the extensions only
1910 // |f2_| offer.
1911 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001912 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07001913 const RtpExtension kUpdatedAudioRtpExtensions[] = {
1914 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
1915 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001916 };
1917
1918 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001919 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07001920 const RtpExtension kUpdatedVideoRtpExtensions[] = {
1921 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
1922 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001923 };
1924
1925 const AudioContentDescription* updated_acd =
1926 GetFirstAudioContentDescription(updated_offer.get());
1927 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1928 updated_acd->rtp_header_extensions());
1929
1930 const VideoContentDescription* updated_vcd =
1931 GetFirstVideoContentDescription(updated_offer.get());
1932 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1933 updated_vcd->rtp_header_extensions());
1934}
1935
deadbeefa5b273a2015-08-20 17:30:13 -07001936// Verify that if the same RTP extension URI is used for audio and video, the
1937// same ID is used. Also verify that the ID isn't changed when creating an
1938// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07001939TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07001940 MediaSessionOptions opts;
1941 opts.recv_audio = true;
1942 opts.recv_video = true;
1943
1944 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
1945 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
1946
kwiberg31022942016-03-11 14:18:21 -08001947 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07001948
1949 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
1950 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07001951 const RtpExtension kExpectedVideoRtpExtension[] = {
1952 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07001953 };
1954
1955 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1956 GetFirstAudioContentDescription(
1957 offer.get())->rtp_header_extensions());
1958 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1959 GetFirstVideoContentDescription(
1960 offer.get())->rtp_header_extensions());
1961
1962 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08001963 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07001964 f1_.CreateOffer(opts, offer.get()));
1965
1966 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1967 GetFirstAudioContentDescription(
1968 updated_offer.get())->rtp_header_extensions());
1969 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1970 GetFirstVideoContentDescription(
1971 updated_offer.get())->rtp_header_extensions());
1972}
1973
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001974TEST(MediaSessionDescription, CopySessionDescription) {
1975 SessionDescription source;
1976 cricket::ContentGroup group(cricket::CN_AUDIO);
1977 source.AddGroup(group);
1978 AudioContentDescription* acd(new AudioContentDescription());
1979 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1980 acd->AddLegacyStream(1);
1981 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1982 VideoContentDescription* vcd(new VideoContentDescription());
1983 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1984 vcd->AddLegacyStream(2);
1985 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1986
kwiberg31022942016-03-11 14:18:21 -08001987 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988 ASSERT_TRUE(copy.get() != NULL);
1989 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1990 const ContentInfo* ac = copy->GetContentByName("audio");
1991 const ContentInfo* vc = copy->GetContentByName("video");
1992 ASSERT_TRUE(ac != NULL);
1993 ASSERT_TRUE(vc != NULL);
1994 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1995 const AudioContentDescription* acd_copy =
1996 static_cast<const AudioContentDescription*>(ac->description);
1997 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1998 EXPECT_EQ(1u, acd->first_ssrc());
1999
2000 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2001 const VideoContentDescription* vcd_copy =
2002 static_cast<const VideoContentDescription*>(vc->description);
2003 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2004 EXPECT_EQ(2u, vcd->first_ssrc());
2005}
2006
2007// The below TestTransportInfoXXX tests create different offers/answers, and
2008// ensure the TransportInfo in the SessionDescription matches what we expect.
2009TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2010 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002011 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012 TestTransportInfo(true, options, false);
2013}
2014
2015TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2016 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002017 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002018 TestTransportInfo(true, options, true);
2019}
2020
2021TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2022 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002023 options.recv_audio = true;
2024 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 options.data_channel_type = cricket::DCT_RTP;
2026 TestTransportInfo(true, options, false);
2027}
2028
2029TEST_F(MediaSessionDescriptionFactoryTest,
2030 TestTransportInfoOfferMultimediaCurrent) {
2031 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002032 options.recv_audio = true;
2033 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034 options.data_channel_type = cricket::DCT_RTP;
2035 TestTransportInfo(true, options, true);
2036}
2037
2038TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2039 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002040 options.recv_audio = true;
2041 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 options.data_channel_type = cricket::DCT_RTP;
2043 options.bundle_enabled = true;
2044 TestTransportInfo(true, options, false);
2045}
2046
2047TEST_F(MediaSessionDescriptionFactoryTest,
2048 TestTransportInfoOfferBundleCurrent) {
2049 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002050 options.recv_audio = true;
2051 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002052 options.data_channel_type = cricket::DCT_RTP;
2053 options.bundle_enabled = true;
2054 TestTransportInfo(true, options, true);
2055}
2056
2057TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2058 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002059 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060 TestTransportInfo(false, options, false);
2061}
2062
2063TEST_F(MediaSessionDescriptionFactoryTest,
2064 TestTransportInfoAnswerAudioCurrent) {
2065 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002066 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002067 TestTransportInfo(false, options, true);
2068}
2069
2070TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2071 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002072 options.recv_audio = true;
2073 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002074 options.data_channel_type = cricket::DCT_RTP;
2075 TestTransportInfo(false, options, false);
2076}
2077
2078TEST_F(MediaSessionDescriptionFactoryTest,
2079 TestTransportInfoAnswerMultimediaCurrent) {
2080 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002081 options.recv_audio = true;
2082 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002083 options.data_channel_type = cricket::DCT_RTP;
2084 TestTransportInfo(false, options, true);
2085}
2086
2087TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2088 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002089 options.recv_audio = true;
2090 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091 options.data_channel_type = cricket::DCT_RTP;
2092 options.bundle_enabled = true;
2093 TestTransportInfo(false, options, false);
2094}
2095
2096TEST_F(MediaSessionDescriptionFactoryTest,
2097 TestTransportInfoAnswerBundleCurrent) {
2098 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002099 options.recv_audio = true;
2100 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002101 options.data_channel_type = cricket::DCT_RTP;
2102 options.bundle_enabled = true;
2103 TestTransportInfo(false, options, true);
2104}
2105
2106// Create an offer with bundle enabled and verify the crypto parameters are
2107// the common set of the available cryptos.
2108TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2109 TestCryptoWithBundle(true);
2110}
2111
2112// Create an answer with bundle enabled and verify the crypto parameters are
2113// the common set of the available cryptos.
2114TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2115 TestCryptoWithBundle(false);
2116}
2117
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002118// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2119// DTLS is not enabled locally.
2120TEST_F(MediaSessionDescriptionFactoryTest,
2121 TestOfferDtlsSavpfWithoutDtlsFailed) {
2122 f1_.set_secure(SEC_ENABLED);
2123 f2_.set_secure(SEC_ENABLED);
2124 tdf1_.set_secure(SEC_DISABLED);
2125 tdf2_.set_secure(SEC_DISABLED);
2126
kwiberg31022942016-03-11 14:18:21 -08002127 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002128 f1_.CreateOffer(MediaSessionOptions(), NULL));
2129 ASSERT_TRUE(offer.get() != NULL);
2130 ContentInfo* offer_content = offer->GetContentByName("audio");
2131 ASSERT_TRUE(offer_content != NULL);
2132 AudioContentDescription* offer_audio_desc =
2133 static_cast<AudioContentDescription*>(offer_content->description);
2134 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2135
kwiberg31022942016-03-11 14:18:21 -08002136 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002137 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2138 ASSERT_TRUE(answer != NULL);
2139 ContentInfo* answer_content = answer->GetContentByName("audio");
2140 ASSERT_TRUE(answer_content != NULL);
2141
2142 ASSERT_TRUE(answer_content->rejected);
2143}
2144
2145// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2146// UDP/TLS/RTP/SAVPF.
2147TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2148 f1_.set_secure(SEC_ENABLED);
2149 f2_.set_secure(SEC_ENABLED);
2150 tdf1_.set_secure(SEC_ENABLED);
2151 tdf2_.set_secure(SEC_ENABLED);
2152
kwiberg31022942016-03-11 14:18:21 -08002153 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002154 f1_.CreateOffer(MediaSessionOptions(), NULL));
2155 ASSERT_TRUE(offer.get() != NULL);
2156 ContentInfo* offer_content = offer->GetContentByName("audio");
2157 ASSERT_TRUE(offer_content != NULL);
2158 AudioContentDescription* offer_audio_desc =
2159 static_cast<AudioContentDescription*>(offer_content->description);
2160 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2161
kwiberg31022942016-03-11 14:18:21 -08002162 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002163 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2164 ASSERT_TRUE(answer != NULL);
2165
2166 const ContentInfo* answer_content = answer->GetContentByName("audio");
2167 ASSERT_TRUE(answer_content != NULL);
2168 ASSERT_FALSE(answer_content->rejected);
2169
2170 const AudioContentDescription* answer_audio_desc =
2171 static_cast<const AudioContentDescription*>(answer_content->description);
2172 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2173 answer_audio_desc->protocol());
2174}
2175
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176// Test that we include both SDES and DTLS in the offer, but only include SDES
2177// in the answer if DTLS isn't negotiated.
2178TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2179 f1_.set_secure(SEC_ENABLED);
2180 f2_.set_secure(SEC_ENABLED);
2181 tdf1_.set_secure(SEC_ENABLED);
2182 tdf2_.set_secure(SEC_DISABLED);
2183 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002184 options.recv_audio = true;
2185 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002186 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 const cricket::MediaContentDescription* audio_media_desc;
2188 const cricket::MediaContentDescription* video_media_desc;
2189 const cricket::TransportDescription* audio_trans_desc;
2190 const cricket::TransportDescription* video_trans_desc;
2191
2192 // Generate an offer with SDES and DTLS support.
2193 offer.reset(f1_.CreateOffer(options, NULL));
2194 ASSERT_TRUE(offer.get() != NULL);
2195
2196 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2197 offer->GetContentDescriptionByName("audio"));
2198 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002199 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002200 offer->GetContentDescriptionByName("video"));
2201 ASSERT_TRUE(video_media_desc != NULL);
2202 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2203 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2204
2205 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2206 ASSERT_TRUE(audio_trans_desc != NULL);
2207 video_trans_desc = offer->GetTransportDescriptionByName("video");
2208 ASSERT_TRUE(video_trans_desc != NULL);
2209 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2210 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2211
2212 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2213 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2214 ASSERT_TRUE(answer.get() != NULL);
2215
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002216 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002217 answer->GetContentDescriptionByName("audio"));
2218 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002219 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002220 answer->GetContentDescriptionByName("video"));
2221 ASSERT_TRUE(video_media_desc != NULL);
2222 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2223 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2224
2225 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2226 ASSERT_TRUE(audio_trans_desc != NULL);
2227 video_trans_desc = answer->GetTransportDescriptionByName("video");
2228 ASSERT_TRUE(video_trans_desc != NULL);
2229 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2230 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2231
2232 // Enable DTLS; the answer should now only have DTLS support.
2233 tdf2_.set_secure(SEC_ENABLED);
2234 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2235 ASSERT_TRUE(answer.get() != NULL);
2236
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002237 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002238 answer->GetContentDescriptionByName("audio"));
2239 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002240 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002241 answer->GetContentDescriptionByName("video"));
2242 ASSERT_TRUE(video_media_desc != NULL);
2243 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2244 EXPECT_TRUE(video_media_desc->cryptos().empty());
2245 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2246 audio_media_desc->protocol());
2247 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2248 video_media_desc->protocol());
2249
2250 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2251 ASSERT_TRUE(audio_trans_desc != NULL);
2252 video_trans_desc = answer->GetTransportDescriptionByName("video");
2253 ASSERT_TRUE(video_trans_desc != NULL);
2254 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2255 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002256
2257 // Try creating offer again. DTLS enabled now, crypto's should be empty
2258 // in new offer.
2259 offer.reset(f1_.CreateOffer(options, offer.get()));
2260 ASSERT_TRUE(offer.get() != NULL);
2261 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2262 offer->GetContentDescriptionByName("audio"));
2263 ASSERT_TRUE(audio_media_desc != NULL);
2264 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2265 offer->GetContentDescriptionByName("video"));
2266 ASSERT_TRUE(video_media_desc != NULL);
2267 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2268 EXPECT_TRUE(video_media_desc->cryptos().empty());
2269
2270 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2271 ASSERT_TRUE(audio_trans_desc != NULL);
2272 video_trans_desc = offer->GetTransportDescriptionByName("video");
2273 ASSERT_TRUE(video_trans_desc != NULL);
2274 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2275 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002276}
2277
2278// Test that an answer can't be created if cryptos are required but the offer is
2279// unsecure.
2280TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2281 MediaSessionOptions options;
2282 f1_.set_secure(SEC_DISABLED);
2283 tdf1_.set_secure(SEC_DISABLED);
2284 f2_.set_secure(SEC_REQUIRED);
2285 tdf1_.set_secure(SEC_ENABLED);
2286
kwiberg31022942016-03-11 14:18:21 -08002287 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002288 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002289 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002290 f2_.CreateAnswer(offer.get(), options, NULL));
2291 EXPECT_TRUE(answer.get() == NULL);
2292}
2293
2294// Test that we accept a DTLS offer without SDES and create an appropriate
2295// answer.
2296TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2297 f1_.set_secure(SEC_DISABLED);
2298 f2_.set_secure(SEC_ENABLED);
2299 tdf1_.set_secure(SEC_ENABLED);
2300 tdf2_.set_secure(SEC_ENABLED);
2301 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002302 options.recv_audio = true;
2303 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002304 options.data_channel_type = cricket::DCT_RTP;
2305
kwiberg31022942016-03-11 14:18:21 -08002306 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002307
2308 // Generate an offer with DTLS but without SDES.
2309 offer.reset(f1_.CreateOffer(options, NULL));
2310 ASSERT_TRUE(offer.get() != NULL);
2311
2312 const AudioContentDescription* audio_offer =
2313 GetFirstAudioContentDescription(offer.get());
2314 ASSERT_TRUE(audio_offer->cryptos().empty());
2315 const VideoContentDescription* video_offer =
2316 GetFirstVideoContentDescription(offer.get());
2317 ASSERT_TRUE(video_offer->cryptos().empty());
2318 const DataContentDescription* data_offer =
2319 GetFirstDataContentDescription(offer.get());
2320 ASSERT_TRUE(data_offer->cryptos().empty());
2321
2322 const cricket::TransportDescription* audio_offer_trans_desc =
2323 offer->GetTransportDescriptionByName("audio");
2324 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2325 const cricket::TransportDescription* video_offer_trans_desc =
2326 offer->GetTransportDescriptionByName("video");
2327 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2328 const cricket::TransportDescription* data_offer_trans_desc =
2329 offer->GetTransportDescriptionByName("data");
2330 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2331
2332 // Generate an answer with DTLS.
2333 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2334 ASSERT_TRUE(answer.get() != NULL);
2335
2336 const cricket::TransportDescription* audio_answer_trans_desc =
2337 answer->GetTransportDescriptionByName("audio");
2338 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2339 const cricket::TransportDescription* video_answer_trans_desc =
2340 answer->GetTransportDescriptionByName("video");
2341 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2342 const cricket::TransportDescription* data_answer_trans_desc =
2343 answer->GetTransportDescriptionByName("data");
2344 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2345}
2346
2347// Verifies if vad_enabled option is set to false, CN codecs are not present in
2348// offer or answer.
2349TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2350 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002351 options.recv_audio = true;
2352 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002353 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002354 ASSERT_TRUE(offer.get() != NULL);
2355 const ContentInfo* audio_content = offer->GetContentByName("audio");
2356 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2357
2358 options.vad_enabled = false;
2359 offer.reset(f1_.CreateOffer(options, NULL));
2360 ASSERT_TRUE(offer.get() != NULL);
2361 audio_content = offer->GetContentByName("audio");
2362 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002363 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002364 f1_.CreateAnswer(offer.get(), options, NULL));
2365 ASSERT_TRUE(answer.get() != NULL);
2366 audio_content = answer->GetContentByName("audio");
2367 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2368}
deadbeef44f08192015-12-15 16:20:09 -08002369
2370// Test that the content name ("mid" in SDP) is unchanged when creating a
2371// new offer.
2372TEST_F(MediaSessionDescriptionFactoryTest,
2373 TestContentNameNotChangedInSubsequentOffers) {
2374 MediaSessionOptions opts;
2375 opts.recv_audio = true;
2376 opts.recv_video = true;
2377 opts.data_channel_type = cricket::DCT_SCTP;
2378 // Create offer and modify the default content names.
kwiberg31022942016-03-11 14:18:21 -08002379 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
deadbeef44f08192015-12-15 16:20:09 -08002380 for (ContentInfo& content : offer->contents()) {
2381 content.name.append("_modified");
2382 }
2383
kwiberg31022942016-03-11 14:18:21 -08002384 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002385 f1_.CreateOffer(opts, offer.get()));
2386 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2387 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2388 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2389 ASSERT_TRUE(audio_content != nullptr);
2390 ASSERT_TRUE(video_content != nullptr);
2391 ASSERT_TRUE(data_content != nullptr);
2392 EXPECT_EQ("audio_modified", audio_content->name);
2393 EXPECT_EQ("video_modified", video_content->name);
2394 EXPECT_EQ("data_modified", data_content->name);
2395}
zhihuangcf5b37c2016-05-05 11:44:35 -07002396
2397class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
2398 public:
2399 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07002400 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
2401 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07002402 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
2403 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07002404 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
2405 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07002406 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
2407 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
2408 f1_.set_secure(SEC_ENABLED);
2409 f2_.set_secure(SEC_ENABLED);
2410 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002411 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002412 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002413 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002414 tdf1_.set_secure(SEC_ENABLED);
2415 tdf2_.set_secure(SEC_ENABLED);
2416 }
2417
2418 protected:
2419 MediaSessionDescriptionFactory f1_;
2420 MediaSessionDescriptionFactory f2_;
2421 TransportDescriptionFactory tdf1_;
2422 TransportDescriptionFactory tdf2_;
2423};
2424
2425TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
2426 MediaSessionOptions opts;
2427 opts.recv_video = true;
2428 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2429 ASSERT_TRUE(offer.get() != nullptr);
2430 // Set the protocol for all the contents.
2431 for (auto content : offer.get()->contents()) {
2432 static_cast<MediaContentDescription*>(content.description)
2433 ->set_protocol(GetParam());
2434 }
2435 std::unique_ptr<SessionDescription> answer(
2436 f2_.CreateAnswer(offer.get(), opts, nullptr));
2437 const ContentInfo* ac = answer->GetContentByName("audio");
2438 const ContentInfo* vc = answer->GetContentByName("video");
2439 ASSERT_TRUE(ac != nullptr);
2440 ASSERT_TRUE(vc != nullptr);
2441 EXPECT_FALSE(ac->rejected); // the offer is accepted
2442 EXPECT_FALSE(vc->rejected);
2443 const AudioContentDescription* acd =
2444 static_cast<const AudioContentDescription*>(ac->description);
2445 const VideoContentDescription* vcd =
2446 static_cast<const VideoContentDescription*>(vc->description);
2447 EXPECT_EQ(GetParam(), acd->protocol());
2448 EXPECT_EQ(GetParam(), vcd->protocol());
2449}
2450
2451INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
2452 MediaProtocolTest,
2453 ::testing::ValuesIn(kMediaProtocols));
2454INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
2455 MediaProtocolTest,
2456 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07002457
2458TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
2459 TransportDescriptionFactory tdf;
2460 MediaSessionDescriptionFactory sf(&tdf);
2461 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2462 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2463
2464 // The merged list of codecs should contain any send codecs that are also
2465 // nominally in the recieve codecs list. Payload types should be picked from
2466 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
2467 // (set to 1). This equals what happens when the send codecs are used in an
2468 // offer and the receive codecs are used in the following answer.
2469 const std::vector<AudioCodec> sendrecv_codecs =
2470 MAKE_VECTOR(kAudioCodecsAnswer);
2471 const std::vector<AudioCodec> no_codecs;
2472
2473 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
2474 << "Please don't change shared test data!";
2475 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
2476 << "Please don't change shared test data!";
2477 // Alter iLBC send codec to have zero channels, to test that that is handled
2478 // properly.
2479 send_codecs[1].channels = 0;
2480
2481 // Alther iLBC receive codec to be lowercase, to test that case conversions
2482 // are handled properly.
2483 recv_codecs[2].name = "ilbc";
2484
2485 // Test proper merge
2486 sf.set_audio_codecs(send_codecs, recv_codecs);
2487 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2488 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
2489 EXPECT_TRUE(sf.audio_codecs() == sendrecv_codecs);
2490
2491 // Test empty send codecs list
2492 sf.set_audio_codecs(no_codecs, recv_codecs);
2493 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2494 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
2495 EXPECT_TRUE(sf.audio_codecs() == no_codecs);
2496
2497 // Test empty recv codecs list
2498 sf.set_audio_codecs(send_codecs, no_codecs);
2499 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2500 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
2501 EXPECT_TRUE(sf.audio_codecs() == no_codecs);
2502
2503 // Test all empty codec lists
2504 sf.set_audio_codecs(no_codecs, no_codecs);
2505 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2506 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
2507 EXPECT_TRUE(sf.audio_codecs() == no_codecs);
2508}
2509
2510namespace {
2511void TestAudioCodecsOffer(MediaContentDirection direction,
2512 bool add_legacy_stream) {
2513 TransportDescriptionFactory tdf;
2514 MediaSessionDescriptionFactory sf(&tdf);
2515 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2516 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2517 const std::vector<AudioCodec> sendrecv_codecs =
2518 MAKE_VECTOR(kAudioCodecsAnswer);
2519 sf.set_audio_codecs(send_codecs, recv_codecs);
2520 sf.set_add_legacy_streams(add_legacy_stream);
2521
2522 MediaSessionOptions opts;
2523 opts.recv_audio = (direction == cricket::MD_RECVONLY ||
2524 direction == cricket::MD_SENDRECV);
2525 opts.recv_video = false;
2526 if (direction == cricket::MD_SENDONLY || direction == cricket::MD_SENDRECV)
2527 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2528
2529 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
2530 ASSERT_TRUE(offer.get() != NULL);
2531 const ContentInfo* ac = offer->GetContentByName("audio");
2532
2533 // If the factory didn't add any audio content to the offer, we cannot check
2534 // that the codecs put in are right. This happens when we neither want to send
2535 // nor receive audio. The checks are still in place if at some point we'd
2536 // instead create an inactive stream.
2537 if (ac) {
2538 AudioContentDescription* acd =
2539 static_cast<AudioContentDescription*>(ac->description);
2540 // sendrecv and inactive should both present lists as if the channel was to
2541 // be used for sending and receiving. Inactive essentially means it might
2542 // eventually be used anything, but we don't know more at this moment.
2543 if (acd->direction() == cricket::MD_SENDONLY) {
2544 EXPECT_TRUE(acd->codecs() == send_codecs);
2545 } else if (acd->direction() == cricket::MD_RECVONLY) {
2546 EXPECT_TRUE(acd->codecs() == recv_codecs);
2547 } else {
2548 EXPECT_TRUE(acd->codecs() == sendrecv_codecs);
2549 }
2550 }
2551}
2552
2553static const AudioCodec kOfferAnswerCodecs[] = {
2554 AudioCodec(0, "codec0", 16000, -1, 1),
2555 AudioCodec(1, "codec1", 8000, 13300, 1),
2556 AudioCodec(2, "codec2", 8000, 64000, 1),
2557 AudioCodec(3, "codec3", 8000, 64000, 1),
2558 AudioCodec(4, "codec4", 8000, 0, 2),
2559 AudioCodec(5, "codec5", 32000, 0, 1),
2560 AudioCodec(6, "codec6", 48000, 0, 1)
2561};
2562
2563
2564/* The codecs groups below are chosen as per the matrix below. The objective is
2565 * to have different sets of codecs in the inputs, to get unique sets of codecs
2566 * after negotiation, depending on offer and answer communication directions.
2567 * One-way directions in the offer should either result in the opposite
2568 * direction in the answer, or an inactive answer. Regardless, the choice of
2569 * codecs should be as if the answer contained the opposite direction.
2570 * Inactive offers should be treated as sendrecv/sendrecv.
2571 *
2572 * | Offer | Answer | Result
2573 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
2574 * 0 | x - - | - x - | x - - - -
2575 * 1 | x x x | - x - | x - - x -
2576 * 2 | - x - | x - - | - x - - -
2577 * 3 | x x x | x - - | - x x - -
2578 * 4 | - x - | x x x | - x - - -
2579 * 5 | x - - | x x x | x - - - -
2580 * 6 | x x x | x x x | x x x x x
2581 */
2582// Codecs used by offerer in the AudioCodecsAnswerTest
2583static const int kOfferSendCodecs[] = { 0, 1, 3, 5, 6 };
2584static const int kOfferRecvCodecs[] = { 1, 2, 3, 4, 6 };
2585// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
2586// jumbled to catch the answer not following the order in the offer.
2587static const int kAnswerSendCodecs[] = { 6, 5, 2, 3, 4 };
2588static const int kAnswerRecvCodecs[] = { 6, 5, 4, 1, 0 };
2589// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
2590static const int kResultSend_RecvCodecs[] = { 0, 1, 5, 6 };
2591static const int kResultRecv_SendCodecs[] = { 2, 3, 4, 6 };
2592static const int kResultSendrecv_SendCodecs[] = { 3, 6 };
2593static const int kResultSendrecv_RecvCodecs[] = { 1, 6 };
2594static const int kResultSendrecv_SendrecvCodecs[] = { 6 };
2595
2596template <typename T, int IDXS>
2597std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
2598 std::vector<T> out;
2599 out.reserve(IDXS);
2600 for (int idx : indices)
2601 out.push_back(array[idx]);
2602
2603 return out;
2604}
2605
2606void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
2607 MediaContentDirection answer_direction,
2608 bool add_legacy_stream) {
2609 TransportDescriptionFactory offer_tdf;
2610 TransportDescriptionFactory answer_tdf;
2611 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
2612 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
2613 offer_factory.set_audio_codecs(
2614 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
2615 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
2616 answer_factory.set_audio_codecs(
2617 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
2618 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
2619
2620 // Never add a legacy stream to offer - we want to control the offer
2621 // parameters exactly.
2622 offer_factory.set_add_legacy_streams(false);
2623 answer_factory.set_add_legacy_streams(add_legacy_stream);
2624 MediaSessionOptions offer_opts;
2625 offer_opts.recv_audio = (offer_direction == cricket::MD_RECVONLY ||
2626 offer_direction == cricket::MD_SENDRECV);
2627 offer_opts.recv_video = false;
2628 if (offer_direction == cricket::MD_SENDONLY ||
2629 offer_direction == cricket::MD_SENDRECV) {
2630 offer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2631 }
2632
2633 std::unique_ptr<SessionDescription> offer(
2634 offer_factory.CreateOffer(offer_opts, NULL));
2635 ASSERT_TRUE(offer.get() != NULL);
2636
2637 MediaSessionOptions answer_opts;
2638 answer_opts.recv_audio = (answer_direction == cricket::MD_RECVONLY ||
2639 answer_direction == cricket::MD_SENDRECV);
2640 answer_opts.recv_video = false;
2641 if (answer_direction == cricket::MD_SENDONLY ||
2642 answer_direction == cricket::MD_SENDRECV) {
2643 answer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2644 }
2645 std::unique_ptr<SessionDescription> answer(
2646 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
2647 const ContentInfo* ac = answer->GetContentByName("audio");
2648
2649 // If the factory didn't add any audio content to the answer, we cannot check
2650 // that the codecs put in are right. This happens when we neither want to send
2651 // nor receive audio. The checks are still in place if at some point we'd
2652 // instead create an inactive stream.
2653 if (ac) {
2654 const AudioContentDescription* acd =
2655 static_cast<const AudioContentDescription*>(ac->description);
2656 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2657
2658
2659 std::vector<AudioCodec> target_codecs;
2660 // For offers with sendrecv or inactive, we should never reply with more
2661 // codecs than offered, with these codec sets.
2662 switch (offer_direction) {
2663 case cricket::MD_INACTIVE:
2664 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2665 kResultSendrecv_SendrecvCodecs);
2666 break;
2667 case cricket::MD_SENDONLY:
2668 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2669 kResultSend_RecvCodecs);
2670 break;
2671 case cricket::MD_RECVONLY:
2672 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2673 kResultRecv_SendCodecs);
2674 break;
2675 case cricket::MD_SENDRECV:
2676 if (acd->direction() == cricket::MD_SENDONLY) {
2677 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2678 kResultSendrecv_SendCodecs);
2679 } else if (acd->direction() == cricket::MD_RECVONLY) {
2680 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2681 kResultSendrecv_RecvCodecs);
2682 } else {
2683 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2684 kResultSendrecv_SendrecvCodecs);
2685 }
2686 break;
2687 }
2688
2689 auto format_codecs = [] (const std::vector<AudioCodec>& codecs) {
2690 std::stringstream os;
2691 bool first = true;
2692 os << "{";
2693 for (const auto& c : codecs) {
2694 os << (first ? " " : ", ") << c.id;
2695 first = false;
2696 }
2697 os << " }";
2698 return os.str();
2699 };
2700
2701 EXPECT_TRUE(acd->codecs() == target_codecs)
2702 << "Expected: " << format_codecs(target_codecs)
2703 << ", got: " << format_codecs(acd->codecs())
2704 << "; Offered: " << MediaContentDirectionToString(offer_direction)
2705 << ", answerer wants: "
2706 << MediaContentDirectionToString(answer_direction)
2707 << "; got: " << MediaContentDirectionToString(acd->direction());
2708 } else {
2709 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
2710 << "Only inactive offers are allowed to not generate any audio content";
2711 }
2712}
2713}
2714
2715class AudioCodecsOfferTest
2716 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2717 bool>> {
2718};
2719
2720TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
2721 TestAudioCodecsOffer(std::tr1::get<0>(GetParam()),
2722 std::tr1::get<1>(GetParam()));
2723}
2724
2725INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2726 AudioCodecsOfferTest,
2727 ::testing::Combine(
2728 ::testing::Values(cricket::MD_SENDONLY,
2729 cricket::MD_RECVONLY,
2730 cricket::MD_SENDRECV,
2731 cricket::MD_INACTIVE),
2732 ::testing::Bool()));
2733
2734class AudioCodecsAnswerTest
2735 : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
2736 MediaContentDirection,
2737 bool>> {
2738};
2739
2740TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
2741 TestAudioCodecsAnswer(std::tr1::get<0>(GetParam()),
2742 std::tr1::get<1>(GetParam()),
2743 std::tr1::get<2>(GetParam()));
2744}
2745
2746INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
2747 AudioCodecsAnswerTest,
2748 ::testing::Combine(
2749 ::testing::Values(cricket::MD_SENDONLY,
2750 cricket::MD_RECVONLY,
2751 cricket::MD_SENDRECV,
2752 cricket::MD_INACTIVE),
2753 ::testing::Values(cricket::MD_SENDONLY,
2754 cricket::MD_RECVONLY,
2755 cricket::MD_SENDRECV,
2756 cricket::MD_INACTIVE),
2757 ::testing::Bool()));