blob: b76cce48cf40192e7e41d5e6ea612f74f1039c99 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <string>
29#include <vector>
30
31#include "talk/base/gunit.h"
32#include "talk/base/fakesslidentity.h"
33#include "talk/base/messagedigest.h"
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +000034#include "talk/base/ssladapter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035#include "talk/media/base/codec.h"
36#include "talk/media/base/testutils.h"
37#include "talk/p2p/base/constants.h"
38#include "talk/p2p/base/transportdescription.h"
39#include "talk/p2p/base/transportinfo.h"
40#include "talk/session/media/mediasession.h"
41#include "talk/session/media/srtpfilter.h"
42
43#ifdef HAVE_SRTP
44#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000045 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046 ASSERT_EQ(s, cd->cryptos().size()); \
47 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
48#else
49#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000050 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051 ASSERT_EQ(0U, cd->cryptos().size());
52#endif
53
54typedef std::vector<cricket::Candidate> Candidates;
55
56using cricket::MediaContentDescription;
57using cricket::MediaSessionDescriptionFactory;
58using cricket::MediaSessionOptions;
59using cricket::MediaType;
60using cricket::SessionDescription;
61using cricket::SsrcGroup;
62using cricket::StreamParams;
63using cricket::StreamParamsVec;
64using cricket::TransportDescription;
65using cricket::TransportDescriptionFactory;
66using cricket::TransportInfo;
67using cricket::ContentInfo;
68using cricket::CryptoParamsVec;
69using cricket::AudioContentDescription;
70using cricket::VideoContentDescription;
71using cricket::DataContentDescription;
72using cricket::GetFirstAudioContentDescription;
73using cricket::GetFirstVideoContentDescription;
74using cricket::GetFirstDataContentDescription;
75using cricket::kAutoBandwidth;
76using cricket::AudioCodec;
77using cricket::VideoCodec;
78using cricket::DataCodec;
79using cricket::NS_JINGLE_RTP;
80using cricket::MEDIA_TYPE_AUDIO;
81using cricket::MEDIA_TYPE_VIDEO;
82using cricket::MEDIA_TYPE_DATA;
83using cricket::RtpHeaderExtension;
84using cricket::SEC_DISABLED;
85using cricket::SEC_ENABLED;
86using cricket::SEC_REQUIRED;
87using cricket::CS_AES_CM_128_HMAC_SHA1_32;
88using cricket::CS_AES_CM_128_HMAC_SHA1_80;
89
90static const AudioCodec kAudioCodecs1[] = {
91 AudioCodec(103, "ISAC", 16000, -1, 1, 6),
92 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
93 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
94 AudioCodec(8, "PCMA", 8000, 64000, 1, 3),
95 AudioCodec(117, "red", 8000, 0, 1, 2),
96 AudioCodec(107, "CN", 48000, 0, 1, 1)
97};
98
99static const AudioCodec kAudioCodecs2[] = {
100 AudioCodec(126, "speex", 16000, 22000, 1, 3),
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +0000101 AudioCodec(0, "PCMU", 8000, 64000, 1, 2),
102 AudioCodec(127, "iLBC", 8000, 13300, 1, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103};
104
105static const AudioCodec kAudioCodecsAnswer[] = {
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +0000106 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
107 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108};
109
110static const VideoCodec kVideoCodecs1[] = {
111 VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
112 VideoCodec(97, "H264", 320, 200, 30, 1)
113};
114
115static const VideoCodec kVideoCodecs2[] = {
116 VideoCodec(126, "H264", 320, 200, 30, 2),
117 VideoCodec(127, "H263", 320, 200, 30, 1)
118};
119
120static const VideoCodec kVideoCodecsAnswer[] = {
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +0000121 VideoCodec(97, "H264", 320, 200, 30, 1)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122};
123
124static const DataCodec kDataCodecs1[] = {
125 DataCodec(98, "binary-data", 2),
126 DataCodec(99, "utf8-text", 1)
127};
128
129static const DataCodec kDataCodecs2[] = {
130 DataCodec(126, "binary-data", 2),
131 DataCodec(127, "utf8-text", 1)
132};
133
134static const DataCodec kDataCodecsAnswer[] = {
135 DataCodec(98, "binary-data", 2),
136 DataCodec(99, "utf8-text", 1)
137};
138
139static const RtpHeaderExtension kAudioRtpExtension1[] = {
140 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
141 RtpHeaderExtension("http://google.com/testing/audio_something", 10),
142};
143
144static const RtpHeaderExtension kAudioRtpExtension2[] = {
145 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
146 RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000147 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148};
149
150static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
151 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
152};
153
154static const RtpHeaderExtension kVideoRtpExtension1[] = {
155 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000156 RtpHeaderExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157};
158
159static const RtpHeaderExtension kVideoRtpExtension2[] = {
160 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
161 RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000162 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163};
164
165static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
166 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
167};
168
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000169static const uint32 kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
170static const uint32 kSimSsrc[] = {10, 20, 30};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171static const uint32 kFec1Ssrc[] = {10, 11};
172static const uint32 kFec2Ssrc[] = {20, 21};
173static const uint32 kFec3Ssrc[] = {30, 31};
174
175static const char kMediaStream1[] = "stream_1";
176static const char kMediaStream2[] = "stream_2";
177static const char kVideoTrack1[] = "video_1";
178static const char kVideoTrack2[] = "video_2";
179static const char kAudioTrack1[] = "audio_1";
180static const char kAudioTrack2[] = "audio_2";
181static const char kAudioTrack3[] = "audio_3";
182static const char kDataTrack1[] = "data_1";
183static const char kDataTrack2[] = "data_2";
184static const char kDataTrack3[] = "data_3";
185
186class MediaSessionDescriptionFactoryTest : public testing::Test {
187 public:
188 MediaSessionDescriptionFactoryTest()
189 : f1_(&tdf1_), f2_(&tdf2_), id1_("id1"), id2_("id2") {
190 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
191 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
192 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
193 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
194 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
195 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
196 tdf1_.set_identity(&id1_);
197 tdf2_.set_identity(&id2_);
198 }
199
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +0000200 static void SetUpTestCase() {
201 talk_base::InitializeSSL();
202 }
203
204 static void TearDownTestCase() {
205 talk_base::CleanupSSL();
206 }
207
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000208 // Create a video StreamParamsVec object with:
209 // - one video stream with 3 simulcast streams and FEC,
210 StreamParamsVec CreateComplexVideoStreamParamsVec() {
211 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
212 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
213 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
214 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
215
216 std::vector<SsrcGroup> ssrc_groups;
217 ssrc_groups.push_back(sim_group);
218 ssrc_groups.push_back(fec_group1);
219 ssrc_groups.push_back(fec_group2);
220 ssrc_groups.push_back(fec_group3);
221
222 StreamParams simulcast_params;
223 simulcast_params.id = kVideoTrack1;
224 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
225 simulcast_params.ssrc_groups = ssrc_groups;
226 simulcast_params.cname = "Video_SIM_FEC";
227 simulcast_params.sync_label = kMediaStream1;
228
229 StreamParamsVec video_streams;
230 video_streams.push_back(simulcast_params);
231
232 return video_streams;
233 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234
235 bool CompareCryptoParams(const CryptoParamsVec& c1,
236 const CryptoParamsVec& c2) {
237 if (c1.size() != c2.size())
238 return false;
239 for (size_t i = 0; i < c1.size(); ++i)
240 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
241 c1[i].key_params != c2[i].key_params ||
242 c1[i].session_params != c2[i].session_params)
243 return false;
244 return true;
245 }
246
247 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
248 bool has_current_desc) {
249 const std::string current_audio_ufrag = "current_audio_ufrag";
250 const std::string current_audio_pwd = "current_audio_pwd";
251 const std::string current_video_ufrag = "current_video_ufrag";
252 const std::string current_video_pwd = "current_video_pwd";
253 const std::string current_data_ufrag = "current_data_ufrag";
254 const std::string current_data_pwd = "current_data_pwd";
255 talk_base::scoped_ptr<SessionDescription> current_desc;
256 talk_base::scoped_ptr<SessionDescription> desc;
257 if (has_current_desc) {
258 current_desc.reset(new SessionDescription());
259 EXPECT_TRUE(current_desc->AddTransportInfo(
260 TransportInfo("audio",
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000261 TransportDescription("",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000263 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000264 EXPECT_TRUE(current_desc->AddTransportInfo(
265 TransportInfo("video",
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000266 TransportDescription("",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000268 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269 EXPECT_TRUE(current_desc->AddTransportInfo(
270 TransportInfo("data",
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000271 TransportDescription("",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000273 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 }
275 if (offer) {
276 desc.reset(f1_.CreateOffer(options, current_desc.get()));
277 } else {
278 talk_base::scoped_ptr<SessionDescription> offer;
279 offer.reset(f1_.CreateOffer(options, NULL));
280 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
281 }
282 ASSERT_TRUE(desc.get() != NULL);
283 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
284 if (options.has_audio) {
285 EXPECT_TRUE(ti_audio != NULL);
286 if (has_current_desc) {
287 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
288 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
289 } else {
290 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
291 ti_audio->description.ice_ufrag.size());
292 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
293 ti_audio->description.ice_pwd.size());
294 }
295
296 } else {
297 EXPECT_TRUE(ti_audio == NULL);
298 }
299 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
300 if (options.has_video) {
301 EXPECT_TRUE(ti_video != NULL);
302 if (options.bundle_enabled) {
303 EXPECT_EQ(ti_audio->description.ice_ufrag,
304 ti_video->description.ice_ufrag);
305 EXPECT_EQ(ti_audio->description.ice_pwd,
306 ti_video->description.ice_pwd);
307 } else {
308 if (has_current_desc) {
309 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
310 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
311 } else {
312 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
313 ti_video->description.ice_ufrag.size());
314 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
315 ti_video->description.ice_pwd.size());
316 }
317 }
318 } else {
319 EXPECT_TRUE(ti_video == NULL);
320 }
321 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
322 if (options.has_data()) {
323 EXPECT_TRUE(ti_data != NULL);
324 if (options.bundle_enabled) {
325 EXPECT_EQ(ti_audio->description.ice_ufrag,
326 ti_data->description.ice_ufrag);
327 EXPECT_EQ(ti_audio->description.ice_pwd,
328 ti_data->description.ice_pwd);
329 } else {
330 if (has_current_desc) {
331 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
332 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
333 } else {
334 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
335 ti_data->description.ice_ufrag.size());
336 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
337 ti_data->description.ice_pwd.size());
338 }
339 }
340 } else {
341 EXPECT_TRUE(ti_video == NULL);
342 }
343 }
344
345 void TestCryptoWithBundle(bool offer) {
346 f1_.set_secure(SEC_ENABLED);
347 MediaSessionOptions options;
348 options.has_audio = true;
349 options.has_video = true;
350 options.data_channel_type = cricket::DCT_RTP;
351 talk_base::scoped_ptr<SessionDescription> ref_desc;
352 talk_base::scoped_ptr<SessionDescription> desc;
353 if (offer) {
354 options.bundle_enabled = false;
355 ref_desc.reset(f1_.CreateOffer(options, NULL));
356 options.bundle_enabled = true;
357 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
358 } else {
359 options.bundle_enabled = true;
360 ref_desc.reset(f1_.CreateOffer(options, NULL));
361 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
362 }
363 ASSERT_TRUE(desc.get() != NULL);
364 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000365 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000366 desc.get()->GetContentDescriptionByName("audio"));
367 ASSERT_TRUE(audio_media_desc != NULL);
368 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000369 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370 desc.get()->GetContentDescriptionByName("video"));
371 ASSERT_TRUE(video_media_desc != NULL);
372 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
373 video_media_desc->cryptos()));
374 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
375 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
376 audio_media_desc->cryptos()[0].cipher_suite);
377
378 // Verify the selected crypto is one from the reference audio
379 // media content.
380 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000381 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382 ref_desc.get()->GetContentDescriptionByName("audio"));
383 bool found = false;
384 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
385 if (ref_audio_media_desc->cryptos()[i].Matches(
386 audio_media_desc->cryptos()[0])) {
387 found = true;
388 break;
389 }
390 }
391 EXPECT_TRUE(found);
392 }
393
394 // This test that the audio and video media direction is set to
395 // |expected_direction_in_answer| in an answer if the offer direction is set
396 // to |direction_in_offer|.
397 void TestMediaDirectionInAnswer(
398 cricket::MediaContentDirection direction_in_offer,
399 cricket::MediaContentDirection expected_direction_in_answer) {
400 MediaSessionOptions opts;
401 opts.has_video = true;
402 talk_base::scoped_ptr<SessionDescription> offer(
403 f1_.CreateOffer(opts, NULL));
404 ASSERT_TRUE(offer.get() != NULL);
405 ContentInfo* ac_offer= offer->GetContentByName("audio");
406 ASSERT_TRUE(ac_offer != NULL);
407 AudioContentDescription* acd_offer =
408 static_cast<AudioContentDescription*>(ac_offer->description);
409 acd_offer->set_direction(direction_in_offer);
410 ContentInfo* vc_offer= offer->GetContentByName("video");
411 ASSERT_TRUE(vc_offer != NULL);
412 VideoContentDescription* vcd_offer =
413 static_cast<VideoContentDescription*>(vc_offer->description);
414 vcd_offer->set_direction(direction_in_offer);
415
416 talk_base::scoped_ptr<SessionDescription> answer(
417 f2_.CreateAnswer(offer.get(), opts, NULL));
418 const AudioContentDescription* acd_answer =
419 GetFirstAudioContentDescription(answer.get());
420 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
421 const VideoContentDescription* vcd_answer =
422 GetFirstVideoContentDescription(answer.get());
423 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
424 }
425
426 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
427 const cricket::ContentDescription* description = content->description;
428 ASSERT(description != NULL);
429 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000430 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431 ASSERT(audio_content_desc != NULL);
432 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
433 if (audio_content_desc->codecs()[i].name == "CN")
434 return false;
435 }
436 return true;
437 }
438
439 protected:
440 MediaSessionDescriptionFactory f1_;
441 MediaSessionDescriptionFactory f2_;
442 TransportDescriptionFactory tdf1_;
443 TransportDescriptionFactory tdf2_;
444 talk_base::FakeSSLIdentity id1_;
445 talk_base::FakeSSLIdentity id2_;
446};
447
448// Create a typical audio offer, and ensure it matches what we expect.
449TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
450 f1_.set_secure(SEC_ENABLED);
451 talk_base::scoped_ptr<SessionDescription> offer(
452 f1_.CreateOffer(MediaSessionOptions(), NULL));
453 ASSERT_TRUE(offer.get() != NULL);
454 const ContentInfo* ac = offer->GetContentByName("audio");
455 const ContentInfo* vc = offer->GetContentByName("video");
456 ASSERT_TRUE(ac != NULL);
457 ASSERT_TRUE(vc == NULL);
458 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
459 const AudioContentDescription* acd =
460 static_cast<const AudioContentDescription*>(ac->description);
461 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
462 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
463 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
464 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
465 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
466 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
467 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
468}
469
470// Create a typical video offer, and ensure it matches what we expect.
471TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
472 MediaSessionOptions opts;
473 opts.has_video = true;
474 f1_.set_secure(SEC_ENABLED);
475 talk_base::scoped_ptr<SessionDescription>
476 offer(f1_.CreateOffer(opts, NULL));
477 ASSERT_TRUE(offer.get() != NULL);
478 const ContentInfo* ac = offer->GetContentByName("audio");
479 const ContentInfo* vc = offer->GetContentByName("video");
480 ASSERT_TRUE(ac != NULL);
481 ASSERT_TRUE(vc != NULL);
482 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
483 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
484 const AudioContentDescription* acd =
485 static_cast<const AudioContentDescription*>(ac->description);
486 const VideoContentDescription* vcd =
487 static_cast<const VideoContentDescription*>(vc->description);
488 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
489 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
490 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
491 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
492 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
493 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
494 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
495 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
496 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
497 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
498 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
499 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
500 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
501 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
502}
503
504// Test creating an offer with bundle where the Codecs have the same dynamic
505// RTP playlod type. The test verifies that the offer don't contain the
506// duplicate RTP payload types.
507TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
508 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
509 const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
510 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
511 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
512 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
513
514 MediaSessionOptions opts;
515 opts.has_audio = true;
516 opts.has_video = true;
517 opts.data_channel_type = cricket::DCT_RTP;
518 opts.bundle_enabled = true;
519 talk_base::scoped_ptr<SessionDescription>
520 offer(f2_.CreateOffer(opts, NULL));
521 const VideoContentDescription* vcd =
522 GetFirstVideoContentDescription(offer.get());
523 const AudioContentDescription* acd =
524 GetFirstAudioContentDescription(offer.get());
525 const DataContentDescription* dcd =
526 GetFirstDataContentDescription(offer.get());
527 ASSERT_TRUE(NULL != vcd);
528 ASSERT_TRUE(NULL != acd);
529 ASSERT_TRUE(NULL != dcd);
530 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
531 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
532 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
533 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
534 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
535 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
536}
537
538// Test creating an updated offer with with bundle, audio, video and data
539// after an audio only session has been negotiated.
540TEST_F(MediaSessionDescriptionFactoryTest,
541 TestCreateUpdatedVideoOfferWithBundle) {
542 f1_.set_secure(SEC_ENABLED);
543 f2_.set_secure(SEC_ENABLED);
544 MediaSessionOptions opts;
545 opts.has_audio = true;
546 opts.has_video = false;
547 opts.data_channel_type = cricket::DCT_NONE;
548 opts.bundle_enabled = true;
549 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
550 talk_base::scoped_ptr<SessionDescription> answer(
551 f2_.CreateAnswer(offer.get(), opts, NULL));
552
553 MediaSessionOptions updated_opts;
554 updated_opts.has_audio = true;
555 updated_opts.has_video = true;
556 updated_opts.data_channel_type = cricket::DCT_RTP;
557 updated_opts.bundle_enabled = true;
558 talk_base::scoped_ptr<SessionDescription> updated_offer(f1_.CreateOffer(
559 updated_opts, answer.get()));
560
561 const AudioContentDescription* acd =
562 GetFirstAudioContentDescription(updated_offer.get());
563 const VideoContentDescription* vcd =
564 GetFirstVideoContentDescription(updated_offer.get());
565 const DataContentDescription* dcd =
566 GetFirstDataContentDescription(updated_offer.get());
567 EXPECT_TRUE(NULL != vcd);
568 EXPECT_TRUE(NULL != acd);
569 EXPECT_TRUE(NULL != dcd);
570
571 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
572 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
573 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
574 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
575 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
576 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
577}
wu@webrtc.org78187522013-10-07 23:32:02 +0000578// Create a RTP data offer, and ensure it matches what we expect.
579TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 MediaSessionOptions opts;
581 opts.data_channel_type = cricket::DCT_RTP;
582 f1_.set_secure(SEC_ENABLED);
583 talk_base::scoped_ptr<SessionDescription>
584 offer(f1_.CreateOffer(opts, NULL));
585 ASSERT_TRUE(offer.get() != NULL);
586 const ContentInfo* ac = offer->GetContentByName("audio");
587 const ContentInfo* dc = offer->GetContentByName("data");
588 ASSERT_TRUE(ac != NULL);
589 ASSERT_TRUE(dc != NULL);
590 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
591 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
592 const AudioContentDescription* acd =
593 static_cast<const AudioContentDescription*>(ac->description);
594 const DataContentDescription* dcd =
595 static_cast<const DataContentDescription*>(dc->description);
596 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
597 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
598 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
599 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
600 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
601 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
602 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
603 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
604 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
605 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
606 EXPECT_EQ(cricket::kDataMaxBandwidth,
607 dcd->bandwidth()); // default bandwidth (auto)
608 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
609 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
610 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
611}
612
wu@webrtc.org78187522013-10-07 23:32:02 +0000613// Create an SCTP data offer with bundle without error.
614TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
615 MediaSessionOptions opts;
616 opts.has_audio = false;
617 opts.bundle_enabled = true;
618 opts.data_channel_type = cricket::DCT_SCTP;
619 f1_.set_secure(SEC_ENABLED);
620 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
621 EXPECT_TRUE(offer.get() != NULL);
622 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
623}
624
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625// Create an audio, video offer without legacy StreamParams.
626TEST_F(MediaSessionDescriptionFactoryTest,
627 TestCreateOfferWithoutLegacyStreams) {
628 MediaSessionOptions opts;
629 opts.has_video = true;
630 f1_.set_add_legacy_streams(false);
631 talk_base::scoped_ptr<SessionDescription>
632 offer(f1_.CreateOffer(opts, NULL));
633 ASSERT_TRUE(offer.get() != NULL);
634 const ContentInfo* ac = offer->GetContentByName("audio");
635 const ContentInfo* vc = offer->GetContentByName("video");
636 ASSERT_TRUE(ac != NULL);
637 ASSERT_TRUE(vc != NULL);
638 const AudioContentDescription* acd =
639 static_cast<const AudioContentDescription*>(ac->description);
640 const VideoContentDescription* vcd =
641 static_cast<const VideoContentDescription*>(vc->description);
642
643 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
644 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
645}
646
647// Create a typical audio answer, and ensure it matches what we expect.
648TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
649 f1_.set_secure(SEC_ENABLED);
650 f2_.set_secure(SEC_ENABLED);
651 talk_base::scoped_ptr<SessionDescription> offer(
652 f1_.CreateOffer(MediaSessionOptions(), NULL));
653 ASSERT_TRUE(offer.get() != NULL);
654 talk_base::scoped_ptr<SessionDescription> answer(
655 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
656 const ContentInfo* ac = answer->GetContentByName("audio");
657 const ContentInfo* vc = answer->GetContentByName("video");
658 ASSERT_TRUE(ac != NULL);
659 ASSERT_TRUE(vc == NULL);
660 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
661 const AudioContentDescription* acd =
662 static_cast<const AudioContentDescription*>(ac->description);
663 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
664 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
665 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
666 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
667 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
668 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
669 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
670}
671
672// Create a typical video answer, and ensure it matches what we expect.
673TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
674 MediaSessionOptions opts;
675 opts.has_video = true;
676 f1_.set_secure(SEC_ENABLED);
677 f2_.set_secure(SEC_ENABLED);
678 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
679 ASSERT_TRUE(offer.get() != NULL);
680 talk_base::scoped_ptr<SessionDescription> answer(
681 f2_.CreateAnswer(offer.get(), opts, NULL));
682 const ContentInfo* ac = answer->GetContentByName("audio");
683 const ContentInfo* vc = answer->GetContentByName("video");
684 ASSERT_TRUE(ac != NULL);
685 ASSERT_TRUE(vc != NULL);
686 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
687 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
688 const AudioContentDescription* acd =
689 static_cast<const AudioContentDescription*>(ac->description);
690 const VideoContentDescription* vcd =
691 static_cast<const VideoContentDescription*>(vc->description);
692 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
693 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
694 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
695 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
696 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
697 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
698 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
699 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
700 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
701 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
702 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
703 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
704}
705
706TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
707 MediaSessionOptions opts;
708 opts.data_channel_type = cricket::DCT_RTP;
709 f1_.set_secure(SEC_ENABLED);
710 f2_.set_secure(SEC_ENABLED);
711 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
712 ASSERT_TRUE(offer.get() != NULL);
713 talk_base::scoped_ptr<SessionDescription> answer(
714 f2_.CreateAnswer(offer.get(), opts, NULL));
715 const ContentInfo* ac = answer->GetContentByName("audio");
716 const ContentInfo* vc = answer->GetContentByName("data");
717 ASSERT_TRUE(ac != NULL);
718 ASSERT_TRUE(vc != NULL);
719 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
720 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
721 const AudioContentDescription* acd =
722 static_cast<const AudioContentDescription*>(ac->description);
723 const DataContentDescription* vcd =
724 static_cast<const DataContentDescription*>(vc->description);
725 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
726 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
727 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
728 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
729 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
730 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
731 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
732 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
733 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
734 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
735 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
736 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
737}
738
739// This test that the media direction is set to send/receive in an answer if
740// the offer is send receive.
741TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
742 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
743}
744
745// This test that the media direction is set to receive only in an answer if
746// the offer is send only.
747TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
748 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
749}
750
751// This test that the media direction is set to send only in an answer if
752// the offer is recv only.
753TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
754 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
755}
756
757// This test that the media direction is set to inactive in an answer if
758// the offer is inactive.
759TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
760 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
761}
762
763// Test that a data content with an unknown protocol is rejected in an answer.
764TEST_F(MediaSessionDescriptionFactoryTest,
765 CreateDataAnswerToOfferWithUnknownProtocol) {
766 MediaSessionOptions opts;
767 opts.data_channel_type = cricket::DCT_RTP;
768 opts.has_audio = false;
769 f1_.set_secure(SEC_ENABLED);
770 f2_.set_secure(SEC_ENABLED);
771 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
772 ContentInfo* dc_offer= offer->GetContentByName("data");
773 ASSERT_TRUE(dc_offer != NULL);
774 DataContentDescription* dcd_offer =
775 static_cast<DataContentDescription*>(dc_offer->description);
776 ASSERT_TRUE(dcd_offer != NULL);
777 std::string protocol = "a weird unknown protocol";
778 dcd_offer->set_protocol(protocol);
779
780 talk_base::scoped_ptr<SessionDescription> answer(
781 f2_.CreateAnswer(offer.get(), opts, NULL));
782
783 const ContentInfo* dc_answer = answer->GetContentByName("data");
784 ASSERT_TRUE(dc_answer != NULL);
785 EXPECT_TRUE(dc_answer->rejected);
786 const DataContentDescription* dcd_answer =
787 static_cast<const DataContentDescription*>(dc_answer->description);
788 ASSERT_TRUE(dcd_answer != NULL);
789 EXPECT_EQ(protocol, dcd_answer->protocol());
790}
791
792// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
793TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
794 MediaSessionOptions opts;
795 f1_.set_secure(SEC_DISABLED);
796 f2_.set_secure(SEC_DISABLED);
797 tdf1_.set_secure(SEC_DISABLED);
798 tdf2_.set_secure(SEC_DISABLED);
799
800 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
801 const AudioContentDescription* offer_acd =
802 GetFirstAudioContentDescription(offer.get());
803 ASSERT_TRUE(offer_acd != NULL);
804 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
805
806 talk_base::scoped_ptr<SessionDescription> answer(
807 f2_.CreateAnswer(offer.get(), opts, NULL));
808
809 const ContentInfo* ac_answer = answer->GetContentByName("audio");
810 ASSERT_TRUE(ac_answer != NULL);
811 EXPECT_FALSE(ac_answer->rejected);
812
813 const AudioContentDescription* answer_acd =
814 GetFirstAudioContentDescription(answer.get());
815 ASSERT_TRUE(answer_acd != NULL);
816 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
817}
818
819// Create a video offer and answer and ensure the RTP header extensions
820// matches what we expect.
821TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
822 MediaSessionOptions opts;
823 opts.has_video = true;
824
825 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
826 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
827 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
828 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
829
830 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
831 ASSERT_TRUE(offer.get() != NULL);
832 talk_base::scoped_ptr<SessionDescription> answer(
833 f2_.CreateAnswer(offer.get(), opts, NULL));
834
835 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
836 GetFirstAudioContentDescription(
837 offer.get())->rtp_header_extensions());
838 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
839 GetFirstVideoContentDescription(
840 offer.get())->rtp_header_extensions());
841 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
842 GetFirstAudioContentDescription(
843 answer.get())->rtp_header_extensions());
844 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
845 GetFirstVideoContentDescription(
846 answer.get())->rtp_header_extensions());
847}
848
849// Create an audio, video, data answer without legacy StreamParams.
850TEST_F(MediaSessionDescriptionFactoryTest,
851 TestCreateAnswerWithoutLegacyStreams) {
852 MediaSessionOptions opts;
853 opts.has_video = true;
854 opts.data_channel_type = cricket::DCT_RTP;
855 f1_.set_add_legacy_streams(false);
856 f2_.set_add_legacy_streams(false);
857 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
858 ASSERT_TRUE(offer.get() != NULL);
859 talk_base::scoped_ptr<SessionDescription> answer(
860 f2_.CreateAnswer(offer.get(), opts, NULL));
861 const ContentInfo* ac = answer->GetContentByName("audio");
862 const ContentInfo* vc = answer->GetContentByName("video");
863 const ContentInfo* dc = answer->GetContentByName("data");
864 ASSERT_TRUE(ac != NULL);
865 ASSERT_TRUE(vc != NULL);
866 const AudioContentDescription* acd =
867 static_cast<const AudioContentDescription*>(ac->description);
868 const VideoContentDescription* vcd =
869 static_cast<const VideoContentDescription*>(vc->description);
870 const DataContentDescription* dcd =
871 static_cast<const DataContentDescription*>(dc->description);
872
873 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
874 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
875 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
876}
877
878TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
879 MediaSessionOptions opts;
880 opts.has_video = true;
881 opts.data_channel_type = cricket::DCT_RTP;
882 f1_.set_secure(SEC_ENABLED);
883 talk_base::scoped_ptr<SessionDescription>
884 offer(f1_.CreateOffer(opts, NULL));
885 ASSERT_TRUE(offer.get() != NULL);
886 const ContentInfo* ac = offer->GetContentByName("audio");
887 const ContentInfo* vc = offer->GetContentByName("video");
888 const ContentInfo* dc = offer->GetContentByName("data");
889 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
890 static_cast<const AudioContentDescription*>(ac->description));
891 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
892 static_cast<const VideoContentDescription*>(vc->description));
893 DataContentDescription* dcd = const_cast<DataContentDescription*>(
894 static_cast<const DataContentDescription*>(dc->description));
895
896 EXPECT_FALSE(acd->partial()); // default is false.
897 acd->set_partial(true);
898 EXPECT_TRUE(acd->partial());
899 acd->set_partial(false);
900 EXPECT_FALSE(acd->partial());
901
902 EXPECT_FALSE(vcd->partial()); // default is false.
903 vcd->set_partial(true);
904 EXPECT_TRUE(vcd->partial());
905 vcd->set_partial(false);
906 EXPECT_FALSE(vcd->partial());
907
908 EXPECT_FALSE(dcd->partial()); // default is false.
909 dcd->set_partial(true);
910 EXPECT_TRUE(dcd->partial());
911 dcd->set_partial(false);
912 EXPECT_FALSE(dcd->partial());
913}
914
915// Create a typical video answer, and ensure it matches what we expect.
916TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
917 MediaSessionOptions offer_opts;
918 MediaSessionOptions answer_opts;
919 answer_opts.has_video = true;
920 offer_opts.has_video = true;
921 answer_opts.data_channel_type = cricket::DCT_RTP;
922 offer_opts.data_channel_type = cricket::DCT_RTP;
923
wu@webrtc.org97077a32013-10-25 21:18:33 +0000924 talk_base::scoped_ptr<SessionDescription> offer;
925 talk_base::scoped_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000926
927 offer_opts.rtcp_mux_enabled = true;
928 answer_opts.rtcp_mux_enabled = true;
929
930 offer.reset(f1_.CreateOffer(offer_opts, NULL));
931 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
932 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
933 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
934 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
935 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
936 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
937 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
938 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
939 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
940 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
941 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
942 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
943 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
944
945 offer_opts.rtcp_mux_enabled = true;
946 answer_opts.rtcp_mux_enabled = false;
947
948 offer.reset(f1_.CreateOffer(offer_opts, NULL));
949 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
950 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
951 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
952 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
953 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
954 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
955 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
956 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
957 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
958 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
959 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
960 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
961 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
962
963 offer_opts.rtcp_mux_enabled = false;
964 answer_opts.rtcp_mux_enabled = true;
965
966 offer.reset(f1_.CreateOffer(offer_opts, NULL));
967 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
968 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
969 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
970 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
971 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
972 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
973 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
974 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
975 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
976 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
977 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
978 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
979 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
980
981 offer_opts.rtcp_mux_enabled = false;
982 answer_opts.rtcp_mux_enabled = false;
983
984 offer.reset(f1_.CreateOffer(offer_opts, NULL));
985 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
986 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
987 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
988 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
989 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
990 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
991 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
992 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
993 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
994 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
995 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
996 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
997 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
998}
999
1000// Create an audio-only answer to a video offer.
1001TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1002 MediaSessionOptions opts;
1003 opts.has_video = true;
1004 talk_base::scoped_ptr<SessionDescription>
1005 offer(f1_.CreateOffer(opts, NULL));
1006 ASSERT_TRUE(offer.get() != NULL);
1007 talk_base::scoped_ptr<SessionDescription> answer(
1008 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1009 const ContentInfo* ac = answer->GetContentByName("audio");
1010 const ContentInfo* vc = answer->GetContentByName("video");
1011 ASSERT_TRUE(ac != NULL);
1012 ASSERT_TRUE(vc != NULL);
1013 ASSERT_TRUE(vc->description != NULL);
1014 EXPECT_TRUE(vc->rejected);
1015}
1016
1017// Create an audio-only answer to an offer with data.
1018TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1019 MediaSessionOptions opts;
1020 opts.data_channel_type = cricket::DCT_RTP;
1021 talk_base::scoped_ptr<SessionDescription>
1022 offer(f1_.CreateOffer(opts, NULL));
1023 ASSERT_TRUE(offer.get() != NULL);
1024 talk_base::scoped_ptr<SessionDescription> answer(
1025 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1026 const ContentInfo* ac = answer->GetContentByName("audio");
1027 const ContentInfo* dc = answer->GetContentByName("data");
1028 ASSERT_TRUE(ac != NULL);
1029 ASSERT_TRUE(dc != NULL);
1030 ASSERT_TRUE(dc->description != NULL);
1031 EXPECT_TRUE(dc->rejected);
1032}
1033
1034// Create an answer that rejects the contents which are rejected in the offer.
1035TEST_F(MediaSessionDescriptionFactoryTest,
1036 CreateAnswerToOfferWithRejectedMedia) {
1037 MediaSessionOptions opts;
1038 opts.has_video = true;
1039 opts.data_channel_type = cricket::DCT_RTP;
1040 talk_base::scoped_ptr<SessionDescription>
1041 offer(f1_.CreateOffer(opts, NULL));
1042 ASSERT_TRUE(offer.get() != NULL);
1043 ContentInfo* ac = offer->GetContentByName("audio");
1044 ContentInfo* vc = offer->GetContentByName("video");
1045 ContentInfo* dc = offer->GetContentByName("data");
1046 ASSERT_TRUE(ac != NULL);
1047 ASSERT_TRUE(vc != NULL);
1048 ASSERT_TRUE(dc != NULL);
1049 ac->rejected = true;
1050 vc->rejected = true;
1051 dc->rejected = true;
1052 talk_base::scoped_ptr<SessionDescription> answer(
1053 f2_.CreateAnswer(offer.get(), opts, NULL));
1054 ac = answer->GetContentByName("audio");
1055 vc = answer->GetContentByName("video");
1056 dc = answer->GetContentByName("data");
1057 ASSERT_TRUE(ac != NULL);
1058 ASSERT_TRUE(vc != NULL);
1059 ASSERT_TRUE(dc != NULL);
1060 EXPECT_TRUE(ac->rejected);
1061 EXPECT_TRUE(vc->rejected);
1062 EXPECT_TRUE(dc->rejected);
1063}
1064
1065// Create an audio and video offer with:
1066// - one video track
1067// - two audio tracks
1068// - two data tracks
1069// and ensure it matches what we expect. Also updates the initial offer by
1070// adding a new video track and replaces one of the audio tracks.
1071TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1072 MediaSessionOptions opts;
1073 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1074 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1075 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1076 opts.data_channel_type = cricket::DCT_RTP;
1077 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1078 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1079
1080 f1_.set_secure(SEC_ENABLED);
1081 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1082
1083 ASSERT_TRUE(offer.get() != NULL);
1084 const ContentInfo* ac = offer->GetContentByName("audio");
1085 const ContentInfo* vc = offer->GetContentByName("video");
1086 const ContentInfo* dc = offer->GetContentByName("data");
1087 ASSERT_TRUE(ac != NULL);
1088 ASSERT_TRUE(vc != NULL);
1089 ASSERT_TRUE(dc != NULL);
1090 const AudioContentDescription* acd =
1091 static_cast<const AudioContentDescription*>(ac->description);
1092 const VideoContentDescription* vcd =
1093 static_cast<const VideoContentDescription*>(vc->description);
1094 const DataContentDescription* dcd =
1095 static_cast<const DataContentDescription*>(dc->description);
1096 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1097 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1098
1099 const StreamParamsVec& audio_streams = acd->streams();
1100 ASSERT_EQ(2U, audio_streams.size());
1101 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1102 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1103 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1104 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1105 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1106 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1107 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1108
1109 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1110 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1111 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1112
1113 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1114 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1115 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1116
1117 const StreamParamsVec& video_streams = vcd->streams();
1118 ASSERT_EQ(1U, video_streams.size());
1119 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1120 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1121 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1122 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1123
1124 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1125 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1126 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1127
1128 const StreamParamsVec& data_streams = dcd->streams();
1129 ASSERT_EQ(2U, data_streams.size());
1130 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1131 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1132 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1133 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1134 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1135 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1136 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1137
1138 EXPECT_EQ(cricket::kDataMaxBandwidth,
1139 dcd->bandwidth()); // default bandwidth (auto)
1140 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1141 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1142
1143
1144 // Update the offer. Add a new video track that is not synched to the
1145 // other tracks and replace audio track 2 with audio track 3.
1146 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1147 opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1148 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1149 opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
1150 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
1151 talk_base::scoped_ptr<SessionDescription>
1152 updated_offer(f1_.CreateOffer(opts, offer.get()));
1153
1154 ASSERT_TRUE(updated_offer.get() != NULL);
1155 ac = updated_offer->GetContentByName("audio");
1156 vc = updated_offer->GetContentByName("video");
1157 dc = updated_offer->GetContentByName("data");
1158 ASSERT_TRUE(ac != NULL);
1159 ASSERT_TRUE(vc != NULL);
1160 ASSERT_TRUE(dc != NULL);
1161 const AudioContentDescription* updated_acd =
1162 static_cast<const AudioContentDescription*>(ac->description);
1163 const VideoContentDescription* updated_vcd =
1164 static_cast<const VideoContentDescription*>(vc->description);
1165 const DataContentDescription* updated_dcd =
1166 static_cast<const DataContentDescription*>(dc->description);
1167
1168 EXPECT_EQ(acd->type(), updated_acd->type());
1169 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1170 EXPECT_EQ(vcd->type(), updated_vcd->type());
1171 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1172 EXPECT_EQ(dcd->type(), updated_dcd->type());
1173 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1174 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1175 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1176 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1177 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1178 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1179 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1180
1181 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1182 ASSERT_EQ(2U, updated_audio_streams.size());
1183 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1184 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1185 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1186 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1187 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1188
1189 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1190 ASSERT_EQ(2U, updated_video_streams.size());
1191 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1192 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1193 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1194
1195 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1196 ASSERT_EQ(2U, updated_data_streams.size());
1197 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1198 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1199 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1200 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1201 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
1202}
1203
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001204// Create an offer with simulcast video stream.
1205TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1206 MediaSessionOptions opts;
1207 const int num_sim_layers = 3;
1208 opts.AddVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
1209 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1210
1211 ASSERT_TRUE(offer.get() != NULL);
1212 const ContentInfo* vc = offer->GetContentByName("video");
1213 ASSERT_TRUE(vc != NULL);
1214 const VideoContentDescription* vcd =
1215 static_cast<const VideoContentDescription*>(vc->description);
1216
1217 const StreamParamsVec& video_streams = vcd->streams();
1218 ASSERT_EQ(1U, video_streams.size());
1219 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1220 const SsrcGroup* sim_ssrc_group =
1221 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1222 ASSERT_TRUE(sim_ssrc_group != NULL);
1223 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1224}
1225
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226// Create an audio and video answer to a standard video offer with:
1227// - one video track
1228// - two audio tracks
1229// - two data tracks
1230// and ensure it matches what we expect. Also updates the initial answer by
1231// adding a new video track and removes one of the audio tracks.
1232TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1233 MediaSessionOptions offer_opts;
1234 offer_opts.has_video = true;
1235 offer_opts.data_channel_type = cricket::DCT_RTP;
1236 f1_.set_secure(SEC_ENABLED);
1237 f2_.set_secure(SEC_ENABLED);
1238 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
1239 NULL));
1240
1241 MediaSessionOptions opts;
1242 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1243 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1244 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1245 opts.data_channel_type = cricket::DCT_RTP;
1246 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1247 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1248
1249 talk_base::scoped_ptr<SessionDescription>
1250 answer(f2_.CreateAnswer(offer.get(), opts, NULL));
1251
1252 ASSERT_TRUE(answer.get() != NULL);
1253 const ContentInfo* ac = answer->GetContentByName("audio");
1254 const ContentInfo* vc = answer->GetContentByName("video");
1255 const ContentInfo* dc = answer->GetContentByName("data");
1256 ASSERT_TRUE(ac != NULL);
1257 ASSERT_TRUE(vc != NULL);
1258 ASSERT_TRUE(dc != NULL);
1259 const AudioContentDescription* acd =
1260 static_cast<const AudioContentDescription*>(ac->description);
1261 const VideoContentDescription* vcd =
1262 static_cast<const VideoContentDescription*>(vc->description);
1263 const DataContentDescription* dcd =
1264 static_cast<const DataContentDescription*>(dc->description);
1265 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1266 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1267 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1268
1269 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1270 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1271
1272 const StreamParamsVec& audio_streams = acd->streams();
1273 ASSERT_EQ(2U, audio_streams.size());
1274 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1275 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1276 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1277 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1278 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1279 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1280 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1281
1282 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1283 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1284
1285 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1286 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1287
1288 const StreamParamsVec& video_streams = vcd->streams();
1289 ASSERT_EQ(1U, video_streams.size());
1290 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1291 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1292 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1293 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1294
1295 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1296 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1297
1298 const StreamParamsVec& data_streams = dcd->streams();
1299 ASSERT_EQ(2U, data_streams.size());
1300 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1301 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1302 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1303 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1304 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1305 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1306 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1307
1308 EXPECT_EQ(cricket::kDataMaxBandwidth,
1309 dcd->bandwidth()); // default bandwidth (auto)
1310 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1311
1312 // Update the answer. Add a new video track that is not synched to the
1313 // other traacks and remove 1 audio track.
1314 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1315 opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1316 opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
1317 talk_base::scoped_ptr<SessionDescription>
1318 updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
1319
1320 ASSERT_TRUE(updated_answer.get() != NULL);
1321 ac = updated_answer->GetContentByName("audio");
1322 vc = updated_answer->GetContentByName("video");
1323 dc = updated_answer->GetContentByName("data");
1324 ASSERT_TRUE(ac != NULL);
1325 ASSERT_TRUE(vc != NULL);
1326 ASSERT_TRUE(dc != NULL);
1327 const AudioContentDescription* updated_acd =
1328 static_cast<const AudioContentDescription*>(ac->description);
1329 const VideoContentDescription* updated_vcd =
1330 static_cast<const VideoContentDescription*>(vc->description);
1331 const DataContentDescription* updated_dcd =
1332 static_cast<const DataContentDescription*>(dc->description);
1333
1334 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1335 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1336 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1337 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1338 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1339 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1340
1341 EXPECT_EQ(acd->type(), updated_acd->type());
1342 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1343 EXPECT_EQ(vcd->type(), updated_vcd->type());
1344 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1345 EXPECT_EQ(dcd->type(), updated_dcd->type());
1346 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1347
1348 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1349 ASSERT_EQ(1U, updated_audio_streams.size());
1350 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1351
1352 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1353 ASSERT_EQ(2U, updated_video_streams.size());
1354 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1355 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1356 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1357
1358 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1359 ASSERT_EQ(1U, updated_data_streams.size());
1360 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1361}
1362
1363
1364// Create an updated offer after creating an answer to the original offer and
1365// verify that the codecs that were part of the original answer are not changed
1366// in the updated offer.
1367TEST_F(MediaSessionDescriptionFactoryTest,
1368 RespondentCreatesOfferAfterCreatingAnswer) {
1369 MediaSessionOptions opts;
1370 opts.has_audio = true;
1371 opts.has_video = true;
1372
1373 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1374 talk_base::scoped_ptr<SessionDescription> answer(
1375 f2_.CreateAnswer(offer.get(), opts, NULL));
1376
1377 const AudioContentDescription* acd =
1378 GetFirstAudioContentDescription(answer.get());
1379 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1380
1381 const VideoContentDescription* vcd =
1382 GetFirstVideoContentDescription(answer.get());
1383 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1384
1385 talk_base::scoped_ptr<SessionDescription> updated_offer(
1386 f2_.CreateOffer(opts, answer.get()));
1387
1388 // The expected audio codecs are the common audio codecs from the first
1389 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1390 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001391 // TODO(wu): |updated_offer| should not include the codec
1392 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001393 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394 kAudioCodecsAnswer[0],
1395 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001396 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397 };
1398
1399 // The expected video codecs are the common video codecs from the first
1400 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1401 // preference order.
1402 const VideoCodec kUpdatedVideoCodecOffer[] = {
1403 kVideoCodecsAnswer[0],
1404 kVideoCodecs2[1],
1405 };
1406
1407 const AudioContentDescription* updated_acd =
1408 GetFirstAudioContentDescription(updated_offer.get());
1409 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1410
1411 const VideoContentDescription* updated_vcd =
1412 GetFirstVideoContentDescription(updated_offer.get());
1413 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1414}
1415
1416// Create an updated offer after creating an answer to the original offer and
1417// verify that the codecs that were part of the original answer are not changed
1418// in the updated offer. In this test Rtx is enabled.
1419TEST_F(MediaSessionDescriptionFactoryTest,
1420 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1421 MediaSessionOptions opts;
1422 opts.has_video = true;
1423 opts.has_audio = false;
1424 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1425 VideoCodec rtx_f1;
1426 rtx_f1.id = 126;
1427 rtx_f1.name = cricket::kRtxCodecName;
1428
1429 // This creates rtx for H264 with the payload type |f1_| uses.
1430 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1431 talk_base::ToString<int>(kVideoCodecs1[1].id);
1432 f1_codecs.push_back(rtx_f1);
1433 f1_.set_video_codecs(f1_codecs);
1434
1435 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1436 VideoCodec rtx_f2;
1437 rtx_f2.id = 127;
1438 rtx_f2.name = cricket::kRtxCodecName;
1439
1440 // This creates rtx for H264 with the payload type |f2_| uses.
1441 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1442 talk_base::ToString<int>(kVideoCodecs2[0].id);
1443 f2_codecs.push_back(rtx_f2);
1444 f2_.set_video_codecs(f2_codecs);
1445
1446 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1447 ASSERT_TRUE(offer.get() != NULL);
1448 talk_base::scoped_ptr<SessionDescription> answer(
1449 f2_.CreateAnswer(offer.get(), opts, NULL));
1450
1451 const VideoContentDescription* vcd =
1452 GetFirstVideoContentDescription(answer.get());
1453
1454 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1455 expected_codecs.push_back(rtx_f1);
1456
1457 EXPECT_EQ(expected_codecs, vcd->codecs());
1458
1459 // Now, make sure we get same result, except for the preference order,
1460 // if |f2_| creates an updated offer even though the default payload types
1461 // are different from |f1_|.
1462 expected_codecs[0].preference = f1_codecs[1].preference;
1463
1464 talk_base::scoped_ptr<SessionDescription> updated_offer(
1465 f2_.CreateOffer(opts, answer.get()));
1466 ASSERT_TRUE(updated_offer);
1467 talk_base::scoped_ptr<SessionDescription> updated_answer(
1468 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1469
1470 const VideoContentDescription* updated_vcd =
1471 GetFirstVideoContentDescription(updated_answer.get());
1472
1473 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1474}
1475
1476// Create an updated offer that adds video after creating an audio only answer
1477// to the original offer. This test verifies that if a video codec and the RTX
1478// codec have the same default payload type as an audio codec that is already in
1479// use, the added codecs payload types are changed.
1480TEST_F(MediaSessionDescriptionFactoryTest,
1481 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1482 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1483 VideoCodec rtx_f1;
1484 rtx_f1.id = 126;
1485 rtx_f1.name = cricket::kRtxCodecName;
1486
1487 // This creates rtx for H264 with the payload type |f1_| uses.
1488 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1489 talk_base::ToString<int>(kVideoCodecs1[1].id);
1490 f1_codecs.push_back(rtx_f1);
1491 f1_.set_video_codecs(f1_codecs);
1492
1493 MediaSessionOptions opts;
1494 opts.has_audio = true;
1495 opts.has_video = false;
1496
1497 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1498 talk_base::scoped_ptr<SessionDescription> answer(
1499 f2_.CreateAnswer(offer.get(), opts, NULL));
1500
1501 const AudioContentDescription* acd =
1502 GetFirstAudioContentDescription(answer.get());
1503 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1504
1505 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1506 // reference be the same as an audio codec that was negotiated in the
1507 // first offer/answer exchange.
1508 opts.has_audio = true;
1509 opts.has_video = true;
1510
1511 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1512 int used_pl_type = acd->codecs()[0].id;
1513 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
1514 VideoCodec rtx_f2;
1515 rtx_f2.id = 127;
1516 rtx_f2.name = cricket::kRtxCodecName;
1517 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1518 talk_base::ToString<int>(used_pl_type);
1519 f2_codecs.push_back(rtx_f2);
1520 f2_.set_video_codecs(f2_codecs);
1521
1522 talk_base::scoped_ptr<SessionDescription> updated_offer(
1523 f2_.CreateOffer(opts, answer.get()));
1524 ASSERT_TRUE(updated_offer);
1525 talk_base::scoped_ptr<SessionDescription> updated_answer(
1526 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1527
1528 const AudioContentDescription* updated_acd =
1529 GetFirstAudioContentDescription(answer.get());
1530 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1531
1532 const VideoContentDescription* updated_vcd =
1533 GetFirstVideoContentDescription(updated_answer.get());
1534
1535 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001536 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1538 EXPECT_NE(used_pl_type, new_h264_pl_type);
1539 VideoCodec rtx = updated_vcd->codecs()[1];
1540 int pt_referenced_by_rtx = talk_base::FromString<int>(
1541 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1542 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1543}
1544
1545// Test that RTX is ignored when there is no associated payload type parameter.
1546TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1547 MediaSessionOptions opts;
1548 opts.has_video = true;
1549 opts.has_audio = false;
1550 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1551 VideoCodec rtx_f1;
1552 rtx_f1.id = 126;
1553 rtx_f1.name = cricket::kRtxCodecName;
1554
1555 f1_codecs.push_back(rtx_f1);
1556 f1_.set_video_codecs(f1_codecs);
1557
1558 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1559 VideoCodec rtx_f2;
1560 rtx_f2.id = 127;
1561 rtx_f2.name = cricket::kRtxCodecName;
1562
1563 // This creates rtx for H264 with the payload type |f2_| uses.
1564 rtx_f2.SetParam(cricket::kCodecParamAssociatedPayloadType,
1565 talk_base::ToString<int>(kVideoCodecs2[0].id));
1566 f2_codecs.push_back(rtx_f2);
1567 f2_.set_video_codecs(f2_codecs);
1568
1569 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1570 ASSERT_TRUE(offer.get() != NULL);
1571 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1572 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1573 // is possible to test that that RTX is dropped when
1574 // kCodecParamAssociatedPayloadType is missing in the offer.
1575 VideoContentDescription* desc =
1576 static_cast<cricket::VideoContentDescription*>(
1577 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1578 ASSERT_TRUE(desc != NULL);
1579 std::vector<VideoCodec> codecs = desc->codecs();
1580 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1581 iter != codecs.end(); ++iter) {
1582 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1583 iter->params.clear();
1584 }
1585 }
1586 desc->set_codecs(codecs);
1587
1588 talk_base::scoped_ptr<SessionDescription> answer(
1589 f2_.CreateAnswer(offer.get(), opts, NULL));
1590
1591 const VideoContentDescription* vcd =
1592 GetFirstVideoContentDescription(answer.get());
1593
1594 for (std::vector<VideoCodec>::const_iterator iter = vcd->codecs().begin();
1595 iter != vcd->codecs().end(); ++iter) {
1596 ASSERT_STRNE(iter->name.c_str(), cricket::kRtxCodecName);
1597 }
1598}
1599
1600// Create an updated offer after creating an answer to the original offer and
1601// verify that the RTP header extensions that were part of the original answer
1602// are not changed in the updated offer.
1603TEST_F(MediaSessionDescriptionFactoryTest,
1604 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1605 MediaSessionOptions opts;
1606 opts.has_audio = true;
1607 opts.has_video = true;
1608
1609 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1610 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1611 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1612 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1613
1614 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1615 talk_base::scoped_ptr<SessionDescription> answer(
1616 f2_.CreateAnswer(offer.get(), opts, NULL));
1617
1618 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1619 GetFirstAudioContentDescription(
1620 answer.get())->rtp_header_extensions());
1621 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1622 GetFirstVideoContentDescription(
1623 answer.get())->rtp_header_extensions());
1624
1625 talk_base::scoped_ptr<SessionDescription> updated_offer(
1626 f2_.CreateOffer(opts, answer.get()));
1627
1628 // The expected RTP header extensions in the new offer are the resulting
1629 // extensions from the first offer/answer exchange plus the extensions only
1630 // |f2_| offer.
1631 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001632 // |f1_| for another extensions, it is changed to 13.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1634 kAudioRtpExtensionAnswer[0],
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001635 RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
1636 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637 };
1638
1639 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001640 // |f1_| for another extensions, is is changed to 12.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001641 const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1642 kVideoRtpExtensionAnswer[0],
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001643 RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
1644 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645 };
1646
1647 const AudioContentDescription* updated_acd =
1648 GetFirstAudioContentDescription(updated_offer.get());
1649 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1650 updated_acd->rtp_header_extensions());
1651
1652 const VideoContentDescription* updated_vcd =
1653 GetFirstVideoContentDescription(updated_offer.get());
1654 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1655 updated_vcd->rtp_header_extensions());
1656}
1657
1658TEST(MediaSessionDescription, CopySessionDescription) {
1659 SessionDescription source;
1660 cricket::ContentGroup group(cricket::CN_AUDIO);
1661 source.AddGroup(group);
1662 AudioContentDescription* acd(new AudioContentDescription());
1663 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1664 acd->AddLegacyStream(1);
1665 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1666 VideoContentDescription* vcd(new VideoContentDescription());
1667 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1668 vcd->AddLegacyStream(2);
1669 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1670
1671 talk_base::scoped_ptr<SessionDescription> copy(source.Copy());
1672 ASSERT_TRUE(copy.get() != NULL);
1673 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1674 const ContentInfo* ac = copy->GetContentByName("audio");
1675 const ContentInfo* vc = copy->GetContentByName("video");
1676 ASSERT_TRUE(ac != NULL);
1677 ASSERT_TRUE(vc != NULL);
1678 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1679 const AudioContentDescription* acd_copy =
1680 static_cast<const AudioContentDescription*>(ac->description);
1681 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1682 EXPECT_EQ(1u, acd->first_ssrc());
1683
1684 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1685 const VideoContentDescription* vcd_copy =
1686 static_cast<const VideoContentDescription*>(vc->description);
1687 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
1688 EXPECT_EQ(2u, vcd->first_ssrc());
1689}
1690
1691// The below TestTransportInfoXXX tests create different offers/answers, and
1692// ensure the TransportInfo in the SessionDescription matches what we expect.
1693TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
1694 MediaSessionOptions options;
1695 options.has_audio = true;
1696 TestTransportInfo(true, options, false);
1697}
1698
1699TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
1700 MediaSessionOptions options;
1701 options.has_audio = true;
1702 TestTransportInfo(true, options, true);
1703}
1704
1705TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
1706 MediaSessionOptions options;
1707 options.has_audio = true;
1708 options.has_video = true;
1709 options.data_channel_type = cricket::DCT_RTP;
1710 TestTransportInfo(true, options, false);
1711}
1712
1713TEST_F(MediaSessionDescriptionFactoryTest,
1714 TestTransportInfoOfferMultimediaCurrent) {
1715 MediaSessionOptions options;
1716 options.has_audio = true;
1717 options.has_video = true;
1718 options.data_channel_type = cricket::DCT_RTP;
1719 TestTransportInfo(true, options, true);
1720}
1721
1722TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
1723 MediaSessionOptions options;
1724 options.has_audio = true;
1725 options.has_video = true;
1726 options.data_channel_type = cricket::DCT_RTP;
1727 options.bundle_enabled = true;
1728 TestTransportInfo(true, options, false);
1729}
1730
1731TEST_F(MediaSessionDescriptionFactoryTest,
1732 TestTransportInfoOfferBundleCurrent) {
1733 MediaSessionOptions options;
1734 options.has_audio = true;
1735 options.has_video = true;
1736 options.data_channel_type = cricket::DCT_RTP;
1737 options.bundle_enabled = true;
1738 TestTransportInfo(true, options, true);
1739}
1740
1741TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
1742 MediaSessionOptions options;
1743 options.has_audio = true;
1744 TestTransportInfo(false, options, false);
1745}
1746
1747TEST_F(MediaSessionDescriptionFactoryTest,
1748 TestTransportInfoAnswerAudioCurrent) {
1749 MediaSessionOptions options;
1750 options.has_audio = true;
1751 TestTransportInfo(false, options, true);
1752}
1753
1754TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
1755 MediaSessionOptions options;
1756 options.has_audio = true;
1757 options.has_video = true;
1758 options.data_channel_type = cricket::DCT_RTP;
1759 TestTransportInfo(false, options, false);
1760}
1761
1762TEST_F(MediaSessionDescriptionFactoryTest,
1763 TestTransportInfoAnswerMultimediaCurrent) {
1764 MediaSessionOptions options;
1765 options.has_audio = true;
1766 options.has_video = true;
1767 options.data_channel_type = cricket::DCT_RTP;
1768 TestTransportInfo(false, options, true);
1769}
1770
1771TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
1772 MediaSessionOptions options;
1773 options.has_audio = true;
1774 options.has_video = true;
1775 options.data_channel_type = cricket::DCT_RTP;
1776 options.bundle_enabled = true;
1777 TestTransportInfo(false, options, false);
1778}
1779
1780TEST_F(MediaSessionDescriptionFactoryTest,
1781 TestTransportInfoAnswerBundleCurrent) {
1782 MediaSessionOptions options;
1783 options.has_audio = true;
1784 options.has_video = true;
1785 options.data_channel_type = cricket::DCT_RTP;
1786 options.bundle_enabled = true;
1787 TestTransportInfo(false, options, true);
1788}
1789
1790// Create an offer with bundle enabled and verify the crypto parameters are
1791// the common set of the available cryptos.
1792TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
1793 TestCryptoWithBundle(true);
1794}
1795
1796// Create an answer with bundle enabled and verify the crypto parameters are
1797// the common set of the available cryptos.
1798TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
1799 TestCryptoWithBundle(false);
1800}
1801
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001802// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
1803// DTLS is not enabled locally.
1804TEST_F(MediaSessionDescriptionFactoryTest,
1805 TestOfferDtlsSavpfWithoutDtlsFailed) {
1806 f1_.set_secure(SEC_ENABLED);
1807 f2_.set_secure(SEC_ENABLED);
1808 tdf1_.set_secure(SEC_DISABLED);
1809 tdf2_.set_secure(SEC_DISABLED);
1810
1811 talk_base::scoped_ptr<SessionDescription> offer(
1812 f1_.CreateOffer(MediaSessionOptions(), NULL));
1813 ASSERT_TRUE(offer.get() != NULL);
1814 ContentInfo* offer_content = offer->GetContentByName("audio");
1815 ASSERT_TRUE(offer_content != NULL);
1816 AudioContentDescription* offer_audio_desc =
1817 static_cast<AudioContentDescription*>(offer_content->description);
1818 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
1819
1820 talk_base::scoped_ptr<SessionDescription> answer(
1821 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1822 ASSERT_TRUE(answer != NULL);
1823 ContentInfo* answer_content = answer->GetContentByName("audio");
1824 ASSERT_TRUE(answer_content != NULL);
1825
1826 ASSERT_TRUE(answer_content->rejected);
1827}
1828
1829// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
1830// UDP/TLS/RTP/SAVPF.
1831TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
1832 f1_.set_secure(SEC_ENABLED);
1833 f2_.set_secure(SEC_ENABLED);
1834 tdf1_.set_secure(SEC_ENABLED);
1835 tdf2_.set_secure(SEC_ENABLED);
1836
1837 talk_base::scoped_ptr<SessionDescription> offer(
1838 f1_.CreateOffer(MediaSessionOptions(), NULL));
1839 ASSERT_TRUE(offer.get() != NULL);
1840 ContentInfo* offer_content = offer->GetContentByName("audio");
1841 ASSERT_TRUE(offer_content != NULL);
1842 AudioContentDescription* offer_audio_desc =
1843 static_cast<AudioContentDescription*>(offer_content->description);
1844 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
1845
1846 talk_base::scoped_ptr<SessionDescription> answer(
1847 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1848 ASSERT_TRUE(answer != NULL);
1849
1850 const ContentInfo* answer_content = answer->GetContentByName("audio");
1851 ASSERT_TRUE(answer_content != NULL);
1852 ASSERT_FALSE(answer_content->rejected);
1853
1854 const AudioContentDescription* answer_audio_desc =
1855 static_cast<const AudioContentDescription*>(answer_content->description);
1856 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
1857 answer_audio_desc->protocol());
1858}
1859
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001860// Test that we include both SDES and DTLS in the offer, but only include SDES
1861// in the answer if DTLS isn't negotiated.
1862TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
1863 f1_.set_secure(SEC_ENABLED);
1864 f2_.set_secure(SEC_ENABLED);
1865 tdf1_.set_secure(SEC_ENABLED);
1866 tdf2_.set_secure(SEC_DISABLED);
1867 MediaSessionOptions options;
1868 options.has_audio = true;
1869 options.has_video = true;
1870 talk_base::scoped_ptr<SessionDescription> offer, answer;
1871 const cricket::MediaContentDescription* audio_media_desc;
1872 const cricket::MediaContentDescription* video_media_desc;
1873 const cricket::TransportDescription* audio_trans_desc;
1874 const cricket::TransportDescription* video_trans_desc;
1875
1876 // Generate an offer with SDES and DTLS support.
1877 offer.reset(f1_.CreateOffer(options, NULL));
1878 ASSERT_TRUE(offer.get() != NULL);
1879
1880 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1881 offer->GetContentDescriptionByName("audio"));
1882 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001883 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884 offer->GetContentDescriptionByName("video"));
1885 ASSERT_TRUE(video_media_desc != NULL);
1886 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
1887 EXPECT_EQ(1u, video_media_desc->cryptos().size());
1888
1889 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
1890 ASSERT_TRUE(audio_trans_desc != NULL);
1891 video_trans_desc = offer->GetTransportDescriptionByName("video");
1892 ASSERT_TRUE(video_trans_desc != NULL);
1893 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1894 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
1895
1896 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
1897 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1898 ASSERT_TRUE(answer.get() != NULL);
1899
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001900 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001901 answer->GetContentDescriptionByName("audio"));
1902 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001903 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 answer->GetContentDescriptionByName("video"));
1905 ASSERT_TRUE(video_media_desc != NULL);
1906 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
1907 EXPECT_EQ(1u, video_media_desc->cryptos().size());
1908
1909 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
1910 ASSERT_TRUE(audio_trans_desc != NULL);
1911 video_trans_desc = answer->GetTransportDescriptionByName("video");
1912 ASSERT_TRUE(video_trans_desc != NULL);
1913 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
1914 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
1915
1916 // Enable DTLS; the answer should now only have DTLS support.
1917 tdf2_.set_secure(SEC_ENABLED);
1918 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1919 ASSERT_TRUE(answer.get() != NULL);
1920
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001921 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001922 answer->GetContentDescriptionByName("audio"));
1923 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001924 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001925 answer->GetContentDescriptionByName("video"));
1926 ASSERT_TRUE(video_media_desc != NULL);
1927 EXPECT_TRUE(audio_media_desc->cryptos().empty());
1928 EXPECT_TRUE(video_media_desc->cryptos().empty());
1929 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
1930 audio_media_desc->protocol());
1931 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
1932 video_media_desc->protocol());
1933
1934 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
1935 ASSERT_TRUE(audio_trans_desc != NULL);
1936 video_trans_desc = answer->GetTransportDescriptionByName("video");
1937 ASSERT_TRUE(video_trans_desc != NULL);
1938 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1939 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001940
1941 // Try creating offer again. DTLS enabled now, crypto's should be empty
1942 // in new offer.
1943 offer.reset(f1_.CreateOffer(options, offer.get()));
1944 ASSERT_TRUE(offer.get() != NULL);
1945 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1946 offer->GetContentDescriptionByName("audio"));
1947 ASSERT_TRUE(audio_media_desc != NULL);
1948 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
1949 offer->GetContentDescriptionByName("video"));
1950 ASSERT_TRUE(video_media_desc != NULL);
1951 EXPECT_TRUE(audio_media_desc->cryptos().empty());
1952 EXPECT_TRUE(video_media_desc->cryptos().empty());
1953
1954 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
1955 ASSERT_TRUE(audio_trans_desc != NULL);
1956 video_trans_desc = offer->GetTransportDescriptionByName("video");
1957 ASSERT_TRUE(video_trans_desc != NULL);
1958 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1959 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001960}
1961
1962// Test that an answer can't be created if cryptos are required but the offer is
1963// unsecure.
1964TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
1965 MediaSessionOptions options;
1966 f1_.set_secure(SEC_DISABLED);
1967 tdf1_.set_secure(SEC_DISABLED);
1968 f2_.set_secure(SEC_REQUIRED);
1969 tdf1_.set_secure(SEC_ENABLED);
1970
1971 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options,
1972 NULL));
1973 ASSERT_TRUE(offer.get() != NULL);
1974 talk_base::scoped_ptr<SessionDescription> answer(
1975 f2_.CreateAnswer(offer.get(), options, NULL));
1976 EXPECT_TRUE(answer.get() == NULL);
1977}
1978
1979// Test that we accept a DTLS offer without SDES and create an appropriate
1980// answer.
1981TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
1982 f1_.set_secure(SEC_DISABLED);
1983 f2_.set_secure(SEC_ENABLED);
1984 tdf1_.set_secure(SEC_ENABLED);
1985 tdf2_.set_secure(SEC_ENABLED);
1986 MediaSessionOptions options;
1987 options.has_audio = true;
1988 options.has_video = true;
1989 options.data_channel_type = cricket::DCT_RTP;
1990
1991 talk_base::scoped_ptr<SessionDescription> offer, answer;
1992
1993 // Generate an offer with DTLS but without SDES.
1994 offer.reset(f1_.CreateOffer(options, NULL));
1995 ASSERT_TRUE(offer.get() != NULL);
1996
1997 const AudioContentDescription* audio_offer =
1998 GetFirstAudioContentDescription(offer.get());
1999 ASSERT_TRUE(audio_offer->cryptos().empty());
2000 const VideoContentDescription* video_offer =
2001 GetFirstVideoContentDescription(offer.get());
2002 ASSERT_TRUE(video_offer->cryptos().empty());
2003 const DataContentDescription* data_offer =
2004 GetFirstDataContentDescription(offer.get());
2005 ASSERT_TRUE(data_offer->cryptos().empty());
2006
2007 const cricket::TransportDescription* audio_offer_trans_desc =
2008 offer->GetTransportDescriptionByName("audio");
2009 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2010 const cricket::TransportDescription* video_offer_trans_desc =
2011 offer->GetTransportDescriptionByName("video");
2012 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2013 const cricket::TransportDescription* data_offer_trans_desc =
2014 offer->GetTransportDescriptionByName("data");
2015 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2016
2017 // Generate an answer with DTLS.
2018 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2019 ASSERT_TRUE(answer.get() != NULL);
2020
2021 const cricket::TransportDescription* audio_answer_trans_desc =
2022 answer->GetTransportDescriptionByName("audio");
2023 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2024 const cricket::TransportDescription* video_answer_trans_desc =
2025 answer->GetTransportDescriptionByName("video");
2026 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2027 const cricket::TransportDescription* data_answer_trans_desc =
2028 answer->GetTransportDescriptionByName("data");
2029 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2030}
2031
2032// Verifies if vad_enabled option is set to false, CN codecs are not present in
2033// offer or answer.
2034TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2035 MediaSessionOptions options;
2036 options.has_audio = true;
2037 options.has_video = true;
2038 talk_base::scoped_ptr<SessionDescription> offer(
2039 f1_.CreateOffer(options, NULL));
2040 ASSERT_TRUE(offer.get() != NULL);
2041 const ContentInfo* audio_content = offer->GetContentByName("audio");
2042 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2043
2044 options.vad_enabled = false;
2045 offer.reset(f1_.CreateOffer(options, NULL));
2046 ASSERT_TRUE(offer.get() != NULL);
2047 audio_content = offer->GetContentByName("audio");
2048 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2049 talk_base::scoped_ptr<SessionDescription> answer(
2050 f1_.CreateAnswer(offer.get(), options, NULL));
2051 ASSERT_TRUE(answer.get() != NULL);
2052 audio_content = answer->GetContentByName("audio");
2053 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2054}