3 * Copyright 2004 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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"
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)
48 #define ASSERT_CRYPTO(cd, s, cs) \
49 ASSERT_FALSE(cd->crypto_required()); \
50 ASSERT_EQ(0U, cd->cryptos().size());
53 typedef std::vector<cricket::Candidate> Candidates;
55 using cricket::MediaContentDescription;
56 using cricket::MediaSessionDescriptionFactory;
57 using cricket::MediaSessionOptions;
58 using cricket::MediaType;
59 using cricket::SessionDescription;
60 using cricket::SsrcGroup;
61 using cricket::StreamParams;
62 using cricket::StreamParamsVec;
63 using cricket::TransportDescription;
64 using cricket::TransportDescriptionFactory;
65 using cricket::TransportInfo;
66 using cricket::ContentInfo;
67 using cricket::CryptoParamsVec;
68 using cricket::AudioContentDescription;
69 using cricket::VideoContentDescription;
70 using cricket::DataContentDescription;
71 using cricket::GetFirstAudioContentDescription;
72 using cricket::GetFirstVideoContentDescription;
73 using cricket::GetFirstDataContentDescription;
74 using cricket::kAutoBandwidth;
75 using cricket::AudioCodec;
76 using cricket::VideoCodec;
77 using cricket::DataCodec;
78 using cricket::NS_JINGLE_RTP;
79 using cricket::MEDIA_TYPE_AUDIO;
80 using cricket::MEDIA_TYPE_VIDEO;
81 using cricket::MEDIA_TYPE_DATA;
82 using cricket::RtpHeaderExtension;
83 using cricket::SEC_DISABLED;
84 using cricket::SEC_ENABLED;
85 using cricket::SEC_REQUIRED;
86 using cricket::CS_AES_CM_128_HMAC_SHA1_32;
87 using cricket::CS_AES_CM_128_HMAC_SHA1_80;
89 static 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)
98 static 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),
104 static const AudioCodec kAudioCodecsAnswer[] = {
105 AudioCodec(102, "iLBC", 8000, 13300, 1, 2),
106 AudioCodec(0, "PCMU", 8000, 64000, 1, 1),
109 static const VideoCodec kVideoCodecs1[] = {
110 VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
111 VideoCodec(97, "H264", 320, 200, 30, 1)
114 static const VideoCodec kVideoCodecs2[] = {
115 VideoCodec(126, "H264", 320, 200, 30, 2),
116 VideoCodec(127, "H263", 320, 200, 30, 1)
119 static const VideoCodec kVideoCodecsAnswer[] = {
120 VideoCodec(97, "H264", 320, 200, 30, 2)
123 static const DataCodec kDataCodecs1[] = {
124 DataCodec(98, "binary-data", 2),
125 DataCodec(99, "utf8-text", 1)
128 static const DataCodec kDataCodecs2[] = {
129 DataCodec(126, "binary-data", 2),
130 DataCodec(127, "utf8-text", 1)
133 static const DataCodec kDataCodecsAnswer[] = {
134 DataCodec(98, "binary-data", 2),
135 DataCodec(99, "utf8-text", 1)
138 static const RtpHeaderExtension kAudioRtpExtension1[] = {
139 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
140 RtpHeaderExtension("http://google.com/testing/audio_something", 10),
143 static const RtpHeaderExtension kAudioRtpExtension2[] = {
144 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
145 RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
148 static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
149 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
152 static const RtpHeaderExtension kVideoRtpExtension1[] = {
153 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
154 RtpHeaderExtension("http://google.com/testing/video_something", 15),
157 static const RtpHeaderExtension kVideoRtpExtension2[] = {
158 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
159 RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
162 static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
163 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
166 static const uint32 kFec1Ssrc[] = {10, 11};
167 static const uint32 kFec2Ssrc[] = {20, 21};
168 static const uint32 kFec3Ssrc[] = {30, 31};
170 static const char kMediaStream1[] = "stream_1";
171 static const char kMediaStream2[] = "stream_2";
172 static const char kVideoTrack1[] = "video_1";
173 static const char kVideoTrack2[] = "video_2";
174 static const char kAudioTrack1[] = "audio_1";
175 static const char kAudioTrack2[] = "audio_2";
176 static const char kAudioTrack3[] = "audio_3";
177 static const char kDataTrack1[] = "data_1";
178 static const char kDataTrack2[] = "data_2";
179 static const char kDataTrack3[] = "data_3";
181 class MediaSessionDescriptionFactoryTest : public testing::Test {
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_);
196 bool CompareCryptoParams(const CryptoParamsVec& c1,
197 const CryptoParamsVec& c2) {
198 if (c1.size() != c2.size())
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)
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",
222 TransportDescription("",
224 current_audio_pwd))));
225 EXPECT_TRUE(current_desc->AddTransportInfo(
226 TransportInfo("video",
227 TransportDescription("",
229 current_video_pwd))));
230 EXPECT_TRUE(current_desc->AddTransportInfo(
231 TransportInfo("data",
232 TransportDescription("",
234 current_data_pwd))));
237 desc.reset(f1_.CreateOffer(options, current_desc.get()));
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()));
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);
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());
258 EXPECT_TRUE(ti_audio == NULL);
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);
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);
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());
280 EXPECT_TRUE(ti_video == NULL);
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);
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);
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());
302 EXPECT_TRUE(ti_video == NULL);
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;
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()));
320 options.bundle_enabled = true;
321 ref_desc.reset(f1_.CreateOffer(options, NULL));
322 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
324 ASSERT_TRUE(desc.get() != NULL);
325 const cricket::MediaContentDescription* audio_media_desc =
326 static_cast<const cricket::MediaContentDescription*>(
327 desc.get()->GetContentDescriptionByName("audio"));
328 ASSERT_TRUE(audio_media_desc != NULL);
329 const cricket::MediaContentDescription* video_media_desc =
330 static_cast<const cricket::MediaContentDescription*>(
331 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);
339 // Verify the selected crypto is one from the reference audio
341 const cricket::MediaContentDescription* ref_audio_media_desc =
342 static_cast<const cricket::MediaContentDescription*>(
343 ref_desc.get()->GetContentDescriptionByName("audio"));
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])) {
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);
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());
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 =
391 static_cast<const cricket::AudioContentDescription*>(description);
392 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")
401 MediaSessionDescriptionFactory f1_;
402 MediaSessionDescriptionFactory f2_;
403 TransportDescriptionFactory tdf1_;
404 TransportDescriptionFactory tdf2_;
405 talk_base::FakeSSLIdentity id1_;
406 talk_base::FakeSSLIdentity id2_;
409 // Create a typical audio offer, and ensure it matches what we expect.
410 TEST_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());
431 // Create a typical video offer, and ensure it matches what we expect.
432 TEST_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());
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.
468 TEST_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);
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);
499 // Test creating an updated offer with with bundle, audio, video and data
500 // after an audio only session has been negotiated.
501 TEST_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));
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()));
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);
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());
539 // Create a RTP data offer, and ensure it matches what we expect.
540 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
541 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());
574 // Create an SCTP data offer with bundle without error.
575 TEST_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);
586 // Create an audio, video offer without legacy StreamParams.
587 TEST_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);
604 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
605 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
608 // Create a typical audio answer, and ensure it matches what we expect.
609 TEST_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());
633 // Create a typical video answer, and ensure it matches what we expect.
634 TEST_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());
667 TEST_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());
700 // This test that the media direction is set to send/receive in an answer if
701 // the offer is send receive.
702 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
703 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
706 // This test that the media direction is set to receive only in an answer if
707 // the offer is send only.
708 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
709 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
712 // This test that the media direction is set to send only in an answer if
713 // the offer is recv only.
714 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
715 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
718 // This test that the media direction is set to inactive in an answer if
719 // the offer is inactive.
720 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
721 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
724 // Test that a data content with an unknown protocol is rejected in an answer.
725 TEST_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);
741 talk_base::scoped_ptr<SessionDescription> answer(
742 f2_.CreateAnswer(offer.get(), opts, NULL));
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());
753 // Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
754 TEST_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);
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());
767 talk_base::scoped_ptr<SessionDescription> answer(
768 f2_.CreateAnswer(offer.get(), opts, NULL));
770 const ContentInfo* ac_answer = answer->GetContentByName("audio");
771 ASSERT_TRUE(ac_answer != NULL);
772 EXPECT_FALSE(ac_answer->rejected);
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());
780 // Create a video offer and answer and ensure the RTP header extensions
781 // matches what we expect.
782 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
783 MediaSessionOptions opts;
784 opts.has_video = true;
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));
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));
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());
810 // Create an audio, video, data answer without legacy StreamParams.
811 TEST_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);
834 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
835 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
836 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
839 TEST_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));
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());
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());
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());
876 // Create a typical video answer, and ensure it matches what we expect.
877 TEST_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;
885 talk_base::scoped_ptr<SessionDescription> offer;
886 talk_base::scoped_ptr<SessionDescription> answer;
888 offer_opts.rtcp_mux_enabled = true;
889 answer_opts.rtcp_mux_enabled = true;
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());
906 offer_opts.rtcp_mux_enabled = true;
907 answer_opts.rtcp_mux_enabled = false;
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());
924 offer_opts.rtcp_mux_enabled = false;
925 answer_opts.rtcp_mux_enabled = true;
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());
942 offer_opts.rtcp_mux_enabled = false;
943 answer_opts.rtcp_mux_enabled = false;
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());
961 // Create an audio-only answer to a video offer.
962 TEST_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);
978 // Create an audio-only answer to an offer with data.
979 TEST_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);
995 // Create an answer that rejects the contents which are rejected in the offer.
996 TEST_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);
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.
1032 TEST_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);
1041 f1_.set_secure(SEC_ENABLED);
1042 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
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());
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]);
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);
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);
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
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);
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]);
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);
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()));
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);
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()));
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);
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);
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);
1165 // Create an offer with simulcast video stream.
1166 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1167 MediaSessionOptions opts;
1168 const int num_sim_layers = 3;
1169 opts.AddVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
1170 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1172 ASSERT_TRUE(offer.get() != NULL);
1173 const ContentInfo* vc = offer->GetContentByName("video");
1174 ASSERT_TRUE(vc != NULL);
1175 const VideoContentDescription* vcd =
1176 static_cast<const VideoContentDescription*>(vc->description);
1178 const StreamParamsVec& video_streams = vcd->streams();
1179 ASSERT_EQ(1U, video_streams.size());
1180 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1181 const SsrcGroup* sim_ssrc_group =
1182 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1183 ASSERT_TRUE(sim_ssrc_group != NULL);
1184 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1187 // Create an audio and video answer to a standard video offer with:
1188 // - one video track
1189 // - two audio tracks
1190 // - two data tracks
1191 // and ensure it matches what we expect. Also updates the initial answer by
1192 // adding a new video track and removes one of the audio tracks.
1193 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1194 MediaSessionOptions offer_opts;
1195 offer_opts.has_video = true;
1196 offer_opts.data_channel_type = cricket::DCT_RTP;
1197 f1_.set_secure(SEC_ENABLED);
1198 f2_.set_secure(SEC_ENABLED);
1199 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
1202 MediaSessionOptions opts;
1203 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1204 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1205 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1206 opts.data_channel_type = cricket::DCT_RTP;
1207 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1208 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1210 talk_base::scoped_ptr<SessionDescription>
1211 answer(f2_.CreateAnswer(offer.get(), opts, NULL));
1213 ASSERT_TRUE(answer.get() != NULL);
1214 const ContentInfo* ac = answer->GetContentByName("audio");
1215 const ContentInfo* vc = answer->GetContentByName("video");
1216 const ContentInfo* dc = answer->GetContentByName("data");
1217 ASSERT_TRUE(ac != NULL);
1218 ASSERT_TRUE(vc != NULL);
1219 ASSERT_TRUE(dc != NULL);
1220 const AudioContentDescription* acd =
1221 static_cast<const AudioContentDescription*>(ac->description);
1222 const VideoContentDescription* vcd =
1223 static_cast<const VideoContentDescription*>(vc->description);
1224 const DataContentDescription* dcd =
1225 static_cast<const DataContentDescription*>(dc->description);
1226 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1227 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1228 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1230 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1231 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1233 const StreamParamsVec& audio_streams = acd->streams();
1234 ASSERT_EQ(2U, audio_streams.size());
1235 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1236 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1237 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1238 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1239 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1240 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1241 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1243 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1244 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1246 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1247 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1249 const StreamParamsVec& video_streams = vcd->streams();
1250 ASSERT_EQ(1U, video_streams.size());
1251 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1252 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1253 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1254 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1256 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1257 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1259 const StreamParamsVec& data_streams = dcd->streams();
1260 ASSERT_EQ(2U, data_streams.size());
1261 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1262 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1263 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1264 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1265 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1266 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1267 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1269 EXPECT_EQ(cricket::kDataMaxBandwidth,
1270 dcd->bandwidth()); // default bandwidth (auto)
1271 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1273 // Update the answer. Add a new video track that is not synched to the
1274 // other traacks and remove 1 audio track.
1275 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1276 opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1277 opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
1278 talk_base::scoped_ptr<SessionDescription>
1279 updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
1281 ASSERT_TRUE(updated_answer.get() != NULL);
1282 ac = updated_answer->GetContentByName("audio");
1283 vc = updated_answer->GetContentByName("video");
1284 dc = updated_answer->GetContentByName("data");
1285 ASSERT_TRUE(ac != NULL);
1286 ASSERT_TRUE(vc != NULL);
1287 ASSERT_TRUE(dc != NULL);
1288 const AudioContentDescription* updated_acd =
1289 static_cast<const AudioContentDescription*>(ac->description);
1290 const VideoContentDescription* updated_vcd =
1291 static_cast<const VideoContentDescription*>(vc->description);
1292 const DataContentDescription* updated_dcd =
1293 static_cast<const DataContentDescription*>(dc->description);
1295 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1296 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1297 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1298 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1299 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1300 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1302 EXPECT_EQ(acd->type(), updated_acd->type());
1303 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1304 EXPECT_EQ(vcd->type(), updated_vcd->type());
1305 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1306 EXPECT_EQ(dcd->type(), updated_dcd->type());
1307 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1309 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1310 ASSERT_EQ(1U, updated_audio_streams.size());
1311 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1313 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1314 ASSERT_EQ(2U, updated_video_streams.size());
1315 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1316 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1317 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1319 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1320 ASSERT_EQ(1U, updated_data_streams.size());
1321 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1325 // Create an updated offer after creating an answer to the original offer and
1326 // verify that the codecs that were part of the original answer are not changed
1327 // in the updated offer.
1328 TEST_F(MediaSessionDescriptionFactoryTest,
1329 RespondentCreatesOfferAfterCreatingAnswer) {
1330 MediaSessionOptions opts;
1331 opts.has_audio = true;
1332 opts.has_video = true;
1334 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1335 talk_base::scoped_ptr<SessionDescription> answer(
1336 f2_.CreateAnswer(offer.get(), opts, NULL));
1338 const AudioContentDescription* acd =
1339 GetFirstAudioContentDescription(answer.get());
1340 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1342 const VideoContentDescription* vcd =
1343 GetFirstVideoContentDescription(answer.get());
1344 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1346 talk_base::scoped_ptr<SessionDescription> updated_offer(
1347 f2_.CreateOffer(opts, answer.get()));
1349 // The expected audio codecs are the common audio codecs from the first
1350 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1351 // preference order.
1352 const AudioCodec kUpdatedAudioCodecOffer[] = {
1354 kAudioCodecsAnswer[0],
1355 kAudioCodecsAnswer[1],
1358 // The expected video codecs are the common video codecs from the first
1359 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1360 // preference order.
1361 const VideoCodec kUpdatedVideoCodecOffer[] = {
1362 kVideoCodecsAnswer[0],
1366 const AudioContentDescription* updated_acd =
1367 GetFirstAudioContentDescription(updated_offer.get());
1368 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1370 const VideoContentDescription* updated_vcd =
1371 GetFirstVideoContentDescription(updated_offer.get());
1372 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1375 // Create an updated offer after creating an answer to the original offer and
1376 // verify that the codecs that were part of the original answer are not changed
1377 // in the updated offer. In this test Rtx is enabled.
1378 TEST_F(MediaSessionDescriptionFactoryTest,
1379 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1380 MediaSessionOptions opts;
1381 opts.has_video = true;
1382 opts.has_audio = false;
1383 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1386 rtx_f1.name = cricket::kRtxCodecName;
1388 // This creates rtx for H264 with the payload type |f1_| uses.
1389 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1390 talk_base::ToString<int>(kVideoCodecs1[1].id);
1391 f1_codecs.push_back(rtx_f1);
1392 f1_.set_video_codecs(f1_codecs);
1394 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1397 rtx_f2.name = cricket::kRtxCodecName;
1399 // This creates rtx for H264 with the payload type |f2_| uses.
1400 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1401 talk_base::ToString<int>(kVideoCodecs2[0].id);
1402 f2_codecs.push_back(rtx_f2);
1403 f2_.set_video_codecs(f2_codecs);
1405 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1406 ASSERT_TRUE(offer.get() != NULL);
1407 talk_base::scoped_ptr<SessionDescription> answer(
1408 f2_.CreateAnswer(offer.get(), opts, NULL));
1410 const VideoContentDescription* vcd =
1411 GetFirstVideoContentDescription(answer.get());
1413 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1414 expected_codecs.push_back(rtx_f1);
1416 EXPECT_EQ(expected_codecs, vcd->codecs());
1418 // Now, make sure we get same result, except for the preference order,
1419 // if |f2_| creates an updated offer even though the default payload types
1420 // are different from |f1_|.
1421 expected_codecs[0].preference = f1_codecs[1].preference;
1423 talk_base::scoped_ptr<SessionDescription> updated_offer(
1424 f2_.CreateOffer(opts, answer.get()));
1425 ASSERT_TRUE(updated_offer);
1426 talk_base::scoped_ptr<SessionDescription> updated_answer(
1427 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1429 const VideoContentDescription* updated_vcd =
1430 GetFirstVideoContentDescription(updated_answer.get());
1432 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1435 // Create an updated offer that adds video after creating an audio only answer
1436 // to the original offer. This test verifies that if a video codec and the RTX
1437 // codec have the same default payload type as an audio codec that is already in
1438 // use, the added codecs payload types are changed.
1439 TEST_F(MediaSessionDescriptionFactoryTest,
1440 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1441 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1444 rtx_f1.name = cricket::kRtxCodecName;
1446 // This creates rtx for H264 with the payload type |f1_| uses.
1447 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1448 talk_base::ToString<int>(kVideoCodecs1[1].id);
1449 f1_codecs.push_back(rtx_f1);
1450 f1_.set_video_codecs(f1_codecs);
1452 MediaSessionOptions opts;
1453 opts.has_audio = true;
1454 opts.has_video = false;
1456 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1457 talk_base::scoped_ptr<SessionDescription> answer(
1458 f2_.CreateAnswer(offer.get(), opts, NULL));
1460 const AudioContentDescription* acd =
1461 GetFirstAudioContentDescription(answer.get());
1462 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1464 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1465 // reference be the same as an audio codec that was negotiated in the
1466 // first offer/answer exchange.
1467 opts.has_audio = true;
1468 opts.has_video = true;
1470 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1471 int used_pl_type = acd->codecs()[0].id;
1472 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
1475 rtx_f2.name = cricket::kRtxCodecName;
1476 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1477 talk_base::ToString<int>(used_pl_type);
1478 f2_codecs.push_back(rtx_f2);
1479 f2_.set_video_codecs(f2_codecs);
1481 talk_base::scoped_ptr<SessionDescription> updated_offer(
1482 f2_.CreateOffer(opts, answer.get()));
1483 ASSERT_TRUE(updated_offer);
1484 talk_base::scoped_ptr<SessionDescription> updated_answer(
1485 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1487 const AudioContentDescription* updated_acd =
1488 GetFirstAudioContentDescription(answer.get());
1489 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1491 const VideoContentDescription* updated_vcd =
1492 GetFirstVideoContentDescription(updated_answer.get());
1494 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
1495 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
1496 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1497 EXPECT_NE(used_pl_type, new_h264_pl_type);
1498 VideoCodec rtx = updated_vcd->codecs()[1];
1499 int pt_referenced_by_rtx = talk_base::FromString<int>(
1500 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1501 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1504 // Test that RTX is ignored when there is no associated payload type parameter.
1505 TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1506 MediaSessionOptions opts;
1507 opts.has_video = true;
1508 opts.has_audio = false;
1509 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1512 rtx_f1.name = cricket::kRtxCodecName;
1514 f1_codecs.push_back(rtx_f1);
1515 f1_.set_video_codecs(f1_codecs);
1517 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1520 rtx_f2.name = cricket::kRtxCodecName;
1522 // This creates rtx for H264 with the payload type |f2_| uses.
1523 rtx_f2.SetParam(cricket::kCodecParamAssociatedPayloadType,
1524 talk_base::ToString<int>(kVideoCodecs2[0].id));
1525 f2_codecs.push_back(rtx_f2);
1526 f2_.set_video_codecs(f2_codecs);
1528 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1529 ASSERT_TRUE(offer.get() != NULL);
1530 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1531 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1532 // is possible to test that that RTX is dropped when
1533 // kCodecParamAssociatedPayloadType is missing in the offer.
1534 VideoContentDescription* desc =
1535 static_cast<cricket::VideoContentDescription*>(
1536 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1537 ASSERT_TRUE(desc != NULL);
1538 std::vector<VideoCodec> codecs = desc->codecs();
1539 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1540 iter != codecs.end(); ++iter) {
1541 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1542 iter->params.clear();
1545 desc->set_codecs(codecs);
1547 talk_base::scoped_ptr<SessionDescription> answer(
1548 f2_.CreateAnswer(offer.get(), opts, NULL));
1550 const VideoContentDescription* vcd =
1551 GetFirstVideoContentDescription(answer.get());
1553 for (std::vector<VideoCodec>::const_iterator iter = vcd->codecs().begin();
1554 iter != vcd->codecs().end(); ++iter) {
1555 ASSERT_STRNE(iter->name.c_str(), cricket::kRtxCodecName);
1559 // Create an updated offer after creating an answer to the original offer and
1560 // verify that the RTP header extensions that were part of the original answer
1561 // are not changed in the updated offer.
1562 TEST_F(MediaSessionDescriptionFactoryTest,
1563 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1564 MediaSessionOptions opts;
1565 opts.has_audio = true;
1566 opts.has_video = true;
1568 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1569 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1570 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1571 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1573 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1574 talk_base::scoped_ptr<SessionDescription> answer(
1575 f2_.CreateAnswer(offer.get(), opts, NULL));
1577 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1578 GetFirstAudioContentDescription(
1579 answer.get())->rtp_header_extensions());
1580 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1581 GetFirstVideoContentDescription(
1582 answer.get())->rtp_header_extensions());
1584 talk_base::scoped_ptr<SessionDescription> updated_offer(
1585 f2_.CreateOffer(opts, answer.get()));
1587 // The expected RTP header extensions in the new offer are the resulting
1588 // extensions from the first offer/answer exchange plus the extensions only
1590 // Since the default local extension id |f2_| uses has already been used by
1591 // |f1_| for another extensions, it is changed to 255.
1592 const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1593 kAudioRtpExtensionAnswer[0],
1594 RtpHeaderExtension(kAudioRtpExtension2[1].uri, 255),
1597 // Since the default local extension id |f2_| uses has already been used by
1598 // |f1_| for another extensions, is is changed to 254.
1599 const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1600 kVideoRtpExtensionAnswer[0],
1601 RtpHeaderExtension(kVideoRtpExtension2[1].uri, 254),
1604 const AudioContentDescription* updated_acd =
1605 GetFirstAudioContentDescription(updated_offer.get());
1606 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1607 updated_acd->rtp_header_extensions());
1609 const VideoContentDescription* updated_vcd =
1610 GetFirstVideoContentDescription(updated_offer.get());
1611 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1612 updated_vcd->rtp_header_extensions());
1615 TEST(MediaSessionDescription, CopySessionDescription) {
1616 SessionDescription source;
1617 cricket::ContentGroup group(cricket::CN_AUDIO);
1618 source.AddGroup(group);
1619 AudioContentDescription* acd(new AudioContentDescription());
1620 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1621 acd->AddLegacyStream(1);
1622 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1623 VideoContentDescription* vcd(new VideoContentDescription());
1624 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1625 vcd->AddLegacyStream(2);
1626 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1628 talk_base::scoped_ptr<SessionDescription> copy(source.Copy());
1629 ASSERT_TRUE(copy.get() != NULL);
1630 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1631 const ContentInfo* ac = copy->GetContentByName("audio");
1632 const ContentInfo* vc = copy->GetContentByName("video");
1633 ASSERT_TRUE(ac != NULL);
1634 ASSERT_TRUE(vc != NULL);
1635 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1636 const AudioContentDescription* acd_copy =
1637 static_cast<const AudioContentDescription*>(ac->description);
1638 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1639 EXPECT_EQ(1u, acd->first_ssrc());
1641 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1642 const VideoContentDescription* vcd_copy =
1643 static_cast<const VideoContentDescription*>(vc->description);
1644 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
1645 EXPECT_EQ(2u, vcd->first_ssrc());
1648 // The below TestTransportInfoXXX tests create different offers/answers, and
1649 // ensure the TransportInfo in the SessionDescription matches what we expect.
1650 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
1651 MediaSessionOptions options;
1652 options.has_audio = true;
1653 TestTransportInfo(true, options, false);
1656 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
1657 MediaSessionOptions options;
1658 options.has_audio = true;
1659 TestTransportInfo(true, options, true);
1662 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
1663 MediaSessionOptions options;
1664 options.has_audio = true;
1665 options.has_video = true;
1666 options.data_channel_type = cricket::DCT_RTP;
1667 TestTransportInfo(true, options, false);
1670 TEST_F(MediaSessionDescriptionFactoryTest,
1671 TestTransportInfoOfferMultimediaCurrent) {
1672 MediaSessionOptions options;
1673 options.has_audio = true;
1674 options.has_video = true;
1675 options.data_channel_type = cricket::DCT_RTP;
1676 TestTransportInfo(true, options, true);
1679 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
1680 MediaSessionOptions options;
1681 options.has_audio = true;
1682 options.has_video = true;
1683 options.data_channel_type = cricket::DCT_RTP;
1684 options.bundle_enabled = true;
1685 TestTransportInfo(true, options, false);
1688 TEST_F(MediaSessionDescriptionFactoryTest,
1689 TestTransportInfoOfferBundleCurrent) {
1690 MediaSessionOptions options;
1691 options.has_audio = true;
1692 options.has_video = true;
1693 options.data_channel_type = cricket::DCT_RTP;
1694 options.bundle_enabled = true;
1695 TestTransportInfo(true, options, true);
1698 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
1699 MediaSessionOptions options;
1700 options.has_audio = true;
1701 TestTransportInfo(false, options, false);
1704 TEST_F(MediaSessionDescriptionFactoryTest,
1705 TestTransportInfoAnswerAudioCurrent) {
1706 MediaSessionOptions options;
1707 options.has_audio = true;
1708 TestTransportInfo(false, options, true);
1711 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
1712 MediaSessionOptions options;
1713 options.has_audio = true;
1714 options.has_video = true;
1715 options.data_channel_type = cricket::DCT_RTP;
1716 TestTransportInfo(false, options, false);
1719 TEST_F(MediaSessionDescriptionFactoryTest,
1720 TestTransportInfoAnswerMultimediaCurrent) {
1721 MediaSessionOptions options;
1722 options.has_audio = true;
1723 options.has_video = true;
1724 options.data_channel_type = cricket::DCT_RTP;
1725 TestTransportInfo(false, options, true);
1728 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
1729 MediaSessionOptions options;
1730 options.has_audio = true;
1731 options.has_video = true;
1732 options.data_channel_type = cricket::DCT_RTP;
1733 options.bundle_enabled = true;
1734 TestTransportInfo(false, options, false);
1737 TEST_F(MediaSessionDescriptionFactoryTest,
1738 TestTransportInfoAnswerBundleCurrent) {
1739 MediaSessionOptions options;
1740 options.has_audio = true;
1741 options.has_video = true;
1742 options.data_channel_type = cricket::DCT_RTP;
1743 options.bundle_enabled = true;
1744 TestTransportInfo(false, options, true);
1747 // Create an offer with bundle enabled and verify the crypto parameters are
1748 // the common set of the available cryptos.
1749 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
1750 TestCryptoWithBundle(true);
1753 // Create an answer with bundle enabled and verify the crypto parameters are
1754 // the common set of the available cryptos.
1755 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
1756 TestCryptoWithBundle(false);
1759 // Test that we include both SDES and DTLS in the offer, but only include SDES
1760 // in the answer if DTLS isn't negotiated.
1761 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
1762 f1_.set_secure(SEC_ENABLED);
1763 f2_.set_secure(SEC_ENABLED);
1764 tdf1_.set_secure(SEC_ENABLED);
1765 tdf2_.set_secure(SEC_DISABLED);
1766 MediaSessionOptions options;
1767 options.has_audio = true;
1768 options.has_video = true;
1769 talk_base::scoped_ptr<SessionDescription> offer, answer;
1770 const cricket::MediaContentDescription* audio_media_desc;
1771 const cricket::MediaContentDescription* video_media_desc;
1772 const cricket::TransportDescription* audio_trans_desc;
1773 const cricket::TransportDescription* video_trans_desc;
1775 // Generate an offer with SDES and DTLS support.
1776 offer.reset(f1_.CreateOffer(options, NULL));
1777 ASSERT_TRUE(offer.get() != NULL);
1779 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1780 offer->GetContentDescriptionByName("audio"));
1781 ASSERT_TRUE(audio_media_desc != NULL);
1782 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
1783 offer->GetContentDescriptionByName("video"));
1784 ASSERT_TRUE(video_media_desc != NULL);
1785 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
1786 EXPECT_EQ(1u, video_media_desc->cryptos().size());
1788 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
1789 ASSERT_TRUE(audio_trans_desc != NULL);
1790 video_trans_desc = offer->GetTransportDescriptionByName("video");
1791 ASSERT_TRUE(video_trans_desc != NULL);
1792 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1793 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
1795 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
1796 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1797 ASSERT_TRUE(answer.get() != NULL);
1799 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1800 answer->GetContentDescriptionByName("audio"));
1801 ASSERT_TRUE(audio_media_desc != NULL);
1802 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
1803 answer->GetContentDescriptionByName("video"));
1804 ASSERT_TRUE(video_media_desc != NULL);
1805 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
1806 EXPECT_EQ(1u, video_media_desc->cryptos().size());
1808 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
1809 ASSERT_TRUE(audio_trans_desc != NULL);
1810 video_trans_desc = answer->GetTransportDescriptionByName("video");
1811 ASSERT_TRUE(video_trans_desc != NULL);
1812 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
1813 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
1815 // Enable DTLS; the answer should now only have DTLS support.
1816 tdf2_.set_secure(SEC_ENABLED);
1817 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1818 ASSERT_TRUE(answer.get() != NULL);
1820 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1821 answer->GetContentDescriptionByName("audio"));
1822 ASSERT_TRUE(audio_media_desc != NULL);
1823 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
1824 answer->GetContentDescriptionByName("video"));
1825 ASSERT_TRUE(video_media_desc != NULL);
1826 EXPECT_TRUE(audio_media_desc->cryptos().empty());
1827 EXPECT_TRUE(video_media_desc->cryptos().empty());
1828 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
1829 audio_media_desc->protocol());
1830 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
1831 video_media_desc->protocol());
1833 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
1834 ASSERT_TRUE(audio_trans_desc != NULL);
1835 video_trans_desc = answer->GetTransportDescriptionByName("video");
1836 ASSERT_TRUE(video_trans_desc != NULL);
1837 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1838 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
1840 // Try creating offer again. DTLS enabled now, crypto's should be empty
1842 offer.reset(f1_.CreateOffer(options, offer.get()));
1843 ASSERT_TRUE(offer.get() != NULL);
1844 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1845 offer->GetContentDescriptionByName("audio"));
1846 ASSERT_TRUE(audio_media_desc != NULL);
1847 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
1848 offer->GetContentDescriptionByName("video"));
1849 ASSERT_TRUE(video_media_desc != NULL);
1850 EXPECT_TRUE(audio_media_desc->cryptos().empty());
1851 EXPECT_TRUE(video_media_desc->cryptos().empty());
1853 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
1854 ASSERT_TRUE(audio_trans_desc != NULL);
1855 video_trans_desc = offer->GetTransportDescriptionByName("video");
1856 ASSERT_TRUE(video_trans_desc != NULL);
1857 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1858 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
1861 // Test that an answer can't be created if cryptos are required but the offer is
1863 TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
1864 MediaSessionOptions options;
1865 f1_.set_secure(SEC_DISABLED);
1866 tdf1_.set_secure(SEC_DISABLED);
1867 f2_.set_secure(SEC_REQUIRED);
1868 tdf1_.set_secure(SEC_ENABLED);
1870 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options,
1872 ASSERT_TRUE(offer.get() != NULL);
1873 talk_base::scoped_ptr<SessionDescription> answer(
1874 f2_.CreateAnswer(offer.get(), options, NULL));
1875 EXPECT_TRUE(answer.get() == NULL);
1878 // Test that we accept a DTLS offer without SDES and create an appropriate
1880 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
1881 f1_.set_secure(SEC_DISABLED);
1882 f2_.set_secure(SEC_ENABLED);
1883 tdf1_.set_secure(SEC_ENABLED);
1884 tdf2_.set_secure(SEC_ENABLED);
1885 MediaSessionOptions options;
1886 options.has_audio = true;
1887 options.has_video = true;
1888 options.data_channel_type = cricket::DCT_RTP;
1890 talk_base::scoped_ptr<SessionDescription> offer, answer;
1892 // Generate an offer with DTLS but without SDES.
1893 offer.reset(f1_.CreateOffer(options, NULL));
1894 ASSERT_TRUE(offer.get() != NULL);
1896 const AudioContentDescription* audio_offer =
1897 GetFirstAudioContentDescription(offer.get());
1898 ASSERT_TRUE(audio_offer->cryptos().empty());
1899 const VideoContentDescription* video_offer =
1900 GetFirstVideoContentDescription(offer.get());
1901 ASSERT_TRUE(video_offer->cryptos().empty());
1902 const DataContentDescription* data_offer =
1903 GetFirstDataContentDescription(offer.get());
1904 ASSERT_TRUE(data_offer->cryptos().empty());
1906 const cricket::TransportDescription* audio_offer_trans_desc =
1907 offer->GetTransportDescriptionByName("audio");
1908 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
1909 const cricket::TransportDescription* video_offer_trans_desc =
1910 offer->GetTransportDescriptionByName("video");
1911 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
1912 const cricket::TransportDescription* data_offer_trans_desc =
1913 offer->GetTransportDescriptionByName("data");
1914 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
1916 // Generate an answer with DTLS.
1917 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1918 ASSERT_TRUE(answer.get() != NULL);
1920 const cricket::TransportDescription* audio_answer_trans_desc =
1921 answer->GetTransportDescriptionByName("audio");
1922 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
1923 const cricket::TransportDescription* video_answer_trans_desc =
1924 answer->GetTransportDescriptionByName("video");
1925 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
1926 const cricket::TransportDescription* data_answer_trans_desc =
1927 answer->GetTransportDescriptionByName("data");
1928 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
1931 // Verifies if vad_enabled option is set to false, CN codecs are not present in
1933 TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
1934 MediaSessionOptions options;
1935 options.has_audio = true;
1936 options.has_video = true;
1937 talk_base::scoped_ptr<SessionDescription> offer(
1938 f1_.CreateOffer(options, NULL));
1939 ASSERT_TRUE(offer.get() != NULL);
1940 const ContentInfo* audio_content = offer->GetContentByName("audio");
1941 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
1943 options.vad_enabled = false;
1944 offer.reset(f1_.CreateOffer(options, NULL));
1945 ASSERT_TRUE(offer.get() != NULL);
1946 audio_content = offer->GetContentByName("audio");
1947 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
1948 talk_base::scoped_ptr<SessionDescription> answer(
1949 f1_.CreateAnswer(offer.get(), options, NULL));
1950 ASSERT_TRUE(answer.get() != NULL);
1951 audio_content = answer->GetContentByName("audio");
1952 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));