1 /* 2 * libjingle 3 * Copyright 2012, 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 "talk/app/webrtc/audiotrack.h" 29 #include "talk/app/webrtc/jsepicecandidate.h" 30 #include "talk/app/webrtc/jsepsessiondescription.h" 31 #include "talk/app/webrtc/mediastreamsignaling.h" 32 #include "talk/app/webrtc/streamcollection.h" 33 #include "talk/app/webrtc/videotrack.h" 34 #include "talk/app/webrtc/test/fakeconstraints.h" 35 #include "talk/app/webrtc/test/fakedtlsidentityservice.h" 36 #include "talk/app/webrtc/test/fakemediastreamsignaling.h" 37 #include "talk/app/webrtc/webrtcsession.h" 38 #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" 39 #include "talk/base/fakenetwork.h" 40 #include "talk/base/firewallsocketserver.h" 41 #include "talk/base/gunit.h" 42 #include "talk/base/logging.h" 43 #include "talk/base/network.h" 44 #include "talk/base/physicalsocketserver.h" 45 #include "talk/base/ssladapter.h" 46 #include "talk/base/sslstreamadapter.h" 47 #include "talk/base/stringutils.h" 48 #include "talk/base/thread.h" 49 #include "talk/base/virtualsocketserver.h" 50 #include "talk/media/base/fakemediaengine.h" 51 #include "talk/media/base/fakevideorenderer.h" 52 #include "talk/media/base/mediachannel.h" 53 #include "talk/media/devices/fakedevicemanager.h" 54 #include "talk/p2p/base/stunserver.h" 55 #include "talk/p2p/base/teststunserver.h" 56 #include "talk/p2p/client/basicportallocator.h" 57 #include "talk/session/media/channelmanager.h" 58 #include "talk/session/media/mediasession.h" 59 60 #define MAYBE_SKIP_TEST(feature) \ 61 if (!(feature())) { \ 62 LOG(LS_INFO) << "Feature disabled... skipping"; \ 63 return; \ 64 } 65 66 using cricket::BaseSession; 67 using cricket::DF_PLAY; 68 using cricket::DF_SEND; 69 using cricket::FakeVoiceMediaChannel; 70 using cricket::NS_GINGLE_P2P; 71 using cricket::NS_JINGLE_ICE_UDP; 72 using cricket::TransportInfo; 73 using talk_base::SocketAddress; 74 using talk_base::scoped_ptr; 75 using webrtc::CreateSessionDescription; 76 using webrtc::CreateSessionDescriptionObserver; 77 using webrtc::CreateSessionDescriptionRequest; 78 using webrtc::DTLSIdentityRequestObserver; 79 using webrtc::DTLSIdentityServiceInterface; 80 using webrtc::FakeConstraints; 81 using webrtc::IceCandidateCollection; 82 using webrtc::JsepIceCandidate; 83 using webrtc::JsepSessionDescription; 84 using webrtc::PeerConnectionFactoryInterface; 85 using webrtc::PeerConnectionInterface; 86 using webrtc::SessionDescriptionInterface; 87 using webrtc::StreamCollection; 88 using webrtc::WebRtcSession; 89 using webrtc::kBundleWithoutRtcpMux; 90 using webrtc::kMlineMismatch; 91 using webrtc::kPushDownAnswerTDFailed; 92 using webrtc::kPushDownPranswerTDFailed; 93 using webrtc::kSdpWithoutCrypto; 94 using webrtc::kSdpWithoutIceUfragPwd; 95 using webrtc::kSdpWithoutSdesAndDtlsDisabled; 96 using webrtc::kSessionError; 97 using webrtc::kSetLocalSdpFailed; 98 using webrtc::kSetRemoteSdpFailed; 99 100 static const int kClientAddrPort = 0; 101 static const char kClientAddrHost1[] = "11.11.11.11"; 102 static const char kClientAddrHost2[] = "22.22.22.22"; 103 static const char kStunAddrHost[] = "99.99.99.1"; 104 105 static const char kSessionVersion[] = "1"; 106 107 // Media index of candidates belonging to the first media content. 108 static const int kMediaContentIndex0 = 0; 109 static const char kMediaContentName0[] = "audio"; 110 111 // Media index of candidates belonging to the second media content. 112 static const int kMediaContentIndex1 = 1; 113 static const char kMediaContentName1[] = "video"; 114 115 static const int kIceCandidatesTimeout = 10000; 116 117 static const char kFakeDtlsFingerprint[] = 118 "BB:CD:72:F7:2F:D0:BA:43:F3:68:B1:0C:23:72:B6:4A:" 119 "0F:DE:34:06:BC:E0:FE:01:BC:73:C8:6D:F4:65:D5:24"; 120 121 // Add some extra |newlines| to the |message| after |line|. 122 static void InjectAfter(const std::string& line, 123 const std::string& newlines, 124 std::string* message) { 125 const std::string tmp = line + newlines; 126 talk_base::replace_substrs(line.c_str(), line.length(), 127 tmp.c_str(), tmp.length(), message); 128 } 129 130 class MockIceObserver : public webrtc::IceObserver { 131 public: 132 MockIceObserver() 133 : oncandidatesready_(false), 134 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew), 135 ice_gathering_state_(PeerConnectionInterface::kIceGatheringNew) { 136 } 137 138 virtual void OnIceConnectionChange( 139 PeerConnectionInterface::IceConnectionState new_state) { 140 ice_connection_state_ = new_state; 141 } 142 virtual void OnIceGatheringChange( 143 PeerConnectionInterface::IceGatheringState new_state) { 144 // We can never transition back to "new". 145 EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, new_state); 146 ice_gathering_state_ = new_state; 147 148 // oncandidatesready_ really means "ICE gathering is complete". 149 // This if statement ensures that this value remains correct when we 150 // transition from kIceGatheringComplete to kIceGatheringGathering. 151 if (new_state == PeerConnectionInterface::kIceGatheringGathering) { 152 oncandidatesready_ = false; 153 } 154 } 155 156 // Found a new candidate. 157 virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { 158 switch (candidate->sdp_mline_index()) { 159 case kMediaContentIndex0: 160 mline_0_candidates_.push_back(candidate->candidate()); 161 break; 162 case kMediaContentIndex1: 163 mline_1_candidates_.push_back(candidate->candidate()); 164 break; 165 default: 166 ASSERT(false); 167 } 168 169 // The ICE gathering state should always be Gathering when a candidate is 170 // received (or possibly Completed in the case of the final candidate). 171 EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, ice_gathering_state_); 172 } 173 174 // TODO(bemasc): Remove this once callers transition to OnIceGatheringChange. 175 virtual void OnIceComplete() { 176 EXPECT_FALSE(oncandidatesready_); 177 oncandidatesready_ = true; 178 179 // OnIceGatheringChange(IceGatheringCompleted) and OnIceComplete() should 180 // be called approximately simultaneously. For ease of testing, this 181 // check additionally requires that they be called in the above order. 182 EXPECT_EQ(PeerConnectionInterface::kIceGatheringComplete, 183 ice_gathering_state_); 184 } 185 186 bool oncandidatesready_; 187 std::vector<cricket::Candidate> mline_0_candidates_; 188 std::vector<cricket::Candidate> mline_1_candidates_; 189 PeerConnectionInterface::IceConnectionState ice_connection_state_; 190 PeerConnectionInterface::IceGatheringState ice_gathering_state_; 191 }; 192 193 class WebRtcSessionForTest : public webrtc::WebRtcSession { 194 public: 195 WebRtcSessionForTest(cricket::ChannelManager* cmgr, 196 talk_base::Thread* signaling_thread, 197 talk_base::Thread* worker_thread, 198 cricket::PortAllocator* port_allocator, 199 webrtc::IceObserver* ice_observer, 200 webrtc::MediaStreamSignaling* mediastream_signaling) 201 : WebRtcSession(cmgr, signaling_thread, worker_thread, port_allocator, 202 mediastream_signaling) { 203 RegisterIceObserver(ice_observer); 204 } 205 virtual ~WebRtcSessionForTest() {} 206 207 using cricket::BaseSession::GetTransportProxy; 208 using webrtc::WebRtcSession::SetAudioPlayout; 209 using webrtc::WebRtcSession::SetAudioSend; 210 using webrtc::WebRtcSession::SetCaptureDevice; 211 using webrtc::WebRtcSession::SetVideoPlayout; 212 using webrtc::WebRtcSession::SetVideoSend; 213 }; 214 215 class WebRtcSessionCreateSDPObserverForTest 216 : public talk_base::RefCountedObject<CreateSessionDescriptionObserver> { 217 public: 218 enum State { 219 kInit, 220 kFailed, 221 kSucceeded, 222 }; 223 WebRtcSessionCreateSDPObserverForTest() : state_(kInit) {} 224 225 // CreateSessionDescriptionObserver implementation. 226 virtual void OnSuccess(SessionDescriptionInterface* desc) { 227 description_.reset(desc); 228 state_ = kSucceeded; 229 } 230 virtual void OnFailure(const std::string& error) { 231 state_ = kFailed; 232 } 233 234 SessionDescriptionInterface* description() { return description_.get(); } 235 236 SessionDescriptionInterface* ReleaseDescription() { 237 return description_.release(); 238 } 239 240 State state() const { return state_; } 241 242 protected: 243 ~WebRtcSessionCreateSDPObserverForTest() {} 244 245 private: 246 talk_base::scoped_ptr<SessionDescriptionInterface> description_; 247 State state_; 248 }; 249 250 class FakeAudioRenderer : public cricket::AudioRenderer { 251 public: 252 FakeAudioRenderer() : channel_id_(-1) {} 253 254 virtual void AddChannel(int channel_id) OVERRIDE { 255 ASSERT(channel_id_ == -1); 256 channel_id_ = channel_id; 257 } 258 virtual void RemoveChannel(int channel_id) OVERRIDE { 259 ASSERT(channel_id == channel_id_); 260 channel_id_ = -1; 261 } 262 263 int channel_id() const { return channel_id_; } 264 private: 265 int channel_id_; 266 }; 267 268 class WebRtcSessionTest : public testing::Test { 269 protected: 270 // TODO Investigate why ChannelManager crashes, if it's created 271 // after stun_server. 272 WebRtcSessionTest() 273 : media_engine_(new cricket::FakeMediaEngine()), 274 data_engine_(new cricket::FakeDataEngine()), 275 device_manager_(new cricket::FakeDeviceManager()), 276 channel_manager_(new cricket::ChannelManager( 277 media_engine_, data_engine_, device_manager_, 278 new cricket::CaptureManager(), talk_base::Thread::Current())), 279 tdesc_factory_(new cricket::TransportDescriptionFactory()), 280 desc_factory_(new cricket::MediaSessionDescriptionFactory( 281 channel_manager_.get(), tdesc_factory_.get())), 282 pss_(new talk_base::PhysicalSocketServer), 283 vss_(new talk_base::VirtualSocketServer(pss_.get())), 284 fss_(new talk_base::FirewallSocketServer(vss_.get())), 285 ss_scope_(fss_.get()), 286 stun_socket_addr_(talk_base::SocketAddress(kStunAddrHost, 287 cricket::STUN_SERVER_PORT)), 288 stun_server_(talk_base::Thread::Current(), stun_socket_addr_), 289 allocator_(&network_manager_, stun_socket_addr_, 290 SocketAddress(), SocketAddress(), SocketAddress()), 291 mediastream_signaling_(channel_manager_.get()) { 292 tdesc_factory_->set_protocol(cricket::ICEPROTO_HYBRID); 293 allocator_.set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | 294 cricket::PORTALLOCATOR_DISABLE_RELAY | 295 cricket::PORTALLOCATOR_ENABLE_BUNDLE); 296 EXPECT_TRUE(channel_manager_->Init()); 297 desc_factory_->set_add_legacy_streams(false); 298 } 299 300 static void SetUpTestCase() { 301 talk_base::InitializeSSL(); 302 } 303 304 static void TearDownTestCase() { 305 talk_base::CleanupSSL(); 306 } 307 308 void AddInterface(const SocketAddress& addr) { 309 network_manager_.AddInterface(addr); 310 } 311 312 void Init(DTLSIdentityServiceInterface* identity_service) { 313 ASSERT_TRUE(session_.get() == NULL); 314 session_.reset(new WebRtcSessionForTest( 315 channel_manager_.get(), talk_base::Thread::Current(), 316 talk_base::Thread::Current(), &allocator_, 317 &observer_, 318 &mediastream_signaling_)); 319 320 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew, 321 observer_.ice_connection_state_); 322 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew, 323 observer_.ice_gathering_state_); 324 325 EXPECT_TRUE(session_->Initialize(options_, constraints_.get(), 326 identity_service)); 327 } 328 329 void InitWithDtmfCodec() { 330 // Add kTelephoneEventCodec for dtmf test. 331 const cricket::AudioCodec kTelephoneEventCodec( 332 106, "telephone-event", 8000, 0, 1, 0); 333 std::vector<cricket::AudioCodec> codecs; 334 codecs.push_back(kTelephoneEventCodec); 335 media_engine_->SetAudioCodecs(codecs); 336 desc_factory_->set_audio_codecs(codecs); 337 Init(NULL); 338 } 339 340 void InitWithDtls(bool identity_request_should_fail = false) { 341 FakeIdentityService* identity_service = new FakeIdentityService(); 342 identity_service->set_should_fail(identity_request_should_fail); 343 Init(identity_service); 344 } 345 346 // Creates a local offer and applies it. Starts ice. 347 // Call mediastream_signaling_.UseOptionsWithStreamX() before this function 348 // to decide which streams to create. 349 void InitiateCall() { 350 SessionDescriptionInterface* offer = CreateOffer(NULL); 351 SetLocalDescriptionWithoutError(offer); 352 EXPECT_TRUE_WAIT(PeerConnectionInterface::kIceGatheringNew != 353 observer_.ice_gathering_state_, 354 kIceCandidatesTimeout); 355 } 356 357 SessionDescriptionInterface* CreateOffer( 358 const webrtc::MediaConstraintsInterface* constraints) { 359 talk_base::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> 360 observer = new WebRtcSessionCreateSDPObserverForTest(); 361 session_->CreateOffer(observer, constraints); 362 EXPECT_TRUE_WAIT( 363 observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit, 364 2000); 365 return observer->ReleaseDescription(); 366 } 367 368 SessionDescriptionInterface* CreateAnswer( 369 const webrtc::MediaConstraintsInterface* constraints) { 370 talk_base::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> observer 371 = new WebRtcSessionCreateSDPObserverForTest(); 372 session_->CreateAnswer(observer, constraints); 373 EXPECT_TRUE_WAIT( 374 observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit, 375 2000); 376 return observer->ReleaseDescription(); 377 } 378 379 bool ChannelsExist() const { 380 return (session_->voice_channel() != NULL && 381 session_->video_channel() != NULL); 382 } 383 384 void CheckTransportChannels() const { 385 EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 1) != NULL); 386 EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 2) != NULL); 387 EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 1) != NULL); 388 EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 2) != NULL); 389 } 390 391 void VerifyCryptoParams(const cricket::SessionDescription* sdp) { 392 ASSERT_TRUE(session_.get() != NULL); 393 const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp); 394 ASSERT_TRUE(content != NULL); 395 const cricket::AudioContentDescription* audio_content = 396 static_cast<const cricket::AudioContentDescription*>( 397 content->description); 398 ASSERT_TRUE(audio_content != NULL); 399 ASSERT_EQ(1U, audio_content->cryptos().size()); 400 ASSERT_EQ(47U, audio_content->cryptos()[0].key_params.size()); 401 ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", 402 audio_content->cryptos()[0].cipher_suite); 403 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), 404 audio_content->protocol()); 405 406 content = cricket::GetFirstVideoContent(sdp); 407 ASSERT_TRUE(content != NULL); 408 const cricket::VideoContentDescription* video_content = 409 static_cast<const cricket::VideoContentDescription*>( 410 content->description); 411 ASSERT_TRUE(video_content != NULL); 412 ASSERT_EQ(1U, video_content->cryptos().size()); 413 ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", 414 video_content->cryptos()[0].cipher_suite); 415 ASSERT_EQ(47U, video_content->cryptos()[0].key_params.size()); 416 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), 417 video_content->protocol()); 418 } 419 420 void VerifyNoCryptoParams(const cricket::SessionDescription* sdp, bool dtls) { 421 const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp); 422 ASSERT_TRUE(content != NULL); 423 const cricket::AudioContentDescription* audio_content = 424 static_cast<const cricket::AudioContentDescription*>( 425 content->description); 426 ASSERT_TRUE(audio_content != NULL); 427 ASSERT_EQ(0U, audio_content->cryptos().size()); 428 429 content = cricket::GetFirstVideoContent(sdp); 430 ASSERT_TRUE(content != NULL); 431 const cricket::VideoContentDescription* video_content = 432 static_cast<const cricket::VideoContentDescription*>( 433 content->description); 434 ASSERT_TRUE(video_content != NULL); 435 ASSERT_EQ(0U, video_content->cryptos().size()); 436 437 if (dtls) { 438 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), 439 audio_content->protocol()); 440 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), 441 video_content->protocol()); 442 } else { 443 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), 444 audio_content->protocol()); 445 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), 446 video_content->protocol()); 447 } 448 } 449 450 // Set the internal fake description factories to do DTLS-SRTP. 451 void SetFactoryDtlsSrtp() { 452 desc_factory_->set_secure(cricket::SEC_ENABLED); 453 std::string identity_name = "WebRTC" + 454 talk_base::ToString(talk_base::CreateRandomId()); 455 identity_.reset(talk_base::SSLIdentity::Generate(identity_name)); 456 tdesc_factory_->set_identity(identity_.get()); 457 tdesc_factory_->set_secure(cricket::SEC_REQUIRED); 458 } 459 460 void VerifyFingerprintStatus(const cricket::SessionDescription* sdp, 461 bool expected) { 462 const TransportInfo* audio = sdp->GetTransportInfoByName("audio"); 463 ASSERT_TRUE(audio != NULL); 464 ASSERT_EQ(expected, audio->description.identity_fingerprint.get() != NULL); 465 const TransportInfo* video = sdp->GetTransportInfoByName("video"); 466 ASSERT_TRUE(video != NULL); 467 ASSERT_EQ(expected, video->description.identity_fingerprint.get() != NULL); 468 } 469 470 void VerifyAnswerFromNonCryptoOffer() { 471 // Create a SDP without Crypto. 472 cricket::MediaSessionOptions options; 473 options.has_video = true; 474 JsepSessionDescription* offer( 475 CreateRemoteOffer(options, cricket::SEC_DISABLED)); 476 ASSERT_TRUE(offer != NULL); 477 VerifyNoCryptoParams(offer->description(), false); 478 SetRemoteDescriptionExpectError("Called with a SDP without crypto enabled", 479 offer); 480 const webrtc::SessionDescriptionInterface* answer = CreateAnswer(NULL); 481 // Answer should be NULL as no crypto params in offer. 482 ASSERT_TRUE(answer == NULL); 483 } 484 485 void VerifyAnswerFromCryptoOffer() { 486 cricket::MediaSessionOptions options; 487 options.has_video = true; 488 options.bundle_enabled = true; 489 scoped_ptr<JsepSessionDescription> offer( 490 CreateRemoteOffer(options, cricket::SEC_REQUIRED)); 491 ASSERT_TRUE(offer.get() != NULL); 492 VerifyCryptoParams(offer->description()); 493 SetRemoteDescriptionWithoutError(offer.release()); 494 scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); 495 ASSERT_TRUE(answer.get() != NULL); 496 VerifyCryptoParams(answer->description()); 497 } 498 499 void CompareIceUfragAndPassword(const cricket::SessionDescription* desc1, 500 const cricket::SessionDescription* desc2, 501 bool expect_equal) { 502 if (desc1->contents().size() != desc2->contents().size()) { 503 EXPECT_FALSE(expect_equal); 504 return; 505 } 506 507 const cricket::ContentInfos& contents = desc1->contents(); 508 cricket::ContentInfos::const_iterator it = contents.begin(); 509 510 for (; it != contents.end(); ++it) { 511 const cricket::TransportDescription* transport_desc1 = 512 desc1->GetTransportDescriptionByName(it->name); 513 const cricket::TransportDescription* transport_desc2 = 514 desc2->GetTransportDescriptionByName(it->name); 515 if (!transport_desc1 || !transport_desc2) { 516 EXPECT_FALSE(expect_equal); 517 return; 518 } 519 if (transport_desc1->ice_pwd != transport_desc2->ice_pwd || 520 transport_desc1->ice_ufrag != transport_desc2->ice_ufrag) { 521 EXPECT_FALSE(expect_equal); 522 return; 523 } 524 } 525 EXPECT_TRUE(expect_equal); 526 } 527 528 void RemoveIceUfragPwdLines(const SessionDescriptionInterface* current_desc, 529 std::string *sdp) { 530 const cricket::SessionDescription* desc = current_desc->description(); 531 EXPECT_TRUE(current_desc->ToString(sdp)); 532 533 const cricket::ContentInfos& contents = desc->contents(); 534 cricket::ContentInfos::const_iterator it = contents.begin(); 535 // Replace ufrag and pwd lines with empty strings. 536 for (; it != contents.end(); ++it) { 537 const cricket::TransportDescription* transport_desc = 538 desc->GetTransportDescriptionByName(it->name); 539 std::string ufrag_line = "a=ice-ufrag:" + transport_desc->ice_ufrag 540 + "\r\n"; 541 std::string pwd_line = "a=ice-pwd:" + transport_desc->ice_pwd 542 + "\r\n"; 543 talk_base::replace_substrs(ufrag_line.c_str(), ufrag_line.length(), 544 "", 0, 545 sdp); 546 talk_base::replace_substrs(pwd_line.c_str(), pwd_line.length(), 547 "", 0, 548 sdp); 549 } 550 } 551 552 // Creates a remote offer and and applies it as a remote description, 553 // creates a local answer and applies is as a local description. 554 // Call mediastream_signaling_.UseOptionsWithStreamX() before this function 555 // to decide which local and remote streams to create. 556 void CreateAndSetRemoteOfferAndLocalAnswer() { 557 SessionDescriptionInterface* offer = CreateRemoteOffer(); 558 SetRemoteDescriptionWithoutError(offer); 559 SessionDescriptionInterface* answer = CreateAnswer(NULL); 560 SetLocalDescriptionWithoutError(answer); 561 } 562 void SetLocalDescriptionWithoutError(SessionDescriptionInterface* desc) { 563 EXPECT_TRUE(session_->SetLocalDescription(desc, NULL)); 564 } 565 void SetLocalDescriptionExpectState(SessionDescriptionInterface* desc, 566 BaseSession::State expected_state) { 567 SetLocalDescriptionWithoutError(desc); 568 EXPECT_EQ(expected_state, session_->state()); 569 } 570 void SetLocalDescriptionExpectError(const std::string& expected_error, 571 SessionDescriptionInterface* desc) { 572 std::string error; 573 EXPECT_FALSE(session_->SetLocalDescription(desc, &error)); 574 EXPECT_NE(std::string::npos, error.find(kSetLocalSdpFailed)); 575 EXPECT_NE(std::string::npos, error.find(expected_error)); 576 } 577 void SetRemoteDescriptionWithoutError(SessionDescriptionInterface* desc) { 578 EXPECT_TRUE(session_->SetRemoteDescription(desc, NULL)); 579 } 580 void SetRemoteDescriptionExpectState(SessionDescriptionInterface* desc, 581 BaseSession::State expected_state) { 582 SetRemoteDescriptionWithoutError(desc); 583 EXPECT_EQ(expected_state, session_->state()); 584 } 585 void SetRemoteDescriptionExpectError(const std::string& expected_error, 586 SessionDescriptionInterface* desc) { 587 std::string error; 588 EXPECT_FALSE(session_->SetRemoteDescription(desc, &error)); 589 EXPECT_NE(std::string::npos, error.find(kSetRemoteSdpFailed)); 590 EXPECT_NE(std::string::npos, error.find(expected_error)); 591 } 592 593 void CreateCryptoOfferAndNonCryptoAnswer(SessionDescriptionInterface** offer, 594 SessionDescriptionInterface** nocrypto_answer) { 595 // Create a SDP without Crypto. 596 cricket::MediaSessionOptions options; 597 options.has_video = true; 598 options.bundle_enabled = true; 599 *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED); 600 ASSERT_TRUE(*offer != NULL); 601 VerifyCryptoParams((*offer)->description()); 602 603 *nocrypto_answer = CreateRemoteAnswer(*offer, options, 604 cricket::SEC_DISABLED); 605 EXPECT_TRUE(*nocrypto_answer != NULL); 606 } 607 608 JsepSessionDescription* CreateRemoteOfferWithVersion( 609 cricket::MediaSessionOptions options, 610 cricket::SecurePolicy secure_policy, 611 const std::string& session_version, 612 const SessionDescriptionInterface* current_desc) { 613 std::string session_id = talk_base::ToString(talk_base::CreateRandomId64()); 614 const cricket::SessionDescription* cricket_desc = NULL; 615 if (current_desc) { 616 cricket_desc = current_desc->description(); 617 session_id = current_desc->session_id(); 618 } 619 620 desc_factory_->set_secure(secure_policy); 621 JsepSessionDescription* offer( 622 new JsepSessionDescription(JsepSessionDescription::kOffer)); 623 if (!offer->Initialize(desc_factory_->CreateOffer(options, cricket_desc), 624 session_id, session_version)) { 625 delete offer; 626 offer = NULL; 627 } 628 return offer; 629 } 630 JsepSessionDescription* CreateRemoteOffer( 631 cricket::MediaSessionOptions options) { 632 return CreateRemoteOfferWithVersion(options, cricket::SEC_ENABLED, 633 kSessionVersion, NULL); 634 } 635 JsepSessionDescription* CreateRemoteOffer( 636 cricket::MediaSessionOptions options, cricket::SecurePolicy policy) { 637 return CreateRemoteOfferWithVersion(options, policy, kSessionVersion, NULL); 638 } 639 JsepSessionDescription* CreateRemoteOffer( 640 cricket::MediaSessionOptions options, 641 const SessionDescriptionInterface* current_desc) { 642 return CreateRemoteOfferWithVersion(options, cricket::SEC_ENABLED, 643 kSessionVersion, current_desc); 644 } 645 646 JsepSessionDescription* CreateRemoteOfferWithSctpPort( 647 const char* sctp_stream_name, int new_port, 648 cricket::MediaSessionOptions options) { 649 options.data_channel_type = cricket::DCT_SCTP; 650 options.AddStream(cricket::MEDIA_TYPE_DATA, "datachannel", 651 sctp_stream_name); 652 return ChangeSDPSctpPort(new_port, CreateRemoteOffer(options)); 653 } 654 655 // Takes ownership of offer_basis (and deletes it). 656 JsepSessionDescription* ChangeSDPSctpPort( 657 int new_port, webrtc::SessionDescriptionInterface *offer_basis) { 658 // Stringify the input SDP, swap the 5000 for 'new_port' and create a new 659 // SessionDescription from the mutated string. 660 const char* default_port_str = "5000"; 661 char new_port_str[16]; 662 talk_base::sprintfn(new_port_str, sizeof(new_port_str), "%d", new_port); 663 std::string offer_str; 664 offer_basis->ToString(&offer_str); 665 talk_base::replace_substrs(default_port_str, strlen(default_port_str), 666 new_port_str, strlen(new_port_str), 667 &offer_str); 668 JsepSessionDescription* offer = new JsepSessionDescription( 669 offer_basis->type()); 670 delete offer_basis; 671 offer->Initialize(offer_str, NULL); 672 return offer; 673 } 674 675 // Create a remote offer. Call mediastream_signaling_.UseOptionsWithStreamX() 676 // before this function to decide which streams to create. 677 JsepSessionDescription* CreateRemoteOffer() { 678 cricket::MediaSessionOptions options; 679 mediastream_signaling_.GetOptionsForAnswer(NULL, &options); 680 return CreateRemoteOffer(options, session_->remote_description()); 681 } 682 683 JsepSessionDescription* CreateRemoteAnswer( 684 const SessionDescriptionInterface* offer, 685 cricket::MediaSessionOptions options, 686 cricket::SecurePolicy policy) { 687 desc_factory_->set_secure(policy); 688 const std::string session_id = 689 talk_base::ToString(talk_base::CreateRandomId64()); 690 JsepSessionDescription* answer( 691 new JsepSessionDescription(JsepSessionDescription::kAnswer)); 692 if (!answer->Initialize(desc_factory_->CreateAnswer(offer->description(), 693 options, NULL), 694 session_id, kSessionVersion)) { 695 delete answer; 696 answer = NULL; 697 } 698 return answer; 699 } 700 701 JsepSessionDescription* CreateRemoteAnswer( 702 const SessionDescriptionInterface* offer, 703 cricket::MediaSessionOptions options) { 704 return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED); 705 } 706 707 // Creates an answer session description with streams based on 708 // |mediastream_signaling_|. Call 709 // mediastream_signaling_.UseOptionsWithStreamX() before this function 710 // to decide which streams to create. 711 JsepSessionDescription* CreateRemoteAnswer( 712 const SessionDescriptionInterface* offer) { 713 cricket::MediaSessionOptions options; 714 mediastream_signaling_.GetOptionsForAnswer(NULL, &options); 715 return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED); 716 } 717 718 void TestSessionCandidatesWithBundleRtcpMux(bool bundle, bool rtcp_mux) { 719 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 720 Init(NULL); 721 mediastream_signaling_.SendAudioVideoStream1(); 722 FakeConstraints constraints; 723 constraints.SetMandatoryUseRtpMux(bundle); 724 SessionDescriptionInterface* offer = CreateOffer(&constraints); 725 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer 726 // and answer. 727 SetLocalDescriptionWithoutError(offer); 728 729 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 730 CreateRemoteAnswer(session_->local_description())); 731 std::string sdp; 732 EXPECT_TRUE(answer->ToString(&sdp)); 733 734 size_t expected_candidate_num = 2; 735 if (!rtcp_mux) { 736 // If rtcp_mux is enabled we should expect 4 candidates - host and srflex 737 // for rtp and rtcp. 738 expected_candidate_num = 4; 739 // Disable rtcp-mux from the answer 740 const std::string kRtcpMux = "a=rtcp-mux"; 741 const std::string kXRtcpMux = "a=xrtcp-mux"; 742 talk_base::replace_substrs(kRtcpMux.c_str(), kRtcpMux.length(), 743 kXRtcpMux.c_str(), kXRtcpMux.length(), 744 &sdp); 745 } 746 747 SessionDescriptionInterface* new_answer = CreateSessionDescription( 748 JsepSessionDescription::kAnswer, sdp, NULL); 749 750 // SetRemoteDescription to enable rtcp mux. 751 SetRemoteDescriptionWithoutError(new_answer); 752 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); 753 EXPECT_EQ(expected_candidate_num, observer_.mline_0_candidates_.size()); 754 EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size()); 755 for (size_t i = 0; i < observer_.mline_0_candidates_.size(); ++i) { 756 cricket::Candidate c0 = observer_.mline_0_candidates_[i]; 757 cricket::Candidate c1 = observer_.mline_1_candidates_[i]; 758 if (bundle) { 759 EXPECT_TRUE(c0.IsEquivalent(c1)); 760 } else { 761 EXPECT_FALSE(c0.IsEquivalent(c1)); 762 } 763 } 764 } 765 // Tests that we can only send DTMF when the dtmf codec is supported. 766 void TestCanInsertDtmf(bool can) { 767 if (can) { 768 InitWithDtmfCodec(); 769 } else { 770 Init(NULL); 771 } 772 mediastream_signaling_.SendAudioVideoStream1(); 773 CreateAndSetRemoteOfferAndLocalAnswer(); 774 EXPECT_FALSE(session_->CanInsertDtmf("")); 775 EXPECT_EQ(can, session_->CanInsertDtmf(kAudioTrack1)); 776 } 777 778 // The method sets up a call from the session to itself, in a loopback 779 // arrangement. It also uses a firewall rule to create a temporary 780 // disconnection. This code is placed as a method so that it can be invoked 781 // by multiple tests with different allocators (e.g. with and without BUNDLE). 782 // While running the call, this method also checks if the session goes through 783 // the correct sequence of ICE states when a connection is established, 784 // broken, and re-established. 785 // The Connection state should go: 786 // New -> Checking -> Connected -> Disconnected -> Connected. 787 // The Gathering state should go: New -> Gathering -> Completed. 788 void TestLoopbackCall() { 789 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 790 Init(NULL); 791 mediastream_signaling_.SendAudioVideoStream1(); 792 SessionDescriptionInterface* offer = CreateOffer(NULL); 793 794 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew, 795 observer_.ice_gathering_state_); 796 SetLocalDescriptionWithoutError(offer); 797 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew, 798 observer_.ice_connection_state_); 799 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringGathering, 800 observer_.ice_gathering_state_, 801 kIceCandidatesTimeout); 802 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); 803 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete, 804 observer_.ice_gathering_state_, 805 kIceCandidatesTimeout); 806 807 std::string sdp; 808 offer->ToString(&sdp); 809 SessionDescriptionInterface* desc = 810 webrtc::CreateSessionDescription(JsepSessionDescription::kAnswer, sdp); 811 ASSERT_TRUE(desc != NULL); 812 SetRemoteDescriptionWithoutError(desc); 813 814 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking, 815 observer_.ice_connection_state_, 816 kIceCandidatesTimeout); 817 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected, 818 observer_.ice_connection_state_, 819 kIceCandidatesTimeout); 820 // TODO(bemasc): EXPECT(Completed) once the details are standardized. 821 822 // Adding firewall rule to block ping requests, which should cause 823 // transport channel failure. 824 fss_->AddRule(false, 825 talk_base::FP_ANY, 826 talk_base::FD_ANY, 827 talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 828 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected, 829 observer_.ice_connection_state_, 830 kIceCandidatesTimeout); 831 832 // Clearing the rules, session should move back to completed state. 833 fss_->ClearRules(); 834 // Session is automatically calling OnSignalingReady after creation of 835 // new portallocator session which will allocate new set of candidates. 836 837 // TODO(bemasc): Change this to Completed once the details are standardized. 838 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected, 839 observer_.ice_connection_state_, 840 kIceCandidatesTimeout); 841 } 842 843 void VerifyTransportType(const std::string& content_name, 844 cricket::TransportProtocol protocol) { 845 const cricket::Transport* transport = session_->GetTransport(content_name); 846 ASSERT_TRUE(transport != NULL); 847 EXPECT_EQ(protocol, transport->protocol()); 848 } 849 850 // Adds CN codecs to FakeMediaEngine and MediaDescriptionFactory. 851 void AddCNCodecs() { 852 const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1, 0); 853 const cricket::AudioCodec kCNCodec2(103, "CN", 16000, 0, 1, 0); 854 855 // Add kCNCodec for dtmf test. 856 std::vector<cricket::AudioCodec> codecs = media_engine_->audio_codecs();; 857 codecs.push_back(kCNCodec1); 858 codecs.push_back(kCNCodec2); 859 media_engine_->SetAudioCodecs(codecs); 860 desc_factory_->set_audio_codecs(codecs); 861 } 862 863 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) { 864 const cricket::ContentDescription* description = content->description; 865 ASSERT(description != NULL); 866 const cricket::AudioContentDescription* audio_content_desc = 867 static_cast<const cricket::AudioContentDescription*>(description); 868 ASSERT(audio_content_desc != NULL); 869 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) { 870 if (audio_content_desc->codecs()[i].name == "CN") 871 return false; 872 } 873 return true; 874 } 875 876 void SetLocalDescriptionWithDataChannel() { 877 webrtc::DataChannelInit dci; 878 dci.reliable = false; 879 session_->CreateDataChannel("datachannel", &dci); 880 SessionDescriptionInterface* offer = CreateOffer(NULL); 881 SetLocalDescriptionWithoutError(offer); 882 } 883 884 void VerifyMultipleAsyncCreateDescription( 885 bool success, CreateSessionDescriptionRequest::Type type) { 886 InitWithDtls(!success); 887 888 if (type == CreateSessionDescriptionRequest::kAnswer) { 889 cricket::MediaSessionOptions options; 890 scoped_ptr<JsepSessionDescription> offer( 891 CreateRemoteOffer(options, cricket::SEC_REQUIRED)); 892 ASSERT_TRUE(offer.get() != NULL); 893 SetRemoteDescriptionWithoutError(offer.release()); 894 } 895 896 const int kNumber = 3; 897 talk_base::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> 898 observers[kNumber]; 899 for (int i = 0; i < kNumber; ++i) { 900 observers[i] = new WebRtcSessionCreateSDPObserverForTest(); 901 if (type == CreateSessionDescriptionRequest::kOffer) { 902 session_->CreateOffer(observers[i], NULL); 903 } else { 904 session_->CreateAnswer(observers[i], NULL); 905 } 906 } 907 908 WebRtcSessionCreateSDPObserverForTest::State expected_state = 909 success ? WebRtcSessionCreateSDPObserverForTest::kSucceeded : 910 WebRtcSessionCreateSDPObserverForTest::kFailed; 911 912 for (int i = 0; i < kNumber; ++i) { 913 EXPECT_EQ_WAIT(expected_state, observers[i]->state(), 1000); 914 if (success) { 915 EXPECT_TRUE(observers[i]->description() != NULL); 916 } else { 917 EXPECT_TRUE(observers[i]->description() == NULL); 918 } 919 } 920 } 921 922 cricket::FakeMediaEngine* media_engine_; 923 cricket::FakeDataEngine* data_engine_; 924 cricket::FakeDeviceManager* device_manager_; 925 talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_; 926 talk_base::scoped_ptr<cricket::TransportDescriptionFactory> tdesc_factory_; 927 talk_base::scoped_ptr<talk_base::SSLIdentity> identity_; 928 talk_base::scoped_ptr<cricket::MediaSessionDescriptionFactory> desc_factory_; 929 talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_; 930 talk_base::scoped_ptr<talk_base::VirtualSocketServer> vss_; 931 talk_base::scoped_ptr<talk_base::FirewallSocketServer> fss_; 932 talk_base::SocketServerScope ss_scope_; 933 talk_base::SocketAddress stun_socket_addr_; 934 cricket::TestStunServer stun_server_; 935 talk_base::FakeNetworkManager network_manager_; 936 cricket::BasicPortAllocator allocator_; 937 PeerConnectionFactoryInterface::Options options_; 938 talk_base::scoped_ptr<FakeConstraints> constraints_; 939 FakeMediaStreamSignaling mediastream_signaling_; 940 talk_base::scoped_ptr<WebRtcSessionForTest> session_; 941 MockIceObserver observer_; 942 cricket::FakeVideoMediaChannel* video_channel_; 943 cricket::FakeVoiceMediaChannel* voice_channel_; 944 }; 945 946 TEST_F(WebRtcSessionTest, TestInitialize) { 947 Init(NULL); 948 } 949 950 TEST_F(WebRtcSessionTest, TestInitializeWithDtls) { 951 InitWithDtls(); 952 } 953 954 // Verifies that WebRtcSession uses SEC_REQUIRED by default. 955 TEST_F(WebRtcSessionTest, TestDefaultSetSecurePolicy) { 956 Init(NULL); 957 EXPECT_EQ(cricket::SEC_REQUIRED, session_->SecurePolicy()); 958 } 959 960 TEST_F(WebRtcSessionTest, TestSessionCandidates) { 961 TestSessionCandidatesWithBundleRtcpMux(false, false); 962 } 963 964 // Below test cases (TestSessionCandidatesWith*) verify the candidates gathered 965 // with rtcp-mux and/or bundle. 966 TEST_F(WebRtcSessionTest, TestSessionCandidatesWithRtcpMux) { 967 TestSessionCandidatesWithBundleRtcpMux(false, true); 968 } 969 970 TEST_F(WebRtcSessionTest, TestSessionCandidatesWithBundleRtcpMux) { 971 TestSessionCandidatesWithBundleRtcpMux(true, true); 972 } 973 974 TEST_F(WebRtcSessionTest, TestMultihomeCandidates) { 975 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 976 AddInterface(talk_base::SocketAddress(kClientAddrHost2, kClientAddrPort)); 977 Init(NULL); 978 mediastream_signaling_.SendAudioVideoStream1(); 979 InitiateCall(); 980 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); 981 EXPECT_EQ(8u, observer_.mline_0_candidates_.size()); 982 EXPECT_EQ(8u, observer_.mline_1_candidates_.size()); 983 } 984 985 TEST_F(WebRtcSessionTest, TestStunError) { 986 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 987 AddInterface(talk_base::SocketAddress(kClientAddrHost2, kClientAddrPort)); 988 fss_->AddRule(false, 989 talk_base::FP_UDP, 990 talk_base::FD_ANY, 991 talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 992 Init(NULL); 993 mediastream_signaling_.SendAudioVideoStream1(); 994 InitiateCall(); 995 // Since kClientAddrHost1 is blocked, not expecting stun candidates for it. 996 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); 997 EXPECT_EQ(6u, observer_.mline_0_candidates_.size()); 998 EXPECT_EQ(6u, observer_.mline_1_candidates_.size()); 999 } 1000 1001 // Test creating offers and receive answers and make sure the 1002 // media engine creates the expected send and receive streams. 1003 TEST_F(WebRtcSessionTest, TestCreateOfferReceiveAnswer) { 1004 Init(NULL); 1005 mediastream_signaling_.SendAudioVideoStream1(); 1006 SessionDescriptionInterface* offer = CreateOffer(NULL); 1007 const std::string session_id_orig = offer->session_id(); 1008 const std::string session_version_orig = offer->session_version(); 1009 SetLocalDescriptionWithoutError(offer); 1010 1011 mediastream_signaling_.SendAudioVideoStream2(); 1012 SessionDescriptionInterface* answer = 1013 CreateRemoteAnswer(session_->local_description()); 1014 SetRemoteDescriptionWithoutError(answer); 1015 1016 video_channel_ = media_engine_->GetVideoChannel(0); 1017 voice_channel_ = media_engine_->GetVoiceChannel(0); 1018 1019 ASSERT_EQ(1u, video_channel_->recv_streams().size()); 1020 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); 1021 1022 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 1023 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); 1024 1025 ASSERT_EQ(1u, video_channel_->send_streams().size()); 1026 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id); 1027 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 1028 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id); 1029 1030 // Create new offer without send streams. 1031 mediastream_signaling_.SendNothing(); 1032 offer = CreateOffer(NULL); 1033 1034 // Verify the session id is the same and the session version is 1035 // increased. 1036 EXPECT_EQ(session_id_orig, offer->session_id()); 1037 EXPECT_LT(talk_base::FromString<uint64>(session_version_orig), 1038 talk_base::FromString<uint64>(offer->session_version())); 1039 1040 SetLocalDescriptionWithoutError(offer); 1041 1042 mediastream_signaling_.SendAudioVideoStream2(); 1043 answer = CreateRemoteAnswer(session_->local_description()); 1044 SetRemoteDescriptionWithoutError(answer); 1045 1046 EXPECT_EQ(0u, video_channel_->send_streams().size()); 1047 EXPECT_EQ(0u, voice_channel_->send_streams().size()); 1048 1049 // Make sure the receive streams have not changed. 1050 ASSERT_EQ(1u, video_channel_->recv_streams().size()); 1051 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); 1052 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 1053 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); 1054 } 1055 1056 // Test receiving offers and creating answers and make sure the 1057 // media engine creates the expected send and receive streams. 1058 TEST_F(WebRtcSessionTest, TestReceiveOfferCreateAnswer) { 1059 Init(NULL); 1060 mediastream_signaling_.SendAudioVideoStream2(); 1061 SessionDescriptionInterface* offer = CreateOffer(NULL); 1062 SetRemoteDescriptionWithoutError(offer); 1063 1064 mediastream_signaling_.SendAudioVideoStream1(); 1065 SessionDescriptionInterface* answer = CreateAnswer(NULL); 1066 SetLocalDescriptionWithoutError(answer); 1067 1068 const std::string session_id_orig = answer->session_id(); 1069 const std::string session_version_orig = answer->session_version(); 1070 1071 video_channel_ = media_engine_->GetVideoChannel(0); 1072 voice_channel_ = media_engine_->GetVoiceChannel(0); 1073 1074 ASSERT_EQ(1u, video_channel_->recv_streams().size()); 1075 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); 1076 1077 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 1078 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); 1079 1080 ASSERT_EQ(1u, video_channel_->send_streams().size()); 1081 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id); 1082 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 1083 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id); 1084 1085 mediastream_signaling_.SendAudioVideoStream1And2(); 1086 offer = CreateOffer(NULL); 1087 SetRemoteDescriptionWithoutError(offer); 1088 1089 // Answer by turning off all send streams. 1090 mediastream_signaling_.SendNothing(); 1091 answer = CreateAnswer(NULL); 1092 1093 // Verify the session id is the same and the session version is 1094 // increased. 1095 EXPECT_EQ(session_id_orig, answer->session_id()); 1096 EXPECT_LT(talk_base::FromString<uint64>(session_version_orig), 1097 talk_base::FromString<uint64>(answer->session_version())); 1098 SetLocalDescriptionWithoutError(answer); 1099 1100 ASSERT_EQ(2u, video_channel_->recv_streams().size()); 1101 EXPECT_TRUE(kVideoTrack1 == video_channel_->recv_streams()[0].id); 1102 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[1].id); 1103 ASSERT_EQ(2u, voice_channel_->recv_streams().size()); 1104 EXPECT_TRUE(kAudioTrack1 == voice_channel_->recv_streams()[0].id); 1105 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[1].id); 1106 1107 // Make sure we have no send streams. 1108 EXPECT_EQ(0u, video_channel_->send_streams().size()); 1109 EXPECT_EQ(0u, voice_channel_->send_streams().size()); 1110 } 1111 1112 // Test we will return fail when apply an offer that doesn't have 1113 // crypto enabled. 1114 TEST_F(WebRtcSessionTest, SetNonCryptoOffer) { 1115 Init(NULL); 1116 cricket::MediaSessionOptions options; 1117 options.has_video = true; 1118 JsepSessionDescription* offer = CreateRemoteOffer( 1119 options, cricket::SEC_DISABLED); 1120 ASSERT_TRUE(offer != NULL); 1121 VerifyNoCryptoParams(offer->description(), false); 1122 // SetRemoteDescription and SetLocalDescription will take the ownership of 1123 // the offer. 1124 SetRemoteDescriptionExpectError(kSdpWithoutCrypto, offer); 1125 offer = CreateRemoteOffer(options, cricket::SEC_DISABLED); 1126 ASSERT_TRUE(offer != NULL); 1127 SetLocalDescriptionExpectError(kSdpWithoutCrypto, offer); 1128 } 1129 1130 // Test we will return fail when apply an answer that doesn't have 1131 // crypto enabled. 1132 TEST_F(WebRtcSessionTest, SetLocalNonCryptoAnswer) { 1133 Init(NULL); 1134 SessionDescriptionInterface* offer = NULL; 1135 SessionDescriptionInterface* answer = NULL; 1136 CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer); 1137 // SetRemoteDescription and SetLocalDescription will take the ownership of 1138 // the offer. 1139 SetRemoteDescriptionWithoutError(offer); 1140 SetLocalDescriptionExpectError(kSdpWithoutCrypto, answer); 1141 } 1142 1143 // Test we will return fail when apply an answer that doesn't have 1144 // crypto enabled. 1145 TEST_F(WebRtcSessionTest, SetRemoteNonCryptoAnswer) { 1146 Init(NULL); 1147 SessionDescriptionInterface* offer = NULL; 1148 SessionDescriptionInterface* answer = NULL; 1149 CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer); 1150 // SetRemoteDescription and SetLocalDescription will take the ownership of 1151 // the offer. 1152 SetLocalDescriptionWithoutError(offer); 1153 SetRemoteDescriptionExpectError(kSdpWithoutCrypto, answer); 1154 } 1155 1156 // Test that we can create and set an offer with a DTLS fingerprint. 1157 TEST_F(WebRtcSessionTest, CreateSetDtlsOffer) { 1158 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 1159 InitWithDtls(); 1160 mediastream_signaling_.SendAudioVideoStream1(); 1161 SessionDescriptionInterface* offer = CreateOffer(NULL); 1162 ASSERT_TRUE(offer != NULL); 1163 VerifyFingerprintStatus(offer->description(), true); 1164 // SetLocalDescription will take the ownership of the offer. 1165 SetLocalDescriptionWithoutError(offer); 1166 } 1167 1168 // Test that we can process an offer with a DTLS fingerprint 1169 // and that we return an answer with a fingerprint. 1170 TEST_F(WebRtcSessionTest, ReceiveDtlsOfferCreateAnswer) { 1171 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 1172 InitWithDtls(); 1173 SetFactoryDtlsSrtp(); 1174 cricket::MediaSessionOptions options; 1175 options.has_video = true; 1176 JsepSessionDescription* offer = CreateRemoteOffer(options); 1177 ASSERT_TRUE(offer != NULL); 1178 VerifyFingerprintStatus(offer->description(), true); 1179 1180 // SetRemoteDescription will take the ownership of the offer. 1181 SetRemoteDescriptionWithoutError(offer); 1182 1183 // Verify that we get a crypto fingerprint in the answer. 1184 SessionDescriptionInterface* answer = CreateAnswer(NULL); 1185 ASSERT_TRUE(answer != NULL); 1186 VerifyFingerprintStatus(answer->description(), true); 1187 // Check that we don't have an a=crypto line in the answer. 1188 VerifyNoCryptoParams(answer->description(), true); 1189 1190 // Now set the local description, which should work, even without a=crypto. 1191 SetLocalDescriptionWithoutError(answer); 1192 } 1193 1194 // Test that even if we support DTLS, if the other side didn't offer a 1195 // fingerprint, we don't either. 1196 TEST_F(WebRtcSessionTest, ReceiveNoDtlsOfferCreateAnswer) { 1197 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 1198 InitWithDtls(); 1199 cricket::MediaSessionOptions options; 1200 options.has_video = true; 1201 JsepSessionDescription* offer = CreateRemoteOffer( 1202 options, cricket::SEC_REQUIRED); 1203 ASSERT_TRUE(offer != NULL); 1204 VerifyFingerprintStatus(offer->description(), false); 1205 1206 // SetRemoteDescription will take the ownership of 1207 // the offer. 1208 SetRemoteDescriptionWithoutError(offer); 1209 1210 // Verify that we don't get a crypto fingerprint in the answer. 1211 SessionDescriptionInterface* answer = CreateAnswer(NULL); 1212 ASSERT_TRUE(answer != NULL); 1213 VerifyFingerprintStatus(answer->description(), false); 1214 1215 // Now set the local description. 1216 SetLocalDescriptionWithoutError(answer); 1217 } 1218 1219 TEST_F(WebRtcSessionTest, TestSetLocalOfferTwice) { 1220 Init(NULL); 1221 mediastream_signaling_.SendNothing(); 1222 // SetLocalDescription take ownership of offer. 1223 SessionDescriptionInterface* offer = CreateOffer(NULL); 1224 SetLocalDescriptionWithoutError(offer); 1225 1226 // SetLocalDescription take ownership of offer. 1227 SessionDescriptionInterface* offer2 = CreateOffer(NULL); 1228 SetLocalDescriptionWithoutError(offer2); 1229 } 1230 1231 TEST_F(WebRtcSessionTest, TestSetRemoteOfferTwice) { 1232 Init(NULL); 1233 mediastream_signaling_.SendNothing(); 1234 // SetLocalDescription take ownership of offer. 1235 SessionDescriptionInterface* offer = CreateOffer(NULL); 1236 SetRemoteDescriptionWithoutError(offer); 1237 1238 SessionDescriptionInterface* offer2 = CreateOffer(NULL); 1239 SetRemoteDescriptionWithoutError(offer2); 1240 } 1241 1242 TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteOffer) { 1243 Init(NULL); 1244 mediastream_signaling_.SendNothing(); 1245 SessionDescriptionInterface* offer = CreateOffer(NULL); 1246 SetLocalDescriptionWithoutError(offer); 1247 offer = CreateOffer(NULL); 1248 SetRemoteDescriptionExpectError( 1249 "Called with type in wrong state, type: offer state: STATE_SENTINITIATE", 1250 offer); 1251 } 1252 1253 TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) { 1254 Init(NULL); 1255 mediastream_signaling_.SendNothing(); 1256 SessionDescriptionInterface* offer = CreateOffer(NULL); 1257 SetRemoteDescriptionWithoutError(offer); 1258 offer = CreateOffer(NULL); 1259 SetLocalDescriptionExpectError( 1260 "Called with type in wrong state, type: " 1261 "offer state: STATE_RECEIVEDINITIATE", 1262 offer); 1263 } 1264 1265 TEST_F(WebRtcSessionTest, TestSetLocalPrAnswer) { 1266 Init(NULL); 1267 mediastream_signaling_.SendNothing(); 1268 SessionDescriptionInterface* offer = CreateRemoteOffer(); 1269 SetRemoteDescriptionExpectState(offer, BaseSession::STATE_RECEIVEDINITIATE); 1270 1271 JsepSessionDescription* pranswer = static_cast<JsepSessionDescription*>( 1272 CreateAnswer(NULL)); 1273 pranswer->set_type(SessionDescriptionInterface::kPrAnswer); 1274 SetLocalDescriptionExpectState(pranswer, BaseSession::STATE_SENTPRACCEPT); 1275 1276 mediastream_signaling_.SendAudioVideoStream1(); 1277 JsepSessionDescription* pranswer2 = static_cast<JsepSessionDescription*>( 1278 CreateAnswer(NULL)); 1279 pranswer2->set_type(SessionDescriptionInterface::kPrAnswer); 1280 1281 SetLocalDescriptionExpectState(pranswer2, BaseSession::STATE_SENTPRACCEPT); 1282 1283 mediastream_signaling_.SendAudioVideoStream2(); 1284 SessionDescriptionInterface* answer = CreateAnswer(NULL); 1285 SetLocalDescriptionExpectState(answer, BaseSession::STATE_SENTACCEPT); 1286 } 1287 1288 TEST_F(WebRtcSessionTest, TestSetRemotePrAnswer) { 1289 Init(NULL); 1290 mediastream_signaling_.SendNothing(); 1291 SessionDescriptionInterface* offer = CreateOffer(NULL); 1292 SetLocalDescriptionExpectState(offer, BaseSession::STATE_SENTINITIATE); 1293 1294 JsepSessionDescription* pranswer = 1295 CreateRemoteAnswer(session_->local_description()); 1296 pranswer->set_type(SessionDescriptionInterface::kPrAnswer); 1297 1298 SetRemoteDescriptionExpectState(pranswer, 1299 BaseSession::STATE_RECEIVEDPRACCEPT); 1300 1301 mediastream_signaling_.SendAudioVideoStream1(); 1302 JsepSessionDescription* pranswer2 = 1303 CreateRemoteAnswer(session_->local_description()); 1304 pranswer2->set_type(SessionDescriptionInterface::kPrAnswer); 1305 1306 SetRemoteDescriptionExpectState(pranswer2, 1307 BaseSession::STATE_RECEIVEDPRACCEPT); 1308 1309 mediastream_signaling_.SendAudioVideoStream2(); 1310 SessionDescriptionInterface* answer = 1311 CreateRemoteAnswer(session_->local_description()); 1312 SetRemoteDescriptionExpectState(answer, BaseSession::STATE_RECEIVEDACCEPT); 1313 } 1314 1315 TEST_F(WebRtcSessionTest, TestSetLocalAnswerWithoutOffer) { 1316 Init(NULL); 1317 mediastream_signaling_.SendNothing(); 1318 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1319 CreateOffer(NULL)); 1320 SessionDescriptionInterface* answer = 1321 CreateRemoteAnswer(offer.get()); 1322 SetLocalDescriptionExpectError( 1323 "Called with type in wrong state, type: answer state: STATE_INIT", 1324 answer); 1325 } 1326 1327 TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) { 1328 Init(NULL); 1329 mediastream_signaling_.SendNothing(); 1330 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1331 CreateOffer(NULL)); 1332 SessionDescriptionInterface* answer = 1333 CreateRemoteAnswer(offer.get()); 1334 SetRemoteDescriptionExpectError( 1335 "Called with type in wrong state, type: answer state: STATE_INIT", 1336 answer); 1337 } 1338 1339 TEST_F(WebRtcSessionTest, TestAddRemoteCandidate) { 1340 Init(NULL); 1341 mediastream_signaling_.SendAudioVideoStream1(); 1342 1343 cricket::Candidate candidate; 1344 candidate.set_component(1); 1345 JsepIceCandidate ice_candidate1(kMediaContentName0, 0, candidate); 1346 1347 // Fail since we have not set a offer description. 1348 EXPECT_FALSE(session_->ProcessIceMessage(&ice_candidate1)); 1349 1350 SessionDescriptionInterface* offer = CreateOffer(NULL); 1351 SetLocalDescriptionWithoutError(offer); 1352 // Candidate should be allowed to add before remote description. 1353 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1)); 1354 candidate.set_component(2); 1355 JsepIceCandidate ice_candidate2(kMediaContentName0, 0, candidate); 1356 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2)); 1357 1358 SessionDescriptionInterface* answer = CreateRemoteAnswer( 1359 session_->local_description()); 1360 SetRemoteDescriptionWithoutError(answer); 1361 1362 // Verifying the candidates are copied properly from internal vector. 1363 const SessionDescriptionInterface* remote_desc = 1364 session_->remote_description(); 1365 ASSERT_TRUE(remote_desc != NULL); 1366 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); 1367 const IceCandidateCollection* candidates = 1368 remote_desc->candidates(kMediaContentIndex0); 1369 ASSERT_EQ(2u, candidates->count()); 1370 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); 1371 EXPECT_EQ(kMediaContentName0, candidates->at(0)->sdp_mid()); 1372 EXPECT_EQ(1, candidates->at(0)->candidate().component()); 1373 EXPECT_EQ(2, candidates->at(1)->candidate().component()); 1374 1375 candidate.set_component(2); 1376 JsepIceCandidate ice_candidate3(kMediaContentName0, 0, candidate); 1377 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate3)); 1378 ASSERT_EQ(3u, candidates->count()); 1379 1380 JsepIceCandidate bad_ice_candidate("bad content name", 99, candidate); 1381 EXPECT_FALSE(session_->ProcessIceMessage(&bad_ice_candidate)); 1382 } 1383 1384 // Test that a remote candidate is added to the remote session description and 1385 // that it is retained if the remote session description is changed. 1386 TEST_F(WebRtcSessionTest, TestRemoteCandidatesAddedToSessionDescription) { 1387 Init(NULL); 1388 cricket::Candidate candidate1; 1389 candidate1.set_component(1); 1390 JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0, 1391 candidate1); 1392 mediastream_signaling_.SendAudioVideoStream1(); 1393 CreateAndSetRemoteOfferAndLocalAnswer(); 1394 1395 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1)); 1396 const SessionDescriptionInterface* remote_desc = 1397 session_->remote_description(); 1398 ASSERT_TRUE(remote_desc != NULL); 1399 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); 1400 const IceCandidateCollection* candidates = 1401 remote_desc->candidates(kMediaContentIndex0); 1402 ASSERT_EQ(1u, candidates->count()); 1403 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); 1404 1405 // Update the RemoteSessionDescription with a new session description and 1406 // a candidate and check that the new remote session description contains both 1407 // candidates. 1408 SessionDescriptionInterface* offer = CreateRemoteOffer(); 1409 cricket::Candidate candidate2; 1410 JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0, 1411 candidate2); 1412 EXPECT_TRUE(offer->AddCandidate(&ice_candidate2)); 1413 SetRemoteDescriptionWithoutError(offer); 1414 1415 remote_desc = session_->remote_description(); 1416 ASSERT_TRUE(remote_desc != NULL); 1417 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); 1418 candidates = remote_desc->candidates(kMediaContentIndex0); 1419 ASSERT_EQ(2u, candidates->count()); 1420 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); 1421 // Username and password have be updated with the TransportInfo of the 1422 // SessionDescription, won't be equal to the original one. 1423 candidate2.set_username(candidates->at(0)->candidate().username()); 1424 candidate2.set_password(candidates->at(0)->candidate().password()); 1425 EXPECT_TRUE(candidate2.IsEquivalent(candidates->at(0)->candidate())); 1426 EXPECT_EQ(kMediaContentIndex0, candidates->at(1)->sdp_mline_index()); 1427 // No need to verify the username and password. 1428 candidate1.set_username(candidates->at(1)->candidate().username()); 1429 candidate1.set_password(candidates->at(1)->candidate().password()); 1430 EXPECT_TRUE(candidate1.IsEquivalent(candidates->at(1)->candidate())); 1431 1432 // Test that the candidate is ignored if we can add the same candidate again. 1433 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2)); 1434 } 1435 1436 // Test that local candidates are added to the local session description and 1437 // that they are retained if the local session description is changed. 1438 TEST_F(WebRtcSessionTest, TestLocalCandidatesAddedToSessionDescription) { 1439 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 1440 Init(NULL); 1441 mediastream_signaling_.SendAudioVideoStream1(); 1442 CreateAndSetRemoteOfferAndLocalAnswer(); 1443 1444 const SessionDescriptionInterface* local_desc = session_->local_description(); 1445 const IceCandidateCollection* candidates = 1446 local_desc->candidates(kMediaContentIndex0); 1447 ASSERT_TRUE(candidates != NULL); 1448 EXPECT_EQ(0u, candidates->count()); 1449 1450 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); 1451 1452 local_desc = session_->local_description(); 1453 candidates = local_desc->candidates(kMediaContentIndex0); 1454 ASSERT_TRUE(candidates != NULL); 1455 EXPECT_LT(0u, candidates->count()); 1456 candidates = local_desc->candidates(1); 1457 ASSERT_TRUE(candidates != NULL); 1458 EXPECT_LT(0u, candidates->count()); 1459 1460 // Update the session descriptions. 1461 mediastream_signaling_.SendAudioVideoStream1(); 1462 CreateAndSetRemoteOfferAndLocalAnswer(); 1463 1464 local_desc = session_->local_description(); 1465 candidates = local_desc->candidates(kMediaContentIndex0); 1466 ASSERT_TRUE(candidates != NULL); 1467 EXPECT_LT(0u, candidates->count()); 1468 candidates = local_desc->candidates(1); 1469 ASSERT_TRUE(candidates != NULL); 1470 EXPECT_LT(0u, candidates->count()); 1471 } 1472 1473 // Test that we can set a remote session description with remote candidates. 1474 TEST_F(WebRtcSessionTest, TestSetRemoteSessionDescriptionWithCandidates) { 1475 Init(NULL); 1476 1477 cricket::Candidate candidate1; 1478 candidate1.set_component(1); 1479 JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0, 1480 candidate1); 1481 mediastream_signaling_.SendAudioVideoStream1(); 1482 SessionDescriptionInterface* offer = CreateOffer(NULL); 1483 1484 EXPECT_TRUE(offer->AddCandidate(&ice_candidate)); 1485 SetRemoteDescriptionWithoutError(offer); 1486 1487 const SessionDescriptionInterface* remote_desc = 1488 session_->remote_description(); 1489 ASSERT_TRUE(remote_desc != NULL); 1490 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); 1491 const IceCandidateCollection* candidates = 1492 remote_desc->candidates(kMediaContentIndex0); 1493 ASSERT_EQ(1u, candidates->count()); 1494 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); 1495 1496 SessionDescriptionInterface* answer = CreateAnswer(NULL); 1497 SetLocalDescriptionWithoutError(answer); 1498 } 1499 1500 // Test that offers and answers contains ice candidates when Ice candidates have 1501 // been gathered. 1502 TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteDescriptionWithCandidates) { 1503 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort)); 1504 Init(NULL); 1505 mediastream_signaling_.SendAudioVideoStream1(); 1506 // Ice is started but candidates are not provided until SetLocalDescription 1507 // is called. 1508 EXPECT_EQ(0u, observer_.mline_0_candidates_.size()); 1509 EXPECT_EQ(0u, observer_.mline_1_candidates_.size()); 1510 CreateAndSetRemoteOfferAndLocalAnswer(); 1511 // Wait until at least one local candidate has been collected. 1512 EXPECT_TRUE_WAIT(0u < observer_.mline_0_candidates_.size(), 1513 kIceCandidatesTimeout); 1514 EXPECT_TRUE_WAIT(0u < observer_.mline_1_candidates_.size(), 1515 kIceCandidatesTimeout); 1516 1517 talk_base::scoped_ptr<SessionDescriptionInterface> local_offer( 1518 CreateOffer(NULL)); 1519 ASSERT_TRUE(local_offer->candidates(kMediaContentIndex0) != NULL); 1520 EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex0)->count()); 1521 ASSERT_TRUE(local_offer->candidates(kMediaContentIndex1) != NULL); 1522 EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex1)->count()); 1523 1524 SessionDescriptionInterface* remote_offer(CreateRemoteOffer()); 1525 SetRemoteDescriptionWithoutError(remote_offer); 1526 SessionDescriptionInterface* answer = CreateAnswer(NULL); 1527 ASSERT_TRUE(answer->candidates(kMediaContentIndex0) != NULL); 1528 EXPECT_LT(0u, answer->candidates(kMediaContentIndex0)->count()); 1529 ASSERT_TRUE(answer->candidates(kMediaContentIndex1) != NULL); 1530 EXPECT_LT(0u, answer->candidates(kMediaContentIndex1)->count()); 1531 SetLocalDescriptionWithoutError(answer); 1532 } 1533 1534 // Verifies TransportProxy and media channels are created with content names 1535 // present in the SessionDescription. 1536 TEST_F(WebRtcSessionTest, TestChannelCreationsWithContentNames) { 1537 Init(NULL); 1538 mediastream_signaling_.SendAudioVideoStream1(); 1539 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1540 CreateOffer(NULL)); 1541 1542 // CreateOffer creates session description with the content names "audio" and 1543 // "video". Goal is to modify these content names and verify transport channel 1544 // proxy in the BaseSession, as proxies are created with the content names 1545 // present in SDP. 1546 std::string sdp; 1547 EXPECT_TRUE(offer->ToString(&sdp)); 1548 const std::string kAudioMid = "a=mid:audio"; 1549 const std::string kAudioMidReplaceStr = "a=mid:audio_content_name"; 1550 const std::string kVideoMid = "a=mid:video"; 1551 const std::string kVideoMidReplaceStr = "a=mid:video_content_name"; 1552 1553 // Replacing |audio| with |audio_content_name|. 1554 talk_base::replace_substrs(kAudioMid.c_str(), kAudioMid.length(), 1555 kAudioMidReplaceStr.c_str(), 1556 kAudioMidReplaceStr.length(), 1557 &sdp); 1558 // Replacing |video| with |video_content_name|. 1559 talk_base::replace_substrs(kVideoMid.c_str(), kVideoMid.length(), 1560 kVideoMidReplaceStr.c_str(), 1561 kVideoMidReplaceStr.length(), 1562 &sdp); 1563 1564 SessionDescriptionInterface* modified_offer = 1565 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); 1566 1567 SetRemoteDescriptionWithoutError(modified_offer); 1568 1569 SessionDescriptionInterface* answer = 1570 CreateAnswer(NULL); 1571 SetLocalDescriptionWithoutError(answer); 1572 1573 EXPECT_TRUE(session_->GetTransportProxy("audio_content_name") != NULL); 1574 EXPECT_TRUE(session_->GetTransportProxy("video_content_name") != NULL); 1575 EXPECT_TRUE((video_channel_ = media_engine_->GetVideoChannel(0)) != NULL); 1576 EXPECT_TRUE((voice_channel_ = media_engine_->GetVoiceChannel(0)) != NULL); 1577 } 1578 1579 // Test that an offer contains the correct media content descriptions based on 1580 // the send streams when no constraints have been set. 1581 TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraintsOrStreams) { 1582 Init(NULL); 1583 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1584 CreateOffer(NULL)); 1585 ASSERT_TRUE(offer != NULL); 1586 const cricket::ContentInfo* content = 1587 cricket::GetFirstAudioContent(offer->description()); 1588 EXPECT_TRUE(content != NULL); 1589 content = cricket::GetFirstVideoContent(offer->description()); 1590 EXPECT_TRUE(content == NULL); 1591 } 1592 1593 // Test that an offer contains the correct media content descriptions based on 1594 // the send streams when no constraints have been set. 1595 TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraints) { 1596 Init(NULL); 1597 // Test Audio only offer. 1598 mediastream_signaling_.UseOptionsAudioOnly(); 1599 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1600 CreateOffer(NULL)); 1601 const cricket::ContentInfo* content = 1602 cricket::GetFirstAudioContent(offer->description()); 1603 EXPECT_TRUE(content != NULL); 1604 content = cricket::GetFirstVideoContent(offer->description()); 1605 EXPECT_TRUE(content == NULL); 1606 1607 // Test Audio / Video offer. 1608 mediastream_signaling_.SendAudioVideoStream1(); 1609 offer.reset(CreateOffer(NULL)); 1610 content = cricket::GetFirstAudioContent(offer->description()); 1611 EXPECT_TRUE(content != NULL); 1612 content = cricket::GetFirstVideoContent(offer->description()); 1613 EXPECT_TRUE(content != NULL); 1614 } 1615 1616 // Test that an offer contains no media content descriptions if 1617 // kOfferToReceiveVideo and kOfferToReceiveAudio constraints are set to false. 1618 TEST_F(WebRtcSessionTest, CreateOfferWithConstraintsWithoutStreams) { 1619 Init(NULL); 1620 webrtc::FakeConstraints constraints_no_receive; 1621 constraints_no_receive.SetMandatoryReceiveAudio(false); 1622 constraints_no_receive.SetMandatoryReceiveVideo(false); 1623 1624 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1625 CreateOffer(&constraints_no_receive)); 1626 ASSERT_TRUE(offer != NULL); 1627 const cricket::ContentInfo* content = 1628 cricket::GetFirstAudioContent(offer->description()); 1629 EXPECT_TRUE(content == NULL); 1630 content = cricket::GetFirstVideoContent(offer->description()); 1631 EXPECT_TRUE(content == NULL); 1632 } 1633 1634 // Test that an offer contains only audio media content descriptions if 1635 // kOfferToReceiveAudio constraints are set to true. 1636 TEST_F(WebRtcSessionTest, CreateAudioOnlyOfferWithConstraints) { 1637 Init(NULL); 1638 webrtc::FakeConstraints constraints_audio_only; 1639 constraints_audio_only.SetMandatoryReceiveAudio(true); 1640 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1641 CreateOffer(&constraints_audio_only)); 1642 1643 const cricket::ContentInfo* content = 1644 cricket::GetFirstAudioContent(offer->description()); 1645 EXPECT_TRUE(content != NULL); 1646 content = cricket::GetFirstVideoContent(offer->description()); 1647 EXPECT_TRUE(content == NULL); 1648 } 1649 1650 // Test that an offer contains audio and video media content descriptions if 1651 // kOfferToReceiveAudio and kOfferToReceiveVideo constraints are set to true. 1652 TEST_F(WebRtcSessionTest, CreateOfferWithConstraints) { 1653 Init(NULL); 1654 // Test Audio / Video offer. 1655 webrtc::FakeConstraints constraints_audio_video; 1656 constraints_audio_video.SetMandatoryReceiveAudio(true); 1657 constraints_audio_video.SetMandatoryReceiveVideo(true); 1658 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1659 CreateOffer(&constraints_audio_video)); 1660 const cricket::ContentInfo* content = 1661 cricket::GetFirstAudioContent(offer->description()); 1662 1663 EXPECT_TRUE(content != NULL); 1664 content = cricket::GetFirstVideoContent(offer->description()); 1665 EXPECT_TRUE(content != NULL); 1666 1667 // TODO(perkj): Should the direction be set to SEND_ONLY if 1668 // The constraints is set to not receive audio or video but a track is added? 1669 } 1670 1671 // Test that an answer can not be created if the last remote description is not 1672 // an offer. 1673 TEST_F(WebRtcSessionTest, CreateAnswerWithoutAnOffer) { 1674 Init(NULL); 1675 SessionDescriptionInterface* offer = CreateOffer(NULL); 1676 SetLocalDescriptionWithoutError(offer); 1677 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); 1678 SetRemoteDescriptionWithoutError(answer); 1679 EXPECT_TRUE(CreateAnswer(NULL) == NULL); 1680 } 1681 1682 // Test that an answer contains the correct media content descriptions when no 1683 // constraints have been set. 1684 TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraintsOrStreams) { 1685 Init(NULL); 1686 // Create a remote offer with audio and video content. 1687 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); 1688 SetRemoteDescriptionWithoutError(offer.release()); 1689 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 1690 CreateAnswer(NULL)); 1691 const cricket::ContentInfo* content = 1692 cricket::GetFirstAudioContent(answer->description()); 1693 ASSERT_TRUE(content != NULL); 1694 EXPECT_FALSE(content->rejected); 1695 1696 content = cricket::GetFirstVideoContent(answer->description()); 1697 ASSERT_TRUE(content != NULL); 1698 EXPECT_FALSE(content->rejected); 1699 } 1700 1701 // Test that an answer contains the correct media content descriptions when no 1702 // constraints have been set and the offer only contain audio. 1703 TEST_F(WebRtcSessionTest, CreateAudioAnswerWithoutConstraintsOrStreams) { 1704 Init(NULL); 1705 // Create a remote offer with audio only. 1706 cricket::MediaSessionOptions options; 1707 options.has_audio = true; 1708 options.has_video = false; 1709 talk_base::scoped_ptr<JsepSessionDescription> offer( 1710 CreateRemoteOffer(options)); 1711 ASSERT_TRUE(cricket::GetFirstVideoContent(offer->description()) == NULL); 1712 ASSERT_TRUE(cricket::GetFirstAudioContent(offer->description()) != NULL); 1713 1714 SetRemoteDescriptionWithoutError(offer.release()); 1715 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 1716 CreateAnswer(NULL)); 1717 const cricket::ContentInfo* content = 1718 cricket::GetFirstAudioContent(answer->description()); 1719 ASSERT_TRUE(content != NULL); 1720 EXPECT_FALSE(content->rejected); 1721 1722 EXPECT_TRUE(cricket::GetFirstVideoContent(answer->description()) == NULL); 1723 } 1724 1725 // Test that an answer contains the correct media content descriptions when no 1726 // constraints have been set. 1727 TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraints) { 1728 Init(NULL); 1729 // Create a remote offer with audio and video content. 1730 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); 1731 SetRemoteDescriptionWithoutError(offer.release()); 1732 // Test with a stream with tracks. 1733 mediastream_signaling_.SendAudioVideoStream1(); 1734 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 1735 CreateAnswer(NULL)); 1736 const cricket::ContentInfo* content = 1737 cricket::GetFirstAudioContent(answer->description()); 1738 ASSERT_TRUE(content != NULL); 1739 EXPECT_FALSE(content->rejected); 1740 1741 content = cricket::GetFirstVideoContent(answer->description()); 1742 ASSERT_TRUE(content != NULL); 1743 EXPECT_FALSE(content->rejected); 1744 } 1745 1746 // Test that an answer contains the correct media content descriptions when 1747 // constraints have been set but no stream is sent. 1748 TEST_F(WebRtcSessionTest, CreateAnswerWithConstraintsWithoutStreams) { 1749 Init(NULL); 1750 // Create a remote offer with audio and video content. 1751 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); 1752 SetRemoteDescriptionWithoutError(offer.release()); 1753 1754 webrtc::FakeConstraints constraints_no_receive; 1755 constraints_no_receive.SetMandatoryReceiveAudio(false); 1756 constraints_no_receive.SetMandatoryReceiveVideo(false); 1757 1758 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 1759 CreateAnswer(&constraints_no_receive)); 1760 const cricket::ContentInfo* content = 1761 cricket::GetFirstAudioContent(answer->description()); 1762 ASSERT_TRUE(content != NULL); 1763 EXPECT_TRUE(content->rejected); 1764 1765 content = cricket::GetFirstVideoContent(answer->description()); 1766 ASSERT_TRUE(content != NULL); 1767 EXPECT_TRUE(content->rejected); 1768 } 1769 1770 // Test that an answer contains the correct media content descriptions when 1771 // constraints have been set and streams are sent. 1772 TEST_F(WebRtcSessionTest, CreateAnswerWithConstraints) { 1773 Init(NULL); 1774 // Create a remote offer with audio and video content. 1775 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); 1776 SetRemoteDescriptionWithoutError(offer.release()); 1777 1778 webrtc::FakeConstraints constraints_no_receive; 1779 constraints_no_receive.SetMandatoryReceiveAudio(false); 1780 constraints_no_receive.SetMandatoryReceiveVideo(false); 1781 1782 // Test with a stream with tracks. 1783 mediastream_signaling_.SendAudioVideoStream1(); 1784 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 1785 CreateAnswer(&constraints_no_receive)); 1786 1787 // TODO(perkj): Should the direction be set to SEND_ONLY? 1788 const cricket::ContentInfo* content = 1789 cricket::GetFirstAudioContent(answer->description()); 1790 ASSERT_TRUE(content != NULL); 1791 EXPECT_FALSE(content->rejected); 1792 1793 // TODO(perkj): Should the direction be set to SEND_ONLY? 1794 content = cricket::GetFirstVideoContent(answer->description()); 1795 ASSERT_TRUE(content != NULL); 1796 EXPECT_FALSE(content->rejected); 1797 } 1798 1799 TEST_F(WebRtcSessionTest, CreateOfferWithoutCNCodecs) { 1800 AddCNCodecs(); 1801 Init(NULL); 1802 webrtc::FakeConstraints constraints; 1803 constraints.SetOptionalVAD(false); 1804 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 1805 CreateOffer(&constraints)); 1806 const cricket::ContentInfo* content = 1807 cricket::GetFirstAudioContent(offer->description()); 1808 EXPECT_TRUE(content != NULL); 1809 EXPECT_TRUE(VerifyNoCNCodecs(content)); 1810 } 1811 1812 TEST_F(WebRtcSessionTest, CreateAnswerWithoutCNCodecs) { 1813 AddCNCodecs(); 1814 Init(NULL); 1815 // Create a remote offer with audio and video content. 1816 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); 1817 SetRemoteDescriptionWithoutError(offer.release()); 1818 1819 webrtc::FakeConstraints constraints; 1820 constraints.SetOptionalVAD(false); 1821 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 1822 CreateAnswer(&constraints)); 1823 const cricket::ContentInfo* content = 1824 cricket::GetFirstAudioContent(answer->description()); 1825 ASSERT_TRUE(content != NULL); 1826 EXPECT_TRUE(VerifyNoCNCodecs(content)); 1827 } 1828 1829 // This test verifies the call setup when remote answer with audio only and 1830 // later updates with video. 1831 TEST_F(WebRtcSessionTest, TestAVOfferWithAudioOnlyAnswer) { 1832 Init(NULL); 1833 EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL); 1834 EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL); 1835 1836 mediastream_signaling_.SendAudioVideoStream1(); 1837 SessionDescriptionInterface* offer = CreateOffer(NULL); 1838 1839 cricket::MediaSessionOptions options; 1840 options.has_video = false; 1841 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer, options); 1842 1843 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer 1844 // and answer; 1845 SetLocalDescriptionWithoutError(offer); 1846 SetRemoteDescriptionWithoutError(answer); 1847 1848 video_channel_ = media_engine_->GetVideoChannel(0); 1849 voice_channel_ = media_engine_->GetVoiceChannel(0); 1850 1851 ASSERT_TRUE(video_channel_ == NULL); 1852 1853 ASSERT_EQ(0u, voice_channel_->recv_streams().size()); 1854 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 1855 EXPECT_EQ(kAudioTrack1, voice_channel_->send_streams()[0].id); 1856 1857 // Let the remote end update the session descriptions, with Audio and Video. 1858 mediastream_signaling_.SendAudioVideoStream2(); 1859 CreateAndSetRemoteOfferAndLocalAnswer(); 1860 1861 video_channel_ = media_engine_->GetVideoChannel(0); 1862 voice_channel_ = media_engine_->GetVoiceChannel(0); 1863 1864 ASSERT_TRUE(video_channel_ != NULL); 1865 ASSERT_TRUE(voice_channel_ != NULL); 1866 1867 ASSERT_EQ(1u, video_channel_->recv_streams().size()); 1868 ASSERT_EQ(1u, video_channel_->send_streams().size()); 1869 EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id); 1870 EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id); 1871 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 1872 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 1873 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id); 1874 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id); 1875 1876 // Change session back to audio only. 1877 mediastream_signaling_.UseOptionsAudioOnly(); 1878 CreateAndSetRemoteOfferAndLocalAnswer(); 1879 1880 EXPECT_EQ(0u, video_channel_->recv_streams().size()); 1881 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 1882 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id); 1883 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 1884 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id); 1885 } 1886 1887 // This test verifies the call setup when remote answer with video only and 1888 // later updates with audio. 1889 TEST_F(WebRtcSessionTest, TestAVOfferWithVideoOnlyAnswer) { 1890 Init(NULL); 1891 EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL); 1892 EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL); 1893 mediastream_signaling_.SendAudioVideoStream1(); 1894 SessionDescriptionInterface* offer = CreateOffer(NULL); 1895 1896 cricket::MediaSessionOptions options; 1897 options.has_audio = false; 1898 options.has_video = true; 1899 SessionDescriptionInterface* answer = CreateRemoteAnswer( 1900 offer, options, cricket::SEC_ENABLED); 1901 1902 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer 1903 // and answer. 1904 SetLocalDescriptionWithoutError(offer); 1905 SetRemoteDescriptionWithoutError(answer); 1906 1907 video_channel_ = media_engine_->GetVideoChannel(0); 1908 voice_channel_ = media_engine_->GetVoiceChannel(0); 1909 1910 ASSERT_TRUE(voice_channel_ == NULL); 1911 ASSERT_TRUE(video_channel_ != NULL); 1912 1913 EXPECT_EQ(0u, video_channel_->recv_streams().size()); 1914 ASSERT_EQ(1u, video_channel_->send_streams().size()); 1915 EXPECT_EQ(kVideoTrack1, video_channel_->send_streams()[0].id); 1916 1917 // Update the session descriptions, with Audio and Video. 1918 mediastream_signaling_.SendAudioVideoStream2(); 1919 CreateAndSetRemoteOfferAndLocalAnswer(); 1920 1921 voice_channel_ = media_engine_->GetVoiceChannel(0); 1922 ASSERT_TRUE(voice_channel_ != NULL); 1923 1924 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 1925 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 1926 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id); 1927 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id); 1928 1929 // Change session back to video only. 1930 mediastream_signaling_.UseOptionsVideoOnly(); 1931 CreateAndSetRemoteOfferAndLocalAnswer(); 1932 1933 video_channel_ = media_engine_->GetVideoChannel(0); 1934 voice_channel_ = media_engine_->GetVoiceChannel(0); 1935 1936 ASSERT_EQ(1u, video_channel_->recv_streams().size()); 1937 EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id); 1938 ASSERT_EQ(1u, video_channel_->send_streams().size()); 1939 EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id); 1940 } 1941 1942 TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) { 1943 Init(NULL); 1944 mediastream_signaling_.SendAudioVideoStream1(); 1945 scoped_ptr<SessionDescriptionInterface> offer( 1946 CreateOffer(NULL)); 1947 VerifyCryptoParams(offer->description()); 1948 SetRemoteDescriptionWithoutError(offer.release()); 1949 scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); 1950 VerifyCryptoParams(answer->description()); 1951 } 1952 1953 TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) { 1954 options_.disable_encryption = true; 1955 Init(NULL); 1956 mediastream_signaling_.SendAudioVideoStream1(); 1957 scoped_ptr<SessionDescriptionInterface> offer( 1958 CreateOffer(NULL)); 1959 VerifyNoCryptoParams(offer->description(), false); 1960 } 1961 1962 TEST_F(WebRtcSessionTest, VerifyAnswerFromNonCryptoOffer) { 1963 Init(NULL); 1964 VerifyAnswerFromNonCryptoOffer(); 1965 } 1966 1967 TEST_F(WebRtcSessionTest, VerifyAnswerFromCryptoOffer) { 1968 Init(NULL); 1969 VerifyAnswerFromCryptoOffer(); 1970 } 1971 1972 // This test verifies that setLocalDescription fails if 1973 // no a=ice-ufrag and a=ice-pwd lines are present in the SDP. 1974 TEST_F(WebRtcSessionTest, TestSetLocalDescriptionWithoutIce) { 1975 Init(NULL); 1976 mediastream_signaling_.SendAudioVideoStream1(); 1977 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL)); 1978 std::string sdp; 1979 RemoveIceUfragPwdLines(offer.get(), &sdp); 1980 SessionDescriptionInterface* modified_offer = 1981 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); 1982 SetLocalDescriptionExpectError(kSdpWithoutIceUfragPwd, modified_offer); 1983 } 1984 1985 // This test verifies that setRemoteDescription fails if 1986 // no a=ice-ufrag and a=ice-pwd lines are present in the SDP. 1987 TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionWithoutIce) { 1988 Init(NULL); 1989 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer()); 1990 std::string sdp; 1991 RemoveIceUfragPwdLines(offer.get(), &sdp); 1992 SessionDescriptionInterface* modified_offer = 1993 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); 1994 SetRemoteDescriptionExpectError(kSdpWithoutIceUfragPwd, modified_offer); 1995 } 1996 1997 TEST_F(WebRtcSessionTest, VerifyBundleFlagInPA) { 1998 // This test verifies BUNDLE flag in PortAllocator, if BUNDLE information in 1999 // local description is removed by the application, BUNDLE flag should be 2000 // disabled in PortAllocator. By default BUNDLE is enabled in the WebRtc. 2001 Init(NULL); 2002 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) == 2003 cricket::PORTALLOCATOR_ENABLE_BUNDLE); 2004 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 2005 CreateOffer(NULL)); 2006 cricket::SessionDescription* offer_copy = 2007 offer->description()->Copy(); 2008 offer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); 2009 JsepSessionDescription* modified_offer = 2010 new JsepSessionDescription(JsepSessionDescription::kOffer); 2011 modified_offer->Initialize(offer_copy, "1", "1"); 2012 2013 SetLocalDescriptionWithoutError(modified_offer); 2014 EXPECT_FALSE(allocator_.flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE); 2015 } 2016 2017 TEST_F(WebRtcSessionTest, TestDisabledBundleInAnswer) { 2018 Init(NULL); 2019 mediastream_signaling_.SendAudioVideoStream1(); 2020 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) == 2021 cricket::PORTALLOCATOR_ENABLE_BUNDLE); 2022 FakeConstraints constraints; 2023 constraints.SetMandatoryUseRtpMux(true); 2024 SessionDescriptionInterface* offer = CreateOffer(&constraints); 2025 SetLocalDescriptionWithoutError(offer); 2026 mediastream_signaling_.SendAudioVideoStream2(); 2027 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 2028 CreateRemoteAnswer(session_->local_description())); 2029 cricket::SessionDescription* answer_copy = answer->description()->Copy(); 2030 answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); 2031 JsepSessionDescription* modified_answer = 2032 new JsepSessionDescription(JsepSessionDescription::kAnswer); 2033 modified_answer->Initialize(answer_copy, "1", "1"); 2034 SetRemoteDescriptionWithoutError(modified_answer); 2035 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) == 2036 cricket::PORTALLOCATOR_ENABLE_BUNDLE); 2037 2038 video_channel_ = media_engine_->GetVideoChannel(0); 2039 voice_channel_ = media_engine_->GetVoiceChannel(0); 2040 2041 ASSERT_EQ(1u, video_channel_->recv_streams().size()); 2042 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); 2043 2044 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); 2045 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); 2046 2047 ASSERT_EQ(1u, video_channel_->send_streams().size()); 2048 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id); 2049 ASSERT_EQ(1u, voice_channel_->send_streams().size()); 2050 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id); 2051 } 2052 2053 // This test verifies that SetLocalDescription and SetRemoteDescription fails 2054 // if BUNDLE is enabled but rtcp-mux is disabled in m-lines. 2055 TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) { 2056 WebRtcSessionTest::Init(NULL); 2057 mediastream_signaling_.SendAudioVideoStream1(); 2058 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) == 2059 cricket::PORTALLOCATOR_ENABLE_BUNDLE); 2060 FakeConstraints constraints; 2061 constraints.SetMandatoryUseRtpMux(true); 2062 SessionDescriptionInterface* offer = CreateOffer(&constraints); 2063 std::string offer_str; 2064 offer->ToString(&offer_str); 2065 // Disable rtcp-mux 2066 const std::string rtcp_mux = "rtcp-mux"; 2067 const std::string xrtcp_mux = "xrtcp-mux"; 2068 talk_base::replace_substrs(rtcp_mux.c_str(), rtcp_mux.length(), 2069 xrtcp_mux.c_str(), xrtcp_mux.length(), 2070 &offer_str); 2071 JsepSessionDescription *local_offer = 2072 new JsepSessionDescription(JsepSessionDescription::kOffer); 2073 EXPECT_TRUE((local_offer)->Initialize(offer_str, NULL)); 2074 SetLocalDescriptionExpectError(kBundleWithoutRtcpMux, local_offer); 2075 JsepSessionDescription *remote_offer = 2076 new JsepSessionDescription(JsepSessionDescription::kOffer); 2077 EXPECT_TRUE((remote_offer)->Initialize(offer_str, NULL)); 2078 SetRemoteDescriptionExpectError(kBundleWithoutRtcpMux, remote_offer); 2079 // Trying unmodified SDP. 2080 SetLocalDescriptionWithoutError(offer); 2081 } 2082 2083 TEST_F(WebRtcSessionTest, SetAudioPlayout) { 2084 Init(NULL); 2085 mediastream_signaling_.SendAudioVideoStream1(); 2086 CreateAndSetRemoteOfferAndLocalAnswer(); 2087 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); 2088 ASSERT_TRUE(channel != NULL); 2089 ASSERT_EQ(1u, channel->recv_streams().size()); 2090 uint32 receive_ssrc = channel->recv_streams()[0].first_ssrc(); 2091 double left_vol, right_vol; 2092 EXPECT_TRUE(channel->GetOutputScaling(receive_ssrc, &left_vol, &right_vol)); 2093 EXPECT_EQ(1, left_vol); 2094 EXPECT_EQ(1, right_vol); 2095 talk_base::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer()); 2096 session_->SetAudioPlayout(receive_ssrc, false, renderer.get()); 2097 EXPECT_TRUE(channel->GetOutputScaling(receive_ssrc, &left_vol, &right_vol)); 2098 EXPECT_EQ(0, left_vol); 2099 EXPECT_EQ(0, right_vol); 2100 EXPECT_EQ(0, renderer->channel_id()); 2101 session_->SetAudioPlayout(receive_ssrc, true, NULL); 2102 EXPECT_TRUE(channel->GetOutputScaling(receive_ssrc, &left_vol, &right_vol)); 2103 EXPECT_EQ(1, left_vol); 2104 EXPECT_EQ(1, right_vol); 2105 EXPECT_EQ(-1, renderer->channel_id()); 2106 } 2107 2108 TEST_F(WebRtcSessionTest, SetAudioSend) { 2109 Init(NULL); 2110 mediastream_signaling_.SendAudioVideoStream1(); 2111 CreateAndSetRemoteOfferAndLocalAnswer(); 2112 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); 2113 ASSERT_TRUE(channel != NULL); 2114 ASSERT_EQ(1u, channel->send_streams().size()); 2115 uint32 send_ssrc = channel->send_streams()[0].first_ssrc(); 2116 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); 2117 2118 cricket::AudioOptions options; 2119 options.echo_cancellation.Set(true); 2120 2121 talk_base::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer()); 2122 session_->SetAudioSend(send_ssrc, false, options, renderer.get()); 2123 EXPECT_TRUE(channel->IsStreamMuted(send_ssrc)); 2124 EXPECT_FALSE(channel->options().echo_cancellation.IsSet()); 2125 EXPECT_EQ(0, renderer->channel_id()); 2126 2127 session_->SetAudioSend(send_ssrc, true, options, NULL); 2128 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); 2129 bool value; 2130 EXPECT_TRUE(channel->options().echo_cancellation.Get(&value)); 2131 EXPECT_TRUE(value); 2132 EXPECT_EQ(-1, renderer->channel_id()); 2133 } 2134 2135 TEST_F(WebRtcSessionTest, SetVideoPlayout) { 2136 Init(NULL); 2137 mediastream_signaling_.SendAudioVideoStream1(); 2138 CreateAndSetRemoteOfferAndLocalAnswer(); 2139 cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0); 2140 ASSERT_TRUE(channel != NULL); 2141 ASSERT_LT(0u, channel->renderers().size()); 2142 EXPECT_TRUE(channel->renderers().begin()->second == NULL); 2143 ASSERT_EQ(1u, channel->recv_streams().size()); 2144 uint32 receive_ssrc = channel->recv_streams()[0].first_ssrc(); 2145 cricket::FakeVideoRenderer renderer; 2146 session_->SetVideoPlayout(receive_ssrc, true, &renderer); 2147 EXPECT_TRUE(channel->renderers().begin()->second == &renderer); 2148 session_->SetVideoPlayout(receive_ssrc, false, &renderer); 2149 EXPECT_TRUE(channel->renderers().begin()->second == NULL); 2150 } 2151 2152 TEST_F(WebRtcSessionTest, SetVideoSend) { 2153 Init(NULL); 2154 mediastream_signaling_.SendAudioVideoStream1(); 2155 CreateAndSetRemoteOfferAndLocalAnswer(); 2156 cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0); 2157 ASSERT_TRUE(channel != NULL); 2158 ASSERT_EQ(1u, channel->send_streams().size()); 2159 uint32 send_ssrc = channel->send_streams()[0].first_ssrc(); 2160 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); 2161 cricket::VideoOptions* options = NULL; 2162 session_->SetVideoSend(send_ssrc, false, options); 2163 EXPECT_TRUE(channel->IsStreamMuted(send_ssrc)); 2164 session_->SetVideoSend(send_ssrc, true, options); 2165 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); 2166 } 2167 2168 TEST_F(WebRtcSessionTest, CanNotInsertDtmf) { 2169 TestCanInsertDtmf(false); 2170 } 2171 2172 TEST_F(WebRtcSessionTest, CanInsertDtmf) { 2173 TestCanInsertDtmf(true); 2174 } 2175 2176 TEST_F(WebRtcSessionTest, InsertDtmf) { 2177 // Setup 2178 Init(NULL); 2179 mediastream_signaling_.SendAudioVideoStream1(); 2180 CreateAndSetRemoteOfferAndLocalAnswer(); 2181 FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); 2182 EXPECT_EQ(0U, channel->dtmf_info_queue().size()); 2183 2184 // Insert DTMF 2185 const int expected_flags = DF_SEND; 2186 const int expected_duration = 90; 2187 session_->InsertDtmf(kAudioTrack1, 0, expected_duration); 2188 session_->InsertDtmf(kAudioTrack1, 1, expected_duration); 2189 session_->InsertDtmf(kAudioTrack1, 2, expected_duration); 2190 2191 // Verify 2192 ASSERT_EQ(3U, channel->dtmf_info_queue().size()); 2193 const uint32 send_ssrc = channel->send_streams()[0].first_ssrc(); 2194 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[0], send_ssrc, 0, 2195 expected_duration, expected_flags)); 2196 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[1], send_ssrc, 1, 2197 expected_duration, expected_flags)); 2198 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[2], send_ssrc, 2, 2199 expected_duration, expected_flags)); 2200 } 2201 2202 // This test verifies the |initiator| flag when session initiates the call. 2203 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsOriginator) { 2204 Init(NULL); 2205 EXPECT_FALSE(session_->initiator()); 2206 SessionDescriptionInterface* offer = CreateOffer(NULL); 2207 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); 2208 SetLocalDescriptionWithoutError(offer); 2209 EXPECT_TRUE(session_->initiator()); 2210 SetRemoteDescriptionWithoutError(answer); 2211 EXPECT_TRUE(session_->initiator()); 2212 } 2213 2214 // This test verifies the |initiator| flag when session receives the call. 2215 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsReceiver) { 2216 Init(NULL); 2217 EXPECT_FALSE(session_->initiator()); 2218 SessionDescriptionInterface* offer = CreateRemoteOffer(); 2219 SetRemoteDescriptionWithoutError(offer); 2220 SessionDescriptionInterface* answer = CreateAnswer(NULL); 2221 2222 EXPECT_FALSE(session_->initiator()); 2223 SetLocalDescriptionWithoutError(answer); 2224 EXPECT_FALSE(session_->initiator()); 2225 } 2226 2227 // This test verifies the ice protocol type at initiator of the call 2228 // if |a=ice-options:google-ice| is present in answer. 2229 TEST_F(WebRtcSessionTest, TestInitiatorGIceInAnswer) { 2230 Init(NULL); 2231 mediastream_signaling_.SendAudioVideoStream1(); 2232 SessionDescriptionInterface* offer = CreateOffer(NULL); 2233 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 2234 CreateRemoteAnswer(offer)); 2235 SetLocalDescriptionWithoutError(offer); 2236 std::string sdp; 2237 EXPECT_TRUE(answer->ToString(&sdp)); 2238 // Adding ice-options to the session level. 2239 InjectAfter("t=0 0\r\n", 2240 "a=ice-options:google-ice\r\n", 2241 &sdp); 2242 SessionDescriptionInterface* answer_with_gice = 2243 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL); 2244 SetRemoteDescriptionWithoutError(answer_with_gice); 2245 VerifyTransportType("audio", cricket::ICEPROTO_GOOGLE); 2246 VerifyTransportType("video", cricket::ICEPROTO_GOOGLE); 2247 } 2248 2249 // This test verifies the ice protocol type at initiator of the call 2250 // if ICE RFC5245 is supported in answer. 2251 TEST_F(WebRtcSessionTest, TestInitiatorIceInAnswer) { 2252 Init(NULL); 2253 mediastream_signaling_.SendAudioVideoStream1(); 2254 SessionDescriptionInterface* offer = CreateOffer(NULL); 2255 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); 2256 SetLocalDescriptionWithoutError(offer); 2257 2258 SetRemoteDescriptionWithoutError(answer); 2259 VerifyTransportType("audio", cricket::ICEPROTO_RFC5245); 2260 VerifyTransportType("video", cricket::ICEPROTO_RFC5245); 2261 } 2262 2263 // This test verifies the ice protocol type at receiver side of the call if 2264 // receiver decides to use google-ice. 2265 TEST_F(WebRtcSessionTest, TestReceiverGIceInOffer) { 2266 Init(NULL); 2267 mediastream_signaling_.SendAudioVideoStream1(); 2268 SessionDescriptionInterface* offer = CreateOffer(NULL); 2269 SetRemoteDescriptionWithoutError(offer); 2270 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 2271 CreateAnswer(NULL)); 2272 std::string sdp; 2273 EXPECT_TRUE(answer->ToString(&sdp)); 2274 // Adding ice-options to the session level. 2275 InjectAfter("t=0 0\r\n", 2276 "a=ice-options:google-ice\r\n", 2277 &sdp); 2278 SessionDescriptionInterface* answer_with_gice = 2279 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL); 2280 SetLocalDescriptionWithoutError(answer_with_gice); 2281 VerifyTransportType("audio", cricket::ICEPROTO_GOOGLE); 2282 VerifyTransportType("video", cricket::ICEPROTO_GOOGLE); 2283 } 2284 2285 // This test verifies the ice protocol type at receiver side of the call if 2286 // receiver decides to use ice RFC 5245. 2287 TEST_F(WebRtcSessionTest, TestReceiverIceInOffer) { 2288 Init(NULL); 2289 mediastream_signaling_.SendAudioVideoStream1(); 2290 SessionDescriptionInterface* offer = CreateOffer(NULL); 2291 SetRemoteDescriptionWithoutError(offer); 2292 SessionDescriptionInterface* answer = CreateAnswer(NULL); 2293 SetLocalDescriptionWithoutError(answer); 2294 VerifyTransportType("audio", cricket::ICEPROTO_RFC5245); 2295 VerifyTransportType("video", cricket::ICEPROTO_RFC5245); 2296 } 2297 2298 // This test verifies the session state when ICE RFC5245 in offer and 2299 // ICE google-ice in answer. 2300 TEST_F(WebRtcSessionTest, TestIceOfferGIceOnlyAnswer) { 2301 Init(NULL); 2302 mediastream_signaling_.SendAudioVideoStream1(); 2303 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 2304 CreateOffer(NULL)); 2305 std::string offer_str; 2306 offer->ToString(&offer_str); 2307 // Disable google-ice 2308 const std::string gice_option = "google-ice"; 2309 const std::string xgoogle_xice = "xgoogle-xice"; 2310 talk_base::replace_substrs(gice_option.c_str(), gice_option.length(), 2311 xgoogle_xice.c_str(), xgoogle_xice.length(), 2312 &offer_str); 2313 JsepSessionDescription *ice_only_offer = 2314 new JsepSessionDescription(JsepSessionDescription::kOffer); 2315 EXPECT_TRUE((ice_only_offer)->Initialize(offer_str, NULL)); 2316 SetLocalDescriptionWithoutError(ice_only_offer); 2317 std::string original_offer_sdp; 2318 EXPECT_TRUE(offer->ToString(&original_offer_sdp)); 2319 SessionDescriptionInterface* pranswer_with_gice = 2320 CreateSessionDescription(JsepSessionDescription::kPrAnswer, 2321 original_offer_sdp, NULL); 2322 SetRemoteDescriptionExpectError(kPushDownPranswerTDFailed, 2323 pranswer_with_gice); 2324 SessionDescriptionInterface* answer_with_gice = 2325 CreateSessionDescription(JsepSessionDescription::kAnswer, 2326 original_offer_sdp, NULL); 2327 SetRemoteDescriptionExpectError(kPushDownAnswerTDFailed, 2328 answer_with_gice); 2329 } 2330 2331 // Verifing local offer and remote answer have matching m-lines as per RFC 3264. 2332 TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) { 2333 Init(NULL); 2334 mediastream_signaling_.SendAudioVideoStream1(); 2335 SessionDescriptionInterface* offer = CreateOffer(NULL); 2336 SetLocalDescriptionWithoutError(offer); 2337 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 2338 CreateRemoteAnswer(session_->local_description())); 2339 2340 cricket::SessionDescription* answer_copy = answer->description()->Copy(); 2341 answer_copy->RemoveContentByName("video"); 2342 JsepSessionDescription* modified_answer = 2343 new JsepSessionDescription(JsepSessionDescription::kAnswer); 2344 2345 EXPECT_TRUE(modified_answer->Initialize(answer_copy, 2346 answer->session_id(), 2347 answer->session_version())); 2348 SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer); 2349 2350 // Modifying content names. 2351 std::string sdp; 2352 EXPECT_TRUE(answer->ToString(&sdp)); 2353 const std::string kAudioMid = "a=mid:audio"; 2354 const std::string kAudioMidReplaceStr = "a=mid:audio_content_name"; 2355 2356 // Replacing |audio| with |audio_content_name|. 2357 talk_base::replace_substrs(kAudioMid.c_str(), kAudioMid.length(), 2358 kAudioMidReplaceStr.c_str(), 2359 kAudioMidReplaceStr.length(), 2360 &sdp); 2361 2362 SessionDescriptionInterface* modified_answer1 = 2363 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL); 2364 SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer1); 2365 2366 SetRemoteDescriptionWithoutError(answer.release()); 2367 } 2368 2369 // Verifying remote offer and local answer have matching m-lines as per 2370 // RFC 3264. 2371 TEST_F(WebRtcSessionTest, TestIncorrectMLinesInLocalAnswer) { 2372 Init(NULL); 2373 mediastream_signaling_.SendAudioVideoStream1(); 2374 SessionDescriptionInterface* offer = CreateRemoteOffer(); 2375 SetRemoteDescriptionWithoutError(offer); 2376 SessionDescriptionInterface* answer = CreateAnswer(NULL); 2377 2378 cricket::SessionDescription* answer_copy = answer->description()->Copy(); 2379 answer_copy->RemoveContentByName("video"); 2380 JsepSessionDescription* modified_answer = 2381 new JsepSessionDescription(JsepSessionDescription::kAnswer); 2382 2383 EXPECT_TRUE(modified_answer->Initialize(answer_copy, 2384 answer->session_id(), 2385 answer->session_version())); 2386 SetLocalDescriptionExpectError(kMlineMismatch, modified_answer); 2387 SetLocalDescriptionWithoutError(answer); 2388 } 2389 2390 // This test verifies that WebRtcSession does not start candidate allocation 2391 // before SetLocalDescription is called. 2392 TEST_F(WebRtcSessionTest, TestIceStartAfterSetLocalDescriptionOnly) { 2393 Init(NULL); 2394 mediastream_signaling_.SendAudioVideoStream1(); 2395 SessionDescriptionInterface* offer = CreateRemoteOffer(); 2396 cricket::Candidate candidate; 2397 candidate.set_component(1); 2398 JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0, 2399 candidate); 2400 EXPECT_TRUE(offer->AddCandidate(&ice_candidate)); 2401 cricket::Candidate candidate1; 2402 candidate1.set_component(1); 2403 JsepIceCandidate ice_candidate1(kMediaContentName1, kMediaContentIndex1, 2404 candidate1); 2405 EXPECT_TRUE(offer->AddCandidate(&ice_candidate1)); 2406 SetRemoteDescriptionWithoutError(offer); 2407 ASSERT_TRUE(session_->GetTransportProxy("audio") != NULL); 2408 ASSERT_TRUE(session_->GetTransportProxy("video") != NULL); 2409 2410 // Pump for 1 second and verify that no candidates are generated. 2411 talk_base::Thread::Current()->ProcessMessages(1000); 2412 EXPECT_TRUE(observer_.mline_0_candidates_.empty()); 2413 EXPECT_TRUE(observer_.mline_1_candidates_.empty()); 2414 2415 SessionDescriptionInterface* answer = CreateAnswer(NULL); 2416 SetLocalDescriptionWithoutError(answer); 2417 EXPECT_TRUE(session_->GetTransportProxy("audio")->negotiated()); 2418 EXPECT_TRUE(session_->GetTransportProxy("video")->negotiated()); 2419 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); 2420 } 2421 2422 // This test verifies that crypto parameter is updated in local session 2423 // description as per security policy set in MediaSessionDescriptionFactory. 2424 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescription) { 2425 Init(NULL); 2426 mediastream_signaling_.SendAudioVideoStream1(); 2427 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 2428 CreateOffer(NULL)); 2429 2430 // Making sure SetLocalDescription correctly sets crypto value in 2431 // SessionDescription object after de-serialization of sdp string. The value 2432 // will be set as per MediaSessionDescriptionFactory. 2433 std::string offer_str; 2434 offer->ToString(&offer_str); 2435 SessionDescriptionInterface* jsep_offer_str = 2436 CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL); 2437 SetLocalDescriptionWithoutError(jsep_offer_str); 2438 EXPECT_TRUE(session_->voice_channel()->secure_required()); 2439 EXPECT_TRUE(session_->video_channel()->secure_required()); 2440 } 2441 2442 // This test verifies the crypto parameter when security is disabled. 2443 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) { 2444 options_.disable_encryption = true; 2445 Init(NULL); 2446 mediastream_signaling_.SendAudioVideoStream1(); 2447 talk_base::scoped_ptr<SessionDescriptionInterface> offer( 2448 CreateOffer(NULL)); 2449 2450 // Making sure SetLocalDescription correctly sets crypto value in 2451 // SessionDescription object after de-serialization of sdp string. The value 2452 // will be set as per MediaSessionDescriptionFactory. 2453 std::string offer_str; 2454 offer->ToString(&offer_str); 2455 SessionDescriptionInterface *jsep_offer_str = 2456 CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL); 2457 SetLocalDescriptionWithoutError(jsep_offer_str); 2458 EXPECT_FALSE(session_->voice_channel()->secure_required()); 2459 EXPECT_FALSE(session_->video_channel()->secure_required()); 2460 } 2461 2462 // This test verifies that an answer contains new ufrag and password if an offer 2463 // with new ufrag and password is received. 2464 TEST_F(WebRtcSessionTest, TestCreateAnswerWithNewUfragAndPassword) { 2465 Init(NULL); 2466 cricket::MediaSessionOptions options; 2467 options.has_audio = true; 2468 options.has_video = true; 2469 talk_base::scoped_ptr<JsepSessionDescription> offer( 2470 CreateRemoteOffer(options)); 2471 SetRemoteDescriptionWithoutError(offer.release()); 2472 2473 mediastream_signaling_.SendAudioVideoStream1(); 2474 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 2475 CreateAnswer(NULL)); 2476 SetLocalDescriptionWithoutError(answer.release()); 2477 2478 // Receive an offer with new ufrag and password. 2479 options.transport_options.ice_restart = true; 2480 talk_base::scoped_ptr<JsepSessionDescription> updated_offer1( 2481 CreateRemoteOffer(options, session_->remote_description())); 2482 SetRemoteDescriptionWithoutError(updated_offer1.release()); 2483 2484 talk_base::scoped_ptr<SessionDescriptionInterface> updated_answer1( 2485 CreateAnswer(NULL)); 2486 2487 CompareIceUfragAndPassword(updated_answer1->description(), 2488 session_->local_description()->description(), 2489 false); 2490 2491 SetLocalDescriptionWithoutError(updated_answer1.release()); 2492 } 2493 2494 // This test verifies that an answer contains old ufrag and password if an offer 2495 // with old ufrag and password is received. 2496 TEST_F(WebRtcSessionTest, TestCreateAnswerWithOldUfragAndPassword) { 2497 Init(NULL); 2498 cricket::MediaSessionOptions options; 2499 options.has_audio = true; 2500 options.has_video = true; 2501 talk_base::scoped_ptr<JsepSessionDescription> offer( 2502 CreateRemoteOffer(options)); 2503 SetRemoteDescriptionWithoutError(offer.release()); 2504 2505 mediastream_signaling_.SendAudioVideoStream1(); 2506 talk_base::scoped_ptr<SessionDescriptionInterface> answer( 2507 CreateAnswer(NULL)); 2508 SetLocalDescriptionWithoutError(answer.release()); 2509 2510 // Receive an offer without changed ufrag or password. 2511 options.transport_options.ice_restart = false; 2512 talk_base::scoped_ptr<JsepSessionDescription> updated_offer2( 2513 CreateRemoteOffer(options, session_->remote_description())); 2514 SetRemoteDescriptionWithoutError(updated_offer2.release()); 2515 2516 talk_base::scoped_ptr<SessionDescriptionInterface> updated_answer2( 2517 CreateAnswer(NULL)); 2518 2519 CompareIceUfragAndPassword(updated_answer2->description(), 2520 session_->local_description()->description(), 2521 true); 2522 2523 SetLocalDescriptionWithoutError(updated_answer2.release()); 2524 } 2525 2526 TEST_F(WebRtcSessionTest, TestSessionContentError) { 2527 Init(NULL); 2528 mediastream_signaling_.SendAudioVideoStream1(); 2529 SessionDescriptionInterface* offer = CreateOffer(NULL); 2530 const std::string session_id_orig = offer->session_id(); 2531 const std::string session_version_orig = offer->session_version(); 2532 SetLocalDescriptionWithoutError(offer); 2533 2534 video_channel_ = media_engine_->GetVideoChannel(0); 2535 video_channel_->set_fail_set_send_codecs(true); 2536 2537 mediastream_signaling_.SendAudioVideoStream2(); 2538 SessionDescriptionInterface* answer = 2539 CreateRemoteAnswer(session_->local_description()); 2540 SetRemoteDescriptionExpectError("ERROR_CONTENT", answer); 2541 } 2542 2543 // Runs the loopback call test with BUNDLE and STUN disabled. 2544 TEST_F(WebRtcSessionTest, TestIceStatesBasic) { 2545 // Lets try with only UDP ports. 2546 allocator_.set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | 2547 cricket::PORTALLOCATOR_DISABLE_TCP | 2548 cricket::PORTALLOCATOR_DISABLE_STUN | 2549 cricket::PORTALLOCATOR_DISABLE_RELAY); 2550 TestLoopbackCall(); 2551 } 2552 2553 // Regression-test for a crash which should have been an error. 2554 TEST_F(WebRtcSessionTest, TestNoStateTransitionPendingError) { 2555 Init(NULL); 2556 cricket::MediaSessionOptions options; 2557 options.has_audio = true; 2558 options.has_video = true; 2559 2560 session_->SetError(cricket::BaseSession::ERROR_CONTENT); 2561 SessionDescriptionInterface* offer = CreateRemoteOffer(options); 2562 SessionDescriptionInterface* answer = 2563 CreateRemoteAnswer(offer, options); 2564 SetRemoteDescriptionExpectError(kSessionError, offer); 2565 SetLocalDescriptionExpectError(kSessionError, answer); 2566 // Not crashing is our success. 2567 } 2568 2569 TEST_F(WebRtcSessionTest, TestRtpDataChannel) { 2570 constraints_.reset(new FakeConstraints()); 2571 constraints_->AddOptional( 2572 webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true); 2573 Init(NULL); 2574 2575 SetLocalDescriptionWithDataChannel(); 2576 EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type()); 2577 } 2578 2579 TEST_F(WebRtcSessionTest, TestRtpDataChannelConstraintTakesPrecedence) { 2580 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2581 2582 constraints_.reset(new FakeConstraints()); 2583 constraints_->AddOptional( 2584 webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true); 2585 options_.disable_sctp_data_channels = false; 2586 2587 InitWithDtls(false); 2588 2589 SetLocalDescriptionWithDataChannel(); 2590 EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type()); 2591 } 2592 2593 TEST_F(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) { 2594 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2595 2596 InitWithDtls(false); 2597 2598 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL)); 2599 EXPECT_TRUE(offer->description()->GetContentByName("data") == NULL); 2600 EXPECT_TRUE(offer->description()->GetTransportInfoByName("data") == NULL); 2601 } 2602 2603 TEST_F(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) { 2604 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2605 SetFactoryDtlsSrtp(); 2606 InitWithDtls(false); 2607 2608 // Create remote offer with SCTP. 2609 cricket::MediaSessionOptions options; 2610 options.data_channel_type = cricket::DCT_SCTP; 2611 JsepSessionDescription* offer = 2612 CreateRemoteOffer(options, cricket::SEC_ENABLED); 2613 SetRemoteDescriptionWithoutError(offer); 2614 2615 // Verifies the answer contains SCTP. 2616 talk_base::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); 2617 EXPECT_TRUE(answer != NULL); 2618 EXPECT_TRUE(answer->description()->GetContentByName("data") != NULL); 2619 EXPECT_TRUE(answer->description()->GetTransportInfoByName("data") != NULL); 2620 } 2621 2622 TEST_F(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) { 2623 constraints_.reset(new FakeConstraints()); 2624 constraints_->AddOptional( 2625 webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, false); 2626 InitWithDtls(false); 2627 2628 SetLocalDescriptionWithDataChannel(); 2629 EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type()); 2630 } 2631 2632 TEST_F(WebRtcSessionTest, TestSctpDataChannelWithDtls) { 2633 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2634 2635 InitWithDtls(false); 2636 2637 SetLocalDescriptionWithDataChannel(); 2638 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type()); 2639 } 2640 2641 TEST_F(WebRtcSessionTest, TestDisableSctpDataChannels) { 2642 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2643 options_.disable_sctp_data_channels = true; 2644 InitWithDtls(false); 2645 2646 SetLocalDescriptionWithDataChannel(); 2647 EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type()); 2648 } 2649 2650 TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) { 2651 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2652 const int new_send_port = 9998; 2653 const int new_recv_port = 7775; 2654 2655 InitWithDtls(false); 2656 SetFactoryDtlsSrtp(); 2657 2658 // By default, don't actually add the codecs to desc_factory_; they don't 2659 // actually get serialized for SCTP in BuildMediaDescription(). Instead, 2660 // let the session description get parsed. That'll get the proper codecs 2661 // into the stream. 2662 cricket::MediaSessionOptions options; 2663 JsepSessionDescription* offer = CreateRemoteOfferWithSctpPort( 2664 "stream1", new_send_port, options); 2665 2666 // SetRemoteDescription will take the ownership of the offer. 2667 SetRemoteDescriptionWithoutError(offer); 2668 2669 SessionDescriptionInterface* answer = ChangeSDPSctpPort( 2670 new_recv_port, CreateAnswer(NULL)); 2671 ASSERT_TRUE(answer != NULL); 2672 2673 // Now set the local description, which'll take ownership of the answer. 2674 SetLocalDescriptionWithoutError(answer); 2675 2676 // TEST PLAN: Set the port number to something new, set it in the SDP, 2677 // and pass it all the way down. 2678 webrtc::DataChannelInit dci; 2679 dci.reliable = true; 2680 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type()); 2681 talk_base::scoped_refptr<webrtc::DataChannel> dc = 2682 session_->CreateDataChannel("datachannel", &dci); 2683 2684 cricket::FakeDataMediaChannel* ch = data_engine_->GetChannel(0); 2685 int portnum = -1; 2686 ASSERT_TRUE(ch != NULL); 2687 ASSERT_EQ(1UL, ch->send_codecs().size()); 2688 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, ch->send_codecs()[0].id); 2689 EXPECT_TRUE(!strcmp(cricket::kGoogleSctpDataCodecName, 2690 ch->send_codecs()[0].name.c_str())); 2691 EXPECT_TRUE(ch->send_codecs()[0].GetParam(cricket::kCodecParamPort, 2692 &portnum)); 2693 EXPECT_EQ(new_send_port, portnum); 2694 2695 ASSERT_EQ(1UL, ch->recv_codecs().size()); 2696 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, ch->recv_codecs()[0].id); 2697 EXPECT_TRUE(!strcmp(cricket::kGoogleSctpDataCodecName, 2698 ch->recv_codecs()[0].name.c_str())); 2699 EXPECT_TRUE(ch->recv_codecs()[0].GetParam(cricket::kCodecParamPort, 2700 &portnum)); 2701 EXPECT_EQ(new_recv_port, portnum); 2702 } 2703 2704 // Verifies that CreateOffer succeeds when CreateOffer is called before async 2705 // identity generation is finished. 2706 TEST_F(WebRtcSessionTest, TestCreateOfferBeforeIdentityRequestReturnSuccess) { 2707 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2708 InitWithDtls(false); 2709 2710 EXPECT_TRUE(session_->waiting_for_identity()); 2711 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL)); 2712 EXPECT_TRUE(offer != NULL); 2713 } 2714 2715 // Verifies that CreateAnswer succeeds when CreateOffer is called before async 2716 // identity generation is finished. 2717 TEST_F(WebRtcSessionTest, TestCreateAnswerBeforeIdentityRequestReturnSuccess) { 2718 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2719 InitWithDtls(false); 2720 2721 cricket::MediaSessionOptions options; 2722 scoped_ptr<JsepSessionDescription> offer( 2723 CreateRemoteOffer(options, cricket::SEC_REQUIRED)); 2724 ASSERT_TRUE(offer.get() != NULL); 2725 SetRemoteDescriptionWithoutError(offer.release()); 2726 2727 talk_base::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); 2728 EXPECT_TRUE(answer != NULL); 2729 } 2730 2731 // Verifies that CreateOffer succeeds when CreateOffer is called after async 2732 // identity generation is finished. 2733 TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnSuccess) { 2734 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2735 InitWithDtls(false); 2736 2737 EXPECT_TRUE_WAIT(!session_->waiting_for_identity(), 1000); 2738 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL)); 2739 EXPECT_TRUE(offer != NULL); 2740 } 2741 2742 // Verifies that CreateOffer fails when CreateOffer is called after async 2743 // identity generation fails. 2744 TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnFailure) { 2745 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2746 InitWithDtls(true); 2747 2748 EXPECT_TRUE_WAIT(!session_->waiting_for_identity(), 1000); 2749 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL)); 2750 EXPECT_TRUE(offer == NULL); 2751 } 2752 2753 // Verifies that CreateOffer succeeds when Multiple CreateOffer calls are made 2754 // before async identity generation is finished. 2755 TEST_F(WebRtcSessionTest, 2756 TestMultipleCreateOfferBeforeIdentityRequestReturnSuccess) { 2757 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2758 VerifyMultipleAsyncCreateDescription( 2759 true, CreateSessionDescriptionRequest::kOffer); 2760 } 2761 2762 // Verifies that CreateOffer fails when Multiple CreateOffer calls are made 2763 // before async identity generation fails. 2764 TEST_F(WebRtcSessionTest, 2765 TestMultipleCreateOfferBeforeIdentityRequestReturnFailure) { 2766 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2767 VerifyMultipleAsyncCreateDescription( 2768 false, CreateSessionDescriptionRequest::kOffer); 2769 } 2770 2771 // Verifies that CreateAnswer succeeds when Multiple CreateAnswer calls are made 2772 // before async identity generation is finished. 2773 TEST_F(WebRtcSessionTest, 2774 TestMultipleCreateAnswerBeforeIdentityRequestReturnSuccess) { 2775 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2776 VerifyMultipleAsyncCreateDescription( 2777 true, CreateSessionDescriptionRequest::kAnswer); 2778 } 2779 2780 // Verifies that CreateAnswer fails when Multiple CreateAnswer calls are made 2781 // before async identity generation fails. 2782 TEST_F(WebRtcSessionTest, 2783 TestMultipleCreateAnswerBeforeIdentityRequestReturnFailure) { 2784 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp); 2785 VerifyMultipleAsyncCreateDescription( 2786 false, CreateSessionDescriptionRequest::kAnswer); 2787 } 2788 2789 // Verifies that setRemoteDescription fails when DTLS is disabled and the remote 2790 // offer has no SDES crypto but only DTLS fingerprint. 2791 TEST_F(WebRtcSessionTest, TestSetRemoteOfferFailIfDtlsDisabledAndNoCrypto) { 2792 // Init without DTLS. 2793 Init(NULL); 2794 // Create a remote offer with secured transport disabled. 2795 cricket::MediaSessionOptions options; 2796 JsepSessionDescription* offer(CreateRemoteOffer( 2797 options, cricket::SEC_DISABLED)); 2798 // Adds a DTLS fingerprint to the remote offer. 2799 cricket::SessionDescription* sdp = offer->description(); 2800 TransportInfo* audio = sdp->GetTransportInfoByName("audio"); 2801 ASSERT_TRUE(audio != NULL); 2802 ASSERT_TRUE(audio->description.identity_fingerprint.get() == NULL); 2803 audio->description.identity_fingerprint.reset( 2804 talk_base::SSLFingerprint::CreateFromRfc4572( 2805 talk_base::DIGEST_SHA_256, kFakeDtlsFingerprint)); 2806 SetRemoteDescriptionExpectError(kSdpWithoutSdesAndDtlsDisabled, 2807 offer); 2808 } 2809 2810 // This test verifies DSCP is properly applied on the media channels. 2811 TEST_F(WebRtcSessionTest, TestDscpConstraint) { 2812 constraints_.reset(new FakeConstraints()); 2813 constraints_->AddOptional( 2814 webrtc::MediaConstraintsInterface::kEnableDscp, true); 2815 Init(NULL); 2816 mediastream_signaling_.SendAudioVideoStream1(); 2817 SessionDescriptionInterface* offer = CreateOffer(NULL); 2818 2819 SetLocalDescriptionWithoutError(offer); 2820 2821 video_channel_ = media_engine_->GetVideoChannel(0); 2822 voice_channel_ = media_engine_->GetVoiceChannel(0); 2823 2824 ASSERT_TRUE(video_channel_ != NULL); 2825 ASSERT_TRUE(voice_channel_ != NULL); 2826 cricket::AudioOptions audio_options; 2827 EXPECT_TRUE(voice_channel_->GetOptions(&audio_options)); 2828 cricket::VideoOptions video_options; 2829 EXPECT_TRUE(video_channel_->GetOptions(&video_options)); 2830 EXPECT_TRUE(audio_options.dscp.IsSet()); 2831 EXPECT_TRUE(audio_options.dscp.GetWithDefaultIfUnset(false)); 2832 EXPECT_TRUE(video_options.dscp.IsSet()); 2833 EXPECT_TRUE(video_options.dscp.GetWithDefaultIfUnset(false)); 2834 } 2835 2836 // TODO(bemasc): Add a TestIceStatesBundle with BUNDLE enabled. That test 2837 // currently fails because upon disconnection and reconnection OnIceComplete is 2838 // called more than once without returning to IceGatheringGathering. 2839