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 <utility>
31 
32 #include "talk/app/webrtc/audiotrack.h"
33 #include "talk/app/webrtc/localaudiosource.h"
34 #include "talk/app/webrtc/mediastream.h"
35 #include "talk/app/webrtc/mediastreamproxy.h"
36 #include "talk/app/webrtc/mediastreamtrackproxy.h"
37 #include "talk/app/webrtc/peerconnection.h"
38 #include "talk/app/webrtc/peerconnectionfactoryproxy.h"
39 #include "talk/app/webrtc/peerconnectionproxy.h"
40 #include "talk/app/webrtc/videosource.h"
41 #include "talk/app/webrtc/videosourceproxy.h"
42 #include "talk/app/webrtc/videotrack.h"
43 #include "talk/media/webrtc/webrtcmediaengine.h"
44 #include "talk/media/webrtc/webrtcvideodecoderfactory.h"
45 #include "talk/media/webrtc/webrtcvideoencoderfactory.h"
46 #include "webrtc/base/bind.h"
47 #include "webrtc/modules/audio_device/include/audio_device.h"
48 #include "webrtc/p2p/base/basicpacketsocketfactory.h"
49 #include "webrtc/p2p/client/basicportallocator.h"
50 
51 namespace webrtc {
52 
53 namespace {
54 
55 // Passes down the calls to |store_|. See usage in CreatePeerConnection.
56 class DtlsIdentityStoreWrapper : public DtlsIdentityStoreInterface {
57  public:
DtlsIdentityStoreWrapper(const rtc::scoped_refptr<RefCountedDtlsIdentityStore> & store)58   DtlsIdentityStoreWrapper(
59       const rtc::scoped_refptr<RefCountedDtlsIdentityStore>& store)
60       : store_(store) {
61     RTC_DCHECK(store_);
62   }
63 
RequestIdentity(rtc::KeyType key_type,const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver> & observer)64   void RequestIdentity(
65       rtc::KeyType key_type,
66       const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>&
67           observer) override {
68     store_->RequestIdentity(key_type, observer);
69   }
70 
71  private:
72   rtc::scoped_refptr<RefCountedDtlsIdentityStore> store_;
73 };
74 
75 }  // anonymous namespace
76 
77 rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory()78 CreatePeerConnectionFactory() {
79   rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
80       new rtc::RefCountedObject<PeerConnectionFactory>());
81 
82 
83   // Call Initialize synchronously but make sure its executed on
84   // |signaling_thread|.
85   MethodCall0<PeerConnectionFactory, bool> call(
86       pc_factory.get(),
87       &PeerConnectionFactory::Initialize);
88   bool result =  call.Marshal(pc_factory->signaling_thread());
89 
90   if (!result) {
91     return NULL;
92   }
93   return PeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(),
94                                             pc_factory);
95 }
96 
97 rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory(rtc::Thread * worker_thread,rtc::Thread * signaling_thread,AudioDeviceModule * default_adm,cricket::WebRtcVideoEncoderFactory * encoder_factory,cricket::WebRtcVideoDecoderFactory * decoder_factory)98 CreatePeerConnectionFactory(
99     rtc::Thread* worker_thread,
100     rtc::Thread* signaling_thread,
101     AudioDeviceModule* default_adm,
102     cricket::WebRtcVideoEncoderFactory* encoder_factory,
103     cricket::WebRtcVideoDecoderFactory* decoder_factory) {
104   rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
105       new rtc::RefCountedObject<PeerConnectionFactory>(worker_thread,
106                                                        signaling_thread,
107                                                        default_adm,
108                                                        encoder_factory,
109                                                        decoder_factory));
110 
111   // Call Initialize synchronously but make sure its executed on
112   // |signaling_thread|.
113   MethodCall0<PeerConnectionFactory, bool> call(
114       pc_factory.get(),
115       &PeerConnectionFactory::Initialize);
116   bool result =  call.Marshal(signaling_thread);
117 
118   if (!result) {
119     return NULL;
120   }
121   return PeerConnectionFactoryProxy::Create(signaling_thread, pc_factory);
122 }
123 
PeerConnectionFactory()124 PeerConnectionFactory::PeerConnectionFactory()
125     : owns_ptrs_(true),
126       wraps_current_thread_(false),
127       signaling_thread_(rtc::ThreadManager::Instance()->CurrentThread()),
128       worker_thread_(new rtc::Thread) {
129   if (!signaling_thread_) {
130     signaling_thread_ = rtc::ThreadManager::Instance()->WrapCurrentThread();
131     wraps_current_thread_ = true;
132   }
133   worker_thread_->Start();
134 }
135 
PeerConnectionFactory(rtc::Thread * worker_thread,rtc::Thread * signaling_thread,AudioDeviceModule * default_adm,cricket::WebRtcVideoEncoderFactory * video_encoder_factory,cricket::WebRtcVideoDecoderFactory * video_decoder_factory)136 PeerConnectionFactory::PeerConnectionFactory(
137     rtc::Thread* worker_thread,
138     rtc::Thread* signaling_thread,
139     AudioDeviceModule* default_adm,
140     cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
141     cricket::WebRtcVideoDecoderFactory* video_decoder_factory)
142     : owns_ptrs_(false),
143       wraps_current_thread_(false),
144       signaling_thread_(signaling_thread),
145       worker_thread_(worker_thread),
146       default_adm_(default_adm),
147       video_encoder_factory_(video_encoder_factory),
148       video_decoder_factory_(video_decoder_factory) {
149   ASSERT(worker_thread != NULL);
150   ASSERT(signaling_thread != NULL);
151   // TODO: Currently there is no way creating an external adm in
152   // libjingle source tree. So we can 't currently assert if this is NULL.
153   // ASSERT(default_adm != NULL);
154 }
155 
~PeerConnectionFactory()156 PeerConnectionFactory::~PeerConnectionFactory() {
157   RTC_DCHECK(signaling_thread_->IsCurrent());
158   channel_manager_.reset(nullptr);
159 
160   // Make sure |worker_thread_| and |signaling_thread_| outlive
161   // |dtls_identity_store_|, |default_socket_factory_| and
162   // |default_network_manager_|.
163   dtls_identity_store_ = nullptr;
164   default_socket_factory_ = nullptr;
165   default_network_manager_ = nullptr;
166 
167   if (owns_ptrs_) {
168     if (wraps_current_thread_)
169       rtc::ThreadManager::Instance()->UnwrapCurrentThread();
170     delete worker_thread_;
171   }
172 }
173 
Initialize()174 bool PeerConnectionFactory::Initialize() {
175   RTC_DCHECK(signaling_thread_->IsCurrent());
176   rtc::InitRandom(rtc::Time());
177 
178   default_network_manager_.reset(new rtc::BasicNetworkManager());
179   if (!default_network_manager_) {
180     return false;
181   }
182 
183   default_socket_factory_.reset(
184       new rtc::BasicPacketSocketFactory(worker_thread_));
185   if (!default_socket_factory_) {
186     return false;
187   }
188 
189   // TODO:  Need to make sure only one VoE is created inside
190   // WebRtcMediaEngine.
191   cricket::MediaEngineInterface* media_engine =
192       worker_thread_->Invoke<cricket::MediaEngineInterface*>(rtc::Bind(
193       &PeerConnectionFactory::CreateMediaEngine_w, this));
194 
195   channel_manager_.reset(
196       new cricket::ChannelManager(media_engine, worker_thread_));
197 
198   channel_manager_->SetVideoRtxEnabled(true);
199   if (!channel_manager_->Init()) {
200     return false;
201   }
202 
203   dtls_identity_store_ = new RefCountedDtlsIdentityStore(
204       signaling_thread_, worker_thread_);
205 
206   return true;
207 }
208 
209 rtc::scoped_refptr<AudioSourceInterface>
CreateAudioSource(const MediaConstraintsInterface * constraints)210 PeerConnectionFactory::CreateAudioSource(
211     const MediaConstraintsInterface* constraints) {
212   RTC_DCHECK(signaling_thread_->IsCurrent());
213   rtc::scoped_refptr<LocalAudioSource> source(
214       LocalAudioSource::Create(options_, constraints));
215   return source;
216 }
217 
218 rtc::scoped_refptr<VideoSourceInterface>
CreateVideoSource(cricket::VideoCapturer * capturer,const MediaConstraintsInterface * constraints)219 PeerConnectionFactory::CreateVideoSource(
220     cricket::VideoCapturer* capturer,
221     const MediaConstraintsInterface* constraints) {
222   RTC_DCHECK(signaling_thread_->IsCurrent());
223   rtc::scoped_refptr<VideoSource> source(VideoSource::Create(
224       channel_manager_.get(), capturer, constraints, false));
225   return VideoSourceProxy::Create(signaling_thread_, source);
226 }
227 
StartAecDump(rtc::PlatformFile file)228 bool PeerConnectionFactory::StartAecDump(rtc::PlatformFile file) {
229   RTC_DCHECK(signaling_thread_->IsCurrent());
230   return channel_manager_->StartAecDump(file);
231 }
232 
StopAecDump()233 void PeerConnectionFactory::StopAecDump() {
234   RTC_DCHECK(signaling_thread_->IsCurrent());
235   channel_manager_->StopAecDump();
236 }
237 
StartRtcEventLog(rtc::PlatformFile file)238 bool PeerConnectionFactory::StartRtcEventLog(rtc::PlatformFile file) {
239   RTC_DCHECK(signaling_thread_->IsCurrent());
240   return channel_manager_->StartRtcEventLog(file);
241 }
242 
StopRtcEventLog()243 void PeerConnectionFactory::StopRtcEventLog() {
244   RTC_DCHECK(signaling_thread_->IsCurrent());
245   channel_manager_->StopRtcEventLog();
246 }
247 
248 rtc::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection(const PeerConnectionInterface::RTCConfiguration & configuration,const MediaConstraintsInterface * constraints,rtc::scoped_ptr<cricket::PortAllocator> allocator,rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,PeerConnectionObserver * observer)249 PeerConnectionFactory::CreatePeerConnection(
250     const PeerConnectionInterface::RTCConfiguration& configuration,
251     const MediaConstraintsInterface* constraints,
252     rtc::scoped_ptr<cricket::PortAllocator> allocator,
253     rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
254     PeerConnectionObserver* observer) {
255   RTC_DCHECK(signaling_thread_->IsCurrent());
256 
257   if (!dtls_identity_store.get()) {
258     // Because |pc|->Initialize takes ownership of the store we need a new
259     // wrapper object that can be deleted without deleting the underlying
260     // |dtls_identity_store_|, protecting it from being deleted multiple times.
261     dtls_identity_store.reset(
262         new DtlsIdentityStoreWrapper(dtls_identity_store_));
263   }
264 
265   if (!allocator) {
266     allocator.reset(new cricket::BasicPortAllocator(
267         default_network_manager_.get(), default_socket_factory_.get()));
268   }
269   allocator->SetNetworkIgnoreMask(options_.network_ignore_mask);
270 
271   rtc::scoped_refptr<PeerConnection> pc(
272       new rtc::RefCountedObject<PeerConnection>(this));
273   if (!pc->Initialize(configuration, constraints, std::move(allocator),
274                       std::move(dtls_identity_store), observer)) {
275     return nullptr;
276   }
277   return PeerConnectionProxy::Create(signaling_thread(), pc);
278 }
279 
280 rtc::scoped_refptr<MediaStreamInterface>
CreateLocalMediaStream(const std::string & label)281 PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
282   RTC_DCHECK(signaling_thread_->IsCurrent());
283   return MediaStreamProxy::Create(signaling_thread_,
284                                   MediaStream::Create(label));
285 }
286 
287 rtc::scoped_refptr<VideoTrackInterface>
CreateVideoTrack(const std::string & id,VideoSourceInterface * source)288 PeerConnectionFactory::CreateVideoTrack(
289     const std::string& id,
290     VideoSourceInterface* source) {
291   RTC_DCHECK(signaling_thread_->IsCurrent());
292   rtc::scoped_refptr<VideoTrackInterface> track(
293       VideoTrack::Create(id, source));
294   return VideoTrackProxy::Create(signaling_thread_, track);
295 }
296 
297 rtc::scoped_refptr<AudioTrackInterface>
CreateAudioTrack(const std::string & id,AudioSourceInterface * source)298 PeerConnectionFactory::CreateAudioTrack(const std::string& id,
299                                         AudioSourceInterface* source) {
300   RTC_DCHECK(signaling_thread_->IsCurrent());
301   rtc::scoped_refptr<AudioTrackInterface> track(AudioTrack::Create(id, source));
302   return AudioTrackProxy::Create(signaling_thread_, track);
303 }
304 
CreateMediaController() const305 webrtc::MediaControllerInterface* PeerConnectionFactory::CreateMediaController()
306     const {
307   RTC_DCHECK(signaling_thread_->IsCurrent());
308   return MediaControllerInterface::Create(worker_thread_,
309                                           channel_manager_.get());
310 }
311 
signaling_thread()312 rtc::Thread* PeerConnectionFactory::signaling_thread() {
313   // This method can be called on a different thread when the factory is
314   // created in CreatePeerConnectionFactory().
315   return signaling_thread_;
316 }
317 
worker_thread()318 rtc::Thread* PeerConnectionFactory::worker_thread() {
319   RTC_DCHECK(signaling_thread_->IsCurrent());
320   return worker_thread_;
321 }
322 
CreateMediaEngine_w()323 cricket::MediaEngineInterface* PeerConnectionFactory::CreateMediaEngine_w() {
324   ASSERT(worker_thread_ == rtc::Thread::Current());
325   return cricket::WebRtcMediaEngineFactory::Create(
326       default_adm_.get(), video_encoder_factory_.get(),
327       video_decoder_factory_.get());
328 }
329 
330 }  // namespace webrtc
331