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/base/bind.h"
45 #include "webrtc/modules/audio_device/include/audio_device.h"
46
47 using rtc::scoped_refptr;
48
49 namespace {
50
51 typedef rtc::TypedMessageData<bool> InitMessageData;
52
53 struct CreatePeerConnectionParams : public rtc::MessageData {
CreatePeerConnectionParams__anon99f75f430111::CreatePeerConnectionParams54 CreatePeerConnectionParams(
55 const webrtc::PeerConnectionInterface::RTCConfiguration& configuration,
56 const webrtc::MediaConstraintsInterface* constraints,
57 webrtc::PortAllocatorFactoryInterface* allocator_factory,
58 webrtc::DTLSIdentityServiceInterface* dtls_identity_service,
59 webrtc::PeerConnectionObserver* observer)
60 : configuration(configuration),
61 constraints(constraints),
62 allocator_factory(allocator_factory),
63 dtls_identity_service(dtls_identity_service),
64 observer(observer) {
65 }
66 scoped_refptr<webrtc::PeerConnectionInterface> peerconnection;
67 const webrtc::PeerConnectionInterface::RTCConfiguration& configuration;
68 const webrtc::MediaConstraintsInterface* constraints;
69 scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory;
70 webrtc::DTLSIdentityServiceInterface* dtls_identity_service;
71 webrtc::PeerConnectionObserver* observer;
72 };
73
74 struct CreateAudioSourceParams : public rtc::MessageData {
CreateAudioSourceParams__anon99f75f430111::CreateAudioSourceParams75 explicit CreateAudioSourceParams(
76 const webrtc::MediaConstraintsInterface* constraints)
77 : constraints(constraints) {
78 }
79 const webrtc::MediaConstraintsInterface* constraints;
80 scoped_refptr<webrtc::AudioSourceInterface> source;
81 };
82
83 struct CreateVideoSourceParams : public rtc::MessageData {
CreateVideoSourceParams__anon99f75f430111::CreateVideoSourceParams84 CreateVideoSourceParams(cricket::VideoCapturer* capturer,
85 const webrtc::MediaConstraintsInterface* constraints)
86 : capturer(capturer),
87 constraints(constraints) {
88 }
89 cricket::VideoCapturer* capturer;
90 const webrtc::MediaConstraintsInterface* constraints;
91 scoped_refptr<webrtc::VideoSourceInterface> source;
92 };
93
94 struct StartAecDumpParams : public rtc::MessageData {
StartAecDumpParams__anon99f75f430111::StartAecDumpParams95 explicit StartAecDumpParams(rtc::PlatformFile aec_dump_file)
96 : aec_dump_file(aec_dump_file) {
97 }
98 rtc::PlatformFile aec_dump_file;
99 bool result;
100 };
101
102 enum {
103 MSG_INIT_FACTORY = 1,
104 MSG_TERMINATE_FACTORY,
105 MSG_CREATE_PEERCONNECTION,
106 MSG_CREATE_AUDIOSOURCE,
107 MSG_CREATE_VIDEOSOURCE,
108 MSG_START_AEC_DUMP,
109 };
110
111 } // namespace
112
113 namespace webrtc {
114
115 rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory()116 CreatePeerConnectionFactory() {
117 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
118 new rtc::RefCountedObject<PeerConnectionFactory>());
119
120 if (!pc_factory->Initialize()) {
121 return NULL;
122 }
123 return pc_factory;
124 }
125
126 rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory(rtc::Thread * worker_thread,rtc::Thread * signaling_thread,AudioDeviceModule * default_adm,cricket::WebRtcVideoEncoderFactory * encoder_factory,cricket::WebRtcVideoDecoderFactory * decoder_factory)127 CreatePeerConnectionFactory(
128 rtc::Thread* worker_thread,
129 rtc::Thread* signaling_thread,
130 AudioDeviceModule* default_adm,
131 cricket::WebRtcVideoEncoderFactory* encoder_factory,
132 cricket::WebRtcVideoDecoderFactory* decoder_factory) {
133 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
134 new rtc::RefCountedObject<PeerConnectionFactory>(worker_thread,
135 signaling_thread,
136 default_adm,
137 encoder_factory,
138 decoder_factory));
139 if (!pc_factory->Initialize()) {
140 return NULL;
141 }
142 return pc_factory;
143 }
144
PeerConnectionFactory()145 PeerConnectionFactory::PeerConnectionFactory()
146 : owns_ptrs_(true),
147 signaling_thread_(new rtc::Thread),
148 worker_thread_(new rtc::Thread) {
149 bool result = signaling_thread_->Start();
150 ASSERT(result);
151 result = worker_thread_->Start();
152 ASSERT(result);
153 }
154
PeerConnectionFactory(rtc::Thread * worker_thread,rtc::Thread * signaling_thread,AudioDeviceModule * default_adm,cricket::WebRtcVideoEncoderFactory * video_encoder_factory,cricket::WebRtcVideoDecoderFactory * video_decoder_factory)155 PeerConnectionFactory::PeerConnectionFactory(
156 rtc::Thread* worker_thread,
157 rtc::Thread* signaling_thread,
158 AudioDeviceModule* default_adm,
159 cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
160 cricket::WebRtcVideoDecoderFactory* video_decoder_factory)
161 : owns_ptrs_(false),
162 signaling_thread_(signaling_thread),
163 worker_thread_(worker_thread),
164 default_adm_(default_adm),
165 video_encoder_factory_(video_encoder_factory),
166 video_decoder_factory_(video_decoder_factory) {
167 ASSERT(worker_thread != NULL);
168 ASSERT(signaling_thread != NULL);
169 // TODO: Currently there is no way creating an external adm in
170 // libjingle source tree. So we can 't currently assert if this is NULL.
171 // ASSERT(default_adm != NULL);
172 }
173
~PeerConnectionFactory()174 PeerConnectionFactory::~PeerConnectionFactory() {
175 signaling_thread_->Clear(this);
176 signaling_thread_->Send(this, MSG_TERMINATE_FACTORY);
177 if (owns_ptrs_) {
178 delete signaling_thread_;
179 delete worker_thread_;
180 }
181 }
182
Initialize()183 bool PeerConnectionFactory::Initialize() {
184 InitMessageData result(false);
185 signaling_thread_->Send(this, MSG_INIT_FACTORY, &result);
186 return result.data();
187 }
188
OnMessage(rtc::Message * msg)189 void PeerConnectionFactory::OnMessage(rtc::Message* msg) {
190 switch (msg->message_id) {
191 case MSG_INIT_FACTORY: {
192 InitMessageData* pdata = static_cast<InitMessageData*>(msg->pdata);
193 pdata->data() = Initialize_s();
194 break;
195 }
196 case MSG_TERMINATE_FACTORY: {
197 Terminate_s();
198 break;
199 }
200 case MSG_CREATE_PEERCONNECTION: {
201 CreatePeerConnectionParams* pdata =
202 static_cast<CreatePeerConnectionParams*> (msg->pdata);
203 pdata->peerconnection = CreatePeerConnection_s(
204 pdata->configuration,
205 pdata->constraints,
206 pdata->allocator_factory,
207 pdata->dtls_identity_service,
208 pdata->observer);
209 break;
210 }
211 case MSG_CREATE_AUDIOSOURCE: {
212 CreateAudioSourceParams* pdata =
213 static_cast<CreateAudioSourceParams*>(msg->pdata);
214 pdata->source = CreateAudioSource_s(pdata->constraints);
215 break;
216 }
217 case MSG_CREATE_VIDEOSOURCE: {
218 CreateVideoSourceParams* pdata =
219 static_cast<CreateVideoSourceParams*>(msg->pdata);
220 pdata->source = CreateVideoSource_s(pdata->capturer, pdata->constraints);
221 break;
222 }
223 case MSG_START_AEC_DUMP: {
224 StartAecDumpParams* pdata =
225 static_cast<StartAecDumpParams*>(msg->pdata);
226 pdata->result = StartAecDump_s(pdata->aec_dump_file);
227 break;
228 }
229 }
230 }
231
Initialize_s()232 bool PeerConnectionFactory::Initialize_s() {
233 rtc::InitRandom(rtc::Time());
234
235 allocator_factory_ = PortAllocatorFactory::Create(worker_thread_);
236 if (!allocator_factory_)
237 return false;
238
239 cricket::DummyDeviceManager* device_manager(
240 new cricket::DummyDeviceManager());
241 // TODO: Need to make sure only one VoE is created inside
242 // WebRtcMediaEngine.
243 cricket::MediaEngineInterface* media_engine(
244 cricket::WebRtcMediaEngineFactory::Create(default_adm_.get(),
245 NULL, // No secondary adm.
246 video_encoder_factory_.get(),
247 video_decoder_factory_.get()));
248
249 channel_manager_.reset(new cricket::ChannelManager(
250 media_engine, device_manager, worker_thread_));
251 channel_manager_->SetVideoRtxEnabled(true);
252 if (!channel_manager_->Init()) {
253 return false;
254 }
255 return true;
256 }
257
258 // Terminate what we created on the signaling thread.
Terminate_s()259 void PeerConnectionFactory::Terminate_s() {
260 channel_manager_.reset(NULL);
261 allocator_factory_ = NULL;
262 }
263
264 rtc::scoped_refptr<AudioSourceInterface>
CreateAudioSource_s(const MediaConstraintsInterface * constraints)265 PeerConnectionFactory::CreateAudioSource_s(
266 const MediaConstraintsInterface* constraints) {
267 rtc::scoped_refptr<LocalAudioSource> source(
268 LocalAudioSource::Create(options_, constraints));
269 return source;
270 }
271
272 rtc::scoped_refptr<VideoSourceInterface>
CreateVideoSource_s(cricket::VideoCapturer * capturer,const MediaConstraintsInterface * constraints)273 PeerConnectionFactory::CreateVideoSource_s(
274 cricket::VideoCapturer* capturer,
275 const MediaConstraintsInterface* constraints) {
276 rtc::scoped_refptr<VideoSource> source(
277 VideoSource::Create(channel_manager_.get(), capturer, constraints));
278 return VideoSourceProxy::Create(signaling_thread_, source);
279 }
280
StartAecDump_s(rtc::PlatformFile file)281 bool PeerConnectionFactory::StartAecDump_s(rtc::PlatformFile file) {
282 return channel_manager_->StartAecDump(file);
283 }
284
285 rtc::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection(const PeerConnectionInterface::RTCConfiguration & configuration,const MediaConstraintsInterface * constraints,PortAllocatorFactoryInterface * allocator_factory,DTLSIdentityServiceInterface * dtls_identity_service,PeerConnectionObserver * observer)286 PeerConnectionFactory::CreatePeerConnection(
287 const PeerConnectionInterface::RTCConfiguration& configuration,
288 const MediaConstraintsInterface* constraints,
289 PortAllocatorFactoryInterface* allocator_factory,
290 DTLSIdentityServiceInterface* dtls_identity_service,
291 PeerConnectionObserver* observer) {
292 CreatePeerConnectionParams params(configuration, constraints,
293 allocator_factory, dtls_identity_service,
294 observer);
295 signaling_thread_->Send(
296 this, MSG_CREATE_PEERCONNECTION, ¶ms);
297 return params.peerconnection;
298 }
299
300 rtc::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection_s(const PeerConnectionInterface::RTCConfiguration & configuration,const MediaConstraintsInterface * constraints,PortAllocatorFactoryInterface * allocator_factory,DTLSIdentityServiceInterface * dtls_identity_service,PeerConnectionObserver * observer)301 PeerConnectionFactory::CreatePeerConnection_s(
302 const PeerConnectionInterface::RTCConfiguration& configuration,
303 const MediaConstraintsInterface* constraints,
304 PortAllocatorFactoryInterface* allocator_factory,
305 DTLSIdentityServiceInterface* dtls_identity_service,
306 PeerConnectionObserver* observer) {
307 ASSERT(allocator_factory || allocator_factory_);
308 rtc::scoped_refptr<PeerConnection> pc(
309 new rtc::RefCountedObject<PeerConnection>(this));
310 if (!pc->Initialize(
311 configuration,
312 constraints,
313 allocator_factory ? allocator_factory : allocator_factory_.get(),
314 dtls_identity_service,
315 observer)) {
316 return NULL;
317 }
318 return PeerConnectionProxy::Create(signaling_thread(), pc);
319 }
320
321 rtc::scoped_refptr<MediaStreamInterface>
CreateLocalMediaStream(const std::string & label)322 PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
323 return MediaStreamProxy::Create(signaling_thread_,
324 MediaStream::Create(label));
325 }
326
327 rtc::scoped_refptr<AudioSourceInterface>
CreateAudioSource(const MediaConstraintsInterface * constraints)328 PeerConnectionFactory::CreateAudioSource(
329 const MediaConstraintsInterface* constraints) {
330 CreateAudioSourceParams params(constraints);
331 signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, ¶ms);
332 return params.source;
333 }
334
335 rtc::scoped_refptr<VideoSourceInterface>
CreateVideoSource(cricket::VideoCapturer * capturer,const MediaConstraintsInterface * constraints)336 PeerConnectionFactory::CreateVideoSource(
337 cricket::VideoCapturer* capturer,
338 const MediaConstraintsInterface* constraints) {
339
340 CreateVideoSourceParams params(capturer,
341 constraints);
342 signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, ¶ms);
343 return params.source;
344 }
345
346 rtc::scoped_refptr<VideoTrackInterface>
CreateVideoTrack(const std::string & id,VideoSourceInterface * source)347 PeerConnectionFactory::CreateVideoTrack(
348 const std::string& id,
349 VideoSourceInterface* source) {
350 rtc::scoped_refptr<VideoTrackInterface> track(
351 VideoTrack::Create(id, source));
352 return VideoTrackProxy::Create(signaling_thread_, track);
353 }
354
355 rtc::scoped_refptr<AudioTrackInterface>
CreateAudioTrack(const std::string & id,AudioSourceInterface * source)356 PeerConnectionFactory::CreateAudioTrack(const std::string& id,
357 AudioSourceInterface* source) {
358 rtc::scoped_refptr<AudioTrackInterface> track(
359 AudioTrack::Create(id, source));
360 return AudioTrackProxy::Create(signaling_thread_, track);
361 }
362
StartAecDump(rtc::PlatformFile file)363 bool PeerConnectionFactory::StartAecDump(rtc::PlatformFile file) {
364 StartAecDumpParams params(file);
365 signaling_thread_->Send(this, MSG_START_AEC_DUMP, ¶ms);
366 return params.result;
367 }
368
channel_manager()369 cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
370 return channel_manager_.get();
371 }
372
signaling_thread()373 rtc::Thread* PeerConnectionFactory::signaling_thread() {
374 return signaling_thread_;
375 }
376
worker_thread()377 rtc::Thread* PeerConnectionFactory::worker_thread() {
378 return worker_thread_;
379 }
380
381 } // namespace webrtc
382