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
51namespace webrtc {
52
53namespace {
54
55// Passes down the calls to |store_|. See usage in CreatePeerConnection.
56class DtlsIdentityStoreWrapper : public DtlsIdentityStoreInterface {
57 public:
58  DtlsIdentityStoreWrapper(
59      const rtc::scoped_refptr<RefCountedDtlsIdentityStore>& store)
60      : store_(store) {
61    RTC_DCHECK(store_);
62  }
63
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
77rtc::scoped_refptr<PeerConnectionFactoryInterface>
78CreatePeerConnectionFactory() {
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
97rtc::scoped_refptr<PeerConnectionFactoryInterface>
98CreatePeerConnectionFactory(
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
124PeerConnectionFactory::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
136PeerConnectionFactory::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
156PeerConnectionFactory::~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
174bool 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
209rtc::scoped_refptr<AudioSourceInterface>
210PeerConnectionFactory::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
218rtc::scoped_refptr<VideoSourceInterface>
219PeerConnectionFactory::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
228bool PeerConnectionFactory::StartAecDump(rtc::PlatformFile file) {
229  RTC_DCHECK(signaling_thread_->IsCurrent());
230  return channel_manager_->StartAecDump(file);
231}
232
233void PeerConnectionFactory::StopAecDump() {
234  RTC_DCHECK(signaling_thread_->IsCurrent());
235  channel_manager_->StopAecDump();
236}
237
238bool PeerConnectionFactory::StartRtcEventLog(rtc::PlatformFile file) {
239  RTC_DCHECK(signaling_thread_->IsCurrent());
240  return channel_manager_->StartRtcEventLog(file);
241}
242
243void PeerConnectionFactory::StopRtcEventLog() {
244  RTC_DCHECK(signaling_thread_->IsCurrent());
245  channel_manager_->StopRtcEventLog();
246}
247
248rtc::scoped_refptr<PeerConnectionInterface>
249PeerConnectionFactory::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
280rtc::scoped_refptr<MediaStreamInterface>
281PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
282  RTC_DCHECK(signaling_thread_->IsCurrent());
283  return MediaStreamProxy::Create(signaling_thread_,
284                                  MediaStream::Create(label));
285}
286
287rtc::scoped_refptr<VideoTrackInterface>
288PeerConnectionFactory::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
297rtc::scoped_refptr<AudioTrackInterface>
298PeerConnectionFactory::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
305webrtc::MediaControllerInterface* PeerConnectionFactory::CreateMediaController()
306    const {
307  RTC_DCHECK(signaling_thread_->IsCurrent());
308  return MediaControllerInterface::Create(worker_thread_,
309                                          channel_manager_.get());
310}
311
312rtc::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
318rtc::Thread* PeerConnectionFactory::worker_thread() {
319  RTC_DCHECK(signaling_thread_->IsCurrent());
320  return worker_thread_;
321}
322
323cricket::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