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