blob: fc2da881f67b8be32547f0993e3988540f126c11 [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
nissec8ee8822017-01-18 07:20:55 -080015#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000016#include "webrtc/base/fakesslidentity.h"
17#include "webrtc/base/gunit.h"
18#include "webrtc/base/messagedigest.h"
19#include "webrtc/base/ssladapter.h"
kjellandera96e2d72016-02-04 23:52:28 -080020#include "webrtc/media/base/codec.h"
21#include "webrtc/media/base/testutils.h"
kjellanderf4752772016-03-02 05:42:30 -080022#include "webrtc/p2p/base/p2pconstants.h"
kjellandera96e2d72016-02-04 23:52:28 -080023#include "webrtc/p2p/base/transportdescription.h"
24#include "webrtc/p2p/base/transportinfo.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010025#include "webrtc/pc/mediasession.h"
26#include "webrtc/pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000027
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029 ASSERT_EQ(s, cd->cryptos().size()); \
30 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031
32typedef std::vector<cricket::Candidate> Candidates;
33
34using cricket::MediaContentDescription;
35using cricket::MediaSessionDescriptionFactory;
ossu075af922016-06-14 03:29:38 -070036using cricket::MediaContentDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037using cricket::MediaSessionOptions;
38using cricket::MediaType;
39using cricket::SessionDescription;
40using cricket::SsrcGroup;
41using cricket::StreamParams;
42using cricket::StreamParamsVec;
43using cricket::TransportDescription;
44using cricket::TransportDescriptionFactory;
45using cricket::TransportInfo;
46using cricket::ContentInfo;
47using cricket::CryptoParamsVec;
48using cricket::AudioContentDescription;
49using cricket::VideoContentDescription;
50using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080051using cricket::GetFirstAudioContent;
52using cricket::GetFirstVideoContent;
53using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054using cricket::GetFirstAudioContentDescription;
55using cricket::GetFirstVideoContentDescription;
56using cricket::GetFirstDataContentDescription;
57using cricket::kAutoBandwidth;
58using cricket::AudioCodec;
59using cricket::VideoCodec;
60using cricket::DataCodec;
61using cricket::NS_JINGLE_RTP;
62using cricket::MEDIA_TYPE_AUDIO;
63using cricket::MEDIA_TYPE_VIDEO;
64using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065using cricket::SEC_DISABLED;
66using cricket::SEC_ENABLED;
67using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070068using rtc::CS_AES_CM_128_HMAC_SHA1_32;
69using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070070using rtc::CS_AEAD_AES_128_GCM;
71using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070072using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073
74static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070075 AudioCodec(103, "ISAC", 16000, -1, 1),
76 AudioCodec(102, "iLBC", 8000, 13300, 1),
77 AudioCodec(0, "PCMU", 8000, 64000, 1),
78 AudioCodec(8, "PCMA", 8000, 64000, 1),
79 AudioCodec(117, "red", 8000, 0, 1),
80 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081
82static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070083 AudioCodec(126, "speex", 16000, 22000, 1),
84 AudioCodec(0, "PCMU", 8000, 64000, 1),
85 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086};
87
88static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070089 AudioCodec(102, "iLBC", 8000, 13300, 1),
90 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091};
92
perkj26752742016-10-24 01:21:16 -070093static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
94 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095
perkj26752742016-10-24 01:21:16 -070096static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
97 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098
perkj26752742016-10-24 01:21:16 -070099static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100
deadbeef67cf2c12016-04-13 10:07:16 -0700101static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
102 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
deadbeef67cf2c12016-04-13 10:07:16 -0700104static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
105 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
deadbeef67cf2c12016-04-13 10:07:16 -0700107static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
108 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
isheriff6f8d6862016-05-26 11:24:55 -0700110static const RtpExtension kAudioRtpExtension1[] = {
111 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
112 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113};
114
isheriff6f8d6862016-05-26 11:24:55 -0700115static const RtpExtension kAudioRtpExtension2[] = {
116 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
117 RtpExtension("http://google.com/testing/audio_something_else", 8),
118 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119};
120
isheriff6f8d6862016-05-26 11:24:55 -0700121static const RtpExtension kAudioRtpExtension3[] = {
122 RtpExtension("http://google.com/testing/audio_something", 2),
123 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700124};
125
isheriff6f8d6862016-05-26 11:24:55 -0700126static const RtpExtension kAudioRtpExtensionAnswer[] = {
127 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128};
129
isheriff6f8d6862016-05-26 11:24:55 -0700130static const RtpExtension kVideoRtpExtension1[] = {
131 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
132 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133};
134
isheriff6f8d6862016-05-26 11:24:55 -0700135static const RtpExtension kVideoRtpExtension2[] = {
136 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
137 RtpExtension("http://google.com/testing/video_something_else", 14),
138 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139};
140
isheriff6f8d6862016-05-26 11:24:55 -0700141static const RtpExtension kVideoRtpExtension3[] = {
142 RtpExtension("http://google.com/testing/video_something", 4),
143 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700144};
145
isheriff6f8d6862016-05-26 11:24:55 -0700146static const RtpExtension kVideoRtpExtensionAnswer[] = {
147 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148};
149
Peter Boström0c4e06b2015-10-07 12:23:21 +0200150static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
151static const uint32_t kSimSsrc[] = {10, 20, 30};
152static const uint32_t kFec1Ssrc[] = {10, 11};
153static const uint32_t kFec2Ssrc[] = {20, 21};
154static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155
156static const char kMediaStream1[] = "stream_1";
157static const char kMediaStream2[] = "stream_2";
158static const char kVideoTrack1[] = "video_1";
159static const char kVideoTrack2[] = "video_2";
160static const char kAudioTrack1[] = "audio_1";
161static const char kAudioTrack2[] = "audio_2";
162static const char kAudioTrack3[] = "audio_3";
163static const char kDataTrack1[] = "data_1";
164static const char kDataTrack2[] = "data_2";
165static const char kDataTrack3[] = "data_3";
166
zhihuangcf5b37c2016-05-05 11:44:35 -0700167static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
168 "RTP/SAVPF"};
169static const char* kMediaProtocolsDtls[] = {
170 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
171 "UDP/TLS/RTP/SAVP"};
172
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000173static bool IsMediaContentOfType(const ContentInfo* content,
174 MediaType media_type) {
175 const MediaContentDescription* mdesc =
176 static_cast<const MediaContentDescription*>(content->description);
177 return mdesc && mdesc->type() == media_type;
178}
179
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000180static cricket::MediaContentDirection
181GetMediaDirection(const ContentInfo* content) {
182 cricket::MediaContentDescription* desc =
183 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
184 return desc->direction();
185}
186
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000187static void AddRtxCodec(const VideoCodec& rtx_codec,
188 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800189 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000190 codecs->push_back(rtx_codec);
191}
192
193template <class T>
194static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
195 std::vector<std::string> codec_names;
196 for (const auto& codec : codecs) {
197 codec_names.push_back(codec.name);
198 }
199 return codec_names;
200}
201
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202class MediaSessionDescriptionFactoryTest : public testing::Test {
203 public:
204 MediaSessionDescriptionFactoryTest()
Henrik Boström3a14bf32015-08-31 09:27:58 +0200205 : f1_(&tdf1_),
206 f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700207 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
208 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
210 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700211 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
212 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000213 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
214 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200215 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700216 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200217 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700218 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219 }
220
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000221 // Create a video StreamParamsVec object with:
222 // - one video stream with 3 simulcast streams and FEC,
223 StreamParamsVec CreateComplexVideoStreamParamsVec() {
224 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
225 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
226 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
227 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
228
229 std::vector<SsrcGroup> ssrc_groups;
230 ssrc_groups.push_back(sim_group);
231 ssrc_groups.push_back(fec_group1);
232 ssrc_groups.push_back(fec_group2);
233 ssrc_groups.push_back(fec_group3);
234
235 StreamParams simulcast_params;
236 simulcast_params.id = kVideoTrack1;
237 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
238 simulcast_params.ssrc_groups = ssrc_groups;
239 simulcast_params.cname = "Video_SIM_FEC";
240 simulcast_params.sync_label = kMediaStream1;
241
242 StreamParamsVec video_streams;
243 video_streams.push_back(simulcast_params);
244
245 return video_streams;
246 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000247
248 bool CompareCryptoParams(const CryptoParamsVec& c1,
249 const CryptoParamsVec& c2) {
250 if (c1.size() != c2.size())
251 return false;
252 for (size_t i = 0; i < c1.size(); ++i)
253 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
254 c1[i].key_params != c2[i].key_params ||
255 c1[i].session_params != c2[i].session_params)
256 return false;
257 return true;
258 }
259
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700260 // Returns true if the transport info contains "renomination" as an
261 // ICE option.
262 bool GetIceRenomination(const TransportInfo* transport_info) {
263 const std::vector<std::string>& ice_options =
264 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700265 auto iter =
266 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700267 return iter != ice_options.end();
268 }
269
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
271 bool has_current_desc) {
272 const std::string current_audio_ufrag = "current_audio_ufrag";
273 const std::string current_audio_pwd = "current_audio_pwd";
274 const std::string current_video_ufrag = "current_video_ufrag";
275 const std::string current_video_pwd = "current_video_pwd";
276 const std::string current_data_ufrag = "current_data_ufrag";
277 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800278 std::unique_ptr<SessionDescription> current_desc;
279 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 if (has_current_desc) {
281 current_desc.reset(new SessionDescription());
282 EXPECT_TRUE(current_desc->AddTransportInfo(
283 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700284 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000285 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 EXPECT_TRUE(current_desc->AddTransportInfo(
287 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700288 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000289 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290 EXPECT_TRUE(current_desc->AddTransportInfo(
291 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700292 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000293 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 }
295 if (offer) {
296 desc.reset(f1_.CreateOffer(options, current_desc.get()));
297 } else {
kwiberg31022942016-03-11 14:18:21 -0800298 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 offer.reset(f1_.CreateOffer(options, NULL));
300 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
301 }
302 ASSERT_TRUE(desc.get() != NULL);
303 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000304 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305 EXPECT_TRUE(ti_audio != NULL);
306 if (has_current_desc) {
307 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
308 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
309 } else {
310 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
311 ti_audio->description.ice_ufrag.size());
312 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
313 ti_audio->description.ice_pwd.size());
314 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700315 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000316
317 } else {
318 EXPECT_TRUE(ti_audio == NULL);
319 }
320 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000321 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 EXPECT_TRUE(ti_video != NULL);
323 if (options.bundle_enabled) {
324 EXPECT_EQ(ti_audio->description.ice_ufrag,
325 ti_video->description.ice_ufrag);
326 EXPECT_EQ(ti_audio->description.ice_pwd,
327 ti_video->description.ice_pwd);
328 } else {
329 if (has_current_desc) {
330 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
331 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
332 } else {
333 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
334 ti_video->description.ice_ufrag.size());
335 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
336 ti_video->description.ice_pwd.size());
337 }
338 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700339 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340 } else {
341 EXPECT_TRUE(ti_video == NULL);
342 }
343 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
344 if (options.has_data()) {
345 EXPECT_TRUE(ti_data != NULL);
346 if (options.bundle_enabled) {
347 EXPECT_EQ(ti_audio->description.ice_ufrag,
348 ti_data->description.ice_ufrag);
349 EXPECT_EQ(ti_audio->description.ice_pwd,
350 ti_data->description.ice_pwd);
351 } else {
352 if (has_current_desc) {
353 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
354 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
355 } else {
356 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
357 ti_data->description.ice_ufrag.size());
358 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
359 ti_data->description.ice_pwd.size());
360 }
361 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700362 EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_data));
363
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 } else {
365 EXPECT_TRUE(ti_video == NULL);
366 }
367 }
368
369 void TestCryptoWithBundle(bool offer) {
370 f1_.set_secure(SEC_ENABLED);
371 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000372 options.recv_audio = true;
373 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000374 options.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -0800375 std::unique_ptr<SessionDescription> ref_desc;
376 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000377 if (offer) {
378 options.bundle_enabled = false;
379 ref_desc.reset(f1_.CreateOffer(options, NULL));
380 options.bundle_enabled = true;
381 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
382 } else {
383 options.bundle_enabled = true;
384 ref_desc.reset(f1_.CreateOffer(options, NULL));
385 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
386 }
387 ASSERT_TRUE(desc.get() != NULL);
388 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000389 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390 desc.get()->GetContentDescriptionByName("audio"));
391 ASSERT_TRUE(audio_media_desc != NULL);
392 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000393 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000394 desc.get()->GetContentDescriptionByName("video"));
395 ASSERT_TRUE(video_media_desc != NULL);
396 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
397 video_media_desc->cryptos()));
398 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
399 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
400 audio_media_desc->cryptos()[0].cipher_suite);
401
402 // Verify the selected crypto is one from the reference audio
403 // media content.
404 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000405 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406 ref_desc.get()->GetContentDescriptionByName("audio"));
407 bool found = false;
408 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
409 if (ref_audio_media_desc->cryptos()[i].Matches(
410 audio_media_desc->cryptos()[0])) {
411 found = true;
412 break;
413 }
414 }
415 EXPECT_TRUE(found);
416 }
417
418 // This test that the audio and video media direction is set to
419 // |expected_direction_in_answer| in an answer if the offer direction is set
420 // to |direction_in_offer|.
421 void TestMediaDirectionInAnswer(
422 cricket::MediaContentDirection direction_in_offer,
423 cricket::MediaContentDirection expected_direction_in_answer) {
424 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000425 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800426 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700428 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 ASSERT_TRUE(ac_offer != NULL);
430 AudioContentDescription* acd_offer =
431 static_cast<AudioContentDescription*>(ac_offer->description);
432 acd_offer->set_direction(direction_in_offer);
terelius8c011e52016-04-26 05:28:11 -0700433 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 ASSERT_TRUE(vc_offer != NULL);
435 VideoContentDescription* vcd_offer =
436 static_cast<VideoContentDescription*>(vc_offer->description);
437 vcd_offer->set_direction(direction_in_offer);
438
kwiberg31022942016-03-11 14:18:21 -0800439 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 f2_.CreateAnswer(offer.get(), opts, NULL));
441 const AudioContentDescription* acd_answer =
442 GetFirstAudioContentDescription(answer.get());
443 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
444 const VideoContentDescription* vcd_answer =
445 GetFirstVideoContentDescription(answer.get());
446 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
447 }
448
449 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
450 const cricket::ContentDescription* description = content->description;
nissec8ee8822017-01-18 07:20:55 -0800451 RTC_CHECK(description != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000453 static_cast<const cricket::AudioContentDescription*>(description);
nissec8ee8822017-01-18 07:20:55 -0800454 RTC_CHECK(audio_content_desc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
456 if (audio_content_desc->codecs()[i].name == "CN")
457 return false;
458 }
459 return true;
460 }
461
jbauchcb560652016-08-04 05:20:32 -0700462 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
463 MediaSessionOptions offer_opts;
464 offer_opts.recv_video = true;
465 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
466 MediaSessionOptions answer_opts;
467 answer_opts.recv_video = true;
468 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
469 f1_.set_secure(SEC_ENABLED);
470 f2_.set_secure(SEC_ENABLED);
471 std::unique_ptr<SessionDescription> offer(
472 f1_.CreateOffer(offer_opts, NULL));
473 ASSERT_TRUE(offer.get() != NULL);
474 std::unique_ptr<SessionDescription> answer(
475 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
476 const ContentInfo* ac = answer->GetContentByName("audio");
477 const ContentInfo* vc = answer->GetContentByName("video");
478 ASSERT_TRUE(ac != NULL);
479 ASSERT_TRUE(vc != NULL);
480 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
481 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
482 const AudioContentDescription* acd =
483 static_cast<const AudioContentDescription*>(ac->description);
484 const VideoContentDescription* vcd =
485 static_cast<const VideoContentDescription*>(vc->description);
486 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
487 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
488 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
489 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
490 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
491 if (gcm_offer && gcm_answer) {
492 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
493 } else {
494 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
495 }
496 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
497 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
498 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
499 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
500 if (gcm_offer && gcm_answer) {
501 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
502 } else {
503 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
504 }
505 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
506 }
507
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 protected:
509 MediaSessionDescriptionFactory f1_;
510 MediaSessionDescriptionFactory f2_;
511 TransportDescriptionFactory tdf1_;
512 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513};
514
515// Create a typical audio offer, and ensure it matches what we expect.
516TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
517 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800518 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 f1_.CreateOffer(MediaSessionOptions(), NULL));
520 ASSERT_TRUE(offer.get() != NULL);
521 const ContentInfo* ac = offer->GetContentByName("audio");
522 const ContentInfo* vc = offer->GetContentByName("video");
523 ASSERT_TRUE(ac != NULL);
524 ASSERT_TRUE(vc == NULL);
525 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
526 const AudioContentDescription* acd =
527 static_cast<const AudioContentDescription*>(ac->description);
528 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700529 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
531 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
532 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
533 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
534 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
535}
536
537// Create a typical video offer, and ensure it matches what we expect.
538TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
539 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000540 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800542 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 ASSERT_TRUE(offer.get() != NULL);
544 const ContentInfo* ac = offer->GetContentByName("audio");
545 const ContentInfo* vc = offer->GetContentByName("video");
546 ASSERT_TRUE(ac != NULL);
547 ASSERT_TRUE(vc != NULL);
548 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
549 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
550 const AudioContentDescription* acd =
551 static_cast<const AudioContentDescription*>(ac->description);
552 const VideoContentDescription* vcd =
553 static_cast<const VideoContentDescription*>(vc->description);
554 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700555 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
557 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
558 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
559 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
560 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
561 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
562 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
563 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
564 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
565 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
566 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
567 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
568}
569
570// Test creating an offer with bundle where the Codecs have the same dynamic
571// RTP playlod type. The test verifies that the offer don't contain the
572// duplicate RTP payload types.
573TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
574 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700575 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
577 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
578 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
579
580 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000581 opts.recv_audio = true;
582 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 opts.data_channel_type = cricket::DCT_RTP;
584 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800585 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 const VideoContentDescription* vcd =
587 GetFirstVideoContentDescription(offer.get());
588 const AudioContentDescription* acd =
589 GetFirstAudioContentDescription(offer.get());
590 const DataContentDescription* dcd =
591 GetFirstDataContentDescription(offer.get());
592 ASSERT_TRUE(NULL != vcd);
593 ASSERT_TRUE(NULL != acd);
594 ASSERT_TRUE(NULL != dcd);
595 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
596 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
597 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
598 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
599 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
600 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
601}
602
603// Test creating an updated offer with with bundle, audio, video and data
604// after an audio only session has been negotiated.
605TEST_F(MediaSessionDescriptionFactoryTest,
606 TestCreateUpdatedVideoOfferWithBundle) {
607 f1_.set_secure(SEC_ENABLED);
608 f2_.set_secure(SEC_ENABLED);
609 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000610 opts.recv_audio = true;
611 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 opts.data_channel_type = cricket::DCT_NONE;
613 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800614 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
615 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 f2_.CreateAnswer(offer.get(), opts, NULL));
617
618 MediaSessionOptions updated_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000619 updated_opts.recv_audio = true;
620 updated_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 updated_opts.data_channel_type = cricket::DCT_RTP;
622 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800623 std::unique_ptr<SessionDescription> updated_offer(
624 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625
626 const AudioContentDescription* acd =
627 GetFirstAudioContentDescription(updated_offer.get());
628 const VideoContentDescription* vcd =
629 GetFirstVideoContentDescription(updated_offer.get());
630 const DataContentDescription* dcd =
631 GetFirstDataContentDescription(updated_offer.get());
632 EXPECT_TRUE(NULL != vcd);
633 EXPECT_TRUE(NULL != acd);
634 EXPECT_TRUE(NULL != dcd);
635
636 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
637 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
638 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
639 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
640 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
641 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
642}
deadbeef44f08192015-12-15 16:20:09 -0800643
wu@webrtc.org78187522013-10-07 23:32:02 +0000644// Create a RTP data offer, and ensure it matches what we expect.
645TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 MediaSessionOptions opts;
647 opts.data_channel_type = cricket::DCT_RTP;
648 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800649 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 ASSERT_TRUE(offer.get() != NULL);
651 const ContentInfo* ac = offer->GetContentByName("audio");
652 const ContentInfo* dc = offer->GetContentByName("data");
653 ASSERT_TRUE(ac != NULL);
654 ASSERT_TRUE(dc != NULL);
655 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
656 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
657 const AudioContentDescription* acd =
658 static_cast<const AudioContentDescription*>(ac->description);
659 const DataContentDescription* dcd =
660 static_cast<const DataContentDescription*>(dc->description);
661 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700662 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
664 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
665 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
666 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
667 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
668 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
669 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
670 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
671 EXPECT_EQ(cricket::kDataMaxBandwidth,
672 dcd->bandwidth()); // default bandwidth (auto)
673 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
674 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
675 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
676}
677
wu@webrtc.org78187522013-10-07 23:32:02 +0000678// Create an SCTP data offer with bundle without error.
679TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
680 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000681 opts.recv_audio = false;
wu@webrtc.org78187522013-10-07 23:32:02 +0000682 opts.bundle_enabled = true;
683 opts.data_channel_type = cricket::DCT_SCTP;
684 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800685 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000686 EXPECT_TRUE(offer.get() != NULL);
687 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
688}
689
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000690// Test creating an sctp data channel from an already generated offer.
691TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
692 MediaSessionOptions opts;
693 opts.recv_audio = false;
694 opts.bundle_enabled = true;
695 opts.data_channel_type = cricket::DCT_SCTP;
696 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800697 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000698 ASSERT_TRUE(offer1.get() != NULL);
699 const ContentInfo* data = offer1->GetContentByName("data");
700 ASSERT_TRUE(data != NULL);
701 const MediaContentDescription* mdesc =
702 static_cast<const MediaContentDescription*>(data->description);
703 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
704
705 // Now set data_channel_type to 'none' (default) and make sure that the
706 // datachannel type that gets generated from the previous offer, is of the
707 // same type.
708 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800709 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000710 f1_.CreateOffer(opts, offer1.get()));
711 data = offer2->GetContentByName("data");
712 ASSERT_TRUE(data != NULL);
713 mdesc = static_cast<const MediaContentDescription*>(data->description);
714 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
715}
716
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717// Create an audio, video offer without legacy StreamParams.
718TEST_F(MediaSessionDescriptionFactoryTest,
719 TestCreateOfferWithoutLegacyStreams) {
720 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000721 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 f1_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -0800723 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 ASSERT_TRUE(offer.get() != NULL);
725 const ContentInfo* ac = offer->GetContentByName("audio");
726 const ContentInfo* vc = offer->GetContentByName("video");
727 ASSERT_TRUE(ac != NULL);
728 ASSERT_TRUE(vc != NULL);
729 const AudioContentDescription* acd =
730 static_cast<const AudioContentDescription*>(ac->description);
731 const VideoContentDescription* vcd =
732 static_cast<const VideoContentDescription*>(vc->description);
733
734 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
735 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
736}
737
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000738// Creates an audio+video sendonly offer.
739TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
740 MediaSessionOptions options;
741 options.recv_audio = false;
742 options.recv_video = false;
743 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
744 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
745
kwiberg31022942016-03-11 14:18:21 -0800746 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000747 ASSERT_TRUE(offer.get() != NULL);
748 EXPECT_EQ(2u, offer->contents().size());
749 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
750 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
751
752 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
753 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
754}
755
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000756// Verifies that the order of the media contents in the current
757// SessionDescription is preserved in the new SessionDescription.
758TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
759 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000760 opts.recv_audio = false;
761 opts.recv_video = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000762 opts.data_channel_type = cricket::DCT_SCTP;
763
kwiberg31022942016-03-11 14:18:21 -0800764 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000765 ASSERT_TRUE(offer1.get() != NULL);
766 EXPECT_EQ(1u, offer1->contents().size());
767 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
768
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000769 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -0800770 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000771 f1_.CreateOffer(opts, offer1.get()));
772 ASSERT_TRUE(offer2.get() != NULL);
773 EXPECT_EQ(2u, offer2->contents().size());
774 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
775 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
776
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000777 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -0800778 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000779 f1_.CreateOffer(opts, offer2.get()));
780 ASSERT_TRUE(offer3.get() != NULL);
781 EXPECT_EQ(3u, offer3->contents().size());
782 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
783 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
784 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
785
786 // Verifies the default order is audio-video-data, so that the previous checks
787 // didn't pass by accident.
kwiberg31022942016-03-11 14:18:21 -0800788 std::unique_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000789 ASSERT_TRUE(offer4.get() != NULL);
790 EXPECT_EQ(3u, offer4->contents().size());
791 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
792 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
793 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
794}
795
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796// Create a typical audio answer, and ensure it matches what we expect.
797TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
798 f1_.set_secure(SEC_ENABLED);
799 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800800 std::unique_ptr<SessionDescription> offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 f1_.CreateOffer(MediaSessionOptions(), NULL));
802 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800803 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
805 const ContentInfo* ac = answer->GetContentByName("audio");
806 const ContentInfo* vc = answer->GetContentByName("video");
807 ASSERT_TRUE(ac != NULL);
808 ASSERT_TRUE(vc == NULL);
809 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
810 const AudioContentDescription* acd =
811 static_cast<const AudioContentDescription*>(ac->description);
812 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
813 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
814 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
815 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
816 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
817 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
818 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
819}
820
jbauchcb560652016-08-04 05:20:32 -0700821// Create a typical audio answer with GCM ciphers enabled, and ensure it
822// matches what we expect.
823TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
824 f1_.set_secure(SEC_ENABLED);
825 f2_.set_secure(SEC_ENABLED);
826 MediaSessionOptions options;
827 options.crypto_options.enable_gcm_crypto_suites = true;
828 std::unique_ptr<SessionDescription> offer(
829 f1_.CreateOffer(options, NULL));
830 ASSERT_TRUE(offer.get() != NULL);
831 std::unique_ptr<SessionDescription> answer(
832 f2_.CreateAnswer(offer.get(), options, NULL));
833 const ContentInfo* ac = answer->GetContentByName("audio");
834 const ContentInfo* vc = answer->GetContentByName("video");
835 ASSERT_TRUE(ac != NULL);
836 ASSERT_TRUE(vc == NULL);
837 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
838 const AudioContentDescription* acd =
839 static_cast<const AudioContentDescription*>(ac->description);
840 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
841 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
842 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
843 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
844 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
845 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
846 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
847}
848
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849// Create a typical video answer, and ensure it matches what we expect.
850TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
851 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000852 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 f1_.set_secure(SEC_ENABLED);
854 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800855 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800857 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858 f2_.CreateAnswer(offer.get(), opts, NULL));
859 const ContentInfo* ac = answer->GetContentByName("audio");
860 const ContentInfo* vc = answer->GetContentByName("video");
861 ASSERT_TRUE(ac != NULL);
862 ASSERT_TRUE(vc != NULL);
863 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
864 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
865 const AudioContentDescription* acd =
866 static_cast<const AudioContentDescription*>(ac->description);
867 const VideoContentDescription* vcd =
868 static_cast<const VideoContentDescription*>(vc->description);
869 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
870 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
871 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
872 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
873 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
874 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
875 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
876 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
877 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
878 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
879 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
880 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
881}
882
jbauchcb560652016-08-04 05:20:32 -0700883// Create a typical video answer with GCM ciphers enabled, and ensure it
884// matches what we expect.
885TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
886 TestVideoGcmCipher(true, true);
887}
888
889// Create a typical video answer with GCM ciphers enabled for the offer only,
890// and ensure it matches what we expect.
891TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
892 TestVideoGcmCipher(true, false);
893}
894
895// Create a typical video answer with GCM ciphers enabled for the answer only,
896// and ensure it matches what we expect.
897TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
898 TestVideoGcmCipher(false, true);
899}
900
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
902 MediaSessionOptions opts;
903 opts.data_channel_type = cricket::DCT_RTP;
904 f1_.set_secure(SEC_ENABLED);
905 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800906 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800908 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909 f2_.CreateAnswer(offer.get(), opts, NULL));
910 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -0800911 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000912 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -0800913 ASSERT_TRUE(dc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -0800915 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916 const AudioContentDescription* acd =
917 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -0800918 const DataContentDescription* dcd =
919 static_cast<const DataContentDescription*>(dc->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
921 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
922 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
923 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
924 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
925 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
zstein4b2e0822017-02-17 19:48:38 -0800926 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
927 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
928 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
929 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
930 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
931 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932}
933
jbauchcb560652016-08-04 05:20:32 -0700934TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
935 MediaSessionOptions opts;
936 opts.data_channel_type = cricket::DCT_RTP;
937 opts.crypto_options.enable_gcm_crypto_suites = true;
938 f1_.set_secure(SEC_ENABLED);
939 f2_.set_secure(SEC_ENABLED);
940 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
941 ASSERT_TRUE(offer.get() != NULL);
942 std::unique_ptr<SessionDescription> answer(
943 f2_.CreateAnswer(offer.get(), opts, NULL));
944 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -0800945 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -0700946 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -0800947 ASSERT_TRUE(dc != NULL);
jbauchcb560652016-08-04 05:20:32 -0700948 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -0800949 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
jbauchcb560652016-08-04 05:20:32 -0700950 const AudioContentDescription* acd =
951 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -0800952 const DataContentDescription* dcd =
953 static_cast<const DataContentDescription*>(dc->description);
jbauchcb560652016-08-04 05:20:32 -0700954 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
955 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
956 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
957 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
958 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
959 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
zstein4b2e0822017-02-17 19:48:38 -0800960 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
961 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
962 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
963 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
964 ASSERT_CRYPTO(dcd, 1U, CS_AEAD_AES_256_GCM);
965 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
966}
967
968// The use_sctpmap flag should be set in a DataContentDescription by default.
969// The answer's use_sctpmap flag should match the offer's.
970TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
971 MediaSessionOptions opts;
972 opts.data_channel_type = cricket::DCT_SCTP;
973 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
974 ASSERT_TRUE(offer.get() != NULL);
975 ContentInfo* dc_offer = offer->GetContentByName("data");
976 ASSERT_TRUE(dc_offer != NULL);
977 DataContentDescription* dcd_offer =
978 static_cast<DataContentDescription*>(dc_offer->description);
979 EXPECT_TRUE(dcd_offer->use_sctpmap());
980
981 std::unique_ptr<SessionDescription> answer(
982 f2_.CreateAnswer(offer.get(), opts, NULL));
983 const ContentInfo* dc_answer = answer->GetContentByName("data");
984 ASSERT_TRUE(dc_answer != NULL);
985 const DataContentDescription* dcd_answer =
986 static_cast<const DataContentDescription*>(dc_answer->description);
987 EXPECT_TRUE(dcd_answer->use_sctpmap());
988}
989
990// The answer's use_sctpmap flag should match the offer's.
991TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
992 MediaSessionOptions opts;
993 opts.data_channel_type = cricket::DCT_SCTP;
994 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
995 ASSERT_TRUE(offer.get() != NULL);
996 ContentInfo* dc_offer = offer->GetContentByName("data");
997 ASSERT_TRUE(dc_offer != NULL);
998 DataContentDescription* dcd_offer =
999 static_cast<DataContentDescription*>(dc_offer->description);
1000 dcd_offer->set_use_sctpmap(false);
1001
1002 std::unique_ptr<SessionDescription> answer(
1003 f2_.CreateAnswer(offer.get(), opts, NULL));
1004 const ContentInfo* dc_answer = answer->GetContentByName("data");
1005 ASSERT_TRUE(dc_answer != NULL);
1006 const DataContentDescription* dcd_answer =
1007 static_cast<const DataContentDescription*>(dc_answer->description);
1008 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001009}
1010
deadbeef8b7e9ad2017-05-25 09:38:55 -07001011// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1012// and "TCP/DTLS/SCTP" offers.
1013TEST_F(MediaSessionDescriptionFactoryTest,
1014 TestCreateDataAnswerToDifferentOfferedProtos) {
1015 // Need to enable DTLS offer/answer generation (disabled by default in this
1016 // test).
1017 f1_.set_secure(SEC_ENABLED);
1018 f2_.set_secure(SEC_ENABLED);
1019 tdf1_.set_secure(SEC_ENABLED);
1020 tdf2_.set_secure(SEC_ENABLED);
1021
1022 MediaSessionOptions opts;
1023 opts.data_channel_type = cricket::DCT_SCTP;
1024 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1025 ASSERT_TRUE(offer.get() != nullptr);
1026 ContentInfo* dc_offer = offer->GetContentByName("data");
1027 ASSERT_TRUE(dc_offer != nullptr);
1028 DataContentDescription* dcd_offer =
1029 static_cast<DataContentDescription*>(dc_offer->description);
1030
1031 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1032 "TCP/DTLS/SCTP"};
1033 for (const std::string& proto : protos) {
1034 dcd_offer->set_protocol(proto);
1035 std::unique_ptr<SessionDescription> answer(
1036 f2_.CreateAnswer(offer.get(), opts, nullptr));
1037 const ContentInfo* dc_answer = answer->GetContentByName("data");
1038 ASSERT_TRUE(dc_answer != nullptr);
1039 const DataContentDescription* dcd_answer =
1040 static_cast<const DataContentDescription*>(dc_answer->description);
1041 EXPECT_FALSE(dc_answer->rejected);
1042 EXPECT_EQ(proto, dcd_answer->protocol());
1043 }
1044}
1045
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001046// Verifies that the order of the media contents in the offer is preserved in
1047// the answer.
1048TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1049 MediaSessionOptions opts;
1050
1051 // Creates a data only offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001052 opts.recv_audio = false;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001053 opts.data_channel_type = cricket::DCT_SCTP;
kwiberg31022942016-03-11 14:18:21 -08001054 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001055 ASSERT_TRUE(offer1.get() != NULL);
1056
1057 // Appends audio to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001058 opts.recv_audio = true;
kwiberg31022942016-03-11 14:18:21 -08001059 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001060 f1_.CreateOffer(opts, offer1.get()));
1061 ASSERT_TRUE(offer2.get() != NULL);
1062
1063 // Appends video to the offer.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001064 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001065 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001066 f1_.CreateOffer(opts, offer2.get()));
1067 ASSERT_TRUE(offer3.get() != NULL);
1068
kwiberg31022942016-03-11 14:18:21 -08001069 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001070 f2_.CreateAnswer(offer3.get(), opts, NULL));
1071 ASSERT_TRUE(answer.get() != NULL);
1072 EXPECT_EQ(3u, answer->contents().size());
1073 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1074 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1075 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1076}
1077
ossu075af922016-06-14 03:29:38 -07001078// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1079// answerer settings.
1080
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081// This test that the media direction is set to send/receive in an answer if
1082// the offer is send receive.
1083TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1084 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1085}
1086
1087// This test that the media direction is set to receive only in an answer if
1088// the offer is send only.
1089TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1090 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1091}
1092
1093// This test that the media direction is set to send only in an answer if
1094// the offer is recv only.
1095TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1096 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1097}
1098
1099// This test that the media direction is set to inactive in an answer if
1100// the offer is inactive.
1101TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1102 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1103}
1104
1105// Test that a data content with an unknown protocol is rejected in an answer.
1106TEST_F(MediaSessionDescriptionFactoryTest,
1107 CreateDataAnswerToOfferWithUnknownProtocol) {
1108 MediaSessionOptions opts;
1109 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001110 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111 f1_.set_secure(SEC_ENABLED);
1112 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001113 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001114 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001115 ASSERT_TRUE(dc_offer != NULL);
1116 DataContentDescription* dcd_offer =
1117 static_cast<DataContentDescription*>(dc_offer->description);
1118 ASSERT_TRUE(dcd_offer != NULL);
1119 std::string protocol = "a weird unknown protocol";
1120 dcd_offer->set_protocol(protocol);
1121
kwiberg31022942016-03-11 14:18:21 -08001122 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123 f2_.CreateAnswer(offer.get(), opts, NULL));
1124
1125 const ContentInfo* dc_answer = answer->GetContentByName("data");
1126 ASSERT_TRUE(dc_answer != NULL);
1127 EXPECT_TRUE(dc_answer->rejected);
1128 const DataContentDescription* dcd_answer =
1129 static_cast<const DataContentDescription*>(dc_answer->description);
1130 ASSERT_TRUE(dcd_answer != NULL);
1131 EXPECT_EQ(protocol, dcd_answer->protocol());
1132}
1133
1134// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1135TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
1136 MediaSessionOptions opts;
1137 f1_.set_secure(SEC_DISABLED);
1138 f2_.set_secure(SEC_DISABLED);
1139 tdf1_.set_secure(SEC_DISABLED);
1140 tdf2_.set_secure(SEC_DISABLED);
1141
kwiberg31022942016-03-11 14:18:21 -08001142 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143 const AudioContentDescription* offer_acd =
1144 GetFirstAudioContentDescription(offer.get());
1145 ASSERT_TRUE(offer_acd != NULL);
1146 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1147
kwiberg31022942016-03-11 14:18:21 -08001148 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001149 f2_.CreateAnswer(offer.get(), opts, NULL));
1150
1151 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1152 ASSERT_TRUE(ac_answer != NULL);
1153 EXPECT_FALSE(ac_answer->rejected);
1154
1155 const AudioContentDescription* answer_acd =
1156 GetFirstAudioContentDescription(answer.get());
1157 ASSERT_TRUE(answer_acd != NULL);
1158 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1159}
1160
1161// Create a video offer and answer and ensure the RTP header extensions
1162// matches what we expect.
1163TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1164 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001165 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001166
1167 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1168 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1169 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1170 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1171
kwiberg31022942016-03-11 14:18:21 -08001172 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001174 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 f2_.CreateAnswer(offer.get(), opts, NULL));
1176
1177 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1178 GetFirstAudioContentDescription(
1179 offer.get())->rtp_header_extensions());
1180 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1181 GetFirstVideoContentDescription(
1182 offer.get())->rtp_header_extensions());
1183 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1184 GetFirstAudioContentDescription(
1185 answer.get())->rtp_header_extensions());
1186 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1187 GetFirstVideoContentDescription(
1188 answer.get())->rtp_header_extensions());
1189}
1190
1191// Create an audio, video, data answer without legacy StreamParams.
1192TEST_F(MediaSessionDescriptionFactoryTest,
1193 TestCreateAnswerWithoutLegacyStreams) {
1194 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001195 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196 opts.data_channel_type = cricket::DCT_RTP;
1197 f1_.set_add_legacy_streams(false);
1198 f2_.set_add_legacy_streams(false);
kwiberg31022942016-03-11 14:18:21 -08001199 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001201 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 f2_.CreateAnswer(offer.get(), opts, NULL));
1203 const ContentInfo* ac = answer->GetContentByName("audio");
1204 const ContentInfo* vc = answer->GetContentByName("video");
1205 const ContentInfo* dc = answer->GetContentByName("data");
1206 ASSERT_TRUE(ac != NULL);
1207 ASSERT_TRUE(vc != NULL);
1208 const AudioContentDescription* acd =
1209 static_cast<const AudioContentDescription*>(ac->description);
1210 const VideoContentDescription* vcd =
1211 static_cast<const VideoContentDescription*>(vc->description);
1212 const DataContentDescription* dcd =
1213 static_cast<const DataContentDescription*>(dc->description);
1214
1215 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1216 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1217 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1218}
1219
1220TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1221 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001222 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223 opts.data_channel_type = cricket::DCT_RTP;
1224 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001225 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226 ASSERT_TRUE(offer.get() != NULL);
1227 const ContentInfo* ac = offer->GetContentByName("audio");
1228 const ContentInfo* vc = offer->GetContentByName("video");
1229 const ContentInfo* dc = offer->GetContentByName("data");
1230 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1231 static_cast<const AudioContentDescription*>(ac->description));
1232 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1233 static_cast<const VideoContentDescription*>(vc->description));
1234 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1235 static_cast<const DataContentDescription*>(dc->description));
1236
1237 EXPECT_FALSE(acd->partial()); // default is false.
1238 acd->set_partial(true);
1239 EXPECT_TRUE(acd->partial());
1240 acd->set_partial(false);
1241 EXPECT_FALSE(acd->partial());
1242
1243 EXPECT_FALSE(vcd->partial()); // default is false.
1244 vcd->set_partial(true);
1245 EXPECT_TRUE(vcd->partial());
1246 vcd->set_partial(false);
1247 EXPECT_FALSE(vcd->partial());
1248
1249 EXPECT_FALSE(dcd->partial()); // default is false.
1250 dcd->set_partial(true);
1251 EXPECT_TRUE(dcd->partial());
1252 dcd->set_partial(false);
1253 EXPECT_FALSE(dcd->partial());
1254}
1255
1256// Create a typical video answer, and ensure it matches what we expect.
1257TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1258 MediaSessionOptions offer_opts;
1259 MediaSessionOptions answer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001260 answer_opts.recv_video = true;
1261 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 answer_opts.data_channel_type = cricket::DCT_RTP;
1263 offer_opts.data_channel_type = cricket::DCT_RTP;
1264
kwiberg31022942016-03-11 14:18:21 -08001265 std::unique_ptr<SessionDescription> offer;
1266 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267
1268 offer_opts.rtcp_mux_enabled = true;
1269 answer_opts.rtcp_mux_enabled = true;
1270
1271 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1272 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1273 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1274 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1275 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1276 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1277 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1278 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1279 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1280 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1281 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1282 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1283 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1284 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1285
1286 offer_opts.rtcp_mux_enabled = true;
1287 answer_opts.rtcp_mux_enabled = false;
1288
1289 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1290 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1291 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1292 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1293 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1294 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1295 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1296 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1297 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1298 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1299 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1300 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1301 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1302 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1303
1304 offer_opts.rtcp_mux_enabled = false;
1305 answer_opts.rtcp_mux_enabled = true;
1306
1307 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1308 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1309 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1310 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1311 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1312 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1313 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1314 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1315 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1316 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1317 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1318 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1319 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1320 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1321
1322 offer_opts.rtcp_mux_enabled = false;
1323 answer_opts.rtcp_mux_enabled = false;
1324
1325 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1326 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1327 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1328 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1329 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1330 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1331 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1332 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1333 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1334 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1335 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1336 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1337 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1338 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1339}
1340
1341// Create an audio-only answer to a video offer.
1342TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1343 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001344 opts.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08001345 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001346 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001347 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001348 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1349 const ContentInfo* ac = answer->GetContentByName("audio");
1350 const ContentInfo* vc = answer->GetContentByName("video");
1351 ASSERT_TRUE(ac != NULL);
1352 ASSERT_TRUE(vc != NULL);
1353 ASSERT_TRUE(vc->description != NULL);
1354 EXPECT_TRUE(vc->rejected);
1355}
1356
1357// Create an audio-only answer to an offer with data.
1358TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1359 MediaSessionOptions opts;
1360 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001361 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001363 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001364 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1365 const ContentInfo* ac = answer->GetContentByName("audio");
1366 const ContentInfo* dc = answer->GetContentByName("data");
1367 ASSERT_TRUE(ac != NULL);
1368 ASSERT_TRUE(dc != NULL);
1369 ASSERT_TRUE(dc->description != NULL);
1370 EXPECT_TRUE(dc->rejected);
1371}
1372
1373// Create an answer that rejects the contents which are rejected in the offer.
1374TEST_F(MediaSessionDescriptionFactoryTest,
1375 CreateAnswerToOfferWithRejectedMedia) {
1376 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001377 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001378 opts.data_channel_type = cricket::DCT_RTP;
kwiberg31022942016-03-11 14:18:21 -08001379 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001380 ASSERT_TRUE(offer.get() != NULL);
1381 ContentInfo* ac = offer->GetContentByName("audio");
1382 ContentInfo* vc = offer->GetContentByName("video");
1383 ContentInfo* dc = offer->GetContentByName("data");
1384 ASSERT_TRUE(ac != NULL);
1385 ASSERT_TRUE(vc != NULL);
1386 ASSERT_TRUE(dc != NULL);
1387 ac->rejected = true;
1388 vc->rejected = true;
1389 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001390 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001391 f2_.CreateAnswer(offer.get(), opts, NULL));
1392 ac = answer->GetContentByName("audio");
1393 vc = answer->GetContentByName("video");
1394 dc = answer->GetContentByName("data");
1395 ASSERT_TRUE(ac != NULL);
1396 ASSERT_TRUE(vc != NULL);
1397 ASSERT_TRUE(dc != NULL);
1398 EXPECT_TRUE(ac->rejected);
1399 EXPECT_TRUE(vc->rejected);
1400 EXPECT_TRUE(dc->rejected);
1401}
1402
1403// Create an audio and video offer with:
1404// - one video track
1405// - two audio tracks
1406// - two data tracks
1407// and ensure it matches what we expect. Also updates the initial offer by
1408// adding a new video track and replaces one of the audio tracks.
1409TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1410 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001411 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1412 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1413 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001414 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001415 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1416 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001417
1418 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001419 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420
1421 ASSERT_TRUE(offer.get() != NULL);
1422 const ContentInfo* ac = offer->GetContentByName("audio");
1423 const ContentInfo* vc = offer->GetContentByName("video");
1424 const ContentInfo* dc = offer->GetContentByName("data");
1425 ASSERT_TRUE(ac != NULL);
1426 ASSERT_TRUE(vc != NULL);
1427 ASSERT_TRUE(dc != NULL);
1428 const AudioContentDescription* acd =
1429 static_cast<const AudioContentDescription*>(ac->description);
1430 const VideoContentDescription* vcd =
1431 static_cast<const VideoContentDescription*>(vc->description);
1432 const DataContentDescription* dcd =
1433 static_cast<const DataContentDescription*>(dc->description);
1434 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001435 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436
1437 const StreamParamsVec& audio_streams = acd->streams();
1438 ASSERT_EQ(2U, audio_streams.size());
1439 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1440 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1441 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1442 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1443 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1444 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1445 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1446
1447 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1448 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1449 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1450
1451 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1452 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1453 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1454
1455 const StreamParamsVec& video_streams = vcd->streams();
1456 ASSERT_EQ(1U, video_streams.size());
1457 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1458 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1459 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1460 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1461
1462 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1463 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1464 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1465
1466 const StreamParamsVec& data_streams = dcd->streams();
1467 ASSERT_EQ(2U, data_streams.size());
1468 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1469 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1470 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1471 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1472 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1473 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1474 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1475
1476 EXPECT_EQ(cricket::kDataMaxBandwidth,
1477 dcd->bandwidth()); // default bandwidth (auto)
1478 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1479 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1480
1481
1482 // Update the offer. Add a new video track that is not synched to the
1483 // other tracks and replace audio track 2 with audio track 3.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001484 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1485 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1486 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1487 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1488 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
kwiberg31022942016-03-11 14:18:21 -08001489 std::unique_ptr<SessionDescription> updated_offer(
1490 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001491
1492 ASSERT_TRUE(updated_offer.get() != NULL);
1493 ac = updated_offer->GetContentByName("audio");
1494 vc = updated_offer->GetContentByName("video");
1495 dc = updated_offer->GetContentByName("data");
1496 ASSERT_TRUE(ac != NULL);
1497 ASSERT_TRUE(vc != NULL);
1498 ASSERT_TRUE(dc != NULL);
1499 const AudioContentDescription* updated_acd =
1500 static_cast<const AudioContentDescription*>(ac->description);
1501 const VideoContentDescription* updated_vcd =
1502 static_cast<const VideoContentDescription*>(vc->description);
1503 const DataContentDescription* updated_dcd =
1504 static_cast<const DataContentDescription*>(dc->description);
1505
1506 EXPECT_EQ(acd->type(), updated_acd->type());
1507 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1508 EXPECT_EQ(vcd->type(), updated_vcd->type());
1509 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1510 EXPECT_EQ(dcd->type(), updated_dcd->type());
1511 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1512 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1513 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1514 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1515 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1516 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1517 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1518
1519 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1520 ASSERT_EQ(2U, updated_audio_streams.size());
1521 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1522 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1523 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1524 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1525 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1526
1527 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1528 ASSERT_EQ(2U, updated_video_streams.size());
1529 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1530 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001531 // All the media streams in one PeerConnection share one RTCP CNAME.
1532 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001533
1534 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1535 ASSERT_EQ(2U, updated_data_streams.size());
1536 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1537 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1538 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1539 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1540 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001541 // The stream correctly got the CNAME from the MediaSessionOptions.
1542 // The Expected RTCP CNAME is the default one as we are using the default
1543 // MediaSessionOptions.
1544 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545}
1546
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001547// Create an offer with simulcast video stream.
1548TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1549 MediaSessionOptions opts;
1550 const int num_sim_layers = 3;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001551 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
kwiberg31022942016-03-11 14:18:21 -08001552 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001553
1554 ASSERT_TRUE(offer.get() != NULL);
1555 const ContentInfo* vc = offer->GetContentByName("video");
1556 ASSERT_TRUE(vc != NULL);
1557 const VideoContentDescription* vcd =
1558 static_cast<const VideoContentDescription*>(vc->description);
1559
1560 const StreamParamsVec& video_streams = vcd->streams();
1561 ASSERT_EQ(1U, video_streams.size());
1562 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1563 const SsrcGroup* sim_ssrc_group =
1564 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1565 ASSERT_TRUE(sim_ssrc_group != NULL);
1566 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1567}
1568
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001569// Create an audio and video answer to a standard video offer with:
1570// - one video track
1571// - two audio tracks
1572// - two data tracks
1573// and ensure it matches what we expect. Also updates the initial answer by
1574// adding a new video track and removes one of the audio tracks.
1575TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1576 MediaSessionOptions offer_opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001577 offer_opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 offer_opts.data_channel_type = cricket::DCT_RTP;
1579 f1_.set_secure(SEC_ENABLED);
1580 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001581 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582
1583 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001584 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1585 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1586 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001587 opts.data_channel_type = cricket::DCT_RTP;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001588 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1589 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001590
kwiberg31022942016-03-11 14:18:21 -08001591 std::unique_ptr<SessionDescription> answer(
1592 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593
1594 ASSERT_TRUE(answer.get() != NULL);
1595 const ContentInfo* ac = answer->GetContentByName("audio");
1596 const ContentInfo* vc = answer->GetContentByName("video");
1597 const ContentInfo* dc = answer->GetContentByName("data");
1598 ASSERT_TRUE(ac != NULL);
1599 ASSERT_TRUE(vc != NULL);
1600 ASSERT_TRUE(dc != NULL);
1601 const AudioContentDescription* acd =
1602 static_cast<const AudioContentDescription*>(ac->description);
1603 const VideoContentDescription* vcd =
1604 static_cast<const VideoContentDescription*>(vc->description);
1605 const DataContentDescription* dcd =
1606 static_cast<const DataContentDescription*>(dc->description);
1607 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1608 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1609 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1610
1611 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1612 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1613
1614 const StreamParamsVec& audio_streams = acd->streams();
1615 ASSERT_EQ(2U, audio_streams.size());
1616 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1617 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1618 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1619 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1620 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1621 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1622 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1623
1624 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1625 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1626
1627 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1628 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1629
1630 const StreamParamsVec& video_streams = vcd->streams();
1631 ASSERT_EQ(1U, video_streams.size());
1632 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1633 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1634 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1635 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1636
1637 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1638 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1639
1640 const StreamParamsVec& data_streams = dcd->streams();
1641 ASSERT_EQ(2U, data_streams.size());
1642 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1643 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1644 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1645 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1646 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1647 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1648 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1649
1650 EXPECT_EQ(cricket::kDataMaxBandwidth,
1651 dcd->bandwidth()); // default bandwidth (auto)
1652 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1653
1654 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001655 // other tracks and remove 1 audio track.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001656 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1657 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1658 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
kwiberg31022942016-03-11 14:18:21 -08001659 std::unique_ptr<SessionDescription> updated_answer(
1660 f2_.CreateAnswer(offer.get(), opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661
1662 ASSERT_TRUE(updated_answer.get() != NULL);
1663 ac = updated_answer->GetContentByName("audio");
1664 vc = updated_answer->GetContentByName("video");
1665 dc = updated_answer->GetContentByName("data");
1666 ASSERT_TRUE(ac != NULL);
1667 ASSERT_TRUE(vc != NULL);
1668 ASSERT_TRUE(dc != NULL);
1669 const AudioContentDescription* updated_acd =
1670 static_cast<const AudioContentDescription*>(ac->description);
1671 const VideoContentDescription* updated_vcd =
1672 static_cast<const VideoContentDescription*>(vc->description);
1673 const DataContentDescription* updated_dcd =
1674 static_cast<const DataContentDescription*>(dc->description);
1675
1676 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1677 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1678 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1679 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1680 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1681 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1682
1683 EXPECT_EQ(acd->type(), updated_acd->type());
1684 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1685 EXPECT_EQ(vcd->type(), updated_vcd->type());
1686 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1687 EXPECT_EQ(dcd->type(), updated_dcd->type());
1688 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1689
1690 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1691 ASSERT_EQ(1U, updated_audio_streams.size());
1692 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1693
1694 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1695 ASSERT_EQ(2U, updated_video_streams.size());
1696 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1697 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001698 // All media streams in one PeerConnection share one CNAME.
1699 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001700
1701 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1702 ASSERT_EQ(1U, updated_data_streams.size());
1703 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1704}
1705
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706// Create an updated offer after creating an answer to the original offer and
1707// verify that the codecs that were part of the original answer are not changed
1708// in the updated offer.
1709TEST_F(MediaSessionDescriptionFactoryTest,
1710 RespondentCreatesOfferAfterCreatingAnswer) {
1711 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001712 opts.recv_audio = true;
1713 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001714
kwiberg31022942016-03-11 14:18:21 -08001715 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1716 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717 f2_.CreateAnswer(offer.get(), opts, NULL));
1718
1719 const AudioContentDescription* acd =
1720 GetFirstAudioContentDescription(answer.get());
1721 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1722
1723 const VideoContentDescription* vcd =
1724 GetFirstVideoContentDescription(answer.get());
1725 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1726
kwiberg31022942016-03-11 14:18:21 -08001727 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001728 f2_.CreateOffer(opts, answer.get()));
1729
1730 // The expected audio codecs are the common audio codecs from the first
1731 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1732 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001733 // TODO(wu): |updated_offer| should not include the codec
1734 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001735 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001736 kAudioCodecsAnswer[0],
1737 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001738 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001739 };
1740
1741 // The expected video codecs are the common video codecs from the first
1742 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1743 // preference order.
1744 const VideoCodec kUpdatedVideoCodecOffer[] = {
1745 kVideoCodecsAnswer[0],
1746 kVideoCodecs2[1],
1747 };
1748
1749 const AudioContentDescription* updated_acd =
1750 GetFirstAudioContentDescription(updated_offer.get());
1751 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1752
1753 const VideoContentDescription* updated_vcd =
1754 GetFirstVideoContentDescription(updated_offer.get());
1755 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1756}
1757
1758// Create an updated offer after creating an answer to the original offer and
1759// verify that the codecs that were part of the original answer are not changed
1760// in the updated offer. In this test Rtx is enabled.
1761TEST_F(MediaSessionDescriptionFactoryTest,
1762 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1763 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001764 opts.recv_video = true;
1765 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001766 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001768 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001769 f1_.set_video_codecs(f1_codecs);
1770
1771 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001772 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001773 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 f2_.set_video_codecs(f2_codecs);
1775
kwiberg31022942016-03-11 14:18:21 -08001776 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001778 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001779 f2_.CreateAnswer(offer.get(), opts, NULL));
1780
1781 const VideoContentDescription* vcd =
1782 GetFirstVideoContentDescription(answer.get());
1783
1784 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001785 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1786 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787
1788 EXPECT_EQ(expected_codecs, vcd->codecs());
1789
deadbeef67cf2c12016-04-13 10:07:16 -07001790 // Now, make sure we get same result (except for the order) if |f2_| creates
1791 // an updated offer even though the default payload types between |f1_| and
1792 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08001793 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001794 f2_.CreateOffer(opts, answer.get()));
1795 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001796 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001797 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1798
1799 const VideoContentDescription* updated_vcd =
1800 GetFirstVideoContentDescription(updated_answer.get());
1801
1802 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1803}
1804
1805// Create an updated offer that adds video after creating an audio only answer
1806// to the original offer. This test verifies that if a video codec and the RTX
1807// codec have the same default payload type as an audio codec that is already in
1808// use, the added codecs payload types are changed.
1809TEST_F(MediaSessionDescriptionFactoryTest,
1810 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1811 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001812 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001813 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001814 f1_.set_video_codecs(f1_codecs);
1815
1816 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001817 opts.recv_audio = true;
1818 opts.recv_video = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001819
kwiberg31022942016-03-11 14:18:21 -08001820 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1821 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001822 f2_.CreateAnswer(offer.get(), opts, NULL));
1823
1824 const AudioContentDescription* acd =
1825 GetFirstAudioContentDescription(answer.get());
1826 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1827
1828 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1829 // reference be the same as an audio codec that was negotiated in the
1830 // first offer/answer exchange.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001831 opts.recv_audio = true;
1832 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001833
1834 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1835 int used_pl_type = acd->codecs()[0].id;
1836 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001837 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001838 f2_.set_video_codecs(f2_codecs);
1839
kwiberg31022942016-03-11 14:18:21 -08001840 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001841 f2_.CreateOffer(opts, answer.get()));
1842 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001843 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1845
1846 const AudioContentDescription* updated_acd =
1847 GetFirstAudioContentDescription(answer.get());
1848 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1849
1850 const VideoContentDescription* updated_vcd =
1851 GetFirstVideoContentDescription(updated_answer.get());
1852
1853 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001854 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001855 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1856 EXPECT_NE(used_pl_type, new_h264_pl_type);
1857 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001858 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001859 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1860 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1861}
1862
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001863// Create an updated offer with RTX after creating an answer to an offer
1864// without RTX, and with different default payload types.
1865// Verify that the added RTX codec references the correct payload type.
1866TEST_F(MediaSessionDescriptionFactoryTest,
1867 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
1868 MediaSessionOptions opts;
1869 opts.recv_video = true;
1870 opts.recv_audio = true;
1871
1872 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1873 // This creates rtx for H264 with the payload type |f2_| uses.
1874 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1875 f2_.set_video_codecs(f2_codecs);
1876
kwiberg31022942016-03-11 14:18:21 -08001877 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001878 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08001879 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001880 f2_.CreateAnswer(offer.get(), opts, nullptr));
1881
1882 const VideoContentDescription* vcd =
1883 GetFirstVideoContentDescription(answer.get());
1884
1885 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1886 EXPECT_EQ(expected_codecs, vcd->codecs());
1887
1888 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
1889 // updated offer, even though the default payload types are different from
1890 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08001891 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08001892 f2_.CreateOffer(opts, answer.get()));
1893 ASSERT_TRUE(updated_offer);
1894
1895 const VideoContentDescription* updated_vcd =
1896 GetFirstVideoContentDescription(updated_offer.get());
1897
1898 // New offer should attempt to add H263, and RTX for H264.
1899 expected_codecs.push_back(kVideoCodecs2[1]);
1900 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
1901 &expected_codecs);
1902 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1903}
1904
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001905// Test that RTX is ignored when there is no associated payload type parameter.
1906TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1907 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001908 opts.recv_video = true;
1909 opts.recv_audio = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001910 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001911 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07001912 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001913 f1_.set_video_codecs(f1_codecs);
1914
1915 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001916 // This creates RTX for H264 with the payload type |f2_| uses.
1917 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001918 f2_.set_video_codecs(f2_codecs);
1919
kwiberg31022942016-03-11 14:18:21 -08001920 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001921 ASSERT_TRUE(offer.get() != NULL);
1922 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1923 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1924 // is possible to test that that RTX is dropped when
1925 // kCodecParamAssociatedPayloadType is missing in the offer.
1926 VideoContentDescription* desc =
1927 static_cast<cricket::VideoContentDescription*>(
1928 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1929 ASSERT_TRUE(desc != NULL);
1930 std::vector<VideoCodec> codecs = desc->codecs();
1931 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1932 iter != codecs.end(); ++iter) {
1933 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1934 iter->params.clear();
1935 }
1936 }
1937 desc->set_codecs(codecs);
1938
kwiberg31022942016-03-11 14:18:21 -08001939 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940 f2_.CreateAnswer(offer.get(), opts, NULL));
1941
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001942 std::vector<std::string> codec_names =
1943 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1944 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1945 cricket::kRtxCodecName));
1946}
1947
1948// Test that RTX will be filtered out in the answer if its associated payload
1949// type doesn't match the local value.
1950TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1951 MediaSessionOptions opts;
1952 opts.recv_video = true;
1953 opts.recv_audio = false;
1954 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1955 // This creates RTX for H264 in sender.
1956 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1957 f1_.set_video_codecs(f1_codecs);
1958
1959 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1960 // This creates RTX for H263 in receiver.
1961 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1962 f2_.set_video_codecs(f2_codecs);
1963
kwiberg31022942016-03-11 14:18:21 -08001964 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001965 ASSERT_TRUE(offer.get() != NULL);
1966 // Associated payload type doesn't match, therefore, RTX codec is removed in
1967 // the answer.
kwiberg31022942016-03-11 14:18:21 -08001968 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001969 f2_.CreateAnswer(offer.get(), opts, NULL));
1970
1971 std::vector<std::string> codec_names =
1972 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1973 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1974 cricket::kRtxCodecName));
1975}
1976
1977// Test that when multiple RTX codecs are offered, only the matched RTX codec
1978// is added in the answer, and the unsupported RTX codec is filtered out.
1979TEST_F(MediaSessionDescriptionFactoryTest,
1980 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1981 MediaSessionOptions opts;
1982 opts.recv_video = true;
1983 opts.recv_audio = false;
1984 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1985 // This creates RTX for H264-SVC in sender.
1986 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1987 f1_.set_video_codecs(f1_codecs);
1988
1989 // This creates RTX for H264 in sender.
1990 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1991 f1_.set_video_codecs(f1_codecs);
1992
1993 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1994 // This creates RTX for H264 in receiver.
1995 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1996 f2_.set_video_codecs(f2_codecs);
1997
1998 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1999 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002000 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002001 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002002 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002003 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004 const VideoContentDescription* vcd =
2005 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002006 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2007 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2008 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002009
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002010 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011}
2012
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002013// Test that after one RTX codec has been negotiated, a new offer can attempt
2014// to add another.
2015TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2016 MediaSessionOptions opts;
2017 opts.recv_video = true;
2018 opts.recv_audio = false;
2019 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2020 // This creates RTX for H264 for the offerer.
2021 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2022 f1_.set_video_codecs(f1_codecs);
2023
kwiberg31022942016-03-11 14:18:21 -08002024 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002025 ASSERT_TRUE(offer);
2026 const VideoContentDescription* vcd =
2027 GetFirstVideoContentDescription(offer.get());
2028
2029 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2030 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2031 &expected_codecs);
2032 EXPECT_EQ(expected_codecs, vcd->codecs());
2033
2034 // Now, attempt to add RTX for H264-SVC.
2035 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2036 f1_.set_video_codecs(f1_codecs);
2037
kwiberg31022942016-03-11 14:18:21 -08002038 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002039 f1_.CreateOffer(opts, offer.get()));
2040 ASSERT_TRUE(updated_offer);
2041 vcd = GetFirstVideoContentDescription(updated_offer.get());
2042
2043 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2044 &expected_codecs);
2045 EXPECT_EQ(expected_codecs, vcd->codecs());
2046}
2047
Noah Richards2e7a0982015-05-18 14:02:54 -07002048// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2049// generated for each simulcast ssrc and correctly grouped.
2050TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2051 MediaSessionOptions opts;
2052 opts.recv_video = true;
2053 opts.recv_audio = false;
2054
2055 // Add simulcast streams.
2056 opts.AddSendVideoStream("stream1", "stream1label", 3);
2057
2058 // Use a single real codec, and then add RTX for it.
2059 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002060 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002061 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2062 f1_.set_video_codecs(f1_codecs);
2063
2064 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2065 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002066 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002067 ASSERT_TRUE(offer.get() != NULL);
2068 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2069 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2070 ASSERT_TRUE(desc != NULL);
2071 EXPECT_TRUE(desc->multistream());
2072 const StreamParamsVec& streams = desc->streams();
2073 // Single stream.
2074 ASSERT_EQ(1u, streams.size());
2075 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2076 EXPECT_EQ(6u, streams[0].ssrcs.size());
2077 // And should have a SIM group for the simulcast.
2078 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2079 // And a FID group for RTX.
2080 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002081 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002082 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2083 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002084 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002085 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2086 EXPECT_EQ(3u, fid_ssrcs.size());
2087}
2088
brandtr03d5fb12016-11-22 03:37:59 -08002089// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2090// together with a FEC-FR grouping.
2091TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2092 MediaSessionOptions opts;
2093 opts.recv_video = true;
2094 opts.recv_audio = false;
2095
2096 // Add single stream.
2097 opts.AddSendVideoStream("stream1", "stream1label", 1);
2098
2099 // Use a single real codec, and then add FlexFEC for it.
2100 std::vector<VideoCodec> f1_codecs;
2101 f1_codecs.push_back(VideoCodec(97, "H264"));
2102 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2103 f1_.set_video_codecs(f1_codecs);
2104
2105 // Ensure that the offer has a single FlexFEC ssrc and that
2106 // there is no FEC-FR ssrc + grouping for each.
2107 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2108 ASSERT_TRUE(offer.get() != nullptr);
2109 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2110 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2111 ASSERT_TRUE(desc != nullptr);
2112 EXPECT_TRUE(desc->multistream());
2113 const StreamParamsVec& streams = desc->streams();
2114 // Single stream.
2115 ASSERT_EQ(1u, streams.size());
2116 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2117 EXPECT_EQ(2u, streams[0].ssrcs.size());
2118 // And should have a FEC-FR group for FlexFEC.
2119 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2120 std::vector<uint32_t> primary_ssrcs;
2121 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2122 ASSERT_EQ(1u, primary_ssrcs.size());
2123 uint32_t flexfec_ssrc;
2124 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2125 EXPECT_NE(flexfec_ssrc, 0u);
2126}
2127
2128// Test that FlexFEC is disabled for simulcast.
2129// TODO(brandtr): Remove this test when we support simulcast, either through
2130// multiple FlexfecSenders, or through multistream protection.
2131TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2132 MediaSessionOptions opts;
2133 opts.recv_video = true;
2134 opts.recv_audio = false;
2135
2136 // Add simulcast streams.
2137 opts.AddSendVideoStream("stream1", "stream1label", 3);
2138
2139 // Use a single real codec, and then add FlexFEC for it.
2140 std::vector<VideoCodec> f1_codecs;
2141 f1_codecs.push_back(VideoCodec(97, "H264"));
2142 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2143 f1_.set_video_codecs(f1_codecs);
2144
2145 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2146 // there is no FEC-FR ssrc + grouping for each.
2147 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2148 ASSERT_TRUE(offer.get() != nullptr);
2149 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2150 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2151 ASSERT_TRUE(desc != nullptr);
2152 EXPECT_FALSE(desc->multistream());
2153 const StreamParamsVec& streams = desc->streams();
2154 // Single stream.
2155 ASSERT_EQ(1u, streams.size());
2156 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2157 EXPECT_EQ(3u, streams[0].ssrcs.size());
2158 // And should have a SIM group for the simulcast.
2159 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2160 // And not a FEC-FR group for FlexFEC.
2161 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2162 std::vector<uint32_t> primary_ssrcs;
2163 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2164 EXPECT_EQ(3u, primary_ssrcs.size());
2165 for (uint32_t primary_ssrc : primary_ssrcs) {
2166 uint32_t flexfec_ssrc;
2167 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2168 }
2169}
2170
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171// Create an updated offer after creating an answer to the original offer and
2172// verify that the RTP header extensions that were part of the original answer
2173// are not changed in the updated offer.
2174TEST_F(MediaSessionDescriptionFactoryTest,
2175 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2176 MediaSessionOptions opts;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002177 opts.recv_audio = true;
2178 opts.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179
2180 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2181 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2182 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2183 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2184
kwiberg31022942016-03-11 14:18:21 -08002185 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2186 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 f2_.CreateAnswer(offer.get(), opts, NULL));
2188
2189 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2190 GetFirstAudioContentDescription(
2191 answer.get())->rtp_header_extensions());
2192 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2193 GetFirstVideoContentDescription(
2194 answer.get())->rtp_header_extensions());
2195
kwiberg31022942016-03-11 14:18:21 -08002196 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197 f2_.CreateOffer(opts, answer.get()));
2198
2199 // The expected RTP header extensions in the new offer are the resulting
2200 // extensions from the first offer/answer exchange plus the extensions only
2201 // |f2_| offer.
2202 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002203 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002204 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2205 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2206 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002207 };
2208
2209 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002210 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002211 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2212 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2213 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 };
2215
2216 const AudioContentDescription* updated_acd =
2217 GetFirstAudioContentDescription(updated_offer.get());
2218 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2219 updated_acd->rtp_header_extensions());
2220
2221 const VideoContentDescription* updated_vcd =
2222 GetFirstVideoContentDescription(updated_offer.get());
2223 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2224 updated_vcd->rtp_header_extensions());
2225}
2226
deadbeefa5b273a2015-08-20 17:30:13 -07002227// Verify that if the same RTP extension URI is used for audio and video, the
2228// same ID is used. Also verify that the ID isn't changed when creating an
2229// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002230TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002231 MediaSessionOptions opts;
2232 opts.recv_audio = true;
2233 opts.recv_video = true;
2234
2235 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2236 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2237
kwiberg31022942016-03-11 14:18:21 -08002238 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002239
2240 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2241 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002242 const RtpExtension kExpectedVideoRtpExtension[] = {
2243 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002244 };
2245
2246 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2247 GetFirstAudioContentDescription(
2248 offer.get())->rtp_header_extensions());
2249 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2250 GetFirstVideoContentDescription(
2251 offer.get())->rtp_header_extensions());
2252
2253 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002254 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002255 f1_.CreateOffer(opts, offer.get()));
2256
2257 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2258 GetFirstAudioContentDescription(
2259 updated_offer.get())->rtp_header_extensions());
2260 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2261 GetFirstVideoContentDescription(
2262 updated_offer.get())->rtp_header_extensions());
2263}
2264
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265TEST(MediaSessionDescription, CopySessionDescription) {
2266 SessionDescription source;
2267 cricket::ContentGroup group(cricket::CN_AUDIO);
2268 source.AddGroup(group);
2269 AudioContentDescription* acd(new AudioContentDescription());
2270 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2271 acd->AddLegacyStream(1);
2272 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2273 VideoContentDescription* vcd(new VideoContentDescription());
2274 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2275 vcd->AddLegacyStream(2);
2276 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2277
kwiberg31022942016-03-11 14:18:21 -08002278 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002279 ASSERT_TRUE(copy.get() != NULL);
2280 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2281 const ContentInfo* ac = copy->GetContentByName("audio");
2282 const ContentInfo* vc = copy->GetContentByName("video");
2283 ASSERT_TRUE(ac != NULL);
2284 ASSERT_TRUE(vc != NULL);
2285 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2286 const AudioContentDescription* acd_copy =
2287 static_cast<const AudioContentDescription*>(ac->description);
2288 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2289 EXPECT_EQ(1u, acd->first_ssrc());
2290
2291 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2292 const VideoContentDescription* vcd_copy =
2293 static_cast<const VideoContentDescription*>(vc->description);
2294 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2295 EXPECT_EQ(2u, vcd->first_ssrc());
2296}
2297
2298// The below TestTransportInfoXXX tests create different offers/answers, and
2299// ensure the TransportInfo in the SessionDescription matches what we expect.
2300TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2301 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002302 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002303 TestTransportInfo(true, options, false);
2304}
2305
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002306TEST_F(MediaSessionDescriptionFactoryTest,
2307 TestTransportInfoOfferIceRenomination) {
2308 MediaSessionOptions options;
2309 options.enable_ice_renomination = true;
2310 TestTransportInfo(true, options, false);
2311}
2312
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002313TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2314 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002315 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002316 TestTransportInfo(true, options, true);
2317}
2318
2319TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2320 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002321 options.recv_audio = true;
2322 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002323 options.data_channel_type = cricket::DCT_RTP;
2324 TestTransportInfo(true, options, false);
2325}
2326
2327TEST_F(MediaSessionDescriptionFactoryTest,
2328 TestTransportInfoOfferMultimediaCurrent) {
2329 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002330 options.recv_audio = true;
2331 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002332 options.data_channel_type = cricket::DCT_RTP;
2333 TestTransportInfo(true, options, true);
2334}
2335
2336TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2337 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002338 options.recv_audio = true;
2339 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340 options.data_channel_type = cricket::DCT_RTP;
2341 options.bundle_enabled = true;
2342 TestTransportInfo(true, options, false);
2343}
2344
2345TEST_F(MediaSessionDescriptionFactoryTest,
2346 TestTransportInfoOfferBundleCurrent) {
2347 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002348 options.recv_audio = true;
2349 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002350 options.data_channel_type = cricket::DCT_RTP;
2351 options.bundle_enabled = true;
2352 TestTransportInfo(true, options, true);
2353}
2354
2355TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2356 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002357 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002358 TestTransportInfo(false, options, false);
2359}
2360
2361TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002362 TestTransportInfoAnswerIceRenomination) {
2363 MediaSessionOptions options;
2364 options.enable_ice_renomination = true;
2365 TestTransportInfo(false, options, false);
2366}
2367
2368TEST_F(MediaSessionDescriptionFactoryTest,
2369 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002371 options.recv_audio = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002372 TestTransportInfo(false, options, true);
2373}
2374
2375TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2376 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002377 options.recv_audio = true;
2378 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002379 options.data_channel_type = cricket::DCT_RTP;
2380 TestTransportInfo(false, options, false);
2381}
2382
2383TEST_F(MediaSessionDescriptionFactoryTest,
2384 TestTransportInfoAnswerMultimediaCurrent) {
2385 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002386 options.recv_audio = true;
2387 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002388 options.data_channel_type = cricket::DCT_RTP;
2389 TestTransportInfo(false, options, true);
2390}
2391
2392TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2393 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002394 options.recv_audio = true;
2395 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002396 options.data_channel_type = cricket::DCT_RTP;
2397 options.bundle_enabled = true;
2398 TestTransportInfo(false, options, false);
2399}
2400
2401TEST_F(MediaSessionDescriptionFactoryTest,
2402 TestTransportInfoAnswerBundleCurrent) {
2403 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002404 options.recv_audio = true;
2405 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002406 options.data_channel_type = cricket::DCT_RTP;
2407 options.bundle_enabled = true;
2408 TestTransportInfo(false, options, true);
2409}
2410
2411// Create an offer with bundle enabled and verify the crypto parameters are
2412// the common set of the available cryptos.
2413TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2414 TestCryptoWithBundle(true);
2415}
2416
2417// Create an answer with bundle enabled and verify the crypto parameters are
2418// the common set of the available cryptos.
2419TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2420 TestCryptoWithBundle(false);
2421}
2422
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002423// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2424// DTLS is not enabled locally.
2425TEST_F(MediaSessionDescriptionFactoryTest,
2426 TestOfferDtlsSavpfWithoutDtlsFailed) {
2427 f1_.set_secure(SEC_ENABLED);
2428 f2_.set_secure(SEC_ENABLED);
2429 tdf1_.set_secure(SEC_DISABLED);
2430 tdf2_.set_secure(SEC_DISABLED);
2431
kwiberg31022942016-03-11 14:18:21 -08002432 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002433 f1_.CreateOffer(MediaSessionOptions(), NULL));
2434 ASSERT_TRUE(offer.get() != NULL);
2435 ContentInfo* offer_content = offer->GetContentByName("audio");
2436 ASSERT_TRUE(offer_content != NULL);
2437 AudioContentDescription* offer_audio_desc =
2438 static_cast<AudioContentDescription*>(offer_content->description);
2439 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2440
kwiberg31022942016-03-11 14:18:21 -08002441 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002442 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2443 ASSERT_TRUE(answer != NULL);
2444 ContentInfo* answer_content = answer->GetContentByName("audio");
2445 ASSERT_TRUE(answer_content != NULL);
2446
2447 ASSERT_TRUE(answer_content->rejected);
2448}
2449
2450// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2451// UDP/TLS/RTP/SAVPF.
2452TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2453 f1_.set_secure(SEC_ENABLED);
2454 f2_.set_secure(SEC_ENABLED);
2455 tdf1_.set_secure(SEC_ENABLED);
2456 tdf2_.set_secure(SEC_ENABLED);
2457
kwiberg31022942016-03-11 14:18:21 -08002458 std::unique_ptr<SessionDescription> offer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002459 f1_.CreateOffer(MediaSessionOptions(), NULL));
2460 ASSERT_TRUE(offer.get() != NULL);
2461 ContentInfo* offer_content = offer->GetContentByName("audio");
2462 ASSERT_TRUE(offer_content != NULL);
2463 AudioContentDescription* offer_audio_desc =
2464 static_cast<AudioContentDescription*>(offer_content->description);
2465 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2466
kwiberg31022942016-03-11 14:18:21 -08002467 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002468 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2469 ASSERT_TRUE(answer != NULL);
2470
2471 const ContentInfo* answer_content = answer->GetContentByName("audio");
2472 ASSERT_TRUE(answer_content != NULL);
2473 ASSERT_FALSE(answer_content->rejected);
2474
2475 const AudioContentDescription* answer_audio_desc =
2476 static_cast<const AudioContentDescription*>(answer_content->description);
2477 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2478 answer_audio_desc->protocol());
2479}
2480
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002481// Test that we include both SDES and DTLS in the offer, but only include SDES
2482// in the answer if DTLS isn't negotiated.
2483TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2484 f1_.set_secure(SEC_ENABLED);
2485 f2_.set_secure(SEC_ENABLED);
2486 tdf1_.set_secure(SEC_ENABLED);
2487 tdf2_.set_secure(SEC_DISABLED);
2488 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002489 options.recv_audio = true;
2490 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002491 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492 const cricket::MediaContentDescription* audio_media_desc;
2493 const cricket::MediaContentDescription* video_media_desc;
2494 const cricket::TransportDescription* audio_trans_desc;
2495 const cricket::TransportDescription* video_trans_desc;
2496
2497 // Generate an offer with SDES and DTLS support.
2498 offer.reset(f1_.CreateOffer(options, NULL));
2499 ASSERT_TRUE(offer.get() != NULL);
2500
2501 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2502 offer->GetContentDescriptionByName("audio"));
2503 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002504 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002505 offer->GetContentDescriptionByName("video"));
2506 ASSERT_TRUE(video_media_desc != NULL);
2507 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2508 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2509
2510 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2511 ASSERT_TRUE(audio_trans_desc != NULL);
2512 video_trans_desc = offer->GetTransportDescriptionByName("video");
2513 ASSERT_TRUE(video_trans_desc != NULL);
2514 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2515 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2516
2517 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2518 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2519 ASSERT_TRUE(answer.get() != NULL);
2520
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002521 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002522 answer->GetContentDescriptionByName("audio"));
2523 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002524 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525 answer->GetContentDescriptionByName("video"));
2526 ASSERT_TRUE(video_media_desc != NULL);
2527 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2528 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2529
2530 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2531 ASSERT_TRUE(audio_trans_desc != NULL);
2532 video_trans_desc = answer->GetTransportDescriptionByName("video");
2533 ASSERT_TRUE(video_trans_desc != NULL);
2534 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2535 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2536
2537 // Enable DTLS; the answer should now only have DTLS support.
2538 tdf2_.set_secure(SEC_ENABLED);
2539 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2540 ASSERT_TRUE(answer.get() != NULL);
2541
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002542 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002543 answer->GetContentDescriptionByName("audio"));
2544 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002545 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002546 answer->GetContentDescriptionByName("video"));
2547 ASSERT_TRUE(video_media_desc != NULL);
2548 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2549 EXPECT_TRUE(video_media_desc->cryptos().empty());
2550 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2551 audio_media_desc->protocol());
2552 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2553 video_media_desc->protocol());
2554
2555 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2556 ASSERT_TRUE(audio_trans_desc != NULL);
2557 video_trans_desc = answer->GetTransportDescriptionByName("video");
2558 ASSERT_TRUE(video_trans_desc != NULL);
2559 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2560 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002561
2562 // Try creating offer again. DTLS enabled now, crypto's should be empty
2563 // in new offer.
2564 offer.reset(f1_.CreateOffer(options, offer.get()));
2565 ASSERT_TRUE(offer.get() != NULL);
2566 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2567 offer->GetContentDescriptionByName("audio"));
2568 ASSERT_TRUE(audio_media_desc != NULL);
2569 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2570 offer->GetContentDescriptionByName("video"));
2571 ASSERT_TRUE(video_media_desc != NULL);
2572 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2573 EXPECT_TRUE(video_media_desc->cryptos().empty());
2574
2575 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2576 ASSERT_TRUE(audio_trans_desc != NULL);
2577 video_trans_desc = offer->GetTransportDescriptionByName("video");
2578 ASSERT_TRUE(video_trans_desc != NULL);
2579 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2580 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002581}
2582
2583// Test that an answer can't be created if cryptos are required but the offer is
2584// unsecure.
2585TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2586 MediaSessionOptions options;
2587 f1_.set_secure(SEC_DISABLED);
2588 tdf1_.set_secure(SEC_DISABLED);
2589 f2_.set_secure(SEC_REQUIRED);
2590 tdf1_.set_secure(SEC_ENABLED);
2591
kwiberg31022942016-03-11 14:18:21 -08002592 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002593 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002594 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002595 f2_.CreateAnswer(offer.get(), options, NULL));
2596 EXPECT_TRUE(answer.get() == NULL);
2597}
2598
2599// Test that we accept a DTLS offer without SDES and create an appropriate
2600// answer.
2601TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2602 f1_.set_secure(SEC_DISABLED);
2603 f2_.set_secure(SEC_ENABLED);
2604 tdf1_.set_secure(SEC_ENABLED);
2605 tdf2_.set_secure(SEC_ENABLED);
2606 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002607 options.recv_audio = true;
2608 options.recv_video = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002609 options.data_channel_type = cricket::DCT_RTP;
2610
kwiberg31022942016-03-11 14:18:21 -08002611 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002612
2613 // Generate an offer with DTLS but without SDES.
2614 offer.reset(f1_.CreateOffer(options, NULL));
2615 ASSERT_TRUE(offer.get() != NULL);
2616
2617 const AudioContentDescription* audio_offer =
2618 GetFirstAudioContentDescription(offer.get());
2619 ASSERT_TRUE(audio_offer->cryptos().empty());
2620 const VideoContentDescription* video_offer =
2621 GetFirstVideoContentDescription(offer.get());
2622 ASSERT_TRUE(video_offer->cryptos().empty());
2623 const DataContentDescription* data_offer =
2624 GetFirstDataContentDescription(offer.get());
2625 ASSERT_TRUE(data_offer->cryptos().empty());
2626
2627 const cricket::TransportDescription* audio_offer_trans_desc =
2628 offer->GetTransportDescriptionByName("audio");
2629 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2630 const cricket::TransportDescription* video_offer_trans_desc =
2631 offer->GetTransportDescriptionByName("video");
2632 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2633 const cricket::TransportDescription* data_offer_trans_desc =
2634 offer->GetTransportDescriptionByName("data");
2635 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2636
2637 // Generate an answer with DTLS.
2638 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2639 ASSERT_TRUE(answer.get() != NULL);
2640
2641 const cricket::TransportDescription* audio_answer_trans_desc =
2642 answer->GetTransportDescriptionByName("audio");
2643 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2644 const cricket::TransportDescription* video_answer_trans_desc =
2645 answer->GetTransportDescriptionByName("video");
2646 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2647 const cricket::TransportDescription* data_answer_trans_desc =
2648 answer->GetTransportDescriptionByName("data");
2649 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2650}
2651
2652// Verifies if vad_enabled option is set to false, CN codecs are not present in
2653// offer or answer.
2654TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2655 MediaSessionOptions options;
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002656 options.recv_audio = true;
2657 options.recv_video = true;
kwiberg31022942016-03-11 14:18:21 -08002658 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659 ASSERT_TRUE(offer.get() != NULL);
2660 const ContentInfo* audio_content = offer->GetContentByName("audio");
2661 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2662
2663 options.vad_enabled = false;
2664 offer.reset(f1_.CreateOffer(options, NULL));
2665 ASSERT_TRUE(offer.get() != NULL);
2666 audio_content = offer->GetContentByName("audio");
2667 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002668 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002669 f1_.CreateAnswer(offer.get(), options, NULL));
2670 ASSERT_TRUE(answer.get() != NULL);
2671 audio_content = answer->GetContentByName("audio");
2672 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2673}
deadbeef44f08192015-12-15 16:20:09 -08002674
2675// Test that the content name ("mid" in SDP) is unchanged when creating a
2676// new offer.
2677TEST_F(MediaSessionDescriptionFactoryTest,
2678 TestContentNameNotChangedInSubsequentOffers) {
2679 MediaSessionOptions opts;
2680 opts.recv_audio = true;
2681 opts.recv_video = true;
2682 opts.data_channel_type = cricket::DCT_SCTP;
2683 // Create offer and modify the default content names.
kwiberg31022942016-03-11 14:18:21 -08002684 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
deadbeef44f08192015-12-15 16:20:09 -08002685 for (ContentInfo& content : offer->contents()) {
2686 content.name.append("_modified");
2687 }
2688
kwiberg31022942016-03-11 14:18:21 -08002689 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002690 f1_.CreateOffer(opts, offer.get()));
2691 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2692 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2693 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2694 ASSERT_TRUE(audio_content != nullptr);
2695 ASSERT_TRUE(video_content != nullptr);
2696 ASSERT_TRUE(data_content != nullptr);
2697 EXPECT_EQ("audio_modified", audio_content->name);
2698 EXPECT_EQ("video_modified", video_content->name);
2699 EXPECT_EQ("data_modified", data_content->name);
2700}
zhihuangcf5b37c2016-05-05 11:44:35 -07002701
2702class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
2703 public:
2704 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07002705 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
2706 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07002707 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
2708 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07002709 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
2710 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07002711 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
2712 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
2713 f1_.set_secure(SEC_ENABLED);
2714 f2_.set_secure(SEC_ENABLED);
2715 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002716 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002717 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07002718 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07002719 tdf1_.set_secure(SEC_ENABLED);
2720 tdf2_.set_secure(SEC_ENABLED);
2721 }
2722
2723 protected:
2724 MediaSessionDescriptionFactory f1_;
2725 MediaSessionDescriptionFactory f2_;
2726 TransportDescriptionFactory tdf1_;
2727 TransportDescriptionFactory tdf2_;
2728};
2729
2730TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
2731 MediaSessionOptions opts;
2732 opts.recv_video = true;
2733 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2734 ASSERT_TRUE(offer.get() != nullptr);
2735 // Set the protocol for all the contents.
2736 for (auto content : offer.get()->contents()) {
2737 static_cast<MediaContentDescription*>(content.description)
2738 ->set_protocol(GetParam());
2739 }
2740 std::unique_ptr<SessionDescription> answer(
2741 f2_.CreateAnswer(offer.get(), opts, nullptr));
2742 const ContentInfo* ac = answer->GetContentByName("audio");
2743 const ContentInfo* vc = answer->GetContentByName("video");
2744 ASSERT_TRUE(ac != nullptr);
2745 ASSERT_TRUE(vc != nullptr);
2746 EXPECT_FALSE(ac->rejected); // the offer is accepted
2747 EXPECT_FALSE(vc->rejected);
2748 const AudioContentDescription* acd =
2749 static_cast<const AudioContentDescription*>(ac->description);
2750 const VideoContentDescription* vcd =
2751 static_cast<const VideoContentDescription*>(vc->description);
2752 EXPECT_EQ(GetParam(), acd->protocol());
2753 EXPECT_EQ(GetParam(), vcd->protocol());
2754}
2755
2756INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
2757 MediaProtocolTest,
2758 ::testing::ValuesIn(kMediaProtocols));
2759INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
2760 MediaProtocolTest,
2761 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07002762
2763TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
2764 TransportDescriptionFactory tdf;
2765 MediaSessionDescriptionFactory sf(&tdf);
2766 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2767 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2768
2769 // The merged list of codecs should contain any send codecs that are also
2770 // nominally in the recieve codecs list. Payload types should be picked from
2771 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
2772 // (set to 1). This equals what happens when the send codecs are used in an
2773 // offer and the receive codecs are used in the following answer.
2774 const std::vector<AudioCodec> sendrecv_codecs =
2775 MAKE_VECTOR(kAudioCodecsAnswer);
2776 const std::vector<AudioCodec> no_codecs;
2777
2778 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
2779 << "Please don't change shared test data!";
2780 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
2781 << "Please don't change shared test data!";
2782 // Alter iLBC send codec to have zero channels, to test that that is handled
2783 // properly.
2784 send_codecs[1].channels = 0;
2785
2786 // Alther iLBC receive codec to be lowercase, to test that case conversions
2787 // are handled properly.
2788 recv_codecs[2].name = "ilbc";
2789
2790 // Test proper merge
2791 sf.set_audio_codecs(send_codecs, recv_codecs);
2792 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2793 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002794 EXPECT_TRUE(sf.audio_sendrecv_codecs() == sendrecv_codecs);
ossu075af922016-06-14 03:29:38 -07002795
2796 // Test empty send codecs list
2797 sf.set_audio_codecs(no_codecs, recv_codecs);
2798 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2799 EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
ossudedfd282016-06-14 07:12:39 -07002800 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002801
2802 // Test empty recv codecs list
2803 sf.set_audio_codecs(send_codecs, no_codecs);
2804 EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
2805 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002806 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002807
2808 // Test all empty codec lists
2809 sf.set_audio_codecs(no_codecs, no_codecs);
2810 EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
2811 EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
ossudedfd282016-06-14 07:12:39 -07002812 EXPECT_TRUE(sf.audio_sendrecv_codecs() == no_codecs);
ossu075af922016-06-14 03:29:38 -07002813}
2814
2815namespace {
2816void TestAudioCodecsOffer(MediaContentDirection direction,
2817 bool add_legacy_stream) {
2818 TransportDescriptionFactory tdf;
2819 MediaSessionDescriptionFactory sf(&tdf);
2820 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
2821 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
2822 const std::vector<AudioCodec> sendrecv_codecs =
2823 MAKE_VECTOR(kAudioCodecsAnswer);
2824 sf.set_audio_codecs(send_codecs, recv_codecs);
2825 sf.set_add_legacy_streams(add_legacy_stream);
2826
2827 MediaSessionOptions opts;
2828 opts.recv_audio = (direction == cricket::MD_RECVONLY ||
2829 direction == cricket::MD_SENDRECV);
2830 opts.recv_video = false;
2831 if (direction == cricket::MD_SENDONLY || direction == cricket::MD_SENDRECV)
2832 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2833
2834 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
2835 ASSERT_TRUE(offer.get() != NULL);
2836 const ContentInfo* ac = offer->GetContentByName("audio");
2837
2838 // If the factory didn't add any audio content to the offer, we cannot check
2839 // that the codecs put in are right. This happens when we neither want to send
2840 // nor receive audio. The checks are still in place if at some point we'd
2841 // instead create an inactive stream.
2842 if (ac) {
2843 AudioContentDescription* acd =
2844 static_cast<AudioContentDescription*>(ac->description);
2845 // sendrecv and inactive should both present lists as if the channel was to
2846 // be used for sending and receiving. Inactive essentially means it might
2847 // eventually be used anything, but we don't know more at this moment.
2848 if (acd->direction() == cricket::MD_SENDONLY) {
2849 EXPECT_TRUE(acd->codecs() == send_codecs);
2850 } else if (acd->direction() == cricket::MD_RECVONLY) {
2851 EXPECT_TRUE(acd->codecs() == recv_codecs);
2852 } else {
2853 EXPECT_TRUE(acd->codecs() == sendrecv_codecs);
2854 }
2855 }
2856}
2857
2858static const AudioCodec kOfferAnswerCodecs[] = {
2859 AudioCodec(0, "codec0", 16000, -1, 1),
2860 AudioCodec(1, "codec1", 8000, 13300, 1),
2861 AudioCodec(2, "codec2", 8000, 64000, 1),
2862 AudioCodec(3, "codec3", 8000, 64000, 1),
2863 AudioCodec(4, "codec4", 8000, 0, 2),
2864 AudioCodec(5, "codec5", 32000, 0, 1),
2865 AudioCodec(6, "codec6", 48000, 0, 1)
2866};
2867
2868
2869/* The codecs groups below are chosen as per the matrix below. The objective is
2870 * to have different sets of codecs in the inputs, to get unique sets of codecs
2871 * after negotiation, depending on offer and answer communication directions.
2872 * One-way directions in the offer should either result in the opposite
2873 * direction in the answer, or an inactive answer. Regardless, the choice of
2874 * codecs should be as if the answer contained the opposite direction.
2875 * Inactive offers should be treated as sendrecv/sendrecv.
2876 *
2877 * | Offer | Answer | Result
2878 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
2879 * 0 | x - - | - x - | x - - - -
2880 * 1 | x x x | - x - | x - - x -
2881 * 2 | - x - | x - - | - x - - -
2882 * 3 | x x x | x - - | - x x - -
2883 * 4 | - x - | x x x | - x - - -
2884 * 5 | x - - | x x x | x - - - -
2885 * 6 | x x x | x x x | x x x x x
2886 */
2887// Codecs used by offerer in the AudioCodecsAnswerTest
2888static const int kOfferSendCodecs[] = { 0, 1, 3, 5, 6 };
2889static const int kOfferRecvCodecs[] = { 1, 2, 3, 4, 6 };
2890// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
2891// jumbled to catch the answer not following the order in the offer.
2892static const int kAnswerSendCodecs[] = { 6, 5, 2, 3, 4 };
2893static const int kAnswerRecvCodecs[] = { 6, 5, 4, 1, 0 };
2894// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
2895static const int kResultSend_RecvCodecs[] = { 0, 1, 5, 6 };
2896static const int kResultRecv_SendCodecs[] = { 2, 3, 4, 6 };
2897static const int kResultSendrecv_SendCodecs[] = { 3, 6 };
2898static const int kResultSendrecv_RecvCodecs[] = { 1, 6 };
2899static const int kResultSendrecv_SendrecvCodecs[] = { 6 };
2900
2901template <typename T, int IDXS>
2902std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
2903 std::vector<T> out;
2904 out.reserve(IDXS);
2905 for (int idx : indices)
2906 out.push_back(array[idx]);
2907
2908 return out;
2909}
2910
2911void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
2912 MediaContentDirection answer_direction,
2913 bool add_legacy_stream) {
2914 TransportDescriptionFactory offer_tdf;
2915 TransportDescriptionFactory answer_tdf;
2916 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
2917 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
2918 offer_factory.set_audio_codecs(
2919 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
2920 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
2921 answer_factory.set_audio_codecs(
2922 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
2923 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
2924
2925 // Never add a legacy stream to offer - we want to control the offer
2926 // parameters exactly.
2927 offer_factory.set_add_legacy_streams(false);
2928 answer_factory.set_add_legacy_streams(add_legacy_stream);
2929 MediaSessionOptions offer_opts;
2930 offer_opts.recv_audio = (offer_direction == cricket::MD_RECVONLY ||
2931 offer_direction == cricket::MD_SENDRECV);
2932 offer_opts.recv_video = false;
2933 if (offer_direction == cricket::MD_SENDONLY ||
2934 offer_direction == cricket::MD_SENDRECV) {
2935 offer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2936 }
2937
2938 std::unique_ptr<SessionDescription> offer(
2939 offer_factory.CreateOffer(offer_opts, NULL));
2940 ASSERT_TRUE(offer.get() != NULL);
2941
2942 MediaSessionOptions answer_opts;
2943 answer_opts.recv_audio = (answer_direction == cricket::MD_RECVONLY ||
2944 answer_direction == cricket::MD_SENDRECV);
2945 answer_opts.recv_video = false;
2946 if (answer_direction == cricket::MD_SENDONLY ||
2947 answer_direction == cricket::MD_SENDRECV) {
2948 answer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
2949 }
2950 std::unique_ptr<SessionDescription> answer(
2951 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
2952 const ContentInfo* ac = answer->GetContentByName("audio");
2953
2954 // If the factory didn't add any audio content to the answer, we cannot check
2955 // that the codecs put in are right. This happens when we neither want to send
2956 // nor receive audio. The checks are still in place if at some point we'd
2957 // instead create an inactive stream.
2958 if (ac) {
2959 const AudioContentDescription* acd =
2960 static_cast<const AudioContentDescription*>(ac->description);
2961 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2962
2963
2964 std::vector<AudioCodec> target_codecs;
2965 // For offers with sendrecv or inactive, we should never reply with more
2966 // codecs than offered, with these codec sets.
2967 switch (offer_direction) {
2968 case cricket::MD_INACTIVE:
2969 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2970 kResultSendrecv_SendrecvCodecs);
2971 break;
2972 case cricket::MD_SENDONLY:
2973 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2974 kResultSend_RecvCodecs);
2975 break;
2976 case cricket::MD_RECVONLY:
2977 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2978 kResultRecv_SendCodecs);
2979 break;
2980 case cricket::MD_SENDRECV:
2981 if (acd->direction() == cricket::MD_SENDONLY) {
2982 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2983 kResultSendrecv_SendCodecs);
2984 } else if (acd->direction() == cricket::MD_RECVONLY) {
2985 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2986 kResultSendrecv_RecvCodecs);
2987 } else {
2988 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
2989 kResultSendrecv_SendrecvCodecs);
2990 }
2991 break;
2992 }
2993
2994 auto format_codecs = [] (const std::vector<AudioCodec>& codecs) {
2995 std::stringstream os;
2996 bool first = true;
2997 os << "{";
2998 for (const auto& c : codecs) {
2999 os << (first ? " " : ", ") << c.id;
3000 first = false;
3001 }
3002 os << " }";
3003 return os.str();
3004 };
3005
3006 EXPECT_TRUE(acd->codecs() == target_codecs)
3007 << "Expected: " << format_codecs(target_codecs)
3008 << ", got: " << format_codecs(acd->codecs())
3009 << "; Offered: " << MediaContentDirectionToString(offer_direction)
3010 << ", answerer wants: "
3011 << MediaContentDirectionToString(answer_direction)
3012 << "; got: " << MediaContentDirectionToString(acd->direction());
3013 } else {
3014 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
3015 << "Only inactive offers are allowed to not generate any audio content";
3016 }
3017}
brandtr03d5fb12016-11-22 03:37:59 -08003018
3019} // namespace
ossu075af922016-06-14 03:29:38 -07003020
3021class AudioCodecsOfferTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003022 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3023 bool>> {
ossu075af922016-06-14 03:29:38 -07003024};
3025
3026TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003027 TestAudioCodecsOffer(::testing::get<0>(GetParam()),
3028 ::testing::get<1>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003029}
3030
3031INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3032 AudioCodecsOfferTest,
3033 ::testing::Combine(
3034 ::testing::Values(cricket::MD_SENDONLY,
3035 cricket::MD_RECVONLY,
3036 cricket::MD_SENDRECV,
3037 cricket::MD_INACTIVE),
3038 ::testing::Bool()));
3039
3040class AudioCodecsAnswerTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003041 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3042 MediaContentDirection,
3043 bool>> {
ossu075af922016-06-14 03:29:38 -07003044};
3045
3046TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003047 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3048 ::testing::get<1>(GetParam()),
3049 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003050}
3051
3052INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3053 AudioCodecsAnswerTest,
3054 ::testing::Combine(
3055 ::testing::Values(cricket::MD_SENDONLY,
3056 cricket::MD_RECVONLY,
3057 cricket::MD_SENDRECV,
3058 cricket::MD_INACTIVE),
3059 ::testing::Values(cricket::MD_SENDONLY,
3060 cricket::MD_RECVONLY,
3061 cricket::MD_SENDRECV,
3062 cricket::MD_INACTIVE),
3063 ::testing::Bool()));