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::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(options_, 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<VideoSource> source( 273 VideoSource::Create(channel_manager_.get(), capturer, constraints)); 274 return VideoSourceProxy::Create(signaling_thread_, source); 275 } 276 277 scoped_refptr<PeerConnectionInterface> 278 PeerConnectionFactory::CreatePeerConnection( 279 const PeerConnectionInterface::IceServers& configuration, 280 const MediaConstraintsInterface* constraints, 281 PortAllocatorFactoryInterface* allocator_factory, 282 DTLSIdentityServiceInterface* dtls_identity_service, 283 PeerConnectionObserver* observer) { 284 CreatePeerConnectionParams params(configuration, constraints, 285 allocator_factory, dtls_identity_service, 286 observer); 287 signaling_thread_->Send(this, MSG_CREATE_PEERCONNECTION, ¶ms); 288 return params.peerconnection; 289 } 290 291 scoped_refptr<PeerConnectionInterface> 292 PeerConnectionFactory::CreatePeerConnection( 293 const PeerConnectionInterface::IceServers& configuration, 294 const MediaConstraintsInterface* constraints, 295 DTLSIdentityServiceInterface* dtls_identity_service, 296 PeerConnectionObserver* observer) { 297 return CreatePeerConnection( 298 configuration, constraints, NULL, dtls_identity_service, observer); 299 } 300 301 talk_base::scoped_refptr<PeerConnectionInterface> 302 PeerConnectionFactory::CreatePeerConnection_s( 303 const PeerConnectionInterface::IceServers& configuration, 304 const MediaConstraintsInterface* constraints, 305 PortAllocatorFactoryInterface* allocator_factory, 306 DTLSIdentityServiceInterface* dtls_identity_service, 307 PeerConnectionObserver* observer) { 308 ASSERT(allocator_factory || allocator_factory_); 309 talk_base::scoped_refptr<PeerConnection> pc( 310 new talk_base::RefCountedObject<PeerConnection>(this)); 311 if (!pc->Initialize( 312 configuration, 313 constraints, 314 allocator_factory ? allocator_factory : allocator_factory_.get(), 315 dtls_identity_service, 316 observer)) { 317 return NULL; 318 } 319 return PeerConnectionProxy::Create(signaling_thread(), pc); 320 } 321 322 scoped_refptr<MediaStreamInterface> 323 PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) { 324 return MediaStreamProxy::Create(signaling_thread_, 325 MediaStream::Create(label)); 326 } 327 328 talk_base::scoped_refptr<AudioSourceInterface> 329 PeerConnectionFactory::CreateAudioSource( 330 const MediaConstraintsInterface* constraints) { 331 CreateAudioSourceParams params(constraints); 332 signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, ¶ms); 333 return params.source; 334 } 335 336 talk_base::scoped_refptr<VideoSourceInterface> 337 PeerConnectionFactory::CreateVideoSource( 338 cricket::VideoCapturer* capturer, 339 const MediaConstraintsInterface* constraints) { 340 341 CreateVideoSourceParams params(capturer, 342 constraints); 343 signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, ¶ms); 344 return params.source; 345 } 346 347 talk_base::scoped_refptr<VideoTrackInterface> 348 PeerConnectionFactory::CreateVideoTrack( 349 const std::string& id, 350 VideoSourceInterface* source) { 351 talk_base::scoped_refptr<VideoTrackInterface> track( 352 VideoTrack::Create(id, source)); 353 return VideoTrackProxy::Create(signaling_thread_, track); 354 } 355 356 scoped_refptr<AudioTrackInterface> PeerConnectionFactory::CreateAudioTrack( 357 const std::string& id, 358 AudioSourceInterface* source) { 359 talk_base::scoped_refptr<AudioTrackInterface> track( 360 AudioTrack::Create(id, source)); 361 return AudioTrackProxy::Create(signaling_thread_, track); 362 } 363 364 cricket::ChannelManager* PeerConnectionFactory::channel_manager() { 365 return channel_manager_.get(); 366 } 367 368 talk_base::Thread* PeerConnectionFactory::signaling_thread() { 369 return signaling_thread_; 370 } 371 372 talk_base::Thread* PeerConnectionFactory::worker_thread() { 373 return worker_thread_; 374 } 375 376 } // namespace webrtc 377