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