Chromium Code Reviews| Index: content/renderer/media/rtc_peer_connection_handler.cc |
| diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3c93aae5eef22052bcc3492bb0f58eadc7cfe17f |
| --- /dev/null |
| +++ b/content/renderer/media/rtc_peer_connection_handler.cc |
| @@ -0,0 +1,405 @@ |
| +// Copyright (c) 2012 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 "content/renderer/media/rtc_peer_connection_handler.h" |
| + |
| +#include <string> |
| +#include <utility> |
| + |
| +#include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "content/renderer/media/media_stream_dependency_factory.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebMediaConstraints.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebRTCConfiguration.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebRTCICECandidateDescriptor.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebRTCPeerConnectionHandlerClient.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebRTCSessionDescriptionDescriptor.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebRTCSessionDescriptionRequest.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebRTCVoidRequest.h" |
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" |
| + |
| +// Converter functions from libjingle types to WebKit types. |
| + |
| +static WebKit::WebRTCPeerConnectionHandlerClient::ICEState |
| + GetWebKitIceState(webrtc::PeerConnectionInterface::IceState ice_state) { |
| + switch (ice_state) { |
| + case webrtc::PeerConnectionInterface::kIceNew: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateNew; |
| + case webrtc::PeerConnectionInterface::kIceGathering: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateGathering; |
| + case webrtc::PeerConnectionInterface::kIceWaiting: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateWaiting; |
| + case webrtc::PeerConnectionInterface::kIceChecking: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateChecking; |
| + case webrtc::PeerConnectionInterface::kIceConnected: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateConnected; |
| + case webrtc::PeerConnectionInterface::kIceCompleted: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateCompleted; |
| + case webrtc::PeerConnectionInterface::kIceFailed: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateFailed; |
| + case webrtc::PeerConnectionInterface::kIceClosed: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateClosed; |
| + default: |
| + NOTREACHED(); |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ICEStateClosed; |
| + } |
| + NOTREACHED(); |
| +} |
| + |
| +static WebKit::WebRTCPeerConnectionHandlerClient::ReadyState |
| + GetWebKitReadyState( |
| + webrtc::PeerConnectionInterface::ReadyState ready_state) { |
| + switch (ready_state) { |
| + case webrtc::PeerConnectionInterface::kNew: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ReadyStateNew; |
| + case webrtc::PeerConnectionInterface::kOpening: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ReadyStateOpening; |
| + case webrtc::PeerConnectionInterface::kActive: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ReadyStateActive; |
| + case webrtc::PeerConnectionInterface::kClosing: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ReadyStateClosing; |
| + case webrtc::PeerConnectionInterface::kClosed: |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ReadyStateClosed; |
| + default: |
| + NOTREACHED(); |
| + return WebKit::WebRTCPeerConnectionHandlerClient::ReadyStateClosed; |
| + } |
| + NOTREACHED(); |
| +} |
| + |
| +static WebKit::WebRTCSessionDescriptionDescriptor |
| + CreateWebKitSessionDescription( |
| + const webrtc::SessionDescriptionInterface* native_desc) { |
| + WebKit::WebRTCSessionDescriptionDescriptor description; |
| + if (!native_desc) { |
| + LOG(ERROR) << "Native session description is null."; |
| + return description; |
| + } |
| + |
| + std::string sdp; |
| + if (!native_desc->ToString(&sdp)) { |
| + LOG(ERROR) << "Failed to get SDP string of native session description."; |
| + return description; |
| + } |
| + |
| + description.initialize(UTF8ToUTF16(native_desc->type()), UTF8ToUTF16(sdp)); |
| + return description; |
| +} |
| + |
| +// Converter functions from WebKit types to libjingle types. |
| + |
| +static void GetNativeIceServers( |
| + const WebKit::WebRTCConfiguration& server_configuration, |
| + webrtc::JsepInterface::IceServers* servers) { |
| + if (server_configuration.isNull() || !servers) |
| + return; |
| + for (size_t i = 0; i < server_configuration.numberOfServers(); ++i) { |
| + webrtc::JsepInterface::IceServer server; |
| + const WebKit::WebRTCICEServer& webkit_server = |
| + server_configuration.server(i); |
| + server.password = UTF16ToUTF8(webkit_server.credential()); |
| + server.uri = webkit_server.uri().spec(); |
| + servers->push_back(server); |
| + } |
| +} |
| + |
| +// Class mapping responses from calls to libjingle CreateOffer/Answer and |
| +// the WebKit::WebRTCSessionDescriptionRequest. |
| +class CreateSessionDescriptionRequest |
| + : public webrtc::CreateSessionDescriptionObserver { |
| + public: |
| + explicit CreateSessionDescriptionRequest( |
| + const WebKit::WebRTCSessionDescriptionRequest& request) |
| + : webkit_request_(request) {} |
| + |
| + virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) OVERRIDE { |
| + webkit_request_.requestSucceeded(CreateWebKitSessionDescription(desc)); |
| + } |
| + virtual void OnFailure(const std::string& error) OVERRIDE { |
| + webkit_request_.requestFailed(UTF8ToUTF16(error)); |
| + } |
| + |
| + protected: |
| + virtual ~CreateSessionDescriptionRequest() {} |
| + |
| + private: |
| + WebKit::WebRTCSessionDescriptionRequest webkit_request_; |
| +}; |
| + |
| +// Class mapping responses from calls to libjingle |
| +// SetLocalDescription/SetRemoteDescription and a WebKit::WebRTCVoidRequest. |
| +class SetSessionDescriptionRequest |
| + : public webrtc::SetSessionDescriptionObserver { |
| + public: |
| + explicit SetSessionDescriptionRequest( |
| + const WebKit::WebRTCVoidRequest& request) |
| + : webkit_request_(request) {} |
| + |
| + virtual void OnSuccess() OVERRIDE { |
| + webkit_request_.requestSucceeded(); |
| + } |
| + virtual void OnFailure(const std::string& error) OVERRIDE { |
| + webkit_request_.requestFailed(UTF8ToUTF16(error)); |
| + } |
| + |
| + protected: |
| + virtual ~SetSessionDescriptionRequest() {} |
| + |
| + private: |
| + WebKit::WebRTCVoidRequest webkit_request_; |
| +}; |
| + |
| +// TODO(perkj): Implement MediaConstraints when WebKit have done so. |
| +class RTCMediaConstraints : public webrtc::MediaConstraintsInterface { |
| + public: |
| + explicit RTCMediaConstraints( |
| + const WebKit::WebMediaConstraints& /*constraints*/) { |
| + } |
| + ~RTCMediaConstraints() {} |
| +}; |
| + |
| +RTCPeerConnectionHandler::RTCPeerConnectionHandler( |
| + WebKit::WebRTCPeerConnectionHandlerClient* client, |
| + MediaStreamDependencyFactory* dependency_factory) |
| + : PeerConnectionHandlerBase(dependency_factory), |
| + client_(client) { |
| +} |
| + |
| +RTCPeerConnectionHandler::~RTCPeerConnectionHandler() { |
| +} |
| + |
| +bool RTCPeerConnectionHandler::initialize( |
| + const WebKit::WebRTCConfiguration& server_configuration, |
| + const WebKit::WebMediaConstraints& options ) { |
| + webrtc::JsepInterface::IceServers servers; |
| + GetNativeIceServers(server_configuration, &servers); |
| + |
| + RTCMediaConstraints constraints(options); |
| + native_peer_connection_ = |
| + dependency_factory_->CreatePeerConnection( |
| + servers, &constraints, this); |
| + if (!native_peer_connection_) { |
| + LOG(ERROR) << "Failed to initialize native PeerConnection."; |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +void RTCPeerConnectionHandler::createOffer( |
| + const WebKit::WebRTCSessionDescriptionRequest& request, |
| + const WebKit::WebMediaConstraints& options) { |
| + talk_base::scoped_refptr<CreateSessionDescriptionRequest> description_request( |
| + new talk_base::RefCountedObject<CreateSessionDescriptionRequest>( |
| + request)); |
| + RTCMediaConstraints constraints(options); |
| + native_peer_connection_->CreateOffer( |
| + description_request.get(), &constraints); |
| +} |
| + |
| +void RTCPeerConnectionHandler::createAnswer( |
| + const WebKit::WebRTCSessionDescriptionRequest& request, |
| + const WebKit::WebMediaConstraints& options) { |
| + talk_base::scoped_refptr<CreateSessionDescriptionRequest> description_request( |
| + new talk_base::RefCountedObject<CreateSessionDescriptionRequest>( |
| + request)); |
| + RTCMediaConstraints constraints(options); |
| + native_peer_connection_->CreateAnswer(description_request.get(), |
| + &constraints); |
| +} |
| + |
| +void RTCPeerConnectionHandler::setLocalDescription( |
| + const WebKit::WebRTCVoidRequest& request, |
| + const WebKit::WebRTCSessionDescriptionDescriptor& description) { |
| + webrtc::SessionDescriptionInterface* native_desc = |
| + CreateNativeSessionDescription(description); |
| + if (!native_desc) { |
| + LOG(ERROR) << "Failed to parse SessionDescription."; |
|
Ronghua Wu (Left Chromium)
2012/08/15 00:57:32
Can you just LOG the |reason|, so that you don't n
perkj_chrome
2012/08/15 09:12:30
Done.
|
| + WebKit::WebString reason("Failed to parse SessionDescription."); |
| + request.requestFailed(reason); |
| + return; |
| + } |
| + talk_base::scoped_refptr<SetSessionDescriptionRequest> set_request( |
| + new talk_base::RefCountedObject<SetSessionDescriptionRequest>(request)); |
| + native_peer_connection_->SetLocalDescription(set_request.get(), native_desc); |
| +} |
| + |
| +void RTCPeerConnectionHandler::setRemoteDescription( |
| + const WebKit::WebRTCVoidRequest& request, |
| + const WebKit::WebRTCSessionDescriptionDescriptor& description) { |
| + webrtc::SessionDescriptionInterface* native_desc = |
| + CreateNativeSessionDescription(description); |
| + if (!native_desc) { |
| + LOG(ERROR) << "Failed to parse SessionDescription."; |
| + WebKit::WebString reason("Failed to parse SessionDescription."); |
| + request.requestFailed(reason); |
| + return; |
| + } |
| + talk_base::scoped_refptr<SetSessionDescriptionRequest> set_request( |
| + new talk_base::RefCountedObject<SetSessionDescriptionRequest>(request)); |
| + native_peer_connection_->SetRemoteDescription(set_request.get(), native_desc); |
| +} |
| + |
| +WebKit::WebRTCSessionDescriptionDescriptor |
| +RTCPeerConnectionHandler::localDescription() { |
| + const webrtc::SessionDescriptionInterface* native_desc = |
| + native_peer_connection_->local_description(); |
| + WebKit::WebRTCSessionDescriptionDescriptor description = |
| + CreateWebKitSessionDescription(native_desc); |
| + return description; |
| +} |
| + |
| +WebKit::WebRTCSessionDescriptionDescriptor |
| +RTCPeerConnectionHandler::remoteDescription() { |
| + const webrtc::SessionDescriptionInterface* native_desc = |
| + native_peer_connection_->remote_description(); |
| + WebKit::WebRTCSessionDescriptionDescriptor description = |
| + CreateWebKitSessionDescription(native_desc); |
| + return description; |
| +} |
| + |
| +bool RTCPeerConnectionHandler::updateICE( |
| + const WebKit::WebRTCConfiguration& server_configuration, |
| + const WebKit::WebMediaConstraints& options) { |
| + webrtc::JsepInterface::IceServers servers; |
| + GetNativeIceServers(server_configuration, &servers); |
| + RTCMediaConstraints constraints(options); |
| + return native_peer_connection_->UpdateIce(servers, |
| + &constraints); |
| +} |
| + |
| +bool RTCPeerConnectionHandler::addICECandidate( |
| + const WebKit::WebRTCICECandidateDescriptor& candidate) { |
| + scoped_ptr<webrtc::IceCandidateInterface> native_candidate( |
| + dependency_factory_->CreateIceCandidate( |
| + UTF16ToUTF8(candidate.sdpMid()), |
| + candidate.sdpMLineIndex(), |
| + UTF16ToUTF8(candidate.candidate()))); |
| + if (!native_candidate.get()) { |
| + LOG(ERROR) << "Could not create native ICE candidate."; |
| + return false; |
| + } |
| + |
| + bool return_value = |
| + native_peer_connection_->AddIceCandidate(native_candidate.get()); |
| + if (!return_value) |
| + LOG(ERROR) << "Error processing ICE candidate."; |
| + return return_value; |
| +} |
| + |
| +bool RTCPeerConnectionHandler::addStream( |
| + const WebKit::WebMediaStreamDescriptor& stream, |
| + const WebKit::WebMediaConstraints& options) { |
| + RTCMediaConstraints constraints(options); |
| + return AddStream(stream, &constraints); |
| +} |
| + |
| +void RTCPeerConnectionHandler::removeStream( |
| + const WebKit::WebMediaStreamDescriptor& stream) { |
| + RemoveStream(stream); |
| +} |
| + |
| +void RTCPeerConnectionHandler::stop() { |
| + DVLOG(1) << "RTCPeerConnectionHandler::stop"; |
| + native_peer_connection_ = NULL; |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnError() { |
| + // TODO(perkj): Implement. |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnStateChange(StateType state_changed) { |
| + switch (state_changed) { |
| + case kReadyState: { |
| + WebKit::WebRTCPeerConnectionHandlerClient::ReadyState ready_state = |
| + GetWebKitReadyState(native_peer_connection_->ready_state()); |
| + client_->didChangeReadyState(ready_state); |
| + break; |
| + } |
| + case kIceState: { |
| + WebKit::WebRTCPeerConnectionHandlerClient::ICEState ice_state = |
| + GetWebKitIceState(native_peer_connection_->ice_state()); |
| + client_->didChangeICEState(ice_state); |
| + break; |
| + } |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnAddStream( |
| + webrtc::MediaStreamInterface* stream) { |
| + if (!stream) { |
| + LOG(ERROR) << "OnAddStream: stream is null"; |
| + return; |
| + } |
| + |
| + DCHECK(remote_streams_.find(stream) == remote_streams_.end()); |
| + WebKit::WebMediaStreamDescriptor descriptor = |
| + CreateWebKitStreamDescriptor(stream); |
| + remote_streams_.insert( |
| + std::pair<webrtc::MediaStreamInterface*, |
| + WebKit::WebMediaStreamDescriptor>(stream, descriptor)); |
| + client_->didAddRemoteStream(descriptor); |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnRemoveStream( |
| + webrtc::MediaStreamInterface* stream) { |
| + if (!stream) { |
| + LOG(ERROR) << "OnRemoveStream: stream is null"; |
| + return; |
| + } |
| + |
| + RemoteStreamMap::iterator it = remote_streams_.find(stream); |
| + if (it == remote_streams_.end()) { |
| + NOTREACHED() << "Stream not found"; |
| + return; |
| + } |
| + WebKit::WebMediaStreamDescriptor descriptor = it->second; |
| + DCHECK(!descriptor.isNull()); |
| + remote_streams_.erase(it); |
| + client_->didRemoveRemoteStream(descriptor); |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnIceCandidate( |
| + const webrtc::IceCandidateInterface* candidate) { |
| + std::string sdp; |
| + if (!candidate->ToString(&sdp)) { |
| + LOG(ERROR) << "OnIceCandidate: Could not get SDP string."; |
| + return; |
| + } |
| + WebKit::WebRTCICECandidateDescriptor web_candidate; |
| + web_candidate.initialize(UTF8ToUTF16(sdp), |
| + UTF8ToUTF16(candidate->sdp_mid()), |
| + candidate->sdp_mline_index()); |
| + client_->didGenerateICECandidate(web_candidate); |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnIceComplete() { |
| + // Generates a NULL ice candidate object. |
| + WebKit::WebRTCICECandidateDescriptor web_candidate; |
| + client_->didGenerateICECandidate(web_candidate); |
| +} |
| + |
| +void RTCPeerConnectionHandler::OnRenegotiationNeeded() { |
| + client_->doRenegotiate(); |
| +} |
| + |
| +webrtc::SessionDescriptionInterface* |
| + RTCPeerConnectionHandler::CreateNativeSessionDescription( |
| + const WebKit::WebRTCSessionDescriptionDescriptor& description) { |
| + std::string sdp = UTF16ToUTF8(description.sdp()); |
| + std::string type = UTF16ToUTF8(description.type()); |
| + webrtc::SessionDescriptionInterface* native_desc = |
| + dependency_factory_->CreateSessionDescription(type, sdp); |
| + if (!native_desc) { |
| + LOG(ERROR) << "Failed to create native session description. Type: " |
| + << type << " SDP: " << sdp; |
| + return NULL; |
| + } |
| + |
| + return native_desc; |
| +} |