Chromium Code Reviews| Index: components/devtools_bridge/session_dependency_factory.cc |
| diff --git a/components/devtools_bridge/session_dependency_factory.cc b/components/devtools_bridge/session_dependency_factory.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cb018b80a7946ea0ab515177c3146a4dea4be305 |
| --- /dev/null |
| +++ b/components/devtools_bridge/session_dependency_factory.cc |
| @@ -0,0 +1,429 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/devtools_bridge/session_dependency_factory.h" |
| + |
| +#include "components/devtools_bridge/abstract_data_channel.h" |
| +#include "components/devtools_bridge/abstract_peer_connection.h" |
| +#include "components/devtools_bridge/rtc_configuration.h" |
| +#include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h" |
| +#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h" |
| +#include "third_party/webrtc/base/bind.h" |
| +#include "third_party/webrtc/base/ssladapter.h" |
| +#include "third_party/webrtc/base/thread.h" |
| + |
| +namespace devtools_bridge { |
| + |
| +class RTCConfiguration::Impl |
| + : public RTCConfiguration, |
| + public webrtc::PeerConnectionInterface::RTCConfiguration { |
| + public: |
| + |
| + virtual void AddIceServer( |
| + const std::string& uri, |
| + const std::string& username, |
| + const std::string& credential) override { |
| + webrtc::PeerConnectionInterface::IceServer server; |
| + server.uri = uri; |
| + server.username = username; |
| + server.password = credential; |
| + servers.push_back(server); |
| + } |
| + |
| + const Impl& impl() const override { |
| + return *this; |
| + } |
| + |
| + private: |
| + webrtc::PeerConnectionInterface::RTCConfiguration base_; |
| +}; |
| + |
| +namespace { |
| + |
| +template <typename T> |
| +void CheckedRelease(rtc::scoped_refptr<T>* ptr) { |
| + CHECK_EQ(0, ptr->release()->Release()); |
| +} |
| + |
| +class MediaConstraints |
| + : public webrtc::MediaConstraintsInterface { |
| + public: |
| + virtual ~MediaConstraints() {} |
| + |
| + virtual const Constraints& GetMandatory() const override { |
| + return mandatory_; |
| + } |
| + |
| + virtual const Constraints& GetOptional() const override { |
| + return optional_; |
| + } |
| + |
| + void AddMandatory(const std::string& key, const std::string& value) { |
| + mandatory_.push_back(Constraint(key, value)); |
| + } |
| + |
| + private: |
| + Constraints mandatory_; |
| + Constraints optional_; |
| +}; |
| + |
| +class DataChannelImpl : public AbstractDataChannel { |
| + public: |
| + explicit DataChannelImpl( |
| + rtc::scoped_refptr<webrtc::DataChannelInterface> impl) : impl_(impl) { |
| + } |
| + |
| + // TODO(serya): Implement. |
| + |
| + private: |
| + rtc::scoped_refptr<webrtc::DataChannelInterface> const impl_; |
| +}; |
| + |
| +class PeerConnectionObserverImpl |
| + : public webrtc::PeerConnectionObserver { |
| + public: |
| + PeerConnectionObserverImpl(AbstractPeerConnection::Delegate* delegate) |
| + : delegate_(delegate), |
| + connected_(false) { |
| + } |
| + |
| + virtual void OnAddStream(webrtc::MediaStreamInterface* stream) override {} |
| + |
| + virtual void OnRemoveStream(webrtc::MediaStreamInterface* stream) override {} |
| + |
| + virtual void OnDataChannel(webrtc::DataChannelInterface* data_channel) |
| + override {} |
| + |
| + virtual void OnRenegotiationNeeded() override {} |
| + |
| + virtual void OnSignalingChange( |
| + webrtc::PeerConnectionInterface::SignalingState new_state) override { |
| + } |
| + |
| + virtual void OnIceConnectionChange( |
| + webrtc::PeerConnectionInterface::IceConnectionState new_state) override { |
| + bool connected = |
| + new_state == webrtc::PeerConnectionInterface::kIceConnectionConnected || |
| + new_state == webrtc::PeerConnectionInterface::kIceConnectionCompleted; |
| + |
| + if (connected != connected_) { |
| + connected_ = connected; |
| + delegate_->OnIceConnectionChange(connected_); |
| + } |
| + } |
| + |
| + virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) |
| + override { |
| + std::string sdp; |
| + candidate->ToString(&sdp); |
| + |
| + delegate_->OnIceCandidate( |
| + candidate->sdp_mid(), candidate->sdp_mline_index(), sdp); |
| + } |
| + |
| + private: |
| + AbstractPeerConnection::Delegate* const delegate_; |
|
mnaganov (inactive)
2014/11/11 17:11:47
It should be "const Type", not "Type const". Here
SeRya
2014/11/12 08:25:07
This is not the case: "Type* const" is not like "T
|
| + bool connected_; |
| +}; |
| + |
| +/** |
| + * Helper object which may outlive PeerConnectionImpl. Provides access |
| + * to the connection and the delegate to operaion callback objects |
| + * in a safe way. Always accessible on the signaling thread. |
| + */ |
| +class PeerConnectionHolder : public rtc::RefCountInterface { |
| + public: |
| + PeerConnectionHolder( |
| + rtc::Thread* signaling_thread, |
| + webrtc::PeerConnectionInterface* connection, |
| + AbstractPeerConnection::Delegate* delegate) |
| + : signaling_thread_(signaling_thread), |
| + connection_(connection), |
| + delegate_(delegate), |
| + disposed_(false) { |
| + } |
| + |
| + virtual ~PeerConnectionHolder() { |
| + DCHECK(disposed_); |
| + } |
| + |
| + void Dispose() { |
| + DCHECK(!IsDisposed()); |
| + disposed_ = true; |
| + } |
| + |
| + webrtc::PeerConnectionInterface* connection() { |
| + DCHECK(!IsDisposed()); |
| + return connection_; |
| + } |
| + |
| + AbstractPeerConnection::Delegate* delegate() { |
| + DCHECK(!IsDisposed()); |
| + return delegate_; |
| + } |
| + |
| + bool IsDisposed() { |
| + DCHECK(signaling_thread_->IsCurrent()); |
| + return disposed_; |
| + } |
| + |
| + private: |
| + rtc::Thread* const signaling_thread_; |
| + webrtc::PeerConnectionInterface* const connection_; |
| + AbstractPeerConnection::Delegate* const delegate_; |
| + bool disposed_; |
| +}; |
| + |
| +class CreateAndSetHandler |
| + : public webrtc::CreateSessionDescriptionObserver, |
| + public webrtc::SetSessionDescriptionObserver { |
| + public: |
| + explicit CreateAndSetHandler( |
| + rtc::scoped_refptr<PeerConnectionHolder> holder) |
| + : holder_(holder) { |
| + } |
| + |
| + virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { |
| + if (holder_->IsDisposed()) return; |
| + |
| + type_ = desc->type(); |
| + if (desc->ToString(&description_)) { |
| + holder_->connection()->SetLocalDescription(this, desc); |
| + } else { |
| + OnFailure("Can't serialize session description"); |
| + } |
| + } |
| + |
| + virtual void OnSuccess() override { |
| + if (holder_->IsDisposed()) return; |
| + |
| + if (type_ == webrtc::SessionDescriptionInterface::kOffer) { |
| + holder_->delegate()->OnLocalOfferCreatedAndSetSet(description_); |
| + } else { |
| + DCHECK_EQ(webrtc::SessionDescriptionInterface::kAnswer, type_); |
| + |
| + holder_->delegate()->OnLocalAnswerCreatedAndSetSet(description_); |
| + } |
| + } |
| + |
| + virtual void OnFailure(const std::string& error) override { |
| + if (holder_->IsDisposed()) return; |
| + |
| + holder_->delegate()->OnFailure(error); |
| + } |
| + |
| + private: |
| + rtc::scoped_refptr<PeerConnectionHolder> const holder_; |
| + std::string type_; |
| + std::string description_; |
| +}; |
| + |
| +class SetRemoteDescriptionHandler |
| + : public webrtc::SetSessionDescriptionObserver { |
| + public: |
| + SetRemoteDescriptionHandler( |
| + rtc::scoped_refptr<PeerConnectionHolder> holder) |
| + : holder_(holder) { |
| + } |
| + |
| + virtual void OnSuccess() override { |
| + if (holder_->IsDisposed()) return; |
| + |
| + holder_->delegate()->OnRemoteDescriptionSet(); |
| + } |
| + |
| + virtual void OnFailure(const std::string& error) override { |
| + if (holder_->IsDisposed()) return; |
| + |
| + holder_->delegate()->OnFailure(error); |
| + } |
| + |
| + private: |
| + rtc::scoped_refptr<PeerConnectionHolder> const holder_; |
| +}; |
| + |
| +class PeerConnectionImpl : public AbstractPeerConnection { |
| + public: |
| + PeerConnectionImpl( |
| + rtc::Thread* signaling_thread, |
| + rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection, |
| + scoped_ptr<PeerConnectionObserverImpl> observer, |
| + scoped_ptr<AbstractPeerConnection::Delegate> delegate) |
| + : holder_(new rtc::RefCountedObject<PeerConnectionHolder>( |
| + signaling_thread, connection.get(), delegate.get())), |
| + signaling_thread_(signaling_thread), |
| + connection_(connection), |
| + observer_(observer.Pass()), |
| + delegate_(delegate.Pass()) { |
| + } |
| + |
| + virtual ~PeerConnectionImpl() { |
| + signaling_thread_->Invoke<void>(rtc::Bind( |
| + &PeerConnectionImpl::DisposeOnSignalingThread, this)); |
| + } |
| + |
| + virtual void CreateAndSetLocalOffer() override { |
| + connection_->CreateOffer(MakeCreateAndSetHandler(), NULL); |
| + } |
| + |
| + virtual void CreateAndSetLocalAnswer() override { |
| + connection_->CreateAnswer(MakeCreateAndSetHandler(), NULL); |
| + } |
| + |
| + virtual void SetRemoteOffer(const std::string& description) override { |
| + SetRemoteDescription( |
| + webrtc::SessionDescriptionInterface::kOffer, description); |
| + } |
| + |
| + virtual void SetRemoteAnswer(const std::string& description) override { |
| + SetRemoteDescription( |
| + webrtc::SessionDescriptionInterface::kAnswer, description); |
| + } |
| + |
| + void SetRemoteDescription( |
| + const std::string& type, const std::string& description) { |
| + webrtc::SdpParseError error; |
| + scoped_ptr<webrtc::SessionDescriptionInterface> value( |
| + webrtc::CreateSessionDescription(type, description, &error)); |
| + if (value == NULL) { |
| + OnParseError(error); |
| + return; |
| + } |
| + // Takes ownership on |value|. |
| + connection_->SetRemoteDescription( |
| + new rtc::RefCountedObject<SetRemoteDescriptionHandler>(holder_), |
| + value.release()); |
| + } |
| + |
| + virtual void AddIceCandidate( |
| + const std::string& sdp_mid, |
| + int sdp_mline_index, |
| + const std::string& sdp) override { |
| + webrtc::SdpParseError error; |
| + auto candidate = webrtc::CreateIceCandidate( |
| + sdp_mid, sdp_mline_index, sdp, &error); |
| + if (candidate == NULL) { |
| + OnParseError(error); |
| + return; |
| + } |
| + // Doesn't takes ownership. |
| + connection_->AddIceCandidate(candidate); |
| + delete candidate; |
| + } |
| + |
| + virtual scoped_ptr<AbstractDataChannel> CreateDataChannel( |
| + int channelId) override { |
| + webrtc::DataChannelInit init; |
| + init.reliable = true; |
| + init.ordered = true; |
| + init.negotiated = true; |
| + init.id = channelId; |
| + |
| + return make_scoped_ptr(new DataChannelImpl( |
| + connection_->CreateDataChannel("", &init))); |
| + } |
| + |
| + private: |
| + webrtc::CreateSessionDescriptionObserver* MakeCreateAndSetHandler() { |
| + return new rtc::RefCountedObject<CreateAndSetHandler>(holder_); |
| + } |
| + |
| + void DisposeOnSignalingThread() { |
| + DCHECK(signaling_thread_->IsCurrent()); |
| + |
| + CheckedRelease(&connection_); |
| + holder_->Dispose(); |
| + } |
| + |
| + void OnParseError(const webrtc::SdpParseError& error) { |
| + // TODO(serya): Send on signaling thread. |
| + } |
| + |
| + rtc::scoped_refptr<PeerConnectionHolder> const holder_; |
| + rtc::Thread* const signaling_thread_; |
| + rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection_; |
| + scoped_ptr<PeerConnectionObserverImpl> const observer_; |
| + scoped_ptr<AbstractPeerConnection::Delegate> const delegate_; |
| +}; |
| + |
| +class SessionDependencyFactoryImpl : public SessionDependencyFactory { |
| + public: |
| + SessionDependencyFactoryImpl( |
| + const base::Closure& cleanup_on_signaling_thread) |
| + : cleanup_on_signaling_thread_(cleanup_on_signaling_thread) { |
| + signaling_thread_.SetName("signaling_thread", NULL); |
| + signaling_thread_.Start(); |
| + worker_thread_.SetName("worker_thread", NULL); |
| + worker_thread_.Start(); |
| + |
| + factory_ = webrtc::CreatePeerConnectionFactory( |
| + &worker_thread_, &signaling_thread_, NULL, NULL, NULL); |
| + } |
| + |
| + virtual ~SessionDependencyFactoryImpl() { |
| + signaling_thread_.Invoke<void>(rtc::Bind( |
| + &SessionDependencyFactoryImpl::DisposeOnSignalingThread, this)); |
| + } |
| + |
| + virtual scoped_ptr<AbstractPeerConnection> CreatePeerConnection( |
| + scoped_ptr<RTCConfiguration> config, |
| + scoped_ptr<AbstractPeerConnection::Delegate> delegate) override { |
| + auto observer = make_scoped_ptr( |
| + new PeerConnectionObserverImpl(delegate.get())); |
| + |
| + MediaConstraints constraints; |
| + constraints.AddMandatory( |
| + MediaConstraints::kEnableDtlsSrtp, MediaConstraints::kValueTrue); |
| + |
| + auto connection = factory_->CreatePeerConnection( |
| + config->impl(), &constraints, NULL, NULL, observer.get()); |
| + |
| + return make_scoped_ptr(new PeerConnectionImpl( |
| + &signaling_thread_, connection, observer.Pass(), delegate.Pass())); |
| + } |
| + |
| + private: |
| + void DisposeOnSignalingThread() { |
| + DCHECK(signaling_thread_.IsCurrent()); |
| + CheckedRelease(&factory_); |
| + if (!cleanup_on_signaling_thread_.is_null()) { |
| + cleanup_on_signaling_thread_.Run(); |
| + } |
| + } |
| + |
| + base::Closure cleanup_on_signaling_thread_; |
| + rtc::Thread signaling_thread_; |
| + rtc::Thread worker_thread_; |
| + rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory_; |
| +}; |
| + |
| +} // namespace |
| + |
| +// RTCCOnfiguration |
| + |
| +// static |
| +scoped_ptr<RTCConfiguration> RTCConfiguration::CreateInstance() { |
| + return make_scoped_ptr(new RTCConfiguration::Impl()); |
| +} |
| + |
| +// SessionDependencyFactory |
| + |
| +// static |
| +bool SessionDependencyFactory::InitializeSSL() { |
| + return rtc::InitializeSSL(); |
| +} |
| + |
| +// static |
| +bool SessionDependencyFactory::CleanupSSL() { |
| + return rtc::CleanupSSL(); |
| +} |
| + |
| +// static |
| +scoped_ptr<SessionDependencyFactory> SessionDependencyFactory::CreateInstance( |
| + const base::Closure& cleanup_on_signaling_thread) { |
| + return make_scoped_ptr(new SessionDependencyFactoryImpl( |
| + cleanup_on_signaling_thread)); |
| +} |
| + |
| +} // namespace devtools_bridge |