1/* 2 * libjingle 3 * Copyright 2012, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <string> 29 30#include "talk/app/webrtc/fakeportallocatorfactory.h" 31#include "talk/app/webrtc/mediastreaminterface.h" 32#include "talk/app/webrtc/peerconnectionfactory.h" 33#include "talk/app/webrtc/test/fakevideotrackrenderer.h" 34#include "talk/app/webrtc/videosourceinterface.h" 35#include "talk/media/base/fakevideocapturer.h" 36#include "talk/media/webrtc/webrtccommon.h" 37#include "talk/media/webrtc/webrtcvoe.h" 38#include "webrtc/base/gunit.h" 39#include "webrtc/base/scoped_ptr.h" 40#include "webrtc/base/thread.h" 41 42using webrtc::FakeVideoTrackRenderer; 43using webrtc::MediaStreamInterface; 44using webrtc::PeerConnectionFactoryInterface; 45using webrtc::PeerConnectionInterface; 46using webrtc::PeerConnectionObserver; 47using webrtc::PortAllocatorFactoryInterface; 48using webrtc::VideoSourceInterface; 49using webrtc::VideoTrackInterface; 50 51namespace { 52 53typedef std::vector<PortAllocatorFactoryInterface::StunConfiguration> 54 StunConfigurations; 55typedef std::vector<PortAllocatorFactoryInterface::TurnConfiguration> 56 TurnConfigurations; 57 58static const char kStunIceServer[] = "stun:stun.l.google.com:19302"; 59static const char kTurnIceServer[] = "turn:test%40hello.com@test.com:1234"; 60static const char kTurnIceServerWithTransport[] = 61 "turn:test@hello.com?transport=tcp"; 62static const char kSecureTurnIceServer[] = 63 "turns:test@hello.com?transport=tcp"; 64static const char kSecureTurnIceServerWithoutTransportParam[] = 65 "turns:test_no_transport@hello.com:443"; 66static const char kSecureTurnIceServerWithoutTransportAndPortParam[] = 67 "turns:test_no_transport@hello.com"; 68static const char kTurnIceServerWithNoUsernameInUri[] = 69 "turn:test.com:1234"; 70static const char kTurnPassword[] = "turnpassword"; 71static const int kDefaultStunPort = 3478; 72static const int kDefaultStunTlsPort = 5349; 73static const char kTurnUsername[] = "test"; 74static const char kStunIceServerWithIPv4Address[] = "stun:1.2.3.4:1234"; 75static const char kStunIceServerWithIPv4AddressWithoutPort[] = "stun:1.2.3.4"; 76static const char kStunIceServerWithIPv6Address[] = "stun:[2401:fa00:4::]:1234"; 77static const char kStunIceServerWithIPv6AddressWithoutPort[] = 78 "stun:[2401:fa00:4::]"; 79static const char kStunIceServerWithInvalidIPv6Address[] = 80 "stun:[2401:fa00:4:::3478"; 81static const char kTurnIceServerWithIPv6Address[] = 82 "turn:test@[2401:fa00:4::]:1234"; 83 84class NullPeerConnectionObserver : public PeerConnectionObserver { 85 public: 86 virtual void OnError() {} 87 virtual void OnMessage(const std::string& msg) {} 88 virtual void OnSignalingMessage(const std::string& msg) {} 89 virtual void OnSignalingChange( 90 PeerConnectionInterface::SignalingState new_state) {} 91 virtual void OnAddStream(MediaStreamInterface* stream) {} 92 virtual void OnRemoveStream(MediaStreamInterface* stream) {} 93 virtual void OnRenegotiationNeeded() {} 94 virtual void OnIceConnectionChange( 95 PeerConnectionInterface::IceConnectionState new_state) {} 96 virtual void OnIceGatheringChange( 97 PeerConnectionInterface::IceGatheringState new_state) {} 98 virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {} 99}; 100 101} // namespace 102 103class PeerConnectionFactoryTest : public testing::Test { 104 void SetUp() { 105 factory_ = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), 106 rtc::Thread::Current(), 107 NULL, 108 NULL, 109 NULL); 110 111 ASSERT_TRUE(factory_.get() != NULL); 112 allocator_factory_ = webrtc::FakePortAllocatorFactory::Create(); 113 } 114 115 protected: 116 void VerifyStunConfigurations(StunConfigurations stun_config) { 117 webrtc::FakePortAllocatorFactory* allocator = 118 static_cast<webrtc::FakePortAllocatorFactory*>( 119 allocator_factory_.get()); 120 ASSERT_TRUE(allocator != NULL); 121 EXPECT_EQ(stun_config.size(), allocator->stun_configs().size()); 122 for (size_t i = 0; i < stun_config.size(); ++i) { 123 EXPECT_EQ(stun_config[i].server.ToString(), 124 allocator->stun_configs()[i].server.ToString()); 125 } 126 } 127 128 void VerifyTurnConfigurations(TurnConfigurations turn_config) { 129 webrtc::FakePortAllocatorFactory* allocator = 130 static_cast<webrtc::FakePortAllocatorFactory*>( 131 allocator_factory_.get()); 132 ASSERT_TRUE(allocator != NULL); 133 EXPECT_EQ(turn_config.size(), allocator->turn_configs().size()); 134 for (size_t i = 0; i < turn_config.size(); ++i) { 135 EXPECT_EQ(turn_config[i].server.ToString(), 136 allocator->turn_configs()[i].server.ToString()); 137 EXPECT_EQ(turn_config[i].username, allocator->turn_configs()[i].username); 138 EXPECT_EQ(turn_config[i].password, allocator->turn_configs()[i].password); 139 EXPECT_EQ(turn_config[i].transport_type, 140 allocator->turn_configs()[i].transport_type); 141 } 142 } 143 144 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory_; 145 NullPeerConnectionObserver observer_; 146 rtc::scoped_refptr<PortAllocatorFactoryInterface> allocator_factory_; 147}; 148 149// Verify creation of PeerConnection using internal ADM, video factory and 150// internal libjingle threads. 151TEST(PeerConnectionFactoryTestInternal, CreatePCUsingInternalModules) { 152 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 153 webrtc::CreatePeerConnectionFactory()); 154 155 NullPeerConnectionObserver observer; 156 webrtc::PeerConnectionInterface::IceServers servers; 157 158 rtc::scoped_refptr<PeerConnectionInterface> pc( 159 factory->CreatePeerConnection(servers, NULL, NULL, NULL, &observer)); 160 161 EXPECT_TRUE(pc.get() != NULL); 162} 163 164// This test verifies creation of PeerConnection with valid STUN and TURN 165// configuration. Also verifies the URL's parsed correctly as expected. 166TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServers) { 167 PeerConnectionInterface::RTCConfiguration config; 168 webrtc::PeerConnectionInterface::IceServer ice_server; 169 ice_server.uri = kStunIceServer; 170 config.servers.push_back(ice_server); 171 ice_server.uri = kTurnIceServer; 172 ice_server.password = kTurnPassword; 173 config.servers.push_back(ice_server); 174 ice_server.uri = kTurnIceServerWithTransport; 175 ice_server.password = kTurnPassword; 176 config.servers.push_back(ice_server); 177 rtc::scoped_refptr<PeerConnectionInterface> pc( 178 factory_->CreatePeerConnection(config, NULL, 179 allocator_factory_.get(), 180 NULL, 181 &observer_)); 182 EXPECT_TRUE(pc.get() != NULL); 183 StunConfigurations stun_configs; 184 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( 185 "stun.l.google.com", 19302); 186 stun_configs.push_back(stun1); 187 VerifyStunConfigurations(stun_configs); 188 TurnConfigurations turn_configs; 189 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( 190 "test.com", 1234, "test@hello.com", kTurnPassword, "udp", false); 191 turn_configs.push_back(turn1); 192 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( 193 "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); 194 turn_configs.push_back(turn2); 195 VerifyTurnConfigurations(turn_configs); 196} 197 198// This test verifies creation of PeerConnection with valid STUN and TURN 199// configuration. Also verifies the URL's parsed correctly as expected. 200// This version doesn't use RTCConfiguration. 201// TODO(mallinath) - Remove this method after clients start using RTCConfig. 202TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServersOldSignature) { 203 webrtc::PeerConnectionInterface::IceServers ice_servers; 204 webrtc::PeerConnectionInterface::IceServer ice_server; 205 ice_server.uri = kStunIceServer; 206 ice_servers.push_back(ice_server); 207 ice_server.uri = kTurnIceServer; 208 ice_server.password = kTurnPassword; 209 ice_servers.push_back(ice_server); 210 ice_server.uri = kTurnIceServerWithTransport; 211 ice_server.password = kTurnPassword; 212 ice_servers.push_back(ice_server); 213 rtc::scoped_refptr<PeerConnectionInterface> pc( 214 factory_->CreatePeerConnection(ice_servers, NULL, 215 allocator_factory_.get(), 216 NULL, 217 &observer_)); 218 EXPECT_TRUE(pc.get() != NULL); 219 StunConfigurations stun_configs; 220 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( 221 "stun.l.google.com", 19302); 222 stun_configs.push_back(stun1); 223 VerifyStunConfigurations(stun_configs); 224 TurnConfigurations turn_configs; 225 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( 226 "test.com", 1234, "test@hello.com", kTurnPassword, "udp", false); 227 turn_configs.push_back(turn1); 228 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( 229 "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); 230 turn_configs.push_back(turn2); 231 VerifyTurnConfigurations(turn_configs); 232} 233 234TEST_F(PeerConnectionFactoryTest, CreatePCUsingNoUsernameInUri) { 235 PeerConnectionInterface::RTCConfiguration config; 236 webrtc::PeerConnectionInterface::IceServer ice_server; 237 ice_server.uri = kStunIceServer; 238 config.servers.push_back(ice_server); 239 ice_server.uri = kTurnIceServerWithNoUsernameInUri; 240 ice_server.username = kTurnUsername; 241 ice_server.password = kTurnPassword; 242 config.servers.push_back(ice_server); 243 rtc::scoped_refptr<PeerConnectionInterface> pc( 244 factory_->CreatePeerConnection(config, NULL, 245 allocator_factory_.get(), 246 NULL, 247 &observer_)); 248 EXPECT_TRUE(pc.get() != NULL); 249 TurnConfigurations turn_configs; 250 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( 251 "test.com", 1234, kTurnUsername, kTurnPassword, "udp", false); 252 turn_configs.push_back(turn); 253 VerifyTurnConfigurations(turn_configs); 254} 255 256// This test verifies the PeerConnection created properly with TURN url which 257// has transport parameter in it. 258TEST_F(PeerConnectionFactoryTest, CreatePCUsingTurnUrlWithTransportParam) { 259 PeerConnectionInterface::RTCConfiguration config; 260 webrtc::PeerConnectionInterface::IceServer ice_server; 261 ice_server.uri = kTurnIceServerWithTransport; 262 ice_server.password = kTurnPassword; 263 config.servers.push_back(ice_server); 264 rtc::scoped_refptr<PeerConnectionInterface> pc( 265 factory_->CreatePeerConnection(config, NULL, 266 allocator_factory_.get(), 267 NULL, 268 &observer_)); 269 EXPECT_TRUE(pc.get() != NULL); 270 TurnConfigurations turn_configs; 271 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( 272 "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); 273 turn_configs.push_back(turn); 274 VerifyTurnConfigurations(turn_configs); 275} 276 277TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) { 278 PeerConnectionInterface::RTCConfiguration config; 279 webrtc::PeerConnectionInterface::IceServer ice_server; 280 ice_server.uri = kSecureTurnIceServer; 281 ice_server.password = kTurnPassword; 282 config.servers.push_back(ice_server); 283 ice_server.uri = kSecureTurnIceServerWithoutTransportParam; 284 ice_server.password = kTurnPassword; 285 config.servers.push_back(ice_server); 286 ice_server.uri = kSecureTurnIceServerWithoutTransportAndPortParam; 287 ice_server.password = kTurnPassword; 288 config.servers.push_back(ice_server); 289 rtc::scoped_refptr<PeerConnectionInterface> pc( 290 factory_->CreatePeerConnection(config, NULL, 291 allocator_factory_.get(), 292 NULL, 293 &observer_)); 294 EXPECT_TRUE(pc.get() != NULL); 295 TurnConfigurations turn_configs; 296 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( 297 "hello.com", kDefaultStunTlsPort, "test", kTurnPassword, "tcp", true); 298 turn_configs.push_back(turn1); 299 // TURNS with transport param should be default to tcp. 300 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( 301 "hello.com", 443, "test_no_transport", kTurnPassword, "tcp", true); 302 turn_configs.push_back(turn2); 303 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn3( 304 "hello.com", kDefaultStunTlsPort, "test_no_transport", 305 kTurnPassword, "tcp", true); 306 turn_configs.push_back(turn3); 307 VerifyTurnConfigurations(turn_configs); 308} 309 310TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) { 311 PeerConnectionInterface::RTCConfiguration config; 312 webrtc::PeerConnectionInterface::IceServer ice_server; 313 ice_server.uri = kStunIceServerWithIPv4Address; 314 config.servers.push_back(ice_server); 315 ice_server.uri = kStunIceServerWithIPv4AddressWithoutPort; 316 config.servers.push_back(ice_server); 317 ice_server.uri = kStunIceServerWithIPv6Address; 318 config.servers.push_back(ice_server); 319 ice_server.uri = kStunIceServerWithIPv6AddressWithoutPort; 320 config.servers.push_back(ice_server); 321 ice_server.uri = kStunIceServerWithInvalidIPv6Address; 322 config.servers.push_back(ice_server); 323 ice_server.uri = kTurnIceServerWithIPv6Address; 324 ice_server.password = kTurnPassword; 325 config.servers.push_back(ice_server); 326 rtc::scoped_refptr<PeerConnectionInterface> pc( 327 factory_->CreatePeerConnection(config, NULL, 328 allocator_factory_.get(), 329 NULL, 330 &observer_)); 331 EXPECT_TRUE(pc.get() != NULL); 332 StunConfigurations stun_configs; 333 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( 334 "1.2.3.4", 1234); 335 stun_configs.push_back(stun1); 336 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun2( 337 "1.2.3.4", 3478); 338 stun_configs.push_back(stun2); // Default port 339 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun3( 340 "2401:fa00:4::", 1234); 341 stun_configs.push_back(stun3); 342 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun4( 343 "2401:fa00:4::", 3478); 344 stun_configs.push_back(stun4); // Default port 345 VerifyStunConfigurations(stun_configs); 346 347 TurnConfigurations turn_configs; 348 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( 349 "2401:fa00:4::", 1234, "test", kTurnPassword, "udp", false); 350 turn_configs.push_back(turn1); 351 VerifyTurnConfigurations(turn_configs); 352} 353 354// This test verifies the captured stream is rendered locally using a 355// local video track. 356TEST_F(PeerConnectionFactoryTest, LocalRendering) { 357 cricket::FakeVideoCapturer* capturer = new cricket::FakeVideoCapturer(); 358 // The source take ownership of |capturer|. 359 rtc::scoped_refptr<VideoSourceInterface> source( 360 factory_->CreateVideoSource(capturer, NULL)); 361 ASSERT_TRUE(source.get() != NULL); 362 rtc::scoped_refptr<VideoTrackInterface> track( 363 factory_->CreateVideoTrack("testlabel", source)); 364 ASSERT_TRUE(track.get() != NULL); 365 FakeVideoTrackRenderer local_renderer(track); 366 367 EXPECT_EQ(0, local_renderer.num_rendered_frames()); 368 EXPECT_TRUE(capturer->CaptureFrame()); 369 EXPECT_EQ(1, local_renderer.num_rendered_frames()); 370 371 track->set_enabled(false); 372 EXPECT_TRUE(capturer->CaptureFrame()); 373 EXPECT_EQ(1, local_renderer.num_rendered_frames()); 374 375 track->set_enabled(true); 376 EXPECT_TRUE(capturer->CaptureFrame()); 377 EXPECT_EQ(2, local_renderer.num_rendered_frames()); 378} 379