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, ¶ms); 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, ¶ms); 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, ¶ms); 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