/* * 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 InitMessageData; struct CreatePeerConnectionParams : public talk_base::MessageData { CreatePeerConnectionParams( const webrtc::PeerConnectionInterface::IceServers& 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 peerconnection; const webrtc::PeerConnectionInterface::IceServers& configuration; const webrtc::MediaConstraintsInterface* constraints; scoped_refptr allocator_factory; webrtc::DTLSIdentityServiceInterface* dtls_identity_service; webrtc::PeerConnectionObserver* observer; }; struct CreatePeerConnectionParamsDeprecated : public talk_base::MessageData { CreatePeerConnectionParamsDeprecated( const std::string& configuration, webrtc::PortAllocatorFactoryInterface* allocator_factory, webrtc::PeerConnectionObserver* observer) : configuration(configuration), allocator_factory(allocator_factory), observer(observer) { } scoped_refptr peerconnection; const std::string& configuration; scoped_refptr allocator_factory; webrtc::PeerConnectionObserver* observer; }; struct CreateAudioSourceParams : public talk_base::MessageData { explicit CreateAudioSourceParams( const webrtc::MediaConstraintsInterface* constraints) : constraints(constraints) { } const webrtc::MediaConstraintsInterface* constraints; scoped_refptr 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 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 { scoped_refptr CreatePeerConnectionFactory() { scoped_refptr pc_factory( new talk_base::RefCountedObject()); if (!pc_factory->Initialize()) { return NULL; } return pc_factory; } scoped_refptr CreatePeerConnectionFactory( talk_base::Thread* worker_thread, talk_base::Thread* signaling_thread, AudioDeviceModule* default_adm, cricket::WebRtcVideoEncoderFactory* encoder_factory, cricket::WebRtcVideoDecoderFactory* decoder_factory) { scoped_refptr pc_factory( new talk_base::RefCountedObject( 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(msg->pdata); pdata->data() = Initialize_s(); break; } case MSG_TERMINATE_FACTORY: { Terminate_s(); break; } case MSG_CREATE_PEERCONNECTION: { CreatePeerConnectionParams* pdata = static_cast (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(msg->pdata); pdata->source = CreateAudioSource_s(pdata->constraints); break; } case MSG_CREATE_VIDEOSOURCE: { CreateVideoSourceParams* pdata = static_cast(msg->pdata); pdata->source = CreateVideoSource_s(pdata->capturer, pdata->constraints); break; } case MSG_START_AEC_DUMP: { StartAecDumpParams* pdata = static_cast(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_)); 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 PeerConnectionFactory::CreateAudioSource_s( const MediaConstraintsInterface* constraints) { talk_base::scoped_refptr source( LocalAudioSource::Create(options_, constraints)); return source; } talk_base::scoped_refptr PeerConnectionFactory::CreateVideoSource_s( cricket::VideoCapturer* capturer, const MediaConstraintsInterface* constraints) { talk_base::scoped_refptr 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); } scoped_refptr PeerConnectionFactory::CreatePeerConnection( const PeerConnectionInterface::IceServers& 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, ¶ms); return params.peerconnection; } scoped_refptr PeerConnectionFactory::CreatePeerConnection( const PeerConnectionInterface::IceServers& configuration, const MediaConstraintsInterface* constraints, DTLSIdentityServiceInterface* dtls_identity_service, PeerConnectionObserver* observer) { return CreatePeerConnection( configuration, constraints, NULL, dtls_identity_service, observer); } talk_base::scoped_refptr PeerConnectionFactory::CreatePeerConnection_s( const PeerConnectionInterface::IceServers& configuration, const MediaConstraintsInterface* constraints, PortAllocatorFactoryInterface* allocator_factory, DTLSIdentityServiceInterface* dtls_identity_service, PeerConnectionObserver* observer) { ASSERT(allocator_factory || allocator_factory_); talk_base::scoped_refptr pc( new talk_base::RefCountedObject(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); } scoped_refptr PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) { return MediaStreamProxy::Create(signaling_thread_, MediaStream::Create(label)); } talk_base::scoped_refptr PeerConnectionFactory::CreateAudioSource( const MediaConstraintsInterface* constraints) { CreateAudioSourceParams params(constraints); signaling_thread_->Send(this, MSG_CREATE_AUDIOSOURCE, ¶ms); return params.source; } talk_base::scoped_refptr PeerConnectionFactory::CreateVideoSource( cricket::VideoCapturer* capturer, const MediaConstraintsInterface* constraints) { CreateVideoSourceParams params(capturer, constraints); signaling_thread_->Send(this, MSG_CREATE_VIDEOSOURCE, ¶ms); return params.source; } talk_base::scoped_refptr PeerConnectionFactory::CreateVideoTrack( const std::string& id, VideoSourceInterface* source) { talk_base::scoped_refptr track( VideoTrack::Create(id, source)); return VideoTrackProxy::Create(signaling_thread_, track); } scoped_refptr PeerConnectionFactory::CreateAudioTrack( const std::string& id, AudioSourceInterface* source) { talk_base::scoped_refptr 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, ¶ms); 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