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
46using talk_base::scoped_refptr;
47
48namespace {
49
50typedef talk_base::TypedMessageData<bool> InitMessageData;
51
52struct 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
73struct 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
88struct 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
97struct 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
108enum {
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
118namespace webrtc {
119
120scoped_refptr<PeerConnectionFactoryInterface>
121CreatePeerConnectionFactory() {
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
131scoped_refptr<PeerConnectionFactoryInterface>
132CreatePeerConnectionFactory(
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
148PeerConnectionFactory::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
158PeerConnectionFactory::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
177PeerConnectionFactory::~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
186bool PeerConnectionFactory::Initialize() {
187  InitMessageData result(false);
188  signaling_thread_->Send(this, MSG_INIT_FACTORY, &result);
189  return result.data();
190}
191
192void 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
229bool 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.
255void PeerConnectionFactory::Terminate_s() {
256  channel_manager_.reset(NULL);
257  allocator_factory_ = NULL;
258}
259
260talk_base::scoped_refptr<AudioSourceInterface>
261PeerConnectionFactory::CreateAudioSource_s(
262    const MediaConstraintsInterface* constraints) {
263  talk_base::scoped_refptr<LocalAudioSource> source(
264      LocalAudioSource::Create(constraints));
265  return source;
266}
267
268talk_base::scoped_refptr<VideoSourceInterface>
269PeerConnectionFactory::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
278scoped_refptr<PeerConnectionInterface>
279PeerConnectionFactory::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, &params);
289  return params.peerconnection;
290}
291
292scoped_refptr<PeerConnectionInterface>
293PeerConnectionFactory::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
302talk_base::scoped_refptr<PeerConnectionInterface>
303PeerConnectionFactory::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
323scoped_refptr<MediaStreamInterface>
324PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
325  return MediaStreamProxy::Create(signaling_thread_,
326                                  MediaStream::Create(label));
327}
328
329talk_base::scoped_refptr<AudioSourceInterface>
330PeerConnectionFactory::CreateAudioSource(
331    const MediaConstraintsInterface* constraints) {
332  CreateAudioSourceParams params(constraints);
333  signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, &params);
334  return params.source;
335}
336
337talk_base::scoped_refptr<VideoSourceInterface>
338PeerConnectionFactory::CreateVideoSource(
339    cricket::VideoCapturer* capturer,
340    const MediaConstraintsInterface* constraints) {
341
342  CreateVideoSourceParams params(capturer,
343                                 constraints);
344  signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, &params);
345  return params.source;
346}
347
348talk_base::scoped_refptr<VideoTrackInterface>
349PeerConnectionFactory::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
357scoped_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
365cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
366  return channel_manager_.get();
367}
368
369talk_base::Thread* PeerConnectionFactory::signaling_thread() {
370  return signaling_thread_;
371}
372
373talk_base::Thread* PeerConnectionFactory::worker_thread() {
374  return worker_thread_;
375}
376
377}  // namespace webrtc
378