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