3 * Copyright 2012, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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/base/testturnserver.h"
57 #include "talk/p2p/client/basicportallocator.h"
58 #include "talk/session/media/channelmanager.h"
59 #include "talk/session/media/mediasession.h"
61 #define MAYBE_SKIP_TEST(feature) \
63 LOG(LS_INFO) << "Feature disabled... skipping"; \
67 using cricket::BaseSession;
68 using cricket::DF_PLAY;
69 using cricket::DF_SEND;
70 using cricket::FakeVoiceMediaChannel;
71 using cricket::NS_GINGLE_P2P;
72 using cricket::NS_JINGLE_ICE_UDP;
73 using cricket::TransportInfo;
74 using talk_base::SocketAddress;
75 using talk_base::scoped_ptr;
76 using talk_base::Thread;
77 using webrtc::CreateSessionDescription;
78 using webrtc::CreateSessionDescriptionObserver;
79 using webrtc::CreateSessionDescriptionRequest;
80 using webrtc::DTLSIdentityRequestObserver;
81 using webrtc::DTLSIdentityServiceInterface;
82 using webrtc::FakeConstraints;
83 using webrtc::IceCandidateCollection;
84 using webrtc::JsepIceCandidate;
85 using webrtc::JsepSessionDescription;
86 using webrtc::PeerConnectionFactoryInterface;
87 using webrtc::PeerConnectionInterface;
88 using webrtc::SessionDescriptionInterface;
89 using webrtc::StreamCollection;
90 using webrtc::WebRtcSession;
91 using webrtc::kBundleWithoutRtcpMux;
92 using webrtc::kCreateChannelFailed;
93 using webrtc::kInvalidSdp;
94 using webrtc::kMlineMismatch;
95 using webrtc::kPushDownTDFailed;
96 using webrtc::kSdpWithoutIceUfragPwd;
97 using webrtc::kSdpWithoutDtlsFingerprint;
98 using webrtc::kSdpWithoutSdesCrypto;
99 using webrtc::kSessionError;
100 using webrtc::kSessionErrorDesc;
102 static const int kClientAddrPort = 0;
103 static const char kClientAddrHost1[] = "11.11.11.11";
104 static const char kClientAddrHost2[] = "22.22.22.22";
105 static const char kStunAddrHost[] = "99.99.99.1";
106 static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478);
107 static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0);
108 static const char kTurnUsername[] = "test";
109 static const char kTurnPassword[] = "test";
111 static const char kSessionVersion[] = "1";
113 // Media index of candidates belonging to the first media content.
114 static const int kMediaContentIndex0 = 0;
115 static const char kMediaContentName0[] = "audio";
117 // Media index of candidates belonging to the second media content.
118 static const int kMediaContentIndex1 = 1;
119 static const char kMediaContentName1[] = "video";
121 static const int kIceCandidatesTimeout = 10000;
123 static const char kFakeDtlsFingerprint[] =
124 "BB:CD:72:F7:2F:D0:BA:43:F3:68:B1:0C:23:72:B6:4A:"
125 "0F:DE:34:06:BC:E0:FE:01:BC:73:C8:6D:F4:65:D5:24";
127 // Add some extra |newlines| to the |message| after |line|.
128 static void InjectAfter(const std::string& line,
129 const std::string& newlines,
130 std::string* message) {
131 const std::string tmp = line + newlines;
132 talk_base::replace_substrs(line.c_str(), line.length(),
133 tmp.c_str(), tmp.length(), message);
136 class MockIceObserver : public webrtc::IceObserver {
139 : oncandidatesready_(false),
140 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew),
141 ice_gathering_state_(PeerConnectionInterface::kIceGatheringNew) {
144 virtual void OnIceConnectionChange(
145 PeerConnectionInterface::IceConnectionState new_state) {
146 ice_connection_state_ = new_state;
148 virtual void OnIceGatheringChange(
149 PeerConnectionInterface::IceGatheringState new_state) {
150 // We can never transition back to "new".
151 EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, new_state);
152 ice_gathering_state_ = new_state;
154 // oncandidatesready_ really means "ICE gathering is complete".
155 // This if statement ensures that this value remains correct when we
156 // transition from kIceGatheringComplete to kIceGatheringGathering.
157 if (new_state == PeerConnectionInterface::kIceGatheringGathering) {
158 oncandidatesready_ = false;
162 // Found a new candidate.
163 virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {
164 switch (candidate->sdp_mline_index()) {
165 case kMediaContentIndex0:
166 mline_0_candidates_.push_back(candidate->candidate());
168 case kMediaContentIndex1:
169 mline_1_candidates_.push_back(candidate->candidate());
175 // The ICE gathering state should always be Gathering when a candidate is
176 // received (or possibly Completed in the case of the final candidate).
177 EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, ice_gathering_state_);
180 // TODO(bemasc): Remove this once callers transition to OnIceGatheringChange.
181 virtual void OnIceComplete() {
182 EXPECT_FALSE(oncandidatesready_);
183 oncandidatesready_ = true;
185 // OnIceGatheringChange(IceGatheringCompleted) and OnIceComplete() should
186 // be called approximately simultaneously. For ease of testing, this
187 // check additionally requires that they be called in the above order.
188 EXPECT_EQ(PeerConnectionInterface::kIceGatheringComplete,
189 ice_gathering_state_);
192 bool oncandidatesready_;
193 std::vector<cricket::Candidate> mline_0_candidates_;
194 std::vector<cricket::Candidate> mline_1_candidates_;
195 PeerConnectionInterface::IceConnectionState ice_connection_state_;
196 PeerConnectionInterface::IceGatheringState ice_gathering_state_;
199 class WebRtcSessionForTest : public webrtc::WebRtcSession {
201 WebRtcSessionForTest(cricket::ChannelManager* cmgr,
202 talk_base::Thread* signaling_thread,
203 talk_base::Thread* worker_thread,
204 cricket::PortAllocator* port_allocator,
205 webrtc::IceObserver* ice_observer,
206 webrtc::MediaStreamSignaling* mediastream_signaling)
207 : WebRtcSession(cmgr, signaling_thread, worker_thread, port_allocator,
208 mediastream_signaling) {
209 RegisterIceObserver(ice_observer);
211 virtual ~WebRtcSessionForTest() {}
213 using cricket::BaseSession::GetTransportProxy;
214 using webrtc::WebRtcSession::SetAudioPlayout;
215 using webrtc::WebRtcSession::SetAudioSend;
216 using webrtc::WebRtcSession::SetCaptureDevice;
217 using webrtc::WebRtcSession::SetVideoPlayout;
218 using webrtc::WebRtcSession::SetVideoSend;
221 class WebRtcSessionCreateSDPObserverForTest
222 : public talk_base::RefCountedObject<CreateSessionDescriptionObserver> {
229 WebRtcSessionCreateSDPObserverForTest() : state_(kInit) {}
231 // CreateSessionDescriptionObserver implementation.
232 virtual void OnSuccess(SessionDescriptionInterface* desc) {
233 description_.reset(desc);
236 virtual void OnFailure(const std::string& error) {
240 SessionDescriptionInterface* description() { return description_.get(); }
242 SessionDescriptionInterface* ReleaseDescription() {
243 return description_.release();
246 State state() const { return state_; }
249 ~WebRtcSessionCreateSDPObserverForTest() {}
252 talk_base::scoped_ptr<SessionDescriptionInterface> description_;
256 class FakeAudioRenderer : public cricket::AudioRenderer {
258 FakeAudioRenderer() : channel_id_(-1), sink_(NULL) {}
259 virtual ~FakeAudioRenderer() {
264 virtual void AddChannel(int channel_id) OVERRIDE {
265 ASSERT(channel_id_ == -1);
266 channel_id_ = channel_id;
268 virtual void RemoveChannel(int channel_id) OVERRIDE {
269 ASSERT(channel_id == channel_id_);
272 virtual void SetSink(Sink* sink) OVERRIDE {
276 int channel_id() const { return channel_id_; }
277 cricket::AudioRenderer::Sink* sink() const { return sink_; }
280 cricket::AudioRenderer::Sink* sink_;
283 class WebRtcSessionTest : public testing::Test {
285 // TODO Investigate why ChannelManager crashes, if it's created
286 // after stun_server.
288 : media_engine_(new cricket::FakeMediaEngine()),
289 data_engine_(new cricket::FakeDataEngine()),
290 device_manager_(new cricket::FakeDeviceManager()),
291 channel_manager_(new cricket::ChannelManager(
292 media_engine_, data_engine_, device_manager_,
293 new cricket::CaptureManager(), talk_base::Thread::Current())),
294 tdesc_factory_(new cricket::TransportDescriptionFactory()),
295 desc_factory_(new cricket::MediaSessionDescriptionFactory(
296 channel_manager_.get(), tdesc_factory_.get())),
297 pss_(new talk_base::PhysicalSocketServer),
298 vss_(new talk_base::VirtualSocketServer(pss_.get())),
299 fss_(new talk_base::FirewallSocketServer(vss_.get())),
300 ss_scope_(fss_.get()),
301 stun_socket_addr_(talk_base::SocketAddress(kStunAddrHost,
302 cricket::STUN_SERVER_PORT)),
303 stun_server_(Thread::Current(), stun_socket_addr_),
304 turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr),
305 allocator_(new cricket::BasicPortAllocator(
306 &network_manager_, stun_socket_addr_,
307 SocketAddress(), SocketAddress(), SocketAddress())),
308 mediastream_signaling_(channel_manager_.get()),
309 ice_type_(PeerConnectionInterface::kAll) {
310 tdesc_factory_->set_protocol(cricket::ICEPROTO_HYBRID);
311 allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
312 cricket::PORTALLOCATOR_DISABLE_RELAY |
313 cricket::PORTALLOCATOR_ENABLE_BUNDLE);
314 EXPECT_TRUE(channel_manager_->Init());
315 desc_factory_->set_add_legacy_streams(false);
316 allocator_->set_step_delay(cricket::kMinimumStepDelay);
319 static void SetUpTestCase() {
320 talk_base::InitializeSSL();
323 static void TearDownTestCase() {
324 talk_base::CleanupSSL();
327 void AddInterface(const SocketAddress& addr) {
328 network_manager_.AddInterface(addr);
331 void SetIceTransportType(PeerConnectionInterface::IceTransportsType type) {
335 void Init(DTLSIdentityServiceInterface* identity_service) {
336 ASSERT_TRUE(session_.get() == NULL);
337 session_.reset(new WebRtcSessionForTest(
338 channel_manager_.get(), talk_base::Thread::Current(),
339 talk_base::Thread::Current(), allocator_.get(),
341 &mediastream_signaling_));
343 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
344 observer_.ice_connection_state_);
345 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
346 observer_.ice_gathering_state_);
348 EXPECT_TRUE(session_->Initialize(options_, constraints_.get(),
349 identity_service, ice_type_));
352 void InitWithDtmfCodec() {
353 // Add kTelephoneEventCodec for dtmf test.
354 const cricket::AudioCodec kTelephoneEventCodec(
355 106, "telephone-event", 8000, 0, 1, 0);
356 std::vector<cricket::AudioCodec> codecs;
357 codecs.push_back(kTelephoneEventCodec);
358 media_engine_->SetAudioCodecs(codecs);
359 desc_factory_->set_audio_codecs(codecs);
363 void InitWithDtls(bool identity_request_should_fail = false) {
364 FakeIdentityService* identity_service = new FakeIdentityService();
365 identity_service->set_should_fail(identity_request_should_fail);
366 Init(identity_service);
369 // Creates a local offer and applies it. Starts ice.
370 // Call mediastream_signaling_.UseOptionsWithStreamX() before this function
371 // to decide which streams to create.
372 void InitiateCall() {
373 SessionDescriptionInterface* offer = CreateOffer(NULL);
374 SetLocalDescriptionWithoutError(offer);
375 EXPECT_TRUE_WAIT(PeerConnectionInterface::kIceGatheringNew !=
376 observer_.ice_gathering_state_,
377 kIceCandidatesTimeout);
380 SessionDescriptionInterface* CreateOffer(
381 const webrtc::MediaConstraintsInterface* constraints) {
382 talk_base::scoped_refptr<WebRtcSessionCreateSDPObserverForTest>
383 observer = new WebRtcSessionCreateSDPObserverForTest();
384 session_->CreateOffer(observer, constraints);
386 observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit,
388 return observer->ReleaseDescription();
391 SessionDescriptionInterface* CreateAnswer(
392 const webrtc::MediaConstraintsInterface* constraints) {
393 talk_base::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> observer
394 = new WebRtcSessionCreateSDPObserverForTest();
395 session_->CreateAnswer(observer, constraints);
397 observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit,
399 return observer->ReleaseDescription();
402 bool ChannelsExist() const {
403 return (session_->voice_channel() != NULL &&
404 session_->video_channel() != NULL);
407 void CheckTransportChannels() const {
408 EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 1) != NULL);
409 EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 2) != NULL);
410 EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 1) != NULL);
411 EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 2) != NULL);
414 void VerifyCryptoParams(const cricket::SessionDescription* sdp) {
415 ASSERT_TRUE(session_.get() != NULL);
416 const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp);
417 ASSERT_TRUE(content != NULL);
418 const cricket::AudioContentDescription* audio_content =
419 static_cast<const cricket::AudioContentDescription*>(
420 content->description);
421 ASSERT_TRUE(audio_content != NULL);
422 ASSERT_EQ(1U, audio_content->cryptos().size());
423 ASSERT_EQ(47U, audio_content->cryptos()[0].key_params.size());
424 ASSERT_EQ("AES_CM_128_HMAC_SHA1_80",
425 audio_content->cryptos()[0].cipher_suite);
426 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
427 audio_content->protocol());
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(1U, video_content->cryptos().size());
436 ASSERT_EQ("AES_CM_128_HMAC_SHA1_80",
437 video_content->cryptos()[0].cipher_suite);
438 ASSERT_EQ(47U, video_content->cryptos()[0].key_params.size());
439 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
440 video_content->protocol());
443 void VerifyNoCryptoParams(const cricket::SessionDescription* sdp, bool dtls) {
444 const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp);
445 ASSERT_TRUE(content != NULL);
446 const cricket::AudioContentDescription* audio_content =
447 static_cast<const cricket::AudioContentDescription*>(
448 content->description);
449 ASSERT_TRUE(audio_content != NULL);
450 ASSERT_EQ(0U, audio_content->cryptos().size());
452 content = cricket::GetFirstVideoContent(sdp);
453 ASSERT_TRUE(content != NULL);
454 const cricket::VideoContentDescription* video_content =
455 static_cast<const cricket::VideoContentDescription*>(
456 content->description);
457 ASSERT_TRUE(video_content != NULL);
458 ASSERT_EQ(0U, video_content->cryptos().size());
461 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
462 audio_content->protocol());
463 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
464 video_content->protocol());
466 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf),
467 audio_content->protocol());
468 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf),
469 video_content->protocol());
473 // Set the internal fake description factories to do DTLS-SRTP.
474 void SetFactoryDtlsSrtp() {
475 desc_factory_->set_secure(cricket::SEC_DISABLED);
476 std::string identity_name = "WebRTC" +
477 talk_base::ToString(talk_base::CreateRandomId());
478 identity_.reset(talk_base::SSLIdentity::Generate(identity_name));
479 tdesc_factory_->set_identity(identity_.get());
480 tdesc_factory_->set_secure(cricket::SEC_REQUIRED);
483 void VerifyFingerprintStatus(const cricket::SessionDescription* sdp,
485 const TransportInfo* audio = sdp->GetTransportInfoByName("audio");
486 ASSERT_TRUE(audio != NULL);
487 ASSERT_EQ(expected, audio->description.identity_fingerprint.get() != NULL);
488 const TransportInfo* video = sdp->GetTransportInfoByName("video");
489 ASSERT_TRUE(video != NULL);
490 ASSERT_EQ(expected, video->description.identity_fingerprint.get() != NULL);
493 void VerifyAnswerFromNonCryptoOffer() {
494 // Create a SDP without Crypto.
495 cricket::MediaSessionOptions options;
496 options.has_video = true;
497 JsepSessionDescription* offer(
498 CreateRemoteOffer(options, cricket::SEC_DISABLED));
499 ASSERT_TRUE(offer != NULL);
500 VerifyNoCryptoParams(offer->description(), false);
501 SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto,
503 const webrtc::SessionDescriptionInterface* answer = CreateAnswer(NULL);
504 // Answer should be NULL as no crypto params in offer.
505 ASSERT_TRUE(answer == NULL);
508 void VerifyAnswerFromCryptoOffer() {
509 cricket::MediaSessionOptions options;
510 options.has_video = true;
511 options.bundle_enabled = true;
512 scoped_ptr<JsepSessionDescription> offer(
513 CreateRemoteOffer(options, cricket::SEC_REQUIRED));
514 ASSERT_TRUE(offer.get() != NULL);
515 VerifyCryptoParams(offer->description());
516 SetRemoteDescriptionWithoutError(offer.release());
517 scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL));
518 ASSERT_TRUE(answer.get() != NULL);
519 VerifyCryptoParams(answer->description());
522 void CompareIceUfragAndPassword(const cricket::SessionDescription* desc1,
523 const cricket::SessionDescription* desc2,
525 if (desc1->contents().size() != desc2->contents().size()) {
526 EXPECT_FALSE(expect_equal);
530 const cricket::ContentInfos& contents = desc1->contents();
531 cricket::ContentInfos::const_iterator it = contents.begin();
533 for (; it != contents.end(); ++it) {
534 const cricket::TransportDescription* transport_desc1 =
535 desc1->GetTransportDescriptionByName(it->name);
536 const cricket::TransportDescription* transport_desc2 =
537 desc2->GetTransportDescriptionByName(it->name);
538 if (!transport_desc1 || !transport_desc2) {
539 EXPECT_FALSE(expect_equal);
542 if (transport_desc1->ice_pwd != transport_desc2->ice_pwd ||
543 transport_desc1->ice_ufrag != transport_desc2->ice_ufrag) {
544 EXPECT_FALSE(expect_equal);
548 EXPECT_TRUE(expect_equal);
551 void RemoveIceUfragPwdLines(const SessionDescriptionInterface* current_desc,
553 const cricket::SessionDescription* desc = current_desc->description();
554 EXPECT_TRUE(current_desc->ToString(sdp));
556 const cricket::ContentInfos& contents = desc->contents();
557 cricket::ContentInfos::const_iterator it = contents.begin();
558 // Replace ufrag and pwd lines with empty strings.
559 for (; it != contents.end(); ++it) {
560 const cricket::TransportDescription* transport_desc =
561 desc->GetTransportDescriptionByName(it->name);
562 std::string ufrag_line = "a=ice-ufrag:" + transport_desc->ice_ufrag
564 std::string pwd_line = "a=ice-pwd:" + transport_desc->ice_pwd
566 talk_base::replace_substrs(ufrag_line.c_str(), ufrag_line.length(),
569 talk_base::replace_substrs(pwd_line.c_str(), pwd_line.length(),
575 // Creates a remote offer and and applies it as a remote description,
576 // creates a local answer and applies is as a local description.
577 // Call mediastream_signaling_.UseOptionsWithStreamX() before this function
578 // to decide which local and remote streams to create.
579 void CreateAndSetRemoteOfferAndLocalAnswer() {
580 SessionDescriptionInterface* offer = CreateRemoteOffer();
581 SetRemoteDescriptionWithoutError(offer);
582 SessionDescriptionInterface* answer = CreateAnswer(NULL);
583 SetLocalDescriptionWithoutError(answer);
585 void SetLocalDescriptionWithoutError(SessionDescriptionInterface* desc) {
586 EXPECT_TRUE(session_->SetLocalDescription(desc, NULL));
588 void SetLocalDescriptionExpectState(SessionDescriptionInterface* desc,
589 BaseSession::State expected_state) {
590 SetLocalDescriptionWithoutError(desc);
591 EXPECT_EQ(expected_state, session_->state());
593 void SetLocalDescriptionExpectError(const std::string& action,
594 const std::string& expected_error,
595 SessionDescriptionInterface* desc) {
597 EXPECT_FALSE(session_->SetLocalDescription(desc, &error));
598 std::string sdp_type = "local ";
599 sdp_type.append(action);
600 EXPECT_NE(std::string::npos, error.find(sdp_type));
601 EXPECT_NE(std::string::npos, error.find(expected_error));
603 void SetLocalDescriptionOfferExpectError(const std::string& expected_error,
604 SessionDescriptionInterface* desc) {
605 SetLocalDescriptionExpectError(SessionDescriptionInterface::kOffer,
606 expected_error, desc);
608 void SetLocalDescriptionAnswerExpectError(const std::string& expected_error,
609 SessionDescriptionInterface* desc) {
610 SetLocalDescriptionExpectError(SessionDescriptionInterface::kAnswer,
611 expected_error, desc);
613 void SetRemoteDescriptionWithoutError(SessionDescriptionInterface* desc) {
614 EXPECT_TRUE(session_->SetRemoteDescription(desc, NULL));
616 void SetRemoteDescriptionExpectState(SessionDescriptionInterface* desc,
617 BaseSession::State expected_state) {
618 SetRemoteDescriptionWithoutError(desc);
619 EXPECT_EQ(expected_state, session_->state());
621 void SetRemoteDescriptionExpectError(const std::string& action,
622 const std::string& expected_error,
623 SessionDescriptionInterface* desc) {
625 EXPECT_FALSE(session_->SetRemoteDescription(desc, &error));
626 std::string sdp_type = "remote ";
627 sdp_type.append(action);
628 EXPECT_NE(std::string::npos, error.find(sdp_type));
629 EXPECT_NE(std::string::npos, error.find(expected_error));
631 void SetRemoteDescriptionOfferExpectError(
632 const std::string& expected_error, SessionDescriptionInterface* desc) {
633 SetRemoteDescriptionExpectError(SessionDescriptionInterface::kOffer,
634 expected_error, desc);
636 void SetRemoteDescriptionPranswerExpectError(
637 const std::string& expected_error, SessionDescriptionInterface* desc) {
638 SetRemoteDescriptionExpectError(SessionDescriptionInterface::kPrAnswer,
639 expected_error, desc);
641 void SetRemoteDescriptionAnswerExpectError(
642 const std::string& expected_error, SessionDescriptionInterface* desc) {
643 SetRemoteDescriptionExpectError(SessionDescriptionInterface::kAnswer,
644 expected_error, desc);
647 void CreateCryptoOfferAndNonCryptoAnswer(SessionDescriptionInterface** offer,
648 SessionDescriptionInterface** nocrypto_answer) {
649 // Create a SDP without Crypto.
650 cricket::MediaSessionOptions options;
651 options.has_video = true;
652 options.bundle_enabled = true;
653 *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED);
654 ASSERT_TRUE(*offer != NULL);
655 VerifyCryptoParams((*offer)->description());
657 *nocrypto_answer = CreateRemoteAnswer(*offer, options,
658 cricket::SEC_DISABLED);
659 EXPECT_TRUE(*nocrypto_answer != NULL);
662 void CreateDtlsOfferAndNonDtlsAnswer(SessionDescriptionInterface** offer,
663 SessionDescriptionInterface** nodtls_answer) {
664 cricket::MediaSessionOptions options;
665 options.has_video = true;
666 options.bundle_enabled = true;
668 talk_base::scoped_ptr<SessionDescriptionInterface> temp_offer(
669 CreateRemoteOffer(options, cricket::SEC_ENABLED));
672 CreateRemoteAnswer(temp_offer.get(), options, cricket::SEC_ENABLED);
673 EXPECT_TRUE(*nodtls_answer != NULL);
674 VerifyFingerprintStatus((*nodtls_answer)->description(), false);
675 VerifyCryptoParams((*nodtls_answer)->description());
677 SetFactoryDtlsSrtp();
678 *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED);
679 ASSERT_TRUE(*offer != NULL);
680 VerifyFingerprintStatus((*offer)->description(), true);
681 VerifyCryptoParams((*offer)->description());
684 JsepSessionDescription* CreateRemoteOfferWithVersion(
685 cricket::MediaSessionOptions options,
686 cricket::SecurePolicy secure_policy,
687 const std::string& session_version,
688 const SessionDescriptionInterface* current_desc) {
689 std::string session_id = talk_base::ToString(talk_base::CreateRandomId64());
690 const cricket::SessionDescription* cricket_desc = NULL;
692 cricket_desc = current_desc->description();
693 session_id = current_desc->session_id();
696 desc_factory_->set_secure(secure_policy);
697 JsepSessionDescription* offer(
698 new JsepSessionDescription(JsepSessionDescription::kOffer));
699 if (!offer->Initialize(desc_factory_->CreateOffer(options, cricket_desc),
700 session_id, session_version)) {
706 JsepSessionDescription* CreateRemoteOffer(
707 cricket::MediaSessionOptions options) {
708 return CreateRemoteOfferWithVersion(options, cricket::SEC_ENABLED,
709 kSessionVersion, NULL);
711 JsepSessionDescription* CreateRemoteOffer(
712 cricket::MediaSessionOptions options, cricket::SecurePolicy sdes_policy) {
713 return CreateRemoteOfferWithVersion(
714 options, sdes_policy, kSessionVersion, NULL);
716 JsepSessionDescription* CreateRemoteOffer(
717 cricket::MediaSessionOptions options,
718 const SessionDescriptionInterface* current_desc) {
719 return CreateRemoteOfferWithVersion(options, cricket::SEC_ENABLED,
720 kSessionVersion, current_desc);
723 JsepSessionDescription* CreateRemoteOfferWithSctpPort(
724 const char* sctp_stream_name, int new_port,
725 cricket::MediaSessionOptions options) {
726 options.data_channel_type = cricket::DCT_SCTP;
727 options.AddStream(cricket::MEDIA_TYPE_DATA, "datachannel",
729 return ChangeSDPSctpPort(new_port, CreateRemoteOffer(options));
732 // Takes ownership of offer_basis (and deletes it).
733 JsepSessionDescription* ChangeSDPSctpPort(
734 int new_port, webrtc::SessionDescriptionInterface *offer_basis) {
735 // Stringify the input SDP, swap the 5000 for 'new_port' and create a new
736 // SessionDescription from the mutated string.
737 const char* default_port_str = "5000";
738 char new_port_str[16];
739 talk_base::sprintfn(new_port_str, sizeof(new_port_str), "%d", new_port);
740 std::string offer_str;
741 offer_basis->ToString(&offer_str);
742 talk_base::replace_substrs(default_port_str, strlen(default_port_str),
743 new_port_str, strlen(new_port_str),
745 JsepSessionDescription* offer = new JsepSessionDescription(
746 offer_basis->type());
748 offer->Initialize(offer_str, NULL);
752 // Create a remote offer. Call mediastream_signaling_.UseOptionsWithStreamX()
753 // before this function to decide which streams to create.
754 JsepSessionDescription* CreateRemoteOffer() {
755 cricket::MediaSessionOptions options;
756 mediastream_signaling_.GetOptionsForAnswer(NULL, &options);
757 return CreateRemoteOffer(options, session_->remote_description());
760 JsepSessionDescription* CreateRemoteAnswer(
761 const SessionDescriptionInterface* offer,
762 cricket::MediaSessionOptions options,
763 cricket::SecurePolicy policy) {
764 desc_factory_->set_secure(policy);
765 const std::string session_id =
766 talk_base::ToString(talk_base::CreateRandomId64());
767 JsepSessionDescription* answer(
768 new JsepSessionDescription(JsepSessionDescription::kAnswer));
769 if (!answer->Initialize(desc_factory_->CreateAnswer(offer->description(),
771 session_id, kSessionVersion)) {
778 JsepSessionDescription* CreateRemoteAnswer(
779 const SessionDescriptionInterface* offer,
780 cricket::MediaSessionOptions options) {
781 return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED);
784 // Creates an answer session description with streams based on
785 // |mediastream_signaling_|. Call
786 // mediastream_signaling_.UseOptionsWithStreamX() before this function
787 // to decide which streams to create.
788 JsepSessionDescription* CreateRemoteAnswer(
789 const SessionDescriptionInterface* offer) {
790 cricket::MediaSessionOptions options;
791 mediastream_signaling_.GetOptionsForAnswer(NULL, &options);
792 return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED);
795 void TestSessionCandidatesWithBundleRtcpMux(bool bundle, bool rtcp_mux) {
796 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
798 mediastream_signaling_.SendAudioVideoStream1();
799 FakeConstraints constraints;
800 constraints.SetMandatoryUseRtpMux(bundle);
801 SessionDescriptionInterface* offer = CreateOffer(&constraints);
802 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer
804 SetLocalDescriptionWithoutError(offer);
806 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
807 CreateRemoteAnswer(session_->local_description()));
809 EXPECT_TRUE(answer->ToString(&sdp));
811 size_t expected_candidate_num = 2;
813 // If rtcp_mux is enabled we should expect 4 candidates - host and srflex
815 expected_candidate_num = 4;
816 // Disable rtcp-mux from the answer
817 const std::string kRtcpMux = "a=rtcp-mux";
818 const std::string kXRtcpMux = "a=xrtcp-mux";
819 talk_base::replace_substrs(kRtcpMux.c_str(), kRtcpMux.length(),
820 kXRtcpMux.c_str(), kXRtcpMux.length(),
824 SessionDescriptionInterface* new_answer = CreateSessionDescription(
825 JsepSessionDescription::kAnswer, sdp, NULL);
827 // SetRemoteDescription to enable rtcp mux.
828 SetRemoteDescriptionWithoutError(new_answer);
829 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
830 EXPECT_EQ(expected_candidate_num, observer_.mline_0_candidates_.size());
831 EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size());
832 for (size_t i = 0; i < observer_.mline_0_candidates_.size(); ++i) {
833 cricket::Candidate c0 = observer_.mline_0_candidates_[i];
834 cricket::Candidate c1 = observer_.mline_1_candidates_[i];
836 EXPECT_TRUE(c0.IsEquivalent(c1));
838 EXPECT_FALSE(c0.IsEquivalent(c1));
842 // Tests that we can only send DTMF when the dtmf codec is supported.
843 void TestCanInsertDtmf(bool can) {
849 mediastream_signaling_.SendAudioVideoStream1();
850 CreateAndSetRemoteOfferAndLocalAnswer();
851 EXPECT_FALSE(session_->CanInsertDtmf(""));
852 EXPECT_EQ(can, session_->CanInsertDtmf(kAudioTrack1));
855 // The method sets up a call from the session to itself, in a loopback
856 // arrangement. It also uses a firewall rule to create a temporary
857 // disconnection, and then a permanent disconnection.
858 // This code is placed in a method so that it can be invoked
859 // by multiple tests with different allocators (e.g. with and without BUNDLE).
860 // While running the call, this method also checks if the session goes through
861 // the correct sequence of ICE states when a connection is established,
862 // broken, and re-established.
863 // The Connection state should go:
864 // New -> Checking -> (Connected) -> Completed -> Disconnected -> Completed
866 // The Gathering state should go: New -> Gathering -> Completed.
867 void TestLoopbackCall() {
868 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
870 mediastream_signaling_.SendAudioVideoStream1();
871 SessionDescriptionInterface* offer = CreateOffer(NULL);
873 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
874 observer_.ice_gathering_state_);
875 SetLocalDescriptionWithoutError(offer);
876 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
877 observer_.ice_connection_state_);
878 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringGathering,
879 observer_.ice_gathering_state_,
880 kIceCandidatesTimeout);
881 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
882 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete,
883 observer_.ice_gathering_state_,
884 kIceCandidatesTimeout);
887 offer->ToString(&sdp);
888 SessionDescriptionInterface* desc =
889 webrtc::CreateSessionDescription(JsepSessionDescription::kAnswer, sdp);
890 ASSERT_TRUE(desc != NULL);
891 SetRemoteDescriptionWithoutError(desc);
893 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
894 observer_.ice_connection_state_,
895 kIceCandidatesTimeout);
897 // The ice connection state is "Connected" too briefly to catch in a test.
898 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
899 observer_.ice_connection_state_,
900 kIceCandidatesTimeout);
902 // Adding firewall rule to block ping requests, which should cause
903 // transport channel failure.
907 talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
908 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
909 observer_.ice_connection_state_,
910 kIceCandidatesTimeout);
912 // Clearing the rules, session should move back to completed state.
914 // Session is automatically calling OnSignalingReady after creation of
915 // new portallocator session which will allocate new set of candidates.
917 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
918 observer_.ice_connection_state_,
919 kIceCandidatesTimeout);
921 // Now we block ping requests and wait until the ICE connection transitions
922 // to the Failed state. This will take at least 30 seconds because it must
923 // wait for the Port to timeout.
924 int port_timeout = 30000;
928 talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
929 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
930 observer_.ice_connection_state_,
931 kIceCandidatesTimeout + port_timeout);
934 void VerifyTransportType(const std::string& content_name,
935 cricket::TransportProtocol protocol) {
936 const cricket::Transport* transport = session_->GetTransport(content_name);
937 ASSERT_TRUE(transport != NULL);
938 EXPECT_EQ(protocol, transport->protocol());
941 // Adds CN codecs to FakeMediaEngine and MediaDescriptionFactory.
943 const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1, 0);
944 const cricket::AudioCodec kCNCodec2(103, "CN", 16000, 0, 1, 0);
946 // Add kCNCodec for dtmf test.
947 std::vector<cricket::AudioCodec> codecs = media_engine_->audio_codecs();;
948 codecs.push_back(kCNCodec1);
949 codecs.push_back(kCNCodec2);
950 media_engine_->SetAudioCodecs(codecs);
951 desc_factory_->set_audio_codecs(codecs);
954 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
955 const cricket::ContentDescription* description = content->description;
956 ASSERT(description != NULL);
957 const cricket::AudioContentDescription* audio_content_desc =
958 static_cast<const cricket::AudioContentDescription*>(description);
959 ASSERT(audio_content_desc != NULL);
960 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
961 if (audio_content_desc->codecs()[i].name == "CN")
967 void SetLocalDescriptionWithDataChannel() {
968 webrtc::InternalDataChannelInit dci;
969 dci.reliable = false;
970 session_->CreateDataChannel("datachannel", &dci);
971 SessionDescriptionInterface* offer = CreateOffer(NULL);
972 SetLocalDescriptionWithoutError(offer);
975 void VerifyMultipleAsyncCreateDescription(
976 bool success, CreateSessionDescriptionRequest::Type type) {
977 InitWithDtls(!success);
978 SetFactoryDtlsSrtp();
979 if (type == CreateSessionDescriptionRequest::kAnswer) {
980 cricket::MediaSessionOptions options;
981 scoped_ptr<JsepSessionDescription> offer(
982 CreateRemoteOffer(options, cricket::SEC_DISABLED));
983 ASSERT_TRUE(offer.get() != NULL);
984 SetRemoteDescriptionWithoutError(offer.release());
987 const int kNumber = 3;
988 talk_base::scoped_refptr<WebRtcSessionCreateSDPObserverForTest>
990 for (int i = 0; i < kNumber; ++i) {
991 observers[i] = new WebRtcSessionCreateSDPObserverForTest();
992 if (type == CreateSessionDescriptionRequest::kOffer) {
993 session_->CreateOffer(observers[i], NULL);
995 session_->CreateAnswer(observers[i], NULL);
999 WebRtcSessionCreateSDPObserverForTest::State expected_state =
1000 success ? WebRtcSessionCreateSDPObserverForTest::kSucceeded :
1001 WebRtcSessionCreateSDPObserverForTest::kFailed;
1003 for (int i = 0; i < kNumber; ++i) {
1004 EXPECT_EQ_WAIT(expected_state, observers[i]->state(), 1000);
1006 EXPECT_TRUE(observers[i]->description() != NULL);
1008 EXPECT_TRUE(observers[i]->description() == NULL);
1013 cricket::FakeMediaEngine* media_engine_;
1014 cricket::FakeDataEngine* data_engine_;
1015 cricket::FakeDeviceManager* device_manager_;
1016 talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
1017 talk_base::scoped_ptr<cricket::TransportDescriptionFactory> tdesc_factory_;
1018 talk_base::scoped_ptr<talk_base::SSLIdentity> identity_;
1019 talk_base::scoped_ptr<cricket::MediaSessionDescriptionFactory> desc_factory_;
1020 talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
1021 talk_base::scoped_ptr<talk_base::VirtualSocketServer> vss_;
1022 talk_base::scoped_ptr<talk_base::FirewallSocketServer> fss_;
1023 talk_base::SocketServerScope ss_scope_;
1024 talk_base::SocketAddress stun_socket_addr_;
1025 cricket::TestStunServer stun_server_;
1026 cricket::TestTurnServer turn_server_;
1027 talk_base::FakeNetworkManager network_manager_;
1028 talk_base::scoped_ptr<cricket::BasicPortAllocator> allocator_;
1029 PeerConnectionFactoryInterface::Options options_;
1030 talk_base::scoped_ptr<FakeConstraints> constraints_;
1031 FakeMediaStreamSignaling mediastream_signaling_;
1032 talk_base::scoped_ptr<WebRtcSessionForTest> session_;
1033 MockIceObserver observer_;
1034 cricket::FakeVideoMediaChannel* video_channel_;
1035 cricket::FakeVoiceMediaChannel* voice_channel_;
1036 PeerConnectionInterface::IceTransportsType ice_type_;
1039 TEST_F(WebRtcSessionTest, TestInitializeWithDtls) {
1041 // SDES is disabled when DTLS is on.
1042 EXPECT_EQ(cricket::SEC_DISABLED, session_->SdesPolicy());
1045 TEST_F(WebRtcSessionTest, TestInitializeWithoutDtls) {
1047 // SDES is required if DTLS is off.
1048 EXPECT_EQ(cricket::SEC_REQUIRED, session_->SdesPolicy());
1051 TEST_F(WebRtcSessionTest, TestSessionCandidates) {
1052 TestSessionCandidatesWithBundleRtcpMux(false, false);
1055 // Below test cases (TestSessionCandidatesWith*) verify the candidates gathered
1056 // with rtcp-mux and/or bundle.
1057 TEST_F(WebRtcSessionTest, TestSessionCandidatesWithRtcpMux) {
1058 TestSessionCandidatesWithBundleRtcpMux(false, true);
1061 TEST_F(WebRtcSessionTest, TestSessionCandidatesWithBundleRtcpMux) {
1062 TestSessionCandidatesWithBundleRtcpMux(true, true);
1065 TEST_F(WebRtcSessionTest, TestMultihomeCandidates) {
1066 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
1067 AddInterface(talk_base::SocketAddress(kClientAddrHost2, kClientAddrPort));
1069 mediastream_signaling_.SendAudioVideoStream1();
1071 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
1072 EXPECT_EQ(8u, observer_.mline_0_candidates_.size());
1073 EXPECT_EQ(8u, observer_.mline_1_candidates_.size());
1076 TEST_F(WebRtcSessionTest, TestStunError) {
1077 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
1078 AddInterface(talk_base::SocketAddress(kClientAddrHost2, kClientAddrPort));
1079 fss_->AddRule(false,
1082 talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
1084 mediastream_signaling_.SendAudioVideoStream1();
1086 // Since kClientAddrHost1 is blocked, not expecting stun candidates for it.
1087 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
1088 EXPECT_EQ(6u, observer_.mline_0_candidates_.size());
1089 EXPECT_EQ(6u, observer_.mline_1_candidates_.size());
1092 TEST_F(WebRtcSessionTest, SetSdpFailedOnInvalidSdp) {
1094 SessionDescriptionInterface* offer = NULL;
1095 // Since |offer| is NULL, there's no way to tell if it's an offer or answer.
1096 std::string unknown_action;
1097 SetLocalDescriptionExpectError(unknown_action, kInvalidSdp, offer);
1098 SetRemoteDescriptionExpectError(unknown_action, kInvalidSdp, offer);
1101 // Test creating offers and receive answers and make sure the
1102 // media engine creates the expected send and receive streams.
1103 TEST_F(WebRtcSessionTest, TestCreateSdesOfferReceiveSdesAnswer) {
1105 mediastream_signaling_.SendAudioVideoStream1();
1106 SessionDescriptionInterface* offer = CreateOffer(NULL);
1107 const std::string session_id_orig = offer->session_id();
1108 const std::string session_version_orig = offer->session_version();
1109 SetLocalDescriptionWithoutError(offer);
1111 mediastream_signaling_.SendAudioVideoStream2();
1112 SessionDescriptionInterface* answer =
1113 CreateRemoteAnswer(session_->local_description());
1114 SetRemoteDescriptionWithoutError(answer);
1116 video_channel_ = media_engine_->GetVideoChannel(0);
1117 voice_channel_ = media_engine_->GetVoiceChannel(0);
1119 ASSERT_EQ(1u, video_channel_->recv_streams().size());
1120 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
1122 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
1123 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
1125 ASSERT_EQ(1u, video_channel_->send_streams().size());
1126 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id);
1127 ASSERT_EQ(1u, voice_channel_->send_streams().size());
1128 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
1130 // Create new offer without send streams.
1131 mediastream_signaling_.SendNothing();
1132 offer = CreateOffer(NULL);
1134 // Verify the session id is the same and the session version is
1136 EXPECT_EQ(session_id_orig, offer->session_id());
1137 EXPECT_LT(talk_base::FromString<uint64>(session_version_orig),
1138 talk_base::FromString<uint64>(offer->session_version()));
1140 SetLocalDescriptionWithoutError(offer);
1142 mediastream_signaling_.SendAudioVideoStream2();
1143 answer = CreateRemoteAnswer(session_->local_description());
1144 SetRemoteDescriptionWithoutError(answer);
1146 EXPECT_EQ(0u, video_channel_->send_streams().size());
1147 EXPECT_EQ(0u, voice_channel_->send_streams().size());
1149 // Make sure the receive streams have not changed.
1150 ASSERT_EQ(1u, video_channel_->recv_streams().size());
1151 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
1152 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
1153 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
1156 // Test receiving offers and creating answers and make sure the
1157 // media engine creates the expected send and receive streams.
1158 TEST_F(WebRtcSessionTest, TestReceiveSdesOfferCreateSdesAnswer) {
1160 mediastream_signaling_.SendAudioVideoStream2();
1161 SessionDescriptionInterface* offer = CreateOffer(NULL);
1162 VerifyCryptoParams(offer->description());
1163 SetRemoteDescriptionWithoutError(offer);
1165 mediastream_signaling_.SendAudioVideoStream1();
1166 SessionDescriptionInterface* answer = CreateAnswer(NULL);
1167 VerifyCryptoParams(answer->description());
1168 SetLocalDescriptionWithoutError(answer);
1170 const std::string session_id_orig = answer->session_id();
1171 const std::string session_version_orig = answer->session_version();
1173 video_channel_ = media_engine_->GetVideoChannel(0);
1174 voice_channel_ = media_engine_->GetVoiceChannel(0);
1176 ASSERT_EQ(1u, video_channel_->recv_streams().size());
1177 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
1179 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
1180 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
1182 ASSERT_EQ(1u, video_channel_->send_streams().size());
1183 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id);
1184 ASSERT_EQ(1u, voice_channel_->send_streams().size());
1185 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
1187 mediastream_signaling_.SendAudioVideoStream1And2();
1188 offer = CreateOffer(NULL);
1189 SetRemoteDescriptionWithoutError(offer);
1191 // Answer by turning off all send streams.
1192 mediastream_signaling_.SendNothing();
1193 answer = CreateAnswer(NULL);
1195 // Verify the session id is the same and the session version is
1197 EXPECT_EQ(session_id_orig, answer->session_id());
1198 EXPECT_LT(talk_base::FromString<uint64>(session_version_orig),
1199 talk_base::FromString<uint64>(answer->session_version()));
1200 SetLocalDescriptionWithoutError(answer);
1202 ASSERT_EQ(2u, video_channel_->recv_streams().size());
1203 EXPECT_TRUE(kVideoTrack1 == video_channel_->recv_streams()[0].id);
1204 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[1].id);
1205 ASSERT_EQ(2u, voice_channel_->recv_streams().size());
1206 EXPECT_TRUE(kAudioTrack1 == voice_channel_->recv_streams()[0].id);
1207 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[1].id);
1209 // Make sure we have no send streams.
1210 EXPECT_EQ(0u, video_channel_->send_streams().size());
1211 EXPECT_EQ(0u, voice_channel_->send_streams().size());
1214 TEST_F(WebRtcSessionTest, SetLocalSdpFailedOnCreateChannel) {
1216 media_engine_->set_fail_create_channel(true);
1218 SessionDescriptionInterface* offer = CreateOffer(NULL);
1219 ASSERT_TRUE(offer != NULL);
1220 // SetRemoteDescription and SetLocalDescription will take the ownership of
1222 SetRemoteDescriptionOfferExpectError(kCreateChannelFailed, offer);
1223 offer = CreateOffer(NULL);
1224 ASSERT_TRUE(offer != NULL);
1225 SetLocalDescriptionOfferExpectError(kCreateChannelFailed, offer);
1229 // Tests for creating/setting SDP under different SDES/DTLS polices:
1231 // --DTLS off and SDES on
1232 // TestCreateSdesOfferReceiveSdesAnswer/TestReceiveSdesOfferCreateSdesAnswer:
1233 // set local/remote offer/answer with crypto --> success
1234 // TestSetNonSdesOfferWhenSdesOn: set local/remote offer without crypto --->
1236 // TestSetLocalNonSdesAnswerWhenSdesOn: set local answer without crypto -->
1238 // TestSetRemoteNonSdesAnswerWhenSdesOn: set remote answer without crypto -->
1241 // --DTLS on and SDES off
1242 // TestCreateDtlsOfferReceiveDtlsAnswer/TestReceiveDtlsOfferCreateDtlsAnswer:
1243 // set local/remote offer/answer with DTLS fingerprint --> success
1244 // TestReceiveNonDtlsOfferWhenDtlsOn: set local/remote offer without DTLS
1245 // fingerprint --> failure
1246 // TestSetLocalNonDtlsAnswerWhenDtlsOn: set local answer without fingerprint
1248 // TestSetRemoteNonDtlsAnswerWhenDtlsOn: set remote answer without fingerprint
1251 // --Encryption disabled: DTLS off and SDES off
1252 // TestCreateOfferReceiveAnswerWithoutEncryption: set local offer and remote
1253 // answer without SDES or DTLS --> success
1254 // TestCreateAnswerReceiveOfferWithoutEncryption: set remote offer and local
1255 // answer without SDES or DTLS --> success
1258 // Test that we return a failure when applying a remote/local offer that doesn't
1259 // have cryptos enabled when DTLS is off.
1260 TEST_F(WebRtcSessionTest, TestSetNonSdesOfferWhenSdesOn) {
1262 cricket::MediaSessionOptions options;
1263 options.has_video = true;
1264 JsepSessionDescription* offer = CreateRemoteOffer(
1265 options, cricket::SEC_DISABLED);
1266 ASSERT_TRUE(offer != NULL);
1267 VerifyNoCryptoParams(offer->description(), false);
1268 // SetRemoteDescription and SetLocalDescription will take the ownership of
1270 SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer);
1271 offer = CreateRemoteOffer(options, cricket::SEC_DISABLED);
1272 ASSERT_TRUE(offer != NULL);
1273 SetLocalDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer);
1276 // Test that we return a failure when applying a local answer that doesn't have
1277 // cryptos enabled when DTLS is off.
1278 TEST_F(WebRtcSessionTest, TestSetLocalNonSdesAnswerWhenSdesOn) {
1280 SessionDescriptionInterface* offer = NULL;
1281 SessionDescriptionInterface* answer = NULL;
1282 CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer);
1283 // SetRemoteDescription and SetLocalDescription will take the ownership of
1285 SetRemoteDescriptionWithoutError(offer);
1286 SetLocalDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer);
1289 // Test we will return fail when apply an remote answer that doesn't have
1290 // crypto enabled when DTLS is off.
1291 TEST_F(WebRtcSessionTest, TestSetRemoteNonSdesAnswerWhenSdesOn) {
1293 SessionDescriptionInterface* offer = NULL;
1294 SessionDescriptionInterface* answer = NULL;
1295 CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer);
1296 // SetRemoteDescription and SetLocalDescription will take the ownership of
1298 SetLocalDescriptionWithoutError(offer);
1299 SetRemoteDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer);
1302 // Test that we accept an offer with a DTLS fingerprint when DTLS is on
1303 // and that we return an answer with a DTLS fingerprint.
1304 TEST_F(WebRtcSessionTest, TestReceiveDtlsOfferCreateDtlsAnswer) {
1305 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
1306 mediastream_signaling_.SendAudioVideoStream1();
1308 SetFactoryDtlsSrtp();
1309 cricket::MediaSessionOptions options;
1310 options.has_video = true;
1311 JsepSessionDescription* offer =
1312 CreateRemoteOffer(options, cricket::SEC_DISABLED);
1313 ASSERT_TRUE(offer != NULL);
1314 VerifyFingerprintStatus(offer->description(), true);
1315 VerifyNoCryptoParams(offer->description(), true);
1317 // SetRemoteDescription will take the ownership of the offer.
1318 SetRemoteDescriptionWithoutError(offer);
1320 // Verify that we get a crypto fingerprint in the answer.
1321 SessionDescriptionInterface* answer = CreateAnswer(NULL);
1322 ASSERT_TRUE(answer != NULL);
1323 VerifyFingerprintStatus(answer->description(), true);
1324 // Check that we don't have an a=crypto line in the answer.
1325 VerifyNoCryptoParams(answer->description(), true);
1327 // Now set the local description, which should work, even without a=crypto.
1328 SetLocalDescriptionWithoutError(answer);
1331 // Test that we set a local offer with a DTLS fingerprint when DTLS is on
1332 // and then we accept a remote answer with a DTLS fingerprint successfully.
1333 TEST_F(WebRtcSessionTest, TestCreateDtlsOfferReceiveDtlsAnswer) {
1334 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
1335 mediastream_signaling_.SendAudioVideoStream1();
1337 SetFactoryDtlsSrtp();
1339 // Verify that we get a crypto fingerprint in the answer.
1340 SessionDescriptionInterface* offer = CreateOffer(NULL);
1341 ASSERT_TRUE(offer != NULL);
1342 VerifyFingerprintStatus(offer->description(), true);
1343 // Check that we don't have an a=crypto line in the offer.
1344 VerifyNoCryptoParams(offer->description(), true);
1346 // Now set the local description, which should work, even without a=crypto.
1347 SetLocalDescriptionWithoutError(offer);
1349 cricket::MediaSessionOptions options;
1350 options.has_video = true;
1351 JsepSessionDescription* answer =
1352 CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED);
1353 ASSERT_TRUE(answer != NULL);
1354 VerifyFingerprintStatus(answer->description(), true);
1355 VerifyNoCryptoParams(answer->description(), true);
1357 // SetRemoteDescription will take the ownership of the answer.
1358 SetRemoteDescriptionWithoutError(answer);
1361 // Test that if we support DTLS and the other side didn't offer a fingerprint,
1362 // we will fail to set the remote description.
1363 TEST_F(WebRtcSessionTest, TestReceiveNonDtlsOfferWhenDtlsOn) {
1364 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
1366 cricket::MediaSessionOptions options;
1367 options.has_video = true;
1368 options.bundle_enabled = true;
1369 JsepSessionDescription* offer = CreateRemoteOffer(
1370 options, cricket::SEC_REQUIRED);
1371 ASSERT_TRUE(offer != NULL);
1372 VerifyFingerprintStatus(offer->description(), false);
1373 VerifyCryptoParams(offer->description());
1375 // SetRemoteDescription will take the ownership of the offer.
1376 SetRemoteDescriptionOfferExpectError(
1377 kSdpWithoutDtlsFingerprint, offer);
1379 offer = CreateRemoteOffer(options, cricket::SEC_REQUIRED);
1380 // SetLocalDescription will take the ownership of the offer.
1381 SetLocalDescriptionOfferExpectError(
1382 kSdpWithoutDtlsFingerprint, offer);
1385 // Test that we return a failure when applying a local answer that doesn't have
1386 // a DTLS fingerprint when DTLS is required.
1387 TEST_F(WebRtcSessionTest, TestSetLocalNonDtlsAnswerWhenDtlsOn) {
1388 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
1390 SessionDescriptionInterface* offer = NULL;
1391 SessionDescriptionInterface* answer = NULL;
1392 CreateDtlsOfferAndNonDtlsAnswer(&offer, &answer);
1394 // SetRemoteDescription and SetLocalDescription will take the ownership of
1395 // the offer and answer.
1396 SetRemoteDescriptionWithoutError(offer);
1397 SetLocalDescriptionAnswerExpectError(
1398 kSdpWithoutDtlsFingerprint, answer);
1401 // Test that we return a failure when applying a remote answer that doesn't have
1402 // a DTLS fingerprint when DTLS is required.
1403 TEST_F(WebRtcSessionTest, TestSetRemoteNonDtlsAnswerWhenDtlsOn) {
1404 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
1406 SessionDescriptionInterface* offer = CreateOffer(NULL);
1407 cricket::MediaSessionOptions options;
1408 options.has_video = true;
1409 JsepSessionDescription* answer =
1410 CreateRemoteAnswer(offer, options, cricket::SEC_ENABLED);
1412 // SetRemoteDescription and SetLocalDescription will take the ownership of
1413 // the offer and answer.
1414 SetLocalDescriptionWithoutError(offer);
1415 SetRemoteDescriptionAnswerExpectError(
1416 kSdpWithoutDtlsFingerprint, answer);
1419 // Test that we create a local offer without SDES or DTLS and accept a remote
1420 // answer without SDES or DTLS when encryption is disabled.
1421 TEST_F(WebRtcSessionTest, TestCreateOfferReceiveAnswerWithoutEncryption) {
1422 mediastream_signaling_.SendAudioVideoStream1();
1423 options_.disable_encryption = true;
1426 // Verify that we get a crypto fingerprint in the answer.
1427 SessionDescriptionInterface* offer = CreateOffer(NULL);
1428 ASSERT_TRUE(offer != NULL);
1429 VerifyFingerprintStatus(offer->description(), false);
1430 // Check that we don't have an a=crypto line in the offer.
1431 VerifyNoCryptoParams(offer->description(), false);
1433 // Now set the local description, which should work, even without a=crypto.
1434 SetLocalDescriptionWithoutError(offer);
1436 cricket::MediaSessionOptions options;
1437 options.has_video = true;
1438 JsepSessionDescription* answer =
1439 CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED);
1440 ASSERT_TRUE(answer != NULL);
1441 VerifyFingerprintStatus(answer->description(), false);
1442 VerifyNoCryptoParams(answer->description(), false);
1444 // SetRemoteDescription will take the ownership of the answer.
1445 SetRemoteDescriptionWithoutError(answer);
1448 // Test that we create a local answer without SDES or DTLS and accept a remote
1449 // offer without SDES or DTLS when encryption is disabled.
1450 TEST_F(WebRtcSessionTest, TestCreateAnswerReceiveOfferWithoutEncryption) {
1451 options_.disable_encryption = true;
1454 cricket::MediaSessionOptions options;
1455 options.has_video = true;
1456 JsepSessionDescription* offer =
1457 CreateRemoteOffer(options, cricket::SEC_DISABLED);
1458 ASSERT_TRUE(offer != NULL);
1459 VerifyFingerprintStatus(offer->description(), false);
1460 VerifyNoCryptoParams(offer->description(), false);
1462 // SetRemoteDescription will take the ownership of the offer.
1463 SetRemoteDescriptionWithoutError(offer);
1465 // Verify that we get a crypto fingerprint in the answer.
1466 SessionDescriptionInterface* answer = CreateAnswer(NULL);
1467 ASSERT_TRUE(answer != NULL);
1468 VerifyFingerprintStatus(answer->description(), false);
1469 // Check that we don't have an a=crypto line in the answer.
1470 VerifyNoCryptoParams(answer->description(), false);
1472 // Now set the local description, which should work, even without a=crypto.
1473 SetLocalDescriptionWithoutError(answer);
1476 TEST_F(WebRtcSessionTest, TestSetLocalOfferTwice) {
1478 mediastream_signaling_.SendNothing();
1479 // SetLocalDescription take ownership of offer.
1480 SessionDescriptionInterface* offer = CreateOffer(NULL);
1481 SetLocalDescriptionWithoutError(offer);
1483 // SetLocalDescription take ownership of offer.
1484 SessionDescriptionInterface* offer2 = CreateOffer(NULL);
1485 SetLocalDescriptionWithoutError(offer2);
1488 TEST_F(WebRtcSessionTest, TestSetRemoteOfferTwice) {
1490 mediastream_signaling_.SendNothing();
1491 // SetLocalDescription take ownership of offer.
1492 SessionDescriptionInterface* offer = CreateOffer(NULL);
1493 SetRemoteDescriptionWithoutError(offer);
1495 SessionDescriptionInterface* offer2 = CreateOffer(NULL);
1496 SetRemoteDescriptionWithoutError(offer2);
1499 TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteOffer) {
1501 mediastream_signaling_.SendNothing();
1502 SessionDescriptionInterface* offer = CreateOffer(NULL);
1503 SetLocalDescriptionWithoutError(offer);
1504 offer = CreateOffer(NULL);
1505 SetRemoteDescriptionOfferExpectError(
1506 "Called in wrong state: STATE_SENTINITIATE", offer);
1509 TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) {
1511 mediastream_signaling_.SendNothing();
1512 SessionDescriptionInterface* offer = CreateOffer(NULL);
1513 SetRemoteDescriptionWithoutError(offer);
1514 offer = CreateOffer(NULL);
1515 SetLocalDescriptionOfferExpectError(
1516 "Called in wrong state: STATE_RECEIVEDINITIATE", offer);
1519 TEST_F(WebRtcSessionTest, TestSetLocalPrAnswer) {
1521 mediastream_signaling_.SendNothing();
1522 SessionDescriptionInterface* offer = CreateRemoteOffer();
1523 SetRemoteDescriptionExpectState(offer, BaseSession::STATE_RECEIVEDINITIATE);
1525 JsepSessionDescription* pranswer = static_cast<JsepSessionDescription*>(
1526 CreateAnswer(NULL));
1527 pranswer->set_type(SessionDescriptionInterface::kPrAnswer);
1528 SetLocalDescriptionExpectState(pranswer, BaseSession::STATE_SENTPRACCEPT);
1530 mediastream_signaling_.SendAudioVideoStream1();
1531 JsepSessionDescription* pranswer2 = static_cast<JsepSessionDescription*>(
1532 CreateAnswer(NULL));
1533 pranswer2->set_type(SessionDescriptionInterface::kPrAnswer);
1535 SetLocalDescriptionExpectState(pranswer2, BaseSession::STATE_SENTPRACCEPT);
1537 mediastream_signaling_.SendAudioVideoStream2();
1538 SessionDescriptionInterface* answer = CreateAnswer(NULL);
1539 SetLocalDescriptionExpectState(answer, BaseSession::STATE_SENTACCEPT);
1542 TEST_F(WebRtcSessionTest, TestSetRemotePrAnswer) {
1544 mediastream_signaling_.SendNothing();
1545 SessionDescriptionInterface* offer = CreateOffer(NULL);
1546 SetLocalDescriptionExpectState(offer, BaseSession::STATE_SENTINITIATE);
1548 JsepSessionDescription* pranswer =
1549 CreateRemoteAnswer(session_->local_description());
1550 pranswer->set_type(SessionDescriptionInterface::kPrAnswer);
1552 SetRemoteDescriptionExpectState(pranswer,
1553 BaseSession::STATE_RECEIVEDPRACCEPT);
1555 mediastream_signaling_.SendAudioVideoStream1();
1556 JsepSessionDescription* pranswer2 =
1557 CreateRemoteAnswer(session_->local_description());
1558 pranswer2->set_type(SessionDescriptionInterface::kPrAnswer);
1560 SetRemoteDescriptionExpectState(pranswer2,
1561 BaseSession::STATE_RECEIVEDPRACCEPT);
1563 mediastream_signaling_.SendAudioVideoStream2();
1564 SessionDescriptionInterface* answer =
1565 CreateRemoteAnswer(session_->local_description());
1566 SetRemoteDescriptionExpectState(answer, BaseSession::STATE_RECEIVEDACCEPT);
1569 TEST_F(WebRtcSessionTest, TestSetLocalAnswerWithoutOffer) {
1571 mediastream_signaling_.SendNothing();
1572 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1574 SessionDescriptionInterface* answer =
1575 CreateRemoteAnswer(offer.get());
1576 SetLocalDescriptionAnswerExpectError("Called in wrong state: STATE_INIT",
1580 TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) {
1582 mediastream_signaling_.SendNothing();
1583 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1585 SessionDescriptionInterface* answer =
1586 CreateRemoteAnswer(offer.get());
1587 SetRemoteDescriptionAnswerExpectError(
1588 "Called in wrong state: STATE_INIT", answer);
1591 TEST_F(WebRtcSessionTest, TestAddRemoteCandidate) {
1593 mediastream_signaling_.SendAudioVideoStream1();
1595 cricket::Candidate candidate;
1596 candidate.set_component(1);
1597 JsepIceCandidate ice_candidate1(kMediaContentName0, 0, candidate);
1599 // Fail since we have not set a offer description.
1600 EXPECT_FALSE(session_->ProcessIceMessage(&ice_candidate1));
1602 SessionDescriptionInterface* offer = CreateOffer(NULL);
1603 SetLocalDescriptionWithoutError(offer);
1604 // Candidate should be allowed to add before remote description.
1605 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1));
1606 candidate.set_component(2);
1607 JsepIceCandidate ice_candidate2(kMediaContentName0, 0, candidate);
1608 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2));
1610 SessionDescriptionInterface* answer = CreateRemoteAnswer(
1611 session_->local_description());
1612 SetRemoteDescriptionWithoutError(answer);
1614 // Verifying the candidates are copied properly from internal vector.
1615 const SessionDescriptionInterface* remote_desc =
1616 session_->remote_description();
1617 ASSERT_TRUE(remote_desc != NULL);
1618 ASSERT_EQ(2u, remote_desc->number_of_mediasections());
1619 const IceCandidateCollection* candidates =
1620 remote_desc->candidates(kMediaContentIndex0);
1621 ASSERT_EQ(2u, candidates->count());
1622 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index());
1623 EXPECT_EQ(kMediaContentName0, candidates->at(0)->sdp_mid());
1624 EXPECT_EQ(1, candidates->at(0)->candidate().component());
1625 EXPECT_EQ(2, candidates->at(1)->candidate().component());
1627 // |ice_candidate3| is identical to |ice_candidate2|. It can be added
1628 // successfully, but the total count of candidates will not increase.
1629 candidate.set_component(2);
1630 JsepIceCandidate ice_candidate3(kMediaContentName0, 0, candidate);
1631 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate3));
1632 ASSERT_EQ(2u, candidates->count());
1634 JsepIceCandidate bad_ice_candidate("bad content name", 99, candidate);
1635 EXPECT_FALSE(session_->ProcessIceMessage(&bad_ice_candidate));
1638 // Test that a remote candidate is added to the remote session description and
1639 // that it is retained if the remote session description is changed.
1640 TEST_F(WebRtcSessionTest, TestRemoteCandidatesAddedToSessionDescription) {
1642 cricket::Candidate candidate1;
1643 candidate1.set_component(1);
1644 JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0,
1646 mediastream_signaling_.SendAudioVideoStream1();
1647 CreateAndSetRemoteOfferAndLocalAnswer();
1649 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1));
1650 const SessionDescriptionInterface* remote_desc =
1651 session_->remote_description();
1652 ASSERT_TRUE(remote_desc != NULL);
1653 ASSERT_EQ(2u, remote_desc->number_of_mediasections());
1654 const IceCandidateCollection* candidates =
1655 remote_desc->candidates(kMediaContentIndex0);
1656 ASSERT_EQ(1u, candidates->count());
1657 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index());
1659 // Update the RemoteSessionDescription with a new session description and
1660 // a candidate and check that the new remote session description contains both
1662 SessionDescriptionInterface* offer = CreateRemoteOffer();
1663 cricket::Candidate candidate2;
1664 JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0,
1666 EXPECT_TRUE(offer->AddCandidate(&ice_candidate2));
1667 SetRemoteDescriptionWithoutError(offer);
1669 remote_desc = session_->remote_description();
1670 ASSERT_TRUE(remote_desc != NULL);
1671 ASSERT_EQ(2u, remote_desc->number_of_mediasections());
1672 candidates = remote_desc->candidates(kMediaContentIndex0);
1673 ASSERT_EQ(2u, candidates->count());
1674 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index());
1675 // Username and password have be updated with the TransportInfo of the
1676 // SessionDescription, won't be equal to the original one.
1677 candidate2.set_username(candidates->at(0)->candidate().username());
1678 candidate2.set_password(candidates->at(0)->candidate().password());
1679 EXPECT_TRUE(candidate2.IsEquivalent(candidates->at(0)->candidate()));
1680 EXPECT_EQ(kMediaContentIndex0, candidates->at(1)->sdp_mline_index());
1681 // No need to verify the username and password.
1682 candidate1.set_username(candidates->at(1)->candidate().username());
1683 candidate1.set_password(candidates->at(1)->candidate().password());
1684 EXPECT_TRUE(candidate1.IsEquivalent(candidates->at(1)->candidate()));
1686 // Test that the candidate is ignored if we can add the same candidate again.
1687 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2));
1690 // Test that local candidates are added to the local session description and
1691 // that they are retained if the local session description is changed.
1692 TEST_F(WebRtcSessionTest, TestLocalCandidatesAddedToSessionDescription) {
1693 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
1695 mediastream_signaling_.SendAudioVideoStream1();
1696 CreateAndSetRemoteOfferAndLocalAnswer();
1698 const SessionDescriptionInterface* local_desc = session_->local_description();
1699 const IceCandidateCollection* candidates =
1700 local_desc->candidates(kMediaContentIndex0);
1701 ASSERT_TRUE(candidates != NULL);
1702 EXPECT_EQ(0u, candidates->count());
1704 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
1706 local_desc = session_->local_description();
1707 candidates = local_desc->candidates(kMediaContentIndex0);
1708 ASSERT_TRUE(candidates != NULL);
1709 EXPECT_LT(0u, candidates->count());
1710 candidates = local_desc->candidates(1);
1711 ASSERT_TRUE(candidates != NULL);
1712 EXPECT_LT(0u, candidates->count());
1714 // Update the session descriptions.
1715 mediastream_signaling_.SendAudioVideoStream1();
1716 CreateAndSetRemoteOfferAndLocalAnswer();
1718 local_desc = session_->local_description();
1719 candidates = local_desc->candidates(kMediaContentIndex0);
1720 ASSERT_TRUE(candidates != NULL);
1721 EXPECT_LT(0u, candidates->count());
1722 candidates = local_desc->candidates(1);
1723 ASSERT_TRUE(candidates != NULL);
1724 EXPECT_LT(0u, candidates->count());
1727 // Test that we can set a remote session description with remote candidates.
1728 TEST_F(WebRtcSessionTest, TestSetRemoteSessionDescriptionWithCandidates) {
1731 cricket::Candidate candidate1;
1732 candidate1.set_component(1);
1733 JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0,
1735 mediastream_signaling_.SendAudioVideoStream1();
1736 SessionDescriptionInterface* offer = CreateOffer(NULL);
1738 EXPECT_TRUE(offer->AddCandidate(&ice_candidate));
1739 SetRemoteDescriptionWithoutError(offer);
1741 const SessionDescriptionInterface* remote_desc =
1742 session_->remote_description();
1743 ASSERT_TRUE(remote_desc != NULL);
1744 ASSERT_EQ(2u, remote_desc->number_of_mediasections());
1745 const IceCandidateCollection* candidates =
1746 remote_desc->candidates(kMediaContentIndex0);
1747 ASSERT_EQ(1u, candidates->count());
1748 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index());
1750 SessionDescriptionInterface* answer = CreateAnswer(NULL);
1751 SetLocalDescriptionWithoutError(answer);
1754 // Test that offers and answers contains ice candidates when Ice candidates have
1756 TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteDescriptionWithCandidates) {
1757 AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
1759 mediastream_signaling_.SendAudioVideoStream1();
1760 // Ice is started but candidates are not provided until SetLocalDescription
1762 EXPECT_EQ(0u, observer_.mline_0_candidates_.size());
1763 EXPECT_EQ(0u, observer_.mline_1_candidates_.size());
1764 CreateAndSetRemoteOfferAndLocalAnswer();
1765 // Wait until at least one local candidate has been collected.
1766 EXPECT_TRUE_WAIT(0u < observer_.mline_0_candidates_.size(),
1767 kIceCandidatesTimeout);
1768 EXPECT_TRUE_WAIT(0u < observer_.mline_1_candidates_.size(),
1769 kIceCandidatesTimeout);
1771 talk_base::scoped_ptr<SessionDescriptionInterface> local_offer(
1773 ASSERT_TRUE(local_offer->candidates(kMediaContentIndex0) != NULL);
1774 EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex0)->count());
1775 ASSERT_TRUE(local_offer->candidates(kMediaContentIndex1) != NULL);
1776 EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex1)->count());
1778 SessionDescriptionInterface* remote_offer(CreateRemoteOffer());
1779 SetRemoteDescriptionWithoutError(remote_offer);
1780 SessionDescriptionInterface* answer = CreateAnswer(NULL);
1781 ASSERT_TRUE(answer->candidates(kMediaContentIndex0) != NULL);
1782 EXPECT_LT(0u, answer->candidates(kMediaContentIndex0)->count());
1783 ASSERT_TRUE(answer->candidates(kMediaContentIndex1) != NULL);
1784 EXPECT_LT(0u, answer->candidates(kMediaContentIndex1)->count());
1785 SetLocalDescriptionWithoutError(answer);
1788 // Verifies TransportProxy and media channels are created with content names
1789 // present in the SessionDescription.
1790 TEST_F(WebRtcSessionTest, TestChannelCreationsWithContentNames) {
1792 mediastream_signaling_.SendAudioVideoStream1();
1793 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1796 // CreateOffer creates session description with the content names "audio" and
1797 // "video". Goal is to modify these content names and verify transport channel
1798 // proxy in the BaseSession, as proxies are created with the content names
1801 EXPECT_TRUE(offer->ToString(&sdp));
1802 const std::string kAudioMid = "a=mid:audio";
1803 const std::string kAudioMidReplaceStr = "a=mid:audio_content_name";
1804 const std::string kVideoMid = "a=mid:video";
1805 const std::string kVideoMidReplaceStr = "a=mid:video_content_name";
1807 // Replacing |audio| with |audio_content_name|.
1808 talk_base::replace_substrs(kAudioMid.c_str(), kAudioMid.length(),
1809 kAudioMidReplaceStr.c_str(),
1810 kAudioMidReplaceStr.length(),
1812 // Replacing |video| with |video_content_name|.
1813 talk_base::replace_substrs(kVideoMid.c_str(), kVideoMid.length(),
1814 kVideoMidReplaceStr.c_str(),
1815 kVideoMidReplaceStr.length(),
1818 SessionDescriptionInterface* modified_offer =
1819 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
1821 SetRemoteDescriptionWithoutError(modified_offer);
1823 SessionDescriptionInterface* answer =
1825 SetLocalDescriptionWithoutError(answer);
1827 EXPECT_TRUE(session_->GetTransportProxy("audio_content_name") != NULL);
1828 EXPECT_TRUE(session_->GetTransportProxy("video_content_name") != NULL);
1829 EXPECT_TRUE((video_channel_ = media_engine_->GetVideoChannel(0)) != NULL);
1830 EXPECT_TRUE((voice_channel_ = media_engine_->GetVoiceChannel(0)) != NULL);
1833 // Test that an offer contains the correct media content descriptions based on
1834 // the send streams when no constraints have been set.
1835 TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraintsOrStreams) {
1837 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1839 ASSERT_TRUE(offer != NULL);
1840 const cricket::ContentInfo* content =
1841 cricket::GetFirstAudioContent(offer->description());
1842 EXPECT_TRUE(content != NULL);
1843 content = cricket::GetFirstVideoContent(offer->description());
1844 EXPECT_TRUE(content == NULL);
1847 // Test that an offer contains the correct media content descriptions based on
1848 // the send streams when no constraints have been set.
1849 TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraints) {
1851 // Test Audio only offer.
1852 mediastream_signaling_.UseOptionsAudioOnly();
1853 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1855 const cricket::ContentInfo* content =
1856 cricket::GetFirstAudioContent(offer->description());
1857 EXPECT_TRUE(content != NULL);
1858 content = cricket::GetFirstVideoContent(offer->description());
1859 EXPECT_TRUE(content == NULL);
1861 // Test Audio / Video offer.
1862 mediastream_signaling_.SendAudioVideoStream1();
1863 offer.reset(CreateOffer(NULL));
1864 content = cricket::GetFirstAudioContent(offer->description());
1865 EXPECT_TRUE(content != NULL);
1866 content = cricket::GetFirstVideoContent(offer->description());
1867 EXPECT_TRUE(content != NULL);
1870 // Test that an offer contains no media content descriptions if
1871 // kOfferToReceiveVideo and kOfferToReceiveAudio constraints are set to false.
1872 TEST_F(WebRtcSessionTest, CreateOfferWithConstraintsWithoutStreams) {
1874 webrtc::FakeConstraints constraints_no_receive;
1875 constraints_no_receive.SetMandatoryReceiveAudio(false);
1876 constraints_no_receive.SetMandatoryReceiveVideo(false);
1878 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1879 CreateOffer(&constraints_no_receive));
1880 ASSERT_TRUE(offer != NULL);
1881 const cricket::ContentInfo* content =
1882 cricket::GetFirstAudioContent(offer->description());
1883 EXPECT_TRUE(content == NULL);
1884 content = cricket::GetFirstVideoContent(offer->description());
1885 EXPECT_TRUE(content == NULL);
1888 // Test that an offer contains only audio media content descriptions if
1889 // kOfferToReceiveAudio constraints are set to true.
1890 TEST_F(WebRtcSessionTest, CreateAudioOnlyOfferWithConstraints) {
1892 webrtc::FakeConstraints constraints_audio_only;
1893 constraints_audio_only.SetMandatoryReceiveAudio(true);
1894 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1895 CreateOffer(&constraints_audio_only));
1897 const cricket::ContentInfo* content =
1898 cricket::GetFirstAudioContent(offer->description());
1899 EXPECT_TRUE(content != NULL);
1900 content = cricket::GetFirstVideoContent(offer->description());
1901 EXPECT_TRUE(content == NULL);
1904 // Test that an offer contains audio and video media content descriptions if
1905 // kOfferToReceiveAudio and kOfferToReceiveVideo constraints are set to true.
1906 TEST_F(WebRtcSessionTest, CreateOfferWithConstraints) {
1908 // Test Audio / Video offer.
1909 webrtc::FakeConstraints constraints_audio_video;
1910 constraints_audio_video.SetMandatoryReceiveAudio(true);
1911 constraints_audio_video.SetMandatoryReceiveVideo(true);
1912 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
1913 CreateOffer(&constraints_audio_video));
1914 const cricket::ContentInfo* content =
1915 cricket::GetFirstAudioContent(offer->description());
1917 EXPECT_TRUE(content != NULL);
1918 content = cricket::GetFirstVideoContent(offer->description());
1919 EXPECT_TRUE(content != NULL);
1921 // TODO(perkj): Should the direction be set to SEND_ONLY if
1922 // The constraints is set to not receive audio or video but a track is added?
1925 // Test that an answer can not be created if the last remote description is not
1927 TEST_F(WebRtcSessionTest, CreateAnswerWithoutAnOffer) {
1929 SessionDescriptionInterface* offer = CreateOffer(NULL);
1930 SetLocalDescriptionWithoutError(offer);
1931 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
1932 SetRemoteDescriptionWithoutError(answer);
1933 EXPECT_TRUE(CreateAnswer(NULL) == NULL);
1936 // Test that an answer contains the correct media content descriptions when no
1937 // constraints have been set.
1938 TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraintsOrStreams) {
1940 // Create a remote offer with audio and video content.
1941 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
1942 SetRemoteDescriptionWithoutError(offer.release());
1943 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
1944 CreateAnswer(NULL));
1945 const cricket::ContentInfo* content =
1946 cricket::GetFirstAudioContent(answer->description());
1947 ASSERT_TRUE(content != NULL);
1948 EXPECT_FALSE(content->rejected);
1950 content = cricket::GetFirstVideoContent(answer->description());
1951 ASSERT_TRUE(content != NULL);
1952 EXPECT_FALSE(content->rejected);
1955 // Test that an answer contains the correct media content descriptions when no
1956 // constraints have been set and the offer only contain audio.
1957 TEST_F(WebRtcSessionTest, CreateAudioAnswerWithoutConstraintsOrStreams) {
1959 // Create a remote offer with audio only.
1960 cricket::MediaSessionOptions options;
1961 options.has_audio = true;
1962 options.has_video = false;
1963 talk_base::scoped_ptr<JsepSessionDescription> offer(
1964 CreateRemoteOffer(options));
1965 ASSERT_TRUE(cricket::GetFirstVideoContent(offer->description()) == NULL);
1966 ASSERT_TRUE(cricket::GetFirstAudioContent(offer->description()) != NULL);
1968 SetRemoteDescriptionWithoutError(offer.release());
1969 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
1970 CreateAnswer(NULL));
1971 const cricket::ContentInfo* content =
1972 cricket::GetFirstAudioContent(answer->description());
1973 ASSERT_TRUE(content != NULL);
1974 EXPECT_FALSE(content->rejected);
1976 EXPECT_TRUE(cricket::GetFirstVideoContent(answer->description()) == NULL);
1979 // Test that an answer contains the correct media content descriptions when no
1980 // constraints have been set.
1981 TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraints) {
1983 // Create a remote offer with audio and video content.
1984 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
1985 SetRemoteDescriptionWithoutError(offer.release());
1986 // Test with a stream with tracks.
1987 mediastream_signaling_.SendAudioVideoStream1();
1988 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
1989 CreateAnswer(NULL));
1990 const cricket::ContentInfo* content =
1991 cricket::GetFirstAudioContent(answer->description());
1992 ASSERT_TRUE(content != NULL);
1993 EXPECT_FALSE(content->rejected);
1995 content = cricket::GetFirstVideoContent(answer->description());
1996 ASSERT_TRUE(content != NULL);
1997 EXPECT_FALSE(content->rejected);
2000 // Test that an answer contains the correct media content descriptions when
2001 // constraints have been set but no stream is sent.
2002 TEST_F(WebRtcSessionTest, CreateAnswerWithConstraintsWithoutStreams) {
2004 // Create a remote offer with audio and video content.
2005 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
2006 SetRemoteDescriptionWithoutError(offer.release());
2008 webrtc::FakeConstraints constraints_no_receive;
2009 constraints_no_receive.SetMandatoryReceiveAudio(false);
2010 constraints_no_receive.SetMandatoryReceiveVideo(false);
2012 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2013 CreateAnswer(&constraints_no_receive));
2014 const cricket::ContentInfo* content =
2015 cricket::GetFirstAudioContent(answer->description());
2016 ASSERT_TRUE(content != NULL);
2017 EXPECT_TRUE(content->rejected);
2019 content = cricket::GetFirstVideoContent(answer->description());
2020 ASSERT_TRUE(content != NULL);
2021 EXPECT_TRUE(content->rejected);
2024 // Test that an answer contains the correct media content descriptions when
2025 // constraints have been set and streams are sent.
2026 TEST_F(WebRtcSessionTest, CreateAnswerWithConstraints) {
2028 // Create a remote offer with audio and video content.
2029 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
2030 SetRemoteDescriptionWithoutError(offer.release());
2032 webrtc::FakeConstraints constraints_no_receive;
2033 constraints_no_receive.SetMandatoryReceiveAudio(false);
2034 constraints_no_receive.SetMandatoryReceiveVideo(false);
2036 // Test with a stream with tracks.
2037 mediastream_signaling_.SendAudioVideoStream1();
2038 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2039 CreateAnswer(&constraints_no_receive));
2041 // TODO(perkj): Should the direction be set to SEND_ONLY?
2042 const cricket::ContentInfo* content =
2043 cricket::GetFirstAudioContent(answer->description());
2044 ASSERT_TRUE(content != NULL);
2045 EXPECT_FALSE(content->rejected);
2047 // TODO(perkj): Should the direction be set to SEND_ONLY?
2048 content = cricket::GetFirstVideoContent(answer->description());
2049 ASSERT_TRUE(content != NULL);
2050 EXPECT_FALSE(content->rejected);
2053 TEST_F(WebRtcSessionTest, CreateOfferWithoutCNCodecs) {
2056 webrtc::FakeConstraints constraints;
2057 constraints.SetOptionalVAD(false);
2058 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
2059 CreateOffer(&constraints));
2060 const cricket::ContentInfo* content =
2061 cricket::GetFirstAudioContent(offer->description());
2062 EXPECT_TRUE(content != NULL);
2063 EXPECT_TRUE(VerifyNoCNCodecs(content));
2066 TEST_F(WebRtcSessionTest, CreateAnswerWithoutCNCodecs) {
2069 // Create a remote offer with audio and video content.
2070 talk_base::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
2071 SetRemoteDescriptionWithoutError(offer.release());
2073 webrtc::FakeConstraints constraints;
2074 constraints.SetOptionalVAD(false);
2075 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2076 CreateAnswer(&constraints));
2077 const cricket::ContentInfo* content =
2078 cricket::GetFirstAudioContent(answer->description());
2079 ASSERT_TRUE(content != NULL);
2080 EXPECT_TRUE(VerifyNoCNCodecs(content));
2083 // This test verifies the call setup when remote answer with audio only and
2084 // later updates with video.
2085 TEST_F(WebRtcSessionTest, TestAVOfferWithAudioOnlyAnswer) {
2087 EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL);
2088 EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL);
2090 mediastream_signaling_.SendAudioVideoStream1();
2091 SessionDescriptionInterface* offer = CreateOffer(NULL);
2093 cricket::MediaSessionOptions options;
2094 options.has_video = false;
2095 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer, options);
2097 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer
2099 SetLocalDescriptionWithoutError(offer);
2100 SetRemoteDescriptionWithoutError(answer);
2102 video_channel_ = media_engine_->GetVideoChannel(0);
2103 voice_channel_ = media_engine_->GetVoiceChannel(0);
2105 ASSERT_TRUE(video_channel_ == NULL);
2107 ASSERT_EQ(0u, voice_channel_->recv_streams().size());
2108 ASSERT_EQ(1u, voice_channel_->send_streams().size());
2109 EXPECT_EQ(kAudioTrack1, voice_channel_->send_streams()[0].id);
2111 // Let the remote end update the session descriptions, with Audio and Video.
2112 mediastream_signaling_.SendAudioVideoStream2();
2113 CreateAndSetRemoteOfferAndLocalAnswer();
2115 video_channel_ = media_engine_->GetVideoChannel(0);
2116 voice_channel_ = media_engine_->GetVoiceChannel(0);
2118 ASSERT_TRUE(video_channel_ != NULL);
2119 ASSERT_TRUE(voice_channel_ != NULL);
2121 ASSERT_EQ(1u, video_channel_->recv_streams().size());
2122 ASSERT_EQ(1u, video_channel_->send_streams().size());
2123 EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id);
2124 EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id);
2125 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
2126 ASSERT_EQ(1u, voice_channel_->send_streams().size());
2127 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id);
2128 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
2130 // Change session back to audio only.
2131 mediastream_signaling_.UseOptionsAudioOnly();
2132 CreateAndSetRemoteOfferAndLocalAnswer();
2134 EXPECT_EQ(0u, video_channel_->recv_streams().size());
2135 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
2136 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id);
2137 ASSERT_EQ(1u, voice_channel_->send_streams().size());
2138 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
2141 // This test verifies the call setup when remote answer with video only and
2142 // later updates with audio.
2143 TEST_F(WebRtcSessionTest, TestAVOfferWithVideoOnlyAnswer) {
2145 EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL);
2146 EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL);
2147 mediastream_signaling_.SendAudioVideoStream1();
2148 SessionDescriptionInterface* offer = CreateOffer(NULL);
2150 cricket::MediaSessionOptions options;
2151 options.has_audio = false;
2152 options.has_video = true;
2153 SessionDescriptionInterface* answer = CreateRemoteAnswer(
2154 offer, options, cricket::SEC_ENABLED);
2156 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer
2158 SetLocalDescriptionWithoutError(offer);
2159 SetRemoteDescriptionWithoutError(answer);
2161 video_channel_ = media_engine_->GetVideoChannel(0);
2162 voice_channel_ = media_engine_->GetVoiceChannel(0);
2164 ASSERT_TRUE(voice_channel_ == NULL);
2165 ASSERT_TRUE(video_channel_ != NULL);
2167 EXPECT_EQ(0u, video_channel_->recv_streams().size());
2168 ASSERT_EQ(1u, video_channel_->send_streams().size());
2169 EXPECT_EQ(kVideoTrack1, video_channel_->send_streams()[0].id);
2171 // Update the session descriptions, with Audio and Video.
2172 mediastream_signaling_.SendAudioVideoStream2();
2173 CreateAndSetRemoteOfferAndLocalAnswer();
2175 voice_channel_ = media_engine_->GetVoiceChannel(0);
2176 ASSERT_TRUE(voice_channel_ != NULL);
2178 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
2179 ASSERT_EQ(1u, voice_channel_->send_streams().size());
2180 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id);
2181 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
2183 // Change session back to video only.
2184 mediastream_signaling_.UseOptionsVideoOnly();
2185 CreateAndSetRemoteOfferAndLocalAnswer();
2187 video_channel_ = media_engine_->GetVideoChannel(0);
2188 voice_channel_ = media_engine_->GetVoiceChannel(0);
2190 ASSERT_EQ(1u, video_channel_->recv_streams().size());
2191 EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id);
2192 ASSERT_EQ(1u, video_channel_->send_streams().size());
2193 EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id);
2196 TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) {
2198 mediastream_signaling_.SendAudioVideoStream1();
2199 scoped_ptr<SessionDescriptionInterface> offer(
2201 VerifyCryptoParams(offer->description());
2202 SetRemoteDescriptionWithoutError(offer.release());
2203 scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL));
2204 VerifyCryptoParams(answer->description());
2207 TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) {
2208 options_.disable_encryption = true;
2210 mediastream_signaling_.SendAudioVideoStream1();
2211 scoped_ptr<SessionDescriptionInterface> offer(
2213 VerifyNoCryptoParams(offer->description(), false);
2216 TEST_F(WebRtcSessionTest, VerifyAnswerFromNonCryptoOffer) {
2218 VerifyAnswerFromNonCryptoOffer();
2221 TEST_F(WebRtcSessionTest, VerifyAnswerFromCryptoOffer) {
2223 VerifyAnswerFromCryptoOffer();
2226 // This test verifies that setLocalDescription fails if
2227 // no a=ice-ufrag and a=ice-pwd lines are present in the SDP.
2228 TEST_F(WebRtcSessionTest, TestSetLocalDescriptionWithoutIce) {
2230 mediastream_signaling_.SendAudioVideoStream1();
2231 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
2233 RemoveIceUfragPwdLines(offer.get(), &sdp);
2234 SessionDescriptionInterface* modified_offer =
2235 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
2236 SetLocalDescriptionOfferExpectError(kSdpWithoutIceUfragPwd, modified_offer);
2239 // This test verifies that setRemoteDescription fails if
2240 // no a=ice-ufrag and a=ice-pwd lines are present in the SDP.
2241 TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionWithoutIce) {
2243 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer());
2245 RemoveIceUfragPwdLines(offer.get(), &sdp);
2246 SessionDescriptionInterface* modified_offer =
2247 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
2248 SetRemoteDescriptionOfferExpectError(kSdpWithoutIceUfragPwd, modified_offer);
2251 TEST_F(WebRtcSessionTest, VerifyBundleFlagInPA) {
2252 // This test verifies BUNDLE flag in PortAllocator, if BUNDLE information in
2253 // local description is removed by the application, BUNDLE flag should be
2254 // disabled in PortAllocator. By default BUNDLE is enabled in the WebRtc.
2256 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
2257 allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
2258 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
2260 cricket::SessionDescription* offer_copy =
2261 offer->description()->Copy();
2262 offer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2263 JsepSessionDescription* modified_offer =
2264 new JsepSessionDescription(JsepSessionDescription::kOffer);
2265 modified_offer->Initialize(offer_copy, "1", "1");
2267 SetLocalDescriptionWithoutError(modified_offer);
2268 EXPECT_FALSE(allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE);
2271 TEST_F(WebRtcSessionTest, TestDisabledBundleInAnswer) {
2273 mediastream_signaling_.SendAudioVideoStream1();
2274 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
2275 allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
2276 FakeConstraints constraints;
2277 constraints.SetMandatoryUseRtpMux(true);
2278 SessionDescriptionInterface* offer = CreateOffer(&constraints);
2279 SetLocalDescriptionWithoutError(offer);
2280 mediastream_signaling_.SendAudioVideoStream2();
2281 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2282 CreateRemoteAnswer(session_->local_description()));
2283 cricket::SessionDescription* answer_copy = answer->description()->Copy();
2284 answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
2285 JsepSessionDescription* modified_answer =
2286 new JsepSessionDescription(JsepSessionDescription::kAnswer);
2287 modified_answer->Initialize(answer_copy, "1", "1");
2288 SetRemoteDescriptionWithoutError(modified_answer);
2289 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
2290 allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
2292 video_channel_ = media_engine_->GetVideoChannel(0);
2293 voice_channel_ = media_engine_->GetVoiceChannel(0);
2295 ASSERT_EQ(1u, video_channel_->recv_streams().size());
2296 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
2298 ASSERT_EQ(1u, voice_channel_->recv_streams().size());
2299 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
2301 ASSERT_EQ(1u, video_channel_->send_streams().size());
2302 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id);
2303 ASSERT_EQ(1u, voice_channel_->send_streams().size());
2304 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
2307 // This test verifies that SetLocalDescription and SetRemoteDescription fails
2308 // if BUNDLE is enabled but rtcp-mux is disabled in m-lines.
2309 TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) {
2310 WebRtcSessionTest::Init(NULL);
2311 mediastream_signaling_.SendAudioVideoStream1();
2312 EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
2313 allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
2314 FakeConstraints constraints;
2315 constraints.SetMandatoryUseRtpMux(true);
2316 SessionDescriptionInterface* offer = CreateOffer(&constraints);
2317 std::string offer_str;
2318 offer->ToString(&offer_str);
2320 const std::string rtcp_mux = "rtcp-mux";
2321 const std::string xrtcp_mux = "xrtcp-mux";
2322 talk_base::replace_substrs(rtcp_mux.c_str(), rtcp_mux.length(),
2323 xrtcp_mux.c_str(), xrtcp_mux.length(),
2325 JsepSessionDescription *local_offer =
2326 new JsepSessionDescription(JsepSessionDescription::kOffer);
2327 EXPECT_TRUE((local_offer)->Initialize(offer_str, NULL));
2328 SetLocalDescriptionOfferExpectError(kBundleWithoutRtcpMux, local_offer);
2329 JsepSessionDescription *remote_offer =
2330 new JsepSessionDescription(JsepSessionDescription::kOffer);
2331 EXPECT_TRUE((remote_offer)->Initialize(offer_str, NULL));
2332 SetRemoteDescriptionOfferExpectError(kBundleWithoutRtcpMux, remote_offer);
2333 // Trying unmodified SDP.
2334 SetLocalDescriptionWithoutError(offer);
2337 TEST_F(WebRtcSessionTest, SetAudioPlayout) {
2339 mediastream_signaling_.SendAudioVideoStream1();
2340 CreateAndSetRemoteOfferAndLocalAnswer();
2341 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
2342 ASSERT_TRUE(channel != NULL);
2343 ASSERT_EQ(1u, channel->recv_streams().size());
2344 uint32 receive_ssrc = channel->recv_streams()[0].first_ssrc();
2345 double left_vol, right_vol;
2346 EXPECT_TRUE(channel->GetOutputScaling(receive_ssrc, &left_vol, &right_vol));
2347 EXPECT_EQ(1, left_vol);
2348 EXPECT_EQ(1, right_vol);
2349 talk_base::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer());
2350 session_->SetAudioPlayout(receive_ssrc, false, renderer.get());
2351 EXPECT_TRUE(channel->GetOutputScaling(receive_ssrc, &left_vol, &right_vol));
2352 EXPECT_EQ(0, left_vol);
2353 EXPECT_EQ(0, right_vol);
2354 EXPECT_EQ(0, renderer->channel_id());
2355 session_->SetAudioPlayout(receive_ssrc, true, NULL);
2356 EXPECT_TRUE(channel->GetOutputScaling(receive_ssrc, &left_vol, &right_vol));
2357 EXPECT_EQ(1, left_vol);
2358 EXPECT_EQ(1, right_vol);
2359 EXPECT_EQ(-1, renderer->channel_id());
2362 TEST_F(WebRtcSessionTest, SetAudioSend) {
2364 mediastream_signaling_.SendAudioVideoStream1();
2365 CreateAndSetRemoteOfferAndLocalAnswer();
2366 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
2367 ASSERT_TRUE(channel != NULL);
2368 ASSERT_EQ(1u, channel->send_streams().size());
2369 uint32 send_ssrc = channel->send_streams()[0].first_ssrc();
2370 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc));
2372 cricket::AudioOptions options;
2373 options.echo_cancellation.Set(true);
2375 talk_base::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer());
2376 session_->SetAudioSend(send_ssrc, false, options, renderer.get());
2377 EXPECT_TRUE(channel->IsStreamMuted(send_ssrc));
2378 EXPECT_FALSE(channel->options().echo_cancellation.IsSet());
2379 EXPECT_EQ(0, renderer->channel_id());
2380 EXPECT_TRUE(renderer->sink() != NULL);
2382 // This will trigger SetSink(NULL) to the |renderer|.
2383 session_->SetAudioSend(send_ssrc, true, options, NULL);
2384 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc));
2386 EXPECT_TRUE(channel->options().echo_cancellation.Get(&value));
2388 EXPECT_EQ(-1, renderer->channel_id());
2389 EXPECT_TRUE(renderer->sink() == NULL);
2392 TEST_F(WebRtcSessionTest, AudioRendererForLocalStream) {
2394 mediastream_signaling_.SendAudioVideoStream1();
2395 CreateAndSetRemoteOfferAndLocalAnswer();
2396 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
2397 ASSERT_TRUE(channel != NULL);
2398 ASSERT_EQ(1u, channel->send_streams().size());
2399 uint32 send_ssrc = channel->send_streams()[0].first_ssrc();
2401 talk_base::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer());
2402 cricket::AudioOptions options;
2403 session_->SetAudioSend(send_ssrc, true, options, renderer.get());
2404 EXPECT_TRUE(renderer->sink() != NULL);
2406 // Delete the |renderer| and it will trigger OnClose() to the sink, and this
2407 // will invalidate the |renderer_| pointer in the sink and prevent getting a
2408 // SetSink(NULL) callback afterwards.
2411 // This will trigger SetSink(NULL) if no OnClose() callback.
2412 session_->SetAudioSend(send_ssrc, true, options, NULL);
2415 TEST_F(WebRtcSessionTest, SetVideoPlayout) {
2417 mediastream_signaling_.SendAudioVideoStream1();
2418 CreateAndSetRemoteOfferAndLocalAnswer();
2419 cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0);
2420 ASSERT_TRUE(channel != NULL);
2421 ASSERT_LT(0u, channel->renderers().size());
2422 EXPECT_TRUE(channel->renderers().begin()->second == NULL);
2423 ASSERT_EQ(1u, channel->recv_streams().size());
2424 uint32 receive_ssrc = channel->recv_streams()[0].first_ssrc();
2425 cricket::FakeVideoRenderer renderer;
2426 session_->SetVideoPlayout(receive_ssrc, true, &renderer);
2427 EXPECT_TRUE(channel->renderers().begin()->second == &renderer);
2428 session_->SetVideoPlayout(receive_ssrc, false, &renderer);
2429 EXPECT_TRUE(channel->renderers().begin()->second == NULL);
2432 TEST_F(WebRtcSessionTest, SetVideoSend) {
2434 mediastream_signaling_.SendAudioVideoStream1();
2435 CreateAndSetRemoteOfferAndLocalAnswer();
2436 cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0);
2437 ASSERT_TRUE(channel != NULL);
2438 ASSERT_EQ(1u, channel->send_streams().size());
2439 uint32 send_ssrc = channel->send_streams()[0].first_ssrc();
2440 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc));
2441 cricket::VideoOptions* options = NULL;
2442 session_->SetVideoSend(send_ssrc, false, options);
2443 EXPECT_TRUE(channel->IsStreamMuted(send_ssrc));
2444 session_->SetVideoSend(send_ssrc, true, options);
2445 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc));
2448 TEST_F(WebRtcSessionTest, CanNotInsertDtmf) {
2449 TestCanInsertDtmf(false);
2452 TEST_F(WebRtcSessionTest, CanInsertDtmf) {
2453 TestCanInsertDtmf(true);
2456 TEST_F(WebRtcSessionTest, InsertDtmf) {
2459 mediastream_signaling_.SendAudioVideoStream1();
2460 CreateAndSetRemoteOfferAndLocalAnswer();
2461 FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
2462 EXPECT_EQ(0U, channel->dtmf_info_queue().size());
2465 const int expected_flags = DF_SEND;
2466 const int expected_duration = 90;
2467 session_->InsertDtmf(kAudioTrack1, 0, expected_duration);
2468 session_->InsertDtmf(kAudioTrack1, 1, expected_duration);
2469 session_->InsertDtmf(kAudioTrack1, 2, expected_duration);
2472 ASSERT_EQ(3U, channel->dtmf_info_queue().size());
2473 const uint32 send_ssrc = channel->send_streams()[0].first_ssrc();
2474 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[0], send_ssrc, 0,
2475 expected_duration, expected_flags));
2476 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[1], send_ssrc, 1,
2477 expected_duration, expected_flags));
2478 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[2], send_ssrc, 2,
2479 expected_duration, expected_flags));
2482 // This test verifies the |initiator| flag when session initiates the call.
2483 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsOriginator) {
2485 EXPECT_FALSE(session_->initiator());
2486 SessionDescriptionInterface* offer = CreateOffer(NULL);
2487 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
2488 SetLocalDescriptionWithoutError(offer);
2489 EXPECT_TRUE(session_->initiator());
2490 SetRemoteDescriptionWithoutError(answer);
2491 EXPECT_TRUE(session_->initiator());
2494 // This test verifies the |initiator| flag when session receives the call.
2495 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsReceiver) {
2497 EXPECT_FALSE(session_->initiator());
2498 SessionDescriptionInterface* offer = CreateRemoteOffer();
2499 SetRemoteDescriptionWithoutError(offer);
2500 SessionDescriptionInterface* answer = CreateAnswer(NULL);
2502 EXPECT_FALSE(session_->initiator());
2503 SetLocalDescriptionWithoutError(answer);
2504 EXPECT_FALSE(session_->initiator());
2507 // This test verifies the ice protocol type at initiator of the call
2508 // if |a=ice-options:google-ice| is present in answer.
2509 TEST_F(WebRtcSessionTest, TestInitiatorGIceInAnswer) {
2511 mediastream_signaling_.SendAudioVideoStream1();
2512 SessionDescriptionInterface* offer = CreateOffer(NULL);
2513 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2514 CreateRemoteAnswer(offer));
2515 SetLocalDescriptionWithoutError(offer);
2517 EXPECT_TRUE(answer->ToString(&sdp));
2518 // Adding ice-options to the session level.
2519 InjectAfter("t=0 0\r\n",
2520 "a=ice-options:google-ice\r\n",
2522 SessionDescriptionInterface* answer_with_gice =
2523 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
2524 SetRemoteDescriptionWithoutError(answer_with_gice);
2525 VerifyTransportType("audio", cricket::ICEPROTO_GOOGLE);
2526 VerifyTransportType("video", cricket::ICEPROTO_GOOGLE);
2529 // This test verifies the ice protocol type at initiator of the call
2530 // if ICE RFC5245 is supported in answer.
2531 TEST_F(WebRtcSessionTest, TestInitiatorIceInAnswer) {
2533 mediastream_signaling_.SendAudioVideoStream1();
2534 SessionDescriptionInterface* offer = CreateOffer(NULL);
2535 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
2536 SetLocalDescriptionWithoutError(offer);
2538 SetRemoteDescriptionWithoutError(answer);
2539 VerifyTransportType("audio", cricket::ICEPROTO_RFC5245);
2540 VerifyTransportType("video", cricket::ICEPROTO_RFC5245);
2543 // This test verifies the ice protocol type at receiver side of the call if
2544 // receiver decides to use google-ice.
2545 TEST_F(WebRtcSessionTest, TestReceiverGIceInOffer) {
2547 mediastream_signaling_.SendAudioVideoStream1();
2548 SessionDescriptionInterface* offer = CreateOffer(NULL);
2549 SetRemoteDescriptionWithoutError(offer);
2550 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2551 CreateAnswer(NULL));
2553 EXPECT_TRUE(answer->ToString(&sdp));
2554 // Adding ice-options to the session level.
2555 InjectAfter("t=0 0\r\n",
2556 "a=ice-options:google-ice\r\n",
2558 SessionDescriptionInterface* answer_with_gice =
2559 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
2560 SetLocalDescriptionWithoutError(answer_with_gice);
2561 VerifyTransportType("audio", cricket::ICEPROTO_GOOGLE);
2562 VerifyTransportType("video", cricket::ICEPROTO_GOOGLE);
2565 // This test verifies the ice protocol type at receiver side of the call if
2566 // receiver decides to use ice RFC 5245.
2567 TEST_F(WebRtcSessionTest, TestReceiverIceInOffer) {
2569 mediastream_signaling_.SendAudioVideoStream1();
2570 SessionDescriptionInterface* offer = CreateOffer(NULL);
2571 SetRemoteDescriptionWithoutError(offer);
2572 SessionDescriptionInterface* answer = CreateAnswer(NULL);
2573 SetLocalDescriptionWithoutError(answer);
2574 VerifyTransportType("audio", cricket::ICEPROTO_RFC5245);
2575 VerifyTransportType("video", cricket::ICEPROTO_RFC5245);
2578 // This test verifies the session state when ICE RFC5245 in offer and
2579 // ICE google-ice in answer.
2580 TEST_F(WebRtcSessionTest, TestIceOfferGIceOnlyAnswer) {
2582 mediastream_signaling_.SendAudioVideoStream1();
2583 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
2585 std::string offer_str;
2586 offer->ToString(&offer_str);
2587 // Disable google-ice
2588 const std::string gice_option = "google-ice";
2589 const std::string xgoogle_xice = "xgoogle-xice";
2590 talk_base::replace_substrs(gice_option.c_str(), gice_option.length(),
2591 xgoogle_xice.c_str(), xgoogle_xice.length(),
2593 JsepSessionDescription *ice_only_offer =
2594 new JsepSessionDescription(JsepSessionDescription::kOffer);
2595 EXPECT_TRUE((ice_only_offer)->Initialize(offer_str, NULL));
2596 SetLocalDescriptionWithoutError(ice_only_offer);
2597 std::string original_offer_sdp;
2598 EXPECT_TRUE(offer->ToString(&original_offer_sdp));
2599 SessionDescriptionInterface* pranswer_with_gice =
2600 CreateSessionDescription(JsepSessionDescription::kPrAnswer,
2601 original_offer_sdp, NULL);
2602 SetRemoteDescriptionPranswerExpectError(kPushDownTDFailed,
2603 pranswer_with_gice);
2604 SessionDescriptionInterface* answer_with_gice =
2605 CreateSessionDescription(JsepSessionDescription::kAnswer,
2606 original_offer_sdp, NULL);
2607 SetRemoteDescriptionAnswerExpectError(kPushDownTDFailed,
2611 // Verifing local offer and remote answer have matching m-lines as per RFC 3264.
2612 TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) {
2614 mediastream_signaling_.SendAudioVideoStream1();
2615 SessionDescriptionInterface* offer = CreateOffer(NULL);
2616 SetLocalDescriptionWithoutError(offer);
2617 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2618 CreateRemoteAnswer(session_->local_description()));
2620 cricket::SessionDescription* answer_copy = answer->description()->Copy();
2621 answer_copy->RemoveContentByName("video");
2622 JsepSessionDescription* modified_answer =
2623 new JsepSessionDescription(JsepSessionDescription::kAnswer);
2625 EXPECT_TRUE(modified_answer->Initialize(answer_copy,
2626 answer->session_id(),
2627 answer->session_version()));
2628 SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer);
2630 // Different content names.
2632 EXPECT_TRUE(answer->ToString(&sdp));
2633 const std::string kAudioMid = "a=mid:audio";
2634 const std::string kAudioMidReplaceStr = "a=mid:audio_content_name";
2635 talk_base::replace_substrs(kAudioMid.c_str(), kAudioMid.length(),
2636 kAudioMidReplaceStr.c_str(),
2637 kAudioMidReplaceStr.length(),
2639 SessionDescriptionInterface* modified_answer1 =
2640 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
2641 SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer1);
2643 // Different media types.
2644 EXPECT_TRUE(answer->ToString(&sdp));
2645 const std::string kAudioMline = "m=audio";
2646 const std::string kAudioMlineReplaceStr = "m=video";
2647 talk_base::replace_substrs(kAudioMline.c_str(), kAudioMline.length(),
2648 kAudioMlineReplaceStr.c_str(),
2649 kAudioMlineReplaceStr.length(),
2651 SessionDescriptionInterface* modified_answer2 =
2652 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
2653 SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer2);
2655 SetRemoteDescriptionWithoutError(answer.release());
2658 // Verifying remote offer and local answer have matching m-lines as per
2660 TEST_F(WebRtcSessionTest, TestIncorrectMLinesInLocalAnswer) {
2662 mediastream_signaling_.SendAudioVideoStream1();
2663 SessionDescriptionInterface* offer = CreateRemoteOffer();
2664 SetRemoteDescriptionWithoutError(offer);
2665 SessionDescriptionInterface* answer = CreateAnswer(NULL);
2667 cricket::SessionDescription* answer_copy = answer->description()->Copy();
2668 answer_copy->RemoveContentByName("video");
2669 JsepSessionDescription* modified_answer =
2670 new JsepSessionDescription(JsepSessionDescription::kAnswer);
2672 EXPECT_TRUE(modified_answer->Initialize(answer_copy,
2673 answer->session_id(),
2674 answer->session_version()));
2675 SetLocalDescriptionAnswerExpectError(kMlineMismatch, modified_answer);
2676 SetLocalDescriptionWithoutError(answer);
2679 // This test verifies that WebRtcSession does not start candidate allocation
2680 // before SetLocalDescription is called.
2681 TEST_F(WebRtcSessionTest, TestIceStartAfterSetLocalDescriptionOnly) {
2683 mediastream_signaling_.SendAudioVideoStream1();
2684 SessionDescriptionInterface* offer = CreateRemoteOffer();
2685 cricket::Candidate candidate;
2686 candidate.set_component(1);
2687 JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0,
2689 EXPECT_TRUE(offer->AddCandidate(&ice_candidate));
2690 cricket::Candidate candidate1;
2691 candidate1.set_component(1);
2692 JsepIceCandidate ice_candidate1(kMediaContentName1, kMediaContentIndex1,
2694 EXPECT_TRUE(offer->AddCandidate(&ice_candidate1));
2695 SetRemoteDescriptionWithoutError(offer);
2696 ASSERT_TRUE(session_->GetTransportProxy("audio") != NULL);
2697 ASSERT_TRUE(session_->GetTransportProxy("video") != NULL);
2699 // Pump for 1 second and verify that no candidates are generated.
2700 talk_base::Thread::Current()->ProcessMessages(1000);
2701 EXPECT_TRUE(observer_.mline_0_candidates_.empty());
2702 EXPECT_TRUE(observer_.mline_1_candidates_.empty());
2704 SessionDescriptionInterface* answer = CreateAnswer(NULL);
2705 SetLocalDescriptionWithoutError(answer);
2706 EXPECT_TRUE(session_->GetTransportProxy("audio")->negotiated());
2707 EXPECT_TRUE(session_->GetTransportProxy("video")->negotiated());
2708 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
2711 // This test verifies that crypto parameter is updated in local session
2712 // description as per security policy set in MediaSessionDescriptionFactory.
2713 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescription) {
2715 mediastream_signaling_.SendAudioVideoStream1();
2716 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
2719 // Making sure SetLocalDescription correctly sets crypto value in
2720 // SessionDescription object after de-serialization of sdp string. The value
2721 // will be set as per MediaSessionDescriptionFactory.
2722 std::string offer_str;
2723 offer->ToString(&offer_str);
2724 SessionDescriptionInterface* jsep_offer_str =
2725 CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL);
2726 SetLocalDescriptionWithoutError(jsep_offer_str);
2727 EXPECT_TRUE(session_->voice_channel()->secure_required());
2728 EXPECT_TRUE(session_->video_channel()->secure_required());
2731 // This test verifies the crypto parameter when security is disabled.
2732 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) {
2733 options_.disable_encryption = true;
2735 mediastream_signaling_.SendAudioVideoStream1();
2736 talk_base::scoped_ptr<SessionDescriptionInterface> offer(
2739 // Making sure SetLocalDescription correctly sets crypto value in
2740 // SessionDescription object after de-serialization of sdp string. The value
2741 // will be set as per MediaSessionDescriptionFactory.
2742 std::string offer_str;
2743 offer->ToString(&offer_str);
2744 SessionDescriptionInterface *jsep_offer_str =
2745 CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL);
2746 SetLocalDescriptionWithoutError(jsep_offer_str);
2747 EXPECT_FALSE(session_->voice_channel()->secure_required());
2748 EXPECT_FALSE(session_->video_channel()->secure_required());
2751 // This test verifies that an answer contains new ufrag and password if an offer
2752 // with new ufrag and password is received.
2753 TEST_F(WebRtcSessionTest, TestCreateAnswerWithNewUfragAndPassword) {
2755 cricket::MediaSessionOptions options;
2756 options.has_audio = true;
2757 options.has_video = true;
2758 talk_base::scoped_ptr<JsepSessionDescription> offer(
2759 CreateRemoteOffer(options));
2760 SetRemoteDescriptionWithoutError(offer.release());
2762 mediastream_signaling_.SendAudioVideoStream1();
2763 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2764 CreateAnswer(NULL));
2765 SetLocalDescriptionWithoutError(answer.release());
2767 // Receive an offer with new ufrag and password.
2768 options.transport_options.ice_restart = true;
2769 talk_base::scoped_ptr<JsepSessionDescription> updated_offer1(
2770 CreateRemoteOffer(options, session_->remote_description()));
2771 SetRemoteDescriptionWithoutError(updated_offer1.release());
2773 talk_base::scoped_ptr<SessionDescriptionInterface> updated_answer1(
2774 CreateAnswer(NULL));
2776 CompareIceUfragAndPassword(updated_answer1->description(),
2777 session_->local_description()->description(),
2780 SetLocalDescriptionWithoutError(updated_answer1.release());
2783 // This test verifies that an answer contains old ufrag and password if an offer
2784 // with old ufrag and password is received.
2785 TEST_F(WebRtcSessionTest, TestCreateAnswerWithOldUfragAndPassword) {
2787 cricket::MediaSessionOptions options;
2788 options.has_audio = true;
2789 options.has_video = true;
2790 talk_base::scoped_ptr<JsepSessionDescription> offer(
2791 CreateRemoteOffer(options));
2792 SetRemoteDescriptionWithoutError(offer.release());
2794 mediastream_signaling_.SendAudioVideoStream1();
2795 talk_base::scoped_ptr<SessionDescriptionInterface> answer(
2796 CreateAnswer(NULL));
2797 SetLocalDescriptionWithoutError(answer.release());
2799 // Receive an offer without changed ufrag or password.
2800 options.transport_options.ice_restart = false;
2801 talk_base::scoped_ptr<JsepSessionDescription> updated_offer2(
2802 CreateRemoteOffer(options, session_->remote_description()));
2803 SetRemoteDescriptionWithoutError(updated_offer2.release());
2805 talk_base::scoped_ptr<SessionDescriptionInterface> updated_answer2(
2806 CreateAnswer(NULL));
2808 CompareIceUfragAndPassword(updated_answer2->description(),
2809 session_->local_description()->description(),
2812 SetLocalDescriptionWithoutError(updated_answer2.release());
2815 TEST_F(WebRtcSessionTest, TestSessionContentError) {
2817 mediastream_signaling_.SendAudioVideoStream1();
2818 SessionDescriptionInterface* offer = CreateOffer(NULL);
2819 const std::string session_id_orig = offer->session_id();
2820 const std::string session_version_orig = offer->session_version();
2821 SetLocalDescriptionWithoutError(offer);
2823 video_channel_ = media_engine_->GetVideoChannel(0);
2824 video_channel_->set_fail_set_send_codecs(true);
2826 mediastream_signaling_.SendAudioVideoStream2();
2827 SessionDescriptionInterface* answer =
2828 CreateRemoteAnswer(session_->local_description());
2829 SetRemoteDescriptionAnswerExpectError("ERROR_CONTENT", answer);
2832 // Runs the loopback call test with BUNDLE and STUN disabled.
2833 TEST_F(WebRtcSessionTest, TestIceStatesBasic) {
2834 // Lets try with only UDP ports.
2835 allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
2836 cricket::PORTALLOCATOR_DISABLE_TCP |
2837 cricket::PORTALLOCATOR_DISABLE_STUN |
2838 cricket::PORTALLOCATOR_DISABLE_RELAY);
2842 // Runs the loopback call test with BUNDLE and STUN enabled.
2843 TEST_F(WebRtcSessionTest, TestIceStatesBundle) {
2844 allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
2845 cricket::PORTALLOCATOR_ENABLE_BUNDLE |
2846 cricket::PORTALLOCATOR_DISABLE_TCP |
2847 cricket::PORTALLOCATOR_DISABLE_RELAY);
2851 TEST_F(WebRtcSessionTest, SetSdpFailedOnSessionError) {
2853 cricket::MediaSessionOptions options;
2854 options.has_audio = true;
2855 options.has_video = true;
2857 cricket::BaseSession::Error error_code = cricket::BaseSession::ERROR_CONTENT;
2858 std::string error_code_str = "ERROR_CONTENT";
2859 std::string error_desc = "Fake session error description.";
2860 session_->SetError(error_code, error_desc);
2862 SessionDescriptionInterface* offer = CreateRemoteOffer(options);
2863 SessionDescriptionInterface* answer =
2864 CreateRemoteAnswer(offer, options);
2867 std::ostringstream session_error_msg;
2868 session_error_msg << kSessionError << error_code_str << ". ";
2869 session_error_msg << kSessionErrorDesc << error_desc << ".";
2870 SetRemoteDescriptionExpectError(action, session_error_msg.str(), offer);
2871 SetLocalDescriptionExpectError(action, session_error_msg.str(), answer);
2874 TEST_F(WebRtcSessionTest, TestRtpDataChannel) {
2875 constraints_.reset(new FakeConstraints());
2876 constraints_->AddOptional(
2877 webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true);
2880 SetLocalDescriptionWithDataChannel();
2881 EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type());
2884 TEST_F(WebRtcSessionTest, TestRtpDataChannelConstraintTakesPrecedence) {
2885 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
2887 constraints_.reset(new FakeConstraints());
2888 constraints_->AddOptional(
2889 webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true);
2890 options_.disable_sctp_data_channels = false;
2894 SetLocalDescriptionWithDataChannel();
2895 EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type());
2898 TEST_F(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) {
2899 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
2903 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
2904 EXPECT_TRUE(offer->description()->GetContentByName("data") == NULL);
2905 EXPECT_TRUE(offer->description()->GetTransportInfoByName("data") == NULL);
2908 TEST_F(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) {
2909 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
2910 SetFactoryDtlsSrtp();
2913 // Create remote offer with SCTP.
2914 cricket::MediaSessionOptions options;
2915 options.data_channel_type = cricket::DCT_SCTP;
2916 JsepSessionDescription* offer =
2917 CreateRemoteOffer(options, cricket::SEC_DISABLED);
2918 SetRemoteDescriptionWithoutError(offer);
2920 // Verifies the answer contains SCTP.
2921 talk_base::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL));
2922 EXPECT_TRUE(answer != NULL);
2923 EXPECT_TRUE(answer->description()->GetContentByName("data") != NULL);
2924 EXPECT_TRUE(answer->description()->GetTransportInfoByName("data") != NULL);
2927 TEST_F(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) {
2928 constraints_.reset(new FakeConstraints());
2929 constraints_->AddOptional(
2930 webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, false);
2933 SetLocalDescriptionWithDataChannel();
2934 EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type());
2937 TEST_F(WebRtcSessionTest, TestSctpDataChannelWithDtls) {
2938 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
2942 SetLocalDescriptionWithDataChannel();
2943 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
2946 TEST_F(WebRtcSessionTest, TestDisableSctpDataChannels) {
2947 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
2948 options_.disable_sctp_data_channels = true;
2951 SetLocalDescriptionWithDataChannel();
2952 EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type());
2955 TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
2956 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
2957 const int new_send_port = 9998;
2958 const int new_recv_port = 7775;
2961 SetFactoryDtlsSrtp();
2963 // By default, don't actually add the codecs to desc_factory_; they don't
2964 // actually get serialized for SCTP in BuildMediaDescription(). Instead,
2965 // let the session description get parsed. That'll get the proper codecs
2967 cricket::MediaSessionOptions options;
2968 JsepSessionDescription* offer = CreateRemoteOfferWithSctpPort(
2969 "stream1", new_send_port, options);
2971 // SetRemoteDescription will take the ownership of the offer.
2972 SetRemoteDescriptionWithoutError(offer);
2974 SessionDescriptionInterface* answer = ChangeSDPSctpPort(
2975 new_recv_port, CreateAnswer(NULL));
2976 ASSERT_TRUE(answer != NULL);
2978 // Now set the local description, which'll take ownership of the answer.
2979 SetLocalDescriptionWithoutError(answer);
2981 // TEST PLAN: Set the port number to something new, set it in the SDP,
2982 // and pass it all the way down.
2983 webrtc::InternalDataChannelInit dci;
2984 dci.reliable = true;
2985 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
2986 talk_base::scoped_refptr<webrtc::DataChannel> dc =
2987 session_->CreateDataChannel("datachannel", &dci);
2989 cricket::FakeDataMediaChannel* ch = data_engine_->GetChannel(0);
2991 ASSERT_TRUE(ch != NULL);
2992 ASSERT_EQ(1UL, ch->send_codecs().size());
2993 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, ch->send_codecs()[0].id);
2994 EXPECT_TRUE(!strcmp(cricket::kGoogleSctpDataCodecName,
2995 ch->send_codecs()[0].name.c_str()));
2996 EXPECT_TRUE(ch->send_codecs()[0].GetParam(cricket::kCodecParamPort,
2998 EXPECT_EQ(new_send_port, portnum);
3000 ASSERT_EQ(1UL, ch->recv_codecs().size());
3001 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, ch->recv_codecs()[0].id);
3002 EXPECT_TRUE(!strcmp(cricket::kGoogleSctpDataCodecName,
3003 ch->recv_codecs()[0].name.c_str()));
3004 EXPECT_TRUE(ch->recv_codecs()[0].GetParam(cricket::kCodecParamPort,
3006 EXPECT_EQ(new_recv_port, portnum);
3009 // Verifies that CreateOffer succeeds when CreateOffer is called before async
3010 // identity generation is finished.
3011 TEST_F(WebRtcSessionTest, TestCreateOfferBeforeIdentityRequestReturnSuccess) {
3012 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3015 EXPECT_TRUE(session_->waiting_for_identity());
3016 mediastream_signaling_.SendAudioVideoStream1();
3017 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
3018 EXPECT_TRUE(offer != NULL);
3019 VerifyNoCryptoParams(offer->description(), true);
3020 VerifyFingerprintStatus(offer->description(), true);
3023 // Verifies that CreateAnswer succeeds when CreateOffer is called before async
3024 // identity generation is finished.
3025 TEST_F(WebRtcSessionTest, TestCreateAnswerBeforeIdentityRequestReturnSuccess) {
3026 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3028 SetFactoryDtlsSrtp();
3030 cricket::MediaSessionOptions options;
3031 options.has_video = true;
3032 scoped_ptr<JsepSessionDescription> offer(
3033 CreateRemoteOffer(options, cricket::SEC_DISABLED));
3034 ASSERT_TRUE(offer.get() != NULL);
3035 SetRemoteDescriptionWithoutError(offer.release());
3037 talk_base::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL));
3038 EXPECT_TRUE(answer != NULL);
3039 VerifyNoCryptoParams(answer->description(), true);
3040 VerifyFingerprintStatus(answer->description(), true);
3043 // Verifies that CreateOffer succeeds when CreateOffer is called after async
3044 // identity generation is finished.
3045 TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnSuccess) {
3046 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3049 EXPECT_TRUE_WAIT(!session_->waiting_for_identity(), 1000);
3050 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
3051 EXPECT_TRUE(offer != NULL);
3054 // Verifies that CreateOffer fails when CreateOffer is called after async
3055 // identity generation fails.
3056 TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnFailure) {
3057 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3060 EXPECT_TRUE_WAIT(!session_->waiting_for_identity(), 1000);
3061 talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
3062 EXPECT_TRUE(offer == NULL);
3065 // Verifies that CreateOffer succeeds when Multiple CreateOffer calls are made
3066 // before async identity generation is finished.
3067 TEST_F(WebRtcSessionTest,
3068 TestMultipleCreateOfferBeforeIdentityRequestReturnSuccess) {
3069 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3070 VerifyMultipleAsyncCreateDescription(
3071 true, CreateSessionDescriptionRequest::kOffer);
3074 // Verifies that CreateOffer fails when Multiple CreateOffer calls are made
3075 // before async identity generation fails.
3076 TEST_F(WebRtcSessionTest,
3077 TestMultipleCreateOfferBeforeIdentityRequestReturnFailure) {
3078 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3079 VerifyMultipleAsyncCreateDescription(
3080 false, CreateSessionDescriptionRequest::kOffer);
3083 // Verifies that CreateAnswer succeeds when Multiple CreateAnswer calls are made
3084 // before async identity generation is finished.
3085 TEST_F(WebRtcSessionTest,
3086 TestMultipleCreateAnswerBeforeIdentityRequestReturnSuccess) {
3087 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3088 VerifyMultipleAsyncCreateDescription(
3089 true, CreateSessionDescriptionRequest::kAnswer);
3092 // Verifies that CreateAnswer fails when Multiple CreateAnswer calls are made
3093 // before async identity generation fails.
3094 TEST_F(WebRtcSessionTest,
3095 TestMultipleCreateAnswerBeforeIdentityRequestReturnFailure) {
3096 MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
3097 VerifyMultipleAsyncCreateDescription(
3098 false, CreateSessionDescriptionRequest::kAnswer);
3101 // Verifies that setRemoteDescription fails when DTLS is disabled and the remote
3102 // offer has no SDES crypto but only DTLS fingerprint.
3103 TEST_F(WebRtcSessionTest, TestSetRemoteOfferFailIfDtlsDisabledAndNoCrypto) {
3104 // Init without DTLS.
3106 // Create a remote offer with secured transport disabled.
3107 cricket::MediaSessionOptions options;
3108 JsepSessionDescription* offer(CreateRemoteOffer(
3109 options, cricket::SEC_DISABLED));
3110 // Adds a DTLS fingerprint to the remote offer.
3111 cricket::SessionDescription* sdp = offer->description();
3112 TransportInfo* audio = sdp->GetTransportInfoByName("audio");
3113 ASSERT_TRUE(audio != NULL);
3114 ASSERT_TRUE(audio->description.identity_fingerprint.get() == NULL);
3115 audio->description.identity_fingerprint.reset(
3116 talk_base::SSLFingerprint::CreateFromRfc4572(
3117 talk_base::DIGEST_SHA_256, kFakeDtlsFingerprint));
3118 SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto,
3122 // This test verifies DSCP is properly applied on the media channels.
3123 TEST_F(WebRtcSessionTest, TestDscpConstraint) {
3124 constraints_.reset(new FakeConstraints());
3125 constraints_->AddOptional(
3126 webrtc::MediaConstraintsInterface::kEnableDscp, true);
3128 mediastream_signaling_.SendAudioVideoStream1();
3129 SessionDescriptionInterface* offer = CreateOffer(NULL);
3131 SetLocalDescriptionWithoutError(offer);
3133 video_channel_ = media_engine_->GetVideoChannel(0);
3134 voice_channel_ = media_engine_->GetVoiceChannel(0);
3136 ASSERT_TRUE(video_channel_ != NULL);
3137 ASSERT_TRUE(voice_channel_ != NULL);
3138 cricket::AudioOptions audio_options;
3139 EXPECT_TRUE(voice_channel_->GetOptions(&audio_options));
3140 cricket::VideoOptions video_options;
3141 EXPECT_TRUE(video_channel_->GetOptions(&video_options));
3142 EXPECT_TRUE(audio_options.dscp.IsSet());
3143 EXPECT_TRUE(audio_options.dscp.GetWithDefaultIfUnset(false));
3144 EXPECT_TRUE(video_options.dscp.IsSet());
3145 EXPECT_TRUE(video_options.dscp.GetWithDefaultIfUnset(false));
3148 TEST_F(WebRtcSessionTest, TestSuspendBelowMinBitrateConstraint) {
3149 constraints_.reset(new FakeConstraints());
3150 constraints_->AddOptional(
3151 webrtc::MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate,
3154 mediastream_signaling_.SendAudioVideoStream1();
3155 SessionDescriptionInterface* offer = CreateOffer(NULL);
3157 SetLocalDescriptionWithoutError(offer);
3159 video_channel_ = media_engine_->GetVideoChannel(0);
3161 ASSERT_TRUE(video_channel_ != NULL);
3162 cricket::VideoOptions video_options;
3163 EXPECT_TRUE(video_channel_->GetOptions(&video_options));
3165 video_options.suspend_below_min_bitrate.GetWithDefaultIfUnset(false));
3168 // TODO(bemasc): Add a TestIceStatesBundle with BUNDLE enabled. That test
3169 // currently fails because upon disconnection and reconnection OnIceComplete is
3170 // called more than once without returning to IceGatheringGathering.