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/videosourceinterface.h" 34 #include "talk/app/webrtc/test/fakevideotrackrenderer.h" 35 #include "talk/base/gunit.h" 36 #include "talk/base/scoped_ptr.h" 37 #include "talk/base/thread.h" 38 #include "talk/media/base/fakevideocapturer.h" 39 #include "talk/media/webrtc/webrtccommon.h" 40 #include "talk/media/webrtc/webrtcvoe.h" 41 42 using webrtc::FakeVideoTrackRenderer; 43 using webrtc::MediaStreamInterface; 44 using webrtc::PeerConnectionFactoryInterface; 45 using webrtc::PeerConnectionInterface; 46 using webrtc::PeerConnectionObserver; 47 using webrtc::PortAllocatorFactoryInterface; 48 using webrtc::VideoSourceInterface; 49 using webrtc::VideoTrackInterface; 50 51 namespace { 52 53 typedef std::vector<PortAllocatorFactoryInterface::StunConfiguration> 54 StunConfigurations; 55 typedef std::vector<PortAllocatorFactoryInterface::TurnConfiguration> 56 TurnConfigurations; 57 58 static const char kStunIceServer[] = "stun:stun.l.google.com:19302"; 59 static const char kTurnIceServer[] = "turn:test%40hello.com (at) test.com:1234"; 60 static const char kTurnIceServerWithTransport[] = 61 "turn:test (at) hello.com?transport=tcp"; 62 static const char kSecureTurnIceServer[] = 63 "turns:test (at) hello.com?transport=tcp"; 64 static const char kTurnIceServerWithNoUsernameInUri[] = 65 "turn:test.com:1234"; 66 static const char kTurnPassword[] = "turnpassword"; 67 static const int kDefaultStunPort = 3478; 68 static const int kDefaultStunTlsPort = 5349; 69 static const char kTurnUsername[] = "test"; 70 71 class NullPeerConnectionObserver : public PeerConnectionObserver { 72 public: 73 virtual void OnError() {} 74 virtual void OnMessage(const std::string& msg) {} 75 virtual void OnSignalingMessage(const std::string& msg) {} 76 virtual void OnSignalingChange( 77 PeerConnectionInterface::SignalingState new_state) {} 78 virtual void OnAddStream(MediaStreamInterface* stream) {} 79 virtual void OnRemoveStream(MediaStreamInterface* stream) {} 80 virtual void OnRenegotiationNeeded() {} 81 virtual void OnIceConnectionChange( 82 PeerConnectionInterface::IceConnectionState new_state) {} 83 virtual void OnIceGatheringChange( 84 PeerConnectionInterface::IceGatheringState new_state) {} 85 virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {} 86 }; 87 88 } // namespace 89 90 class PeerConnectionFactoryTest : public testing::Test { 91 void SetUp() { 92 factory_ = webrtc::CreatePeerConnectionFactory(talk_base::Thread::Current(), 93 talk_base::Thread::Current(), 94 NULL, 95 NULL, 96 NULL); 97 98 ASSERT_TRUE(factory_.get() != NULL); 99 allocator_factory_ = webrtc::FakePortAllocatorFactory::Create(); 100 } 101 102 protected: 103 void VerifyStunConfigurations(StunConfigurations stun_config) { 104 webrtc::FakePortAllocatorFactory* allocator = 105 static_cast<webrtc::FakePortAllocatorFactory*>( 106 allocator_factory_.get()); 107 ASSERT_TRUE(allocator != NULL); 108 EXPECT_EQ(stun_config.size(), allocator->stun_configs().size()); 109 for (size_t i = 0; i < stun_config.size(); ++i) { 110 EXPECT_EQ(stun_config[i].server.ToString(), 111 allocator->stun_configs()[i].server.ToString()); 112 } 113 } 114 115 void VerifyTurnConfigurations(TurnConfigurations turn_config) { 116 webrtc::FakePortAllocatorFactory* allocator = 117 static_cast<webrtc::FakePortAllocatorFactory*>( 118 allocator_factory_.get()); 119 ASSERT_TRUE(allocator != NULL); 120 EXPECT_EQ(turn_config.size(), allocator->turn_configs().size()); 121 for (size_t i = 0; i < turn_config.size(); ++i) { 122 EXPECT_EQ(turn_config[i].server.ToString(), 123 allocator->turn_configs()[i].server.ToString()); 124 EXPECT_EQ(turn_config[i].username, allocator->turn_configs()[i].username); 125 EXPECT_EQ(turn_config[i].password, allocator->turn_configs()[i].password); 126 EXPECT_EQ(turn_config[i].transport_type, 127 allocator->turn_configs()[i].transport_type); 128 } 129 } 130 131 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory_; 132 NullPeerConnectionObserver observer_; 133 talk_base::scoped_refptr<PortAllocatorFactoryInterface> allocator_factory_; 134 }; 135 136 // Verify creation of PeerConnection using internal ADM, video factory and 137 // internal libjingle threads. 138 TEST(PeerConnectionFactoryTestInternal, CreatePCUsingInternalModules) { 139 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory( 140 webrtc::CreatePeerConnectionFactory()); 141 142 NullPeerConnectionObserver observer; 143 webrtc::PeerConnectionInterface::IceServers servers; 144 145 talk_base::scoped_refptr<PeerConnectionInterface> pc( 146 factory->CreatePeerConnection(servers, NULL, NULL, &observer)); 147 148 EXPECT_TRUE(pc.get() != NULL); 149 } 150 151 // This test verifies creation of PeerConnection with valid STUN and TURN 152 // configuration. Also verifies the URL's parsed correctly as expected. 153 TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServers) { 154 webrtc::PeerConnectionInterface::IceServers ice_servers; 155 webrtc::PeerConnectionInterface::IceServer ice_server; 156 ice_server.uri = kStunIceServer; 157 ice_servers.push_back(ice_server); 158 ice_server.uri = kTurnIceServer; 159 ice_server.password = kTurnPassword; 160 ice_servers.push_back(ice_server); 161 ice_server.uri = kTurnIceServerWithTransport; 162 ice_server.password = kTurnPassword; 163 ice_servers.push_back(ice_server); 164 talk_base::scoped_refptr<PeerConnectionInterface> pc( 165 factory_->CreatePeerConnection(ice_servers, NULL, 166 allocator_factory_.get(), 167 NULL, 168 &observer_)); 169 EXPECT_TRUE(pc.get() != NULL); 170 StunConfigurations stun_configs; 171 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( 172 "stun.l.google.com", 19302); 173 stun_configs.push_back(stun1); 174 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun2( 175 "test.com", 1234); 176 stun_configs.push_back(stun2); 177 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun3( 178 "hello.com", kDefaultStunPort); 179 stun_configs.push_back(stun3); 180 VerifyStunConfigurations(stun_configs); 181 TurnConfigurations turn_configs; 182 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( 183 "test.com", 1234, "test (at) hello.com", kTurnPassword, "udp", false); 184 turn_configs.push_back(turn1); 185 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( 186 "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); 187 turn_configs.push_back(turn2); 188 VerifyTurnConfigurations(turn_configs); 189 } 190 191 TEST_F(PeerConnectionFactoryTest, CreatePCUsingNoUsernameInUri) { 192 webrtc::PeerConnectionInterface::IceServers ice_servers; 193 webrtc::PeerConnectionInterface::IceServer ice_server; 194 ice_server.uri = kStunIceServer; 195 ice_servers.push_back(ice_server); 196 ice_server.uri = kTurnIceServerWithNoUsernameInUri; 197 ice_server.username = kTurnUsername; 198 ice_server.password = kTurnPassword; 199 ice_servers.push_back(ice_server); 200 talk_base::scoped_refptr<PeerConnectionInterface> pc( 201 factory_->CreatePeerConnection(ice_servers, NULL, 202 allocator_factory_.get(), 203 NULL, 204 &observer_)); 205 EXPECT_TRUE(pc.get() != NULL); 206 TurnConfigurations turn_configs; 207 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( 208 "test.com", 1234, kTurnUsername, kTurnPassword, "udp", false); 209 turn_configs.push_back(turn); 210 VerifyTurnConfigurations(turn_configs); 211 } 212 213 // This test verifies the PeerConnection created properly with TURN url which 214 // has transport parameter in it. 215 TEST_F(PeerConnectionFactoryTest, CreatePCUsingTurnUrlWithTransportParam) { 216 webrtc::PeerConnectionInterface::IceServers ice_servers; 217 webrtc::PeerConnectionInterface::IceServer ice_server; 218 ice_server.uri = kTurnIceServerWithTransport; 219 ice_server.password = kTurnPassword; 220 ice_servers.push_back(ice_server); 221 talk_base::scoped_refptr<PeerConnectionInterface> pc( 222 factory_->CreatePeerConnection(ice_servers, NULL, 223 allocator_factory_.get(), 224 NULL, 225 &observer_)); 226 EXPECT_TRUE(pc.get() != NULL); 227 TurnConfigurations turn_configs; 228 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( 229 "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); 230 turn_configs.push_back(turn); 231 VerifyTurnConfigurations(turn_configs); 232 StunConfigurations stun_configs; 233 webrtc::PortAllocatorFactoryInterface::StunConfiguration stun( 234 "hello.com", kDefaultStunPort); 235 stun_configs.push_back(stun); 236 VerifyStunConfigurations(stun_configs); 237 } 238 239 TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) { 240 webrtc::PeerConnectionInterface::IceServers ice_servers; 241 webrtc::PeerConnectionInterface::IceServer ice_server; 242 ice_server.uri = kSecureTurnIceServer; 243 ice_server.password = kTurnPassword; 244 ice_servers.push_back(ice_server); 245 talk_base::scoped_refptr<PeerConnectionInterface> pc( 246 factory_->CreatePeerConnection(ice_servers, NULL, 247 allocator_factory_.get(), 248 NULL, 249 &observer_)); 250 EXPECT_TRUE(pc.get() != NULL); 251 TurnConfigurations turn_configs; 252 webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( 253 "hello.com", kDefaultStunTlsPort, "test", kTurnPassword, "tcp", true); 254 turn_configs.push_back(turn); 255 VerifyTurnConfigurations(turn_configs); 256 } 257 258 // This test verifies the captured stream is rendered locally using a 259 // local video track. 260 TEST_F(PeerConnectionFactoryTest, LocalRendering) { 261 cricket::FakeVideoCapturer* capturer = new cricket::FakeVideoCapturer(); 262 // The source take ownership of |capturer|. 263 talk_base::scoped_refptr<VideoSourceInterface> source( 264 factory_->CreateVideoSource(capturer, NULL)); 265 ASSERT_TRUE(source.get() != NULL); 266 talk_base::scoped_refptr<VideoTrackInterface> track( 267 factory_->CreateVideoTrack("testlabel", source)); 268 ASSERT_TRUE(track.get() != NULL); 269 FakeVideoTrackRenderer local_renderer(track); 270 271 EXPECT_EQ(0, local_renderer.num_rendered_frames()); 272 EXPECT_TRUE(capturer->CaptureFrame()); 273 EXPECT_EQ(1, local_renderer.num_rendered_frames()); 274 275 track->set_enabled(false); 276 EXPECT_TRUE(capturer->CaptureFrame()); 277 EXPECT_EQ(1, local_renderer.num_rendered_frames()); 278 279 track->set_enabled(true); 280 EXPECT_TRUE(capturer->CaptureFrame()); 281 EXPECT_EQ(2, local_renderer.num_rendered_frames()); 282 } 283