Home | History | Annotate | Download | only in webrtc
      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