webrtc/talk/app/webrtc/peerconnectionfactory.cc

381 lines
14 KiB
C++

/*
* libjingle
* Copyright 2004--2011, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "talk/app/webrtc/peerconnectionfactory.h"
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/localaudiosource.h"
#include "talk/app/webrtc/mediastreamproxy.h"
#include "talk/app/webrtc/mediastreamtrackproxy.h"
#include "talk/app/webrtc/peerconnection.h"
#include "talk/app/webrtc/peerconnectionproxy.h"
#include "talk/app/webrtc/portallocatorfactory.h"
#include "talk/app/webrtc/videosource.h"
#include "talk/app/webrtc/videosourceproxy.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/media/devices/dummydevicemanager.h"
#include "talk/media/webrtc/webrtcmediaengine.h"
#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
#include "webrtc/modules/audio_device/include/audio_device.h"
using talk_base::scoped_refptr;
namespace {
typedef talk_base::TypedMessageData<bool> InitMessageData;
struct CreatePeerConnectionParams : public talk_base::MessageData {
CreatePeerConnectionParams(
const webrtc::PeerConnectionInterface::RTCConfiguration& configuration,
const webrtc::MediaConstraintsInterface* constraints,
webrtc::PortAllocatorFactoryInterface* allocator_factory,
webrtc::DTLSIdentityServiceInterface* dtls_identity_service,
webrtc::PeerConnectionObserver* observer)
: configuration(configuration),
constraints(constraints),
allocator_factory(allocator_factory),
dtls_identity_service(dtls_identity_service),
observer(observer) {
}
scoped_refptr<webrtc::PeerConnectionInterface> peerconnection;
const webrtc::PeerConnectionInterface::RTCConfiguration& configuration;
const webrtc::MediaConstraintsInterface* constraints;
scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory;
webrtc::DTLSIdentityServiceInterface* dtls_identity_service;
webrtc::PeerConnectionObserver* observer;
};
struct CreateAudioSourceParams : public talk_base::MessageData {
explicit CreateAudioSourceParams(
const webrtc::MediaConstraintsInterface* constraints)
: constraints(constraints) {
}
const webrtc::MediaConstraintsInterface* constraints;
scoped_refptr<webrtc::AudioSourceInterface> source;
};
struct CreateVideoSourceParams : public talk_base::MessageData {
CreateVideoSourceParams(cricket::VideoCapturer* capturer,
const webrtc::MediaConstraintsInterface* constraints)
: capturer(capturer),
constraints(constraints) {
}
cricket::VideoCapturer* capturer;
const webrtc::MediaConstraintsInterface* constraints;
scoped_refptr<webrtc::VideoSourceInterface> source;
};
struct StartAecDumpParams : public talk_base::MessageData {
explicit StartAecDumpParams(talk_base::PlatformFile aec_dump_file)
: aec_dump_file(aec_dump_file) {
}
talk_base::PlatformFile aec_dump_file;
bool result;
};
enum {
MSG_INIT_FACTORY = 1,
MSG_TERMINATE_FACTORY,
MSG_CREATE_PEERCONNECTION,
MSG_CREATE_AUDIOSOURCE,
MSG_CREATE_VIDEOSOURCE,
MSG_START_AEC_DUMP,
};
} // namespace
namespace webrtc {
talk_base::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory() {
talk_base::scoped_refptr<PeerConnectionFactory> pc_factory(
new talk_base::RefCountedObject<PeerConnectionFactory>());
if (!pc_factory->Initialize()) {
return NULL;
}
return pc_factory;
}
talk_base::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory(
talk_base::Thread* worker_thread,
talk_base::Thread* signaling_thread,
AudioDeviceModule* default_adm,
cricket::WebRtcVideoEncoderFactory* encoder_factory,
cricket::WebRtcVideoDecoderFactory* decoder_factory) {
talk_base::scoped_refptr<PeerConnectionFactory> pc_factory(
new talk_base::RefCountedObject<PeerConnectionFactory>(worker_thread,
signaling_thread,
default_adm,
encoder_factory,
decoder_factory));
if (!pc_factory->Initialize()) {
return NULL;
}
return pc_factory;
}
PeerConnectionFactory::PeerConnectionFactory()
: owns_ptrs_(true),
signaling_thread_(new talk_base::Thread),
worker_thread_(new talk_base::Thread) {
bool result = signaling_thread_->Start();
ASSERT(result);
result = worker_thread_->Start();
ASSERT(result);
}
PeerConnectionFactory::PeerConnectionFactory(
talk_base::Thread* worker_thread,
talk_base::Thread* signaling_thread,
AudioDeviceModule* default_adm,
cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
cricket::WebRtcVideoDecoderFactory* video_decoder_factory)
: owns_ptrs_(false),
signaling_thread_(signaling_thread),
worker_thread_(worker_thread),
default_adm_(default_adm),
video_encoder_factory_(video_encoder_factory),
video_decoder_factory_(video_decoder_factory) {
ASSERT(worker_thread != NULL);
ASSERT(signaling_thread != NULL);
// TODO: Currently there is no way creating an external adm in
// libjingle source tree. So we can 't currently assert if this is NULL.
// ASSERT(default_adm != NULL);
}
PeerConnectionFactory::~PeerConnectionFactory() {
signaling_thread_->Clear(this);
signaling_thread_->Send(this, MSG_TERMINATE_FACTORY);
if (owns_ptrs_) {
delete signaling_thread_;
delete worker_thread_;
}
}
bool PeerConnectionFactory::Initialize() {
InitMessageData result(false);
signaling_thread_->Send(this, MSG_INIT_FACTORY, &result);
return result.data();
}
void PeerConnectionFactory::OnMessage(talk_base::Message* msg) {
switch (msg->message_id) {
case MSG_INIT_FACTORY: {
InitMessageData* pdata = static_cast<InitMessageData*>(msg->pdata);
pdata->data() = Initialize_s();
break;
}
case MSG_TERMINATE_FACTORY: {
Terminate_s();
break;
}
case MSG_CREATE_PEERCONNECTION: {
CreatePeerConnectionParams* pdata =
static_cast<CreatePeerConnectionParams*> (msg->pdata);
pdata->peerconnection = CreatePeerConnection_s(
pdata->configuration,
pdata->constraints,
pdata->allocator_factory,
pdata->dtls_identity_service,
pdata->observer);
break;
}
case MSG_CREATE_AUDIOSOURCE: {
CreateAudioSourceParams* pdata =
static_cast<CreateAudioSourceParams*>(msg->pdata);
pdata->source = CreateAudioSource_s(pdata->constraints);
break;
}
case MSG_CREATE_VIDEOSOURCE: {
CreateVideoSourceParams* pdata =
static_cast<CreateVideoSourceParams*>(msg->pdata);
pdata->source = CreateVideoSource_s(pdata->capturer, pdata->constraints);
break;
}
case MSG_START_AEC_DUMP: {
StartAecDumpParams* pdata =
static_cast<StartAecDumpParams*>(msg->pdata);
pdata->result = StartAecDump_s(pdata->aec_dump_file);
break;
}
}
}
bool PeerConnectionFactory::Initialize_s() {
talk_base::InitRandom(talk_base::Time());
allocator_factory_ = PortAllocatorFactory::Create(worker_thread_);
if (!allocator_factory_)
return false;
cricket::DummyDeviceManager* device_manager(
new cricket::DummyDeviceManager());
// TODO: Need to make sure only one VoE is created inside
// WebRtcMediaEngine.
cricket::WebRtcMediaEngine* webrtc_media_engine(
new cricket::WebRtcMediaEngine(default_adm_.get(),
NULL, // No secondary adm.
video_encoder_factory_.get(),
video_decoder_factory_.get()));
channel_manager_.reset(new cricket::ChannelManager(
webrtc_media_engine, device_manager, worker_thread_));
channel_manager_->SetVideoRtxEnabled(true);
if (!channel_manager_->Init()) {
return false;
}
return true;
}
// Terminate what we created on the signaling thread.
void PeerConnectionFactory::Terminate_s() {
channel_manager_.reset(NULL);
allocator_factory_ = NULL;
}
talk_base::scoped_refptr<AudioSourceInterface>
PeerConnectionFactory::CreateAudioSource_s(
const MediaConstraintsInterface* constraints) {
talk_base::scoped_refptr<LocalAudioSource> source(
LocalAudioSource::Create(options_, constraints));
return source;
}
talk_base::scoped_refptr<VideoSourceInterface>
PeerConnectionFactory::CreateVideoSource_s(
cricket::VideoCapturer* capturer,
const MediaConstraintsInterface* constraints) {
talk_base::scoped_refptr<VideoSource> source(
VideoSource::Create(channel_manager_.get(), capturer, constraints));
return VideoSourceProxy::Create(signaling_thread_, source);
}
bool PeerConnectionFactory::StartAecDump_s(talk_base::PlatformFile file) {
return channel_manager_->StartAecDump(file);
}
talk_base::scoped_refptr<PeerConnectionInterface>
PeerConnectionFactory::CreatePeerConnection(
const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
PeerConnectionObserver* observer) {
CreatePeerConnectionParams params(configuration, constraints,
allocator_factory, dtls_identity_service,
observer);
signaling_thread_->Send(
this, MSG_CREATE_PEERCONNECTION, &params);
return params.peerconnection;
}
talk_base::scoped_refptr<PeerConnectionInterface>
PeerConnectionFactory::CreatePeerConnection_s(
const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
PeerConnectionObserver* observer) {
ASSERT(allocator_factory || allocator_factory_);
talk_base::scoped_refptr<PeerConnection> pc(
new talk_base::RefCountedObject<PeerConnection>(this));
if (!pc->Initialize(
configuration,
constraints,
allocator_factory ? allocator_factory : allocator_factory_.get(),
dtls_identity_service,
observer)) {
return NULL;
}
return PeerConnectionProxy::Create(signaling_thread(), pc);
}
talk_base::scoped_refptr<MediaStreamInterface>
PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
return MediaStreamProxy::Create(signaling_thread_,
MediaStream::Create(label));
}
talk_base::scoped_refptr<AudioSourceInterface>
PeerConnectionFactory::CreateAudioSource(
const MediaConstraintsInterface* constraints) {
CreateAudioSourceParams params(constraints);
signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, &params);
return params.source;
}
talk_base::scoped_refptr<VideoSourceInterface>
PeerConnectionFactory::CreateVideoSource(
cricket::VideoCapturer* capturer,
const MediaConstraintsInterface* constraints) {
CreateVideoSourceParams params(capturer,
constraints);
signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, &params);
return params.source;
}
talk_base::scoped_refptr<VideoTrackInterface>
PeerConnectionFactory::CreateVideoTrack(
const std::string& id,
VideoSourceInterface* source) {
talk_base::scoped_refptr<VideoTrackInterface> track(
VideoTrack::Create(id, source));
return VideoTrackProxy::Create(signaling_thread_, track);
}
talk_base::scoped_refptr<AudioTrackInterface>
PeerConnectionFactory::CreateAudioTrack(const std::string& id,
AudioSourceInterface* source) {
talk_base::scoped_refptr<AudioTrackInterface> track(
AudioTrack::Create(id, source));
return AudioTrackProxy::Create(signaling_thread_, track);
}
bool PeerConnectionFactory::StartAecDump(talk_base::PlatformFile file) {
StartAecDumpParams params(file);
signaling_thread_->Send(this, MSG_START_AEC_DUMP, &params);
return params.result;
}
cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
return channel_manager_.get();
}
talk_base::Thread* PeerConnectionFactory::signaling_thread() {
return signaling_thread_;
}
talk_base::Thread* PeerConnectionFactory::worker_thread() {
return worker_thread_;
}
} // namespace webrtc