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