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
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(options_, 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<VideoSource> source(
273      VideoSource::Create(channel_manager_.get(), capturer, constraints));
274  return VideoSourceProxy::Create(signaling_thread_, source);
275}
276
277scoped_refptr<PeerConnectionInterface>
278PeerConnectionFactory::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, &params);
288  return params.peerconnection;
289}
290
291scoped_refptr<PeerConnectionInterface>
292PeerConnectionFactory::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
301talk_base::scoped_refptr<PeerConnectionInterface>
302PeerConnectionFactory::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
322scoped_refptr<MediaStreamInterface>
323PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
324  return MediaStreamProxy::Create(signaling_thread_,
325                                  MediaStream::Create(label));
326}
327
328talk_base::scoped_refptr<AudioSourceInterface>
329PeerConnectionFactory::CreateAudioSource(
330    const MediaConstraintsInterface* constraints) {
331  CreateAudioSourceParams params(constraints);
332  signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, &params);
333  return params.source;
334}
335
336talk_base::scoped_refptr<VideoSourceInterface>
337PeerConnectionFactory::CreateVideoSource(
338    cricket::VideoCapturer* capturer,
339    const MediaConstraintsInterface* constraints) {
340
341  CreateVideoSourceParams params(capturer,
342                                 constraints);
343  signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, &params);
344  return params.source;
345}
346
347talk_base::scoped_refptr<VideoTrackInterface>
348PeerConnectionFactory::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
356scoped_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
364cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
365  return channel_manager_.get();
366}
367
368talk_base::Thread* PeerConnectionFactory::signaling_thread() {
369  return signaling_thread_;
370}
371
372talk_base::Thread* PeerConnectionFactory::worker_thread() {
373  return worker_thread_;
374}
375
376}  // namespace webrtc
377