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