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