Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2004--2011, 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/peerconnectionfactory.h"
     29 
     30 #include "talk/app/webrtc/audiotrack.h"
     31 #include "talk/app/webrtc/localaudiosource.h"
     32 #include "talk/app/webrtc/localvideosource.h"
     33 #include "talk/app/webrtc/mediastreamproxy.h"
     34 #include "talk/app/webrtc/mediastreamtrackproxy.h"
     35 #include "talk/app/webrtc/peerconnection.h"
     36 #include "talk/app/webrtc/peerconnectionproxy.h"
     37 #include "talk/app/webrtc/portallocatorfactory.h"
     38 #include "talk/app/webrtc/videosourceproxy.h"
     39 #include "talk/app/webrtc/videotrack.h"
     40 #include "talk/media/devices/dummydevicemanager.h"
     41 #include "talk/media/webrtc/webrtcmediaengine.h"
     42 #include "talk/media/webrtc/webrtcvideodecoderfactory.h"
     43 #include "talk/media/webrtc/webrtcvideoencoderfactory.h"
     44 #include "webrtc/modules/audio_device/include/audio_device.h"
     45 
     46 using talk_base::scoped_refptr;
     47 
     48 namespace {
     49 
     50 typedef talk_base::TypedMessageData<bool> InitMessageData;
     51 
     52 struct CreatePeerConnectionParams : public talk_base::MessageData {
     53   CreatePeerConnectionParams(
     54       const webrtc::PeerConnectionInterface::IceServers& configuration,
     55       const webrtc::MediaConstraintsInterface* constraints,
     56       webrtc::PortAllocatorFactoryInterface* allocator_factory,
     57       webrtc::DTLSIdentityServiceInterface* dtls_identity_service,
     58       webrtc::PeerConnectionObserver* observer)
     59       : configuration(configuration),
     60         constraints(constraints),
     61         allocator_factory(allocator_factory),
     62         dtls_identity_service(dtls_identity_service),
     63         observer(observer) {
     64   }
     65   scoped_refptr<webrtc::PeerConnectionInterface> peerconnection;
     66   const webrtc::PeerConnectionInterface::IceServers& configuration;
     67   const webrtc::MediaConstraintsInterface* constraints;
     68   scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory;
     69   webrtc::DTLSIdentityServiceInterface* dtls_identity_service;
     70   webrtc::PeerConnectionObserver* observer;
     71 };
     72 
     73 struct CreatePeerConnectionParamsDeprecated : public talk_base::MessageData {
     74   CreatePeerConnectionParamsDeprecated(
     75       const std::string& configuration,
     76       webrtc::PortAllocatorFactoryInterface* allocator_factory,
     77         webrtc::PeerConnectionObserver* observer)
     78       : configuration(configuration),
     79         allocator_factory(allocator_factory),
     80         observer(observer) {
     81   }
     82   scoped_refptr<webrtc::PeerConnectionInterface> peerconnection;
     83   const std::string& configuration;
     84   scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory;
     85   webrtc::PeerConnectionObserver* observer;
     86 };
     87 
     88 struct CreateAudioSourceParams : public talk_base::MessageData {
     89   explicit CreateAudioSourceParams(
     90       const webrtc::MediaConstraintsInterface* constraints)
     91       : constraints(constraints) {
     92   }
     93   const webrtc::MediaConstraintsInterface* constraints;
     94   scoped_refptr<webrtc::AudioSourceInterface> source;
     95 };
     96 
     97 struct CreateVideoSourceParams : public talk_base::MessageData {
     98   CreateVideoSourceParams(cricket::VideoCapturer* capturer,
     99                           const webrtc::MediaConstraintsInterface* constraints)
    100       : capturer(capturer),
    101         constraints(constraints) {
    102   }
    103   cricket::VideoCapturer* capturer;
    104   const webrtc::MediaConstraintsInterface* constraints;
    105   scoped_refptr<webrtc::VideoSourceInterface> source;
    106 };
    107 
    108 enum {
    109   MSG_INIT_FACTORY = 1,
    110   MSG_TERMINATE_FACTORY,
    111   MSG_CREATE_PEERCONNECTION,
    112   MSG_CREATE_AUDIOSOURCE,
    113   MSG_CREATE_VIDEOSOURCE,
    114 };
    115 
    116 }  // namespace
    117 
    118 namespace webrtc {
    119 
    120 scoped_refptr<PeerConnectionFactoryInterface>
    121 CreatePeerConnectionFactory() {
    122   scoped_refptr<PeerConnectionFactory> pc_factory(
    123       new talk_base::RefCountedObject<PeerConnectionFactory>());
    124 
    125   if (!pc_factory->Initialize()) {
    126     return NULL;
    127   }
    128   return pc_factory;
    129 }
    130 
    131 scoped_refptr<PeerConnectionFactoryInterface>
    132 CreatePeerConnectionFactory(
    133     talk_base::Thread* worker_thread,
    134     talk_base::Thread* signaling_thread,
    135     AudioDeviceModule* default_adm,
    136     cricket::WebRtcVideoEncoderFactory* encoder_factory,
    137     cricket::WebRtcVideoDecoderFactory* decoder_factory) {
    138   scoped_refptr<PeerConnectionFactory> pc_factory(
    139       new talk_base::RefCountedObject<PeerConnectionFactory>(
    140           worker_thread, signaling_thread, default_adm,
    141           encoder_factory, decoder_factory));
    142   if (!pc_factory->Initialize()) {
    143     return NULL;
    144   }
    145   return pc_factory;
    146 }
    147 
    148 PeerConnectionFactory::PeerConnectionFactory()
    149     : owns_ptrs_(true),
    150       signaling_thread_(new talk_base::Thread),
    151       worker_thread_(new talk_base::Thread) {
    152   bool result = signaling_thread_->Start();
    153   ASSERT(result);
    154   result = worker_thread_->Start();
    155   ASSERT(result);
    156 }
    157 
    158 PeerConnectionFactory::PeerConnectionFactory(
    159     talk_base::Thread* worker_thread,
    160     talk_base::Thread* signaling_thread,
    161     AudioDeviceModule* default_adm,
    162     cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
    163     cricket::WebRtcVideoDecoderFactory* video_decoder_factory)
    164     : owns_ptrs_(false),
    165       signaling_thread_(signaling_thread),
    166       worker_thread_(worker_thread),
    167       default_adm_(default_adm),
    168       video_encoder_factory_(video_encoder_factory),
    169       video_decoder_factory_(video_decoder_factory) {
    170   ASSERT(worker_thread != NULL);
    171   ASSERT(signaling_thread != NULL);
    172   // TODO: Currently there is no way creating an external adm in
    173   // libjingle source tree. So we can 't currently assert if this is NULL.
    174   // ASSERT(default_adm != NULL);
    175 }
    176 
    177 PeerConnectionFactory::~PeerConnectionFactory() {
    178   signaling_thread_->Clear(this);
    179   signaling_thread_->Send(this, MSG_TERMINATE_FACTORY);
    180   if (owns_ptrs_) {
    181     delete signaling_thread_;
    182     delete worker_thread_;
    183   }
    184 }
    185 
    186 bool PeerConnectionFactory::Initialize() {
    187   InitMessageData result(false);
    188   signaling_thread_->Send(this, MSG_INIT_FACTORY, &result);
    189   return result.data();
    190 }
    191 
    192 void PeerConnectionFactory::OnMessage(talk_base::Message* msg) {
    193   switch (msg->message_id) {
    194     case MSG_INIT_FACTORY: {
    195      InitMessageData* pdata = static_cast<InitMessageData*>(msg->pdata);
    196      pdata->data() = Initialize_s();
    197      break;
    198     }
    199     case MSG_TERMINATE_FACTORY: {
    200       Terminate_s();
    201       break;
    202     }
    203     case MSG_CREATE_PEERCONNECTION: {
    204       CreatePeerConnectionParams* pdata =
    205           static_cast<CreatePeerConnectionParams*> (msg->pdata);
    206       pdata->peerconnection = CreatePeerConnection_s(
    207           pdata->configuration,
    208           pdata->constraints,
    209           pdata->allocator_factory,
    210           pdata->dtls_identity_service,
    211           pdata->observer);
    212       break;
    213     }
    214     case MSG_CREATE_AUDIOSOURCE: {
    215       CreateAudioSourceParams* pdata =
    216           static_cast<CreateAudioSourceParams*>(msg->pdata);
    217       pdata->source = CreateAudioSource_s(pdata->constraints);
    218       break;
    219     }
    220     case MSG_CREATE_VIDEOSOURCE: {
    221       CreateVideoSourceParams* pdata =
    222           static_cast<CreateVideoSourceParams*>(msg->pdata);
    223       pdata->source = CreateVideoSource_s(pdata->capturer, pdata->constraints);
    224       break;
    225     }
    226   }
    227 }
    228 
    229 bool PeerConnectionFactory::Initialize_s() {
    230   talk_base::InitRandom(talk_base::Time());
    231 
    232   allocator_factory_ = PortAllocatorFactory::Create(worker_thread_);
    233   if (!allocator_factory_)
    234     return false;
    235 
    236   cricket::DummyDeviceManager* device_manager(
    237       new cricket::DummyDeviceManager());
    238   // TODO:  Need to make sure only one VoE is created inside
    239   // WebRtcMediaEngine.
    240   cricket::WebRtcMediaEngine* webrtc_media_engine(
    241       new cricket::WebRtcMediaEngine(default_adm_.get(),
    242                                      NULL,  // No secondary adm.
    243                                      video_encoder_factory_.get(),
    244                                      video_decoder_factory_.get()));
    245 
    246   channel_manager_.reset(new cricket::ChannelManager(
    247       webrtc_media_engine, device_manager, worker_thread_));
    248   if (!channel_manager_->Init()) {
    249     return false;
    250   }
    251   return true;
    252 }
    253 
    254 // Terminate what we created on the signaling thread.
    255 void PeerConnectionFactory::Terminate_s() {
    256   channel_manager_.reset(NULL);
    257   allocator_factory_ = NULL;
    258 }
    259 
    260 talk_base::scoped_refptr<AudioSourceInterface>
    261 PeerConnectionFactory::CreateAudioSource_s(
    262     const MediaConstraintsInterface* constraints) {
    263   talk_base::scoped_refptr<LocalAudioSource> source(
    264       LocalAudioSource::Create(constraints));
    265   return source;
    266 }
    267 
    268 talk_base::scoped_refptr<VideoSourceInterface>
    269 PeerConnectionFactory::CreateVideoSource_s(
    270     cricket::VideoCapturer* capturer,
    271     const MediaConstraintsInterface* constraints) {
    272   talk_base::scoped_refptr<LocalVideoSource> source(
    273       LocalVideoSource::Create(channel_manager_.get(), capturer,
    274                                constraints));
    275   return VideoSourceProxy::Create(signaling_thread_, source);
    276 }
    277 
    278 scoped_refptr<PeerConnectionInterface>
    279 PeerConnectionFactory::CreatePeerConnection(
    280     const PeerConnectionInterface::IceServers& configuration,
    281     const MediaConstraintsInterface* constraints,
    282     PortAllocatorFactoryInterface* allocator_factory,
    283     DTLSIdentityServiceInterface* dtls_identity_service,
    284     PeerConnectionObserver* observer) {
    285   CreatePeerConnectionParams params(configuration, constraints,
    286                                     allocator_factory, dtls_identity_service,
    287                                     observer);
    288   signaling_thread_->Send(this, MSG_CREATE_PEERCONNECTION, &params);
    289   return params.peerconnection;
    290 }
    291 
    292 scoped_refptr<PeerConnectionInterface>
    293 PeerConnectionFactory::CreatePeerConnection(
    294     const PeerConnectionInterface::IceServers& configuration,
    295     const MediaConstraintsInterface* constraints,
    296     DTLSIdentityServiceInterface* dtls_identity_service,
    297     PeerConnectionObserver* observer) {
    298   return CreatePeerConnection(
    299       configuration, constraints, NULL, dtls_identity_service, observer);
    300 }
    301 
    302 talk_base::scoped_refptr<PeerConnectionInterface>
    303 PeerConnectionFactory::CreatePeerConnection_s(
    304     const PeerConnectionInterface::IceServers& configuration,
    305     const MediaConstraintsInterface* constraints,
    306     PortAllocatorFactoryInterface* allocator_factory,
    307     DTLSIdentityServiceInterface* dtls_identity_service,
    308     PeerConnectionObserver* observer) {
    309   ASSERT(allocator_factory || allocator_factory_);
    310   talk_base::scoped_refptr<PeerConnection> pc(
    311       new talk_base::RefCountedObject<PeerConnection>(this));
    312   if (!pc->Initialize(
    313       configuration,
    314       constraints,
    315       allocator_factory ? allocator_factory : allocator_factory_.get(),
    316       dtls_identity_service,
    317       observer)) {
    318     return NULL;
    319   }
    320   return PeerConnectionProxy::Create(signaling_thread(), pc);
    321 }
    322 
    323 scoped_refptr<MediaStreamInterface>
    324 PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
    325   return MediaStreamProxy::Create(signaling_thread_,
    326                                   MediaStream::Create(label));
    327 }
    328 
    329 talk_base::scoped_refptr<AudioSourceInterface>
    330 PeerConnectionFactory::CreateAudioSource(
    331     const MediaConstraintsInterface* constraints) {
    332   CreateAudioSourceParams params(constraints);
    333   signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, &params);
    334   return params.source;
    335 }
    336 
    337 talk_base::scoped_refptr<VideoSourceInterface>
    338 PeerConnectionFactory::CreateVideoSource(
    339     cricket::VideoCapturer* capturer,
    340     const MediaConstraintsInterface* constraints) {
    341 
    342   CreateVideoSourceParams params(capturer,
    343                                  constraints);
    344   signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, &params);
    345   return params.source;
    346 }
    347 
    348 talk_base::scoped_refptr<VideoTrackInterface>
    349 PeerConnectionFactory::CreateVideoTrack(
    350     const std::string& id,
    351     VideoSourceInterface* source) {
    352   talk_base::scoped_refptr<VideoTrackInterface> track(
    353       VideoTrack::Create(id, source));
    354   return VideoTrackProxy::Create(signaling_thread_, track);
    355 }
    356 
    357 scoped_refptr<AudioTrackInterface> PeerConnectionFactory::CreateAudioTrack(
    358     const std::string& id,
    359     AudioSourceInterface* source) {
    360   talk_base::scoped_refptr<AudioTrackInterface> track(
    361       AudioTrack::Create(id, source));
    362   return AudioTrackProxy::Create(signaling_thread_, track);
    363 }
    364 
    365 cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
    366   return channel_manager_.get();
    367 }
    368 
    369 talk_base::Thread* PeerConnectionFactory::signaling_thread() {
    370   return signaling_thread_;
    371 }
    372 
    373 talk_base::Thread* PeerConnectionFactory::worker_thread() {
    374   return worker_thread_;
    375 }
    376 
    377 }  // namespace webrtc
    378