diff options
-rw-r--r-- | content/renderer/media/media_stream_dependency_factory.cc | 150 | ||||
-rw-r--r-- | content/renderer/media/media_stream_dependency_factory.h | 52 | ||||
-rw-r--r-- | content/renderer/media/media_stream_impl.cc | 281 | ||||
-rw-r--r-- | content/renderer/media/media_stream_impl.h | 51 | ||||
-rw-r--r-- | content/renderer/media/mock_media_stream_dependency_factory.cc | 175 | ||||
-rw-r--r-- | content/renderer/media/mock_media_stream_dependency_factory.h | 68 | ||||
-rw-r--r-- | content/renderer/media/mock_media_stream_impl.cc | 20 | ||||
-rw-r--r-- | content/renderer/media/mock_media_stream_impl.h | 13 | ||||
-rw-r--r-- | content/renderer/media/mock_peer_connection_impl.cc | 113 | ||||
-rw-r--r-- | content/renderer/media/mock_peer_connection_impl.h | 63 | ||||
-rw-r--r-- | content/renderer/media/peer_connection_handler.cc | 304 | ||||
-rw-r--r-- | content/renderer/media/peer_connection_handler.h | 111 | ||||
-rw-r--r-- | content/renderer/media/peer_connection_handler_unittest.cc | 120 | ||||
-rw-r--r-- | third_party/libjingle/libjingle.gyp | 50 |
14 files changed, 935 insertions, 636 deletions
diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc index a9e9d46..43c5d60 100644 --- a/content/renderer/media/media_stream_dependency_factory.cc +++ b/content/renderer/media/media_stream_dependency_factory.cc @@ -4,69 +4,141 @@ #include "content/renderer/media/media_stream_dependency_factory.h" +#include <vector> + #include "content/renderer/media/video_capture_module_impl.h" #include "content/renderer/media/webrtc_audio_device_impl.h" #include "content/renderer/p2p/ipc_network_manager.h" #include "content/renderer/p2p/ipc_socket_factory.h" #include "content/renderer/p2p/port_allocator.h" #include "jingle/glue/thread_wrapper.h" -#include "third_party/libjingle/source/talk/app/webrtcv1/peerconnection.h" -#include "third_party/libjingle/source/talk/session/phone/dummydevicemanager.h" -#include "third_party/libjingle/source/talk/session/phone/webrtcmediaengine.h" +#include "third_party/libjingle/source/talk/app/webrtc/peerconnection.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" +static std::string ParseHostName(const std::string& hostname) { + std::string address; + size_t pos = hostname.find(':'); + if (pos == std::string::npos) { + DVLOG(1) << "No port specified."; + } else { + address = hostname.substr(0, pos); + } + return address; +} + +class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface { + public: + P2PPortAllocatorFactory( + content::P2PSocketDispatcher* socket_dispatcher, + talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory) + : socket_dispatcher_(socket_dispatcher), + network_manager_(network_manager), + socket_factory_(socket_factory) { + } + + virtual cricket::PortAllocator* CreatePortAllocator( + const std::vector<StunConfiguration>& stun_servers, + const std::vector<TurnConfiguration>& turn_configurations) OVERRIDE { + WebKit::WebFrame* web_frame = WebKit::WebFrame::frameForCurrentContext(); + if (!web_frame) { + LOG(ERROR) << "WebFrame is NULL."; + return NULL; + } + webkit_glue::P2PTransport::Config config; + if (stun_servers.size() > 0) { + config.stun_server = ParseHostName(stun_servers[0].server.hostname()); + config.stun_server_port = stun_servers[0].server.port(); + } + if (turn_configurations.size() > 0) { + config.relay_server = ParseHostName( + turn_configurations[0].server.hostname()); + config.relay_server_port = turn_configurations[0].server.port(); + config.relay_username = turn_configurations[0].username; + config.relay_password = turn_configurations[0].password; + } + + return new content::P2PPortAllocator(web_frame, + socket_dispatcher_, + network_manager_, + socket_factory_, + config); + } + + protected: + virtual ~P2PPortAllocatorFactory() {} + + private: + // socket_dispatcher_ is a weak reference, owned by RenderView. It's valid + // for the lifetime of RenderView. + content::P2PSocketDispatcher* socket_dispatcher_; + // network_manager_ and socket_factory_ are a weak references, owned by + // MediaStreamImpl. + talk_base::NetworkManager* network_manager_; + talk_base::PacketSocketFactory* socket_factory_; +}; + + MediaStreamDependencyFactory::MediaStreamDependencyFactory() {} MediaStreamDependencyFactory::~MediaStreamDependencyFactory() {} -cricket::WebRtcMediaEngine* -MediaStreamDependencyFactory::CreateWebRtcMediaEngine() { - webrtc::AudioDeviceModule* adm = new WebRtcAudioDeviceImpl(); - webrtc::AudioDeviceModule* adm_sc = new WebRtcAudioDeviceImpl(); - return new cricket::WebRtcMediaEngine(adm, adm_sc, NULL); -} - bool MediaStreamDependencyFactory::CreatePeerConnectionFactory( - cricket::MediaEngineInterface* media_engine, - talk_base::Thread* worker_thread) { + talk_base::Thread* worker_thread, + talk_base::Thread* signaling_thread, + content::P2PSocketDispatcher* socket_dispatcher, + talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory) { if (!pc_factory_.get()) { - scoped_ptr<webrtc::PeerConnectionFactory> factory( - new webrtc::PeerConnectionFactory(media_engine, - new cricket::DummyDeviceManager(), - worker_thread)); - if (factory->Initialize()) - pc_factory_.reset(factory.release()); + talk_base::scoped_refptr<P2PPortAllocatorFactory> pa_factory = + new talk_base::RefCountedObject<P2PPortAllocatorFactory>( + socket_dispatcher, + network_manager, + socket_factory); + + talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory( + webrtc::CreatePeerConnectionFactory(worker_thread, + signaling_thread, + pa_factory.release(), + new WebRtcAudioDeviceImpl())); + if (factory.get()) + pc_factory_ = factory.release(); } return pc_factory_.get() != NULL; } -void MediaStreamDependencyFactory::DeletePeerConnectionFactory() { - pc_factory_.reset(); +void MediaStreamDependencyFactory::ReleasePeerConnectionFactory() { + if (pc_factory_.get()) + pc_factory_ = NULL; } bool MediaStreamDependencyFactory::PeerConnectionFactoryCreated() { return pc_factory_.get() != NULL; } -cricket::PortAllocator* MediaStreamDependencyFactory::CreatePortAllocator( - content::P2PSocketDispatcher* socket_dispatcher, - talk_base::NetworkManager* network_manager, - talk_base::PacketSocketFactory* socket_factory, - const webkit_glue::P2PTransport::Config& config) { - WebKit::WebFrame* web_frame = WebKit::WebFrame::frameForCurrentContext(); - if (!web_frame) { - DVLOG(1) << "WebFrame is NULL."; - return NULL; - } - return new content::P2PPortAllocator(web_frame, - socket_dispatcher, - network_manager, - socket_factory, - config); +talk_base::scoped_refptr<webrtc::PeerConnectionInterface> +MediaStreamDependencyFactory::CreatePeerConnection( + const std::string& config, + webrtc::PeerConnectionObserver* observer) { + return pc_factory_->CreatePeerConnection(config, observer); +} + +talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> +MediaStreamDependencyFactory::CreateLocalMediaStream( + const std::string& label) { + return pc_factory_->CreateLocalMediaStream(label); +} + +talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> +MediaStreamDependencyFactory::CreateLocalVideoTrack( + const std::string& label, + cricket::VideoCapturer* video_device) { + return pc_factory_->CreateLocalVideoTrack(label, video_device); } -webrtc::PeerConnection* MediaStreamDependencyFactory::CreatePeerConnection( - cricket::PortAllocator* port_allocator, - talk_base::Thread* signaling_thread) { - return pc_factory_->CreatePeerConnection(port_allocator, signaling_thread); +talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> +MediaStreamDependencyFactory::CreateLocalAudioTrack( + const std::string& label, + webrtc::AudioDeviceModule* audio_device) { + return pc_factory_->CreateLocalAudioTrack(label, audio_device); } diff --git a/content/renderer/media/media_stream_dependency_factory.h b/content/renderer/media/media_stream_dependency_factory.h index ea51b58..20efd9e 100644 --- a/content/renderer/media/media_stream_dependency_factory.h +++ b/content/renderer/media/media_stream_dependency_factory.h @@ -10,7 +10,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "content/common/content_export.h" -#include "third_party/libjingle/source/talk/app/webrtcv1/peerconnectionfactory.h" +#include "third_party/libjingle/source/talk/app/webrtc/peerconnection.h" #include "webkit/glue/p2p_transport.h" namespace content { @@ -20,9 +20,7 @@ class P2PSocketDispatcher; } namespace cricket { -class MediaEngineInterface; class PortAllocator; -class WebRtcMediaEngine; } namespace talk_base { @@ -42,35 +40,39 @@ class CONTENT_EXPORT MediaStreamDependencyFactory { MediaStreamDependencyFactory(); virtual ~MediaStreamDependencyFactory(); - // WebRtcMediaEngine is used in CreatePeerConnectionFactory(). - virtual cricket::WebRtcMediaEngine* CreateWebRtcMediaEngine(); - // Creates and deletes |pc_factory_|, which in turn is used for - // creating PeerConnection objects. |media_engine| is the engine created by - // CreateWebRtcMediaEngine(). |port_allocator| and |media_engine| will be - // owned by |pc_factory_|. |worker_thread| is owned by MediaStreamImpl. + // creating PeerConnection objects. virtual bool CreatePeerConnectionFactory( - cricket::MediaEngineInterface* media_engine, - talk_base::Thread* worker_thread); - virtual void DeletePeerConnectionFactory(); - virtual bool PeerConnectionFactoryCreated(); - - // The port allocator is used in CreatePeerConnection(). - virtual cricket::PortAllocator* CreatePortAllocator( + talk_base::Thread* worker_thread, + talk_base::Thread* signaling_thread, content::P2PSocketDispatcher* socket_dispatcher, talk_base::NetworkManager* network_manager, - talk_base::PacketSocketFactory* socket_factory, - const webkit_glue::P2PTransport::Config& config); + talk_base::PacketSocketFactory* socket_factory); + virtual void ReleasePeerConnectionFactory(); + virtual bool PeerConnectionFactoryCreated(); + + // Asks the PeerConnection factory to create a PeerConnection object. + // The PeerConnection object is owned by PeerConnectionHandler. + virtual talk_base::scoped_refptr<webrtc::PeerConnectionInterface> + CreatePeerConnection(const std::string& config, + webrtc::PeerConnectionObserver* observer); + + // Asks the PeerConnection factory to create a Local MediaStream object. + virtual talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> + CreateLocalMediaStream(const std::string& label); + + // Asks the PeerConnection factory to create a Local VideoTrack object. + virtual talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> + CreateLocalVideoTrack(const std::string& label, + cricket::VideoCapturer* video_device); - // Asks the PeerConnection factory to create a PeerConnection object. See - // MediaStreamImpl for details about |signaling_thread|. The PeerConnection - // object is owned by PeerConnectionHandler. - virtual webrtc::PeerConnection* CreatePeerConnection( - cricket::PortAllocator* port_allocator, - talk_base::Thread* signaling_thread); + // Asks the PeerConnection factory to create a Local AudioTrack object. + virtual talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> + CreateLocalAudioTrack(const std::string& label, + webrtc::AudioDeviceModule* audio_device); private: - scoped_ptr<webrtc::PeerConnectionFactory> pc_factory_; + talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_; DISALLOW_COPY_AND_ASSIGN(MediaStreamDependencyFactory); }; diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc index 3236a1f..e9117cc 100644 --- a/content/renderer/media/media_stream_impl.cc +++ b/content/renderer/media/media_stream_impl.cc @@ -14,7 +14,6 @@ #include "content/renderer/media/media_stream_dependency_factory.h" #include "content/renderer/media/media_stream_dispatcher.h" #include "content/renderer/media/peer_connection_handler.h" -#include "content/renderer/media/rtc_video_decoder.h" #include "content/renderer/media/video_capture_impl_manager.h" #include "content/renderer/media/video_capture_module_impl.h" #include "content/renderer/media/webrtc_audio_device_impl.h" @@ -23,9 +22,6 @@ #include "content/renderer/p2p/socket_dispatcher.h" #include "jingle/glue/thread_wrapper.h" #include "media/base/message_loop_factory.h" -#include "third_party/libjingle/source/talk/p2p/client/httpportallocator.h" -#include "third_party/libjingle/source/talk/session/phone/dummydevicemanager.h" -#include "third_party/libjingle/source/talk/session/phone/webrtcmediaengine.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamDescriptor.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamRegistry.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamSource.h" @@ -39,6 +35,39 @@ const int kVideoCaptureFramePerSecond = 30; } // namespace +// The MediaStreamMananger label for a stream is globally unique. The track +// session id is globally unique for the set of audio tracks and video tracks +// respectively. An audio track and a video track can have the same session id +// (without being related). Hence we create a unique track label from the stream +// label, track type and track session id: +// <MediaStreamManager-label>#{audio,video}-<session-ID>. +static std::string CreateTrackLabel( + const std::string& manager_label, + int session_id, + bool is_video) { + std::string track_label = manager_label; + if (is_video) { + track_label += "#video-"; + } else { + track_label += "#audio-"; + } + track_label += session_id; + return track_label; +} + +// Extracting the MediaStreamManager stream label will only work for track +// labels created by CreateTrackLabel. If is wasn't, the contents of the +// returned string is undefined. +static std::string ExtractManagerStreamLabel( + const std::string& track_label) { + std::string manager_label = track_label; + size_t pos = manager_label.rfind("#"); + // If # isn't found, the string is left intact. + manager_label = manager_label.substr(0, pos); + return manager_label; +} + + int MediaStreamImpl::next_request_id_ = 0; MediaStreamImpl::MediaStreamImpl( @@ -48,7 +77,6 @@ MediaStreamImpl::MediaStreamImpl( MediaStreamDependencyFactory* dependency_factory) : dependency_factory_(dependency_factory), media_stream_dispatcher_(media_stream_dispatcher), - media_engine_(NULL), p2p_socket_dispatcher_(p2p_socket_dispatcher), network_manager_(NULL), vc_manager_(vc_manager), @@ -56,14 +84,13 @@ MediaStreamImpl::MediaStreamImpl( message_loop_proxy_(base::MessageLoopProxy::current()), signaling_thread_(NULL), worker_thread_(NULL), - chrome_worker_thread_("Chrome_libJingle_WorkerThread"), - vcm_created_(false) { + chrome_worker_thread_("Chrome_libJingle_WorkerThread") { } MediaStreamImpl::~MediaStreamImpl() { DCHECK(!peer_connection_handler_); if (dependency_factory_.get()) - dependency_factory_->DeletePeerConnectionFactory(); + dependency_factory_->ReleasePeerConnectionFactory(); if (network_manager_) { // The network manager needs to free its resources on the thread they were // created, which is the worked thread. @@ -84,87 +111,35 @@ WebKit::WebPeerConnectionHandler* MediaStreamImpl::CreatePeerConnectionHandler( DVLOG(1) << "A PeerConnection already exists"; return NULL; } - - if (!media_engine_) { - media_engine_ = dependency_factory_->CreateWebRtcMediaEngine(); - } - - if (!signaling_thread_) { - jingle_glue::JingleThreadWrapper::EnsureForCurrentThread(); - jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); - signaling_thread_ = jingle_glue::JingleThreadWrapper::current(); - } - - if (!worker_thread_) { - if (!chrome_worker_thread_.IsRunning()) { - if (!chrome_worker_thread_.Start()) { - LOG(ERROR) << "Could not start worker thread"; - delete media_engine_; - media_engine_ = NULL; - signaling_thread_ = NULL; - return NULL; - } - } - base::WaitableEvent event(true, false); - chrome_worker_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&MediaStreamImpl::InitializeWorkerThread, this, - &worker_thread_, &event)); - event.Wait(); - DCHECK(worker_thread_); - } - - if (!network_manager_) - network_manager_ = new content::IpcNetworkManager(p2p_socket_dispatcher_); - - if (!socket_factory_.get()) { - socket_factory_.reset( - new content::IpcPacketSocketFactory(p2p_socket_dispatcher_)); - } - - if (!dependency_factory_->PeerConnectionFactoryCreated()) { - if (!dependency_factory_->CreatePeerConnectionFactory(media_engine_, - worker_thread_)) { - LOG(ERROR) << "Could not initialize PeerConnection factory"; - return NULL; - } - } + EnsurePeerConnectionFactory(); peer_connection_handler_ = new PeerConnectionHandler( client, this, - dependency_factory_.get(), - signaling_thread_, - p2p_socket_dispatcher_, - network_manager_, - socket_factory_.get()); + dependency_factory_.get()); return peer_connection_handler_; } void MediaStreamImpl::ClosePeerConnection() { DCHECK(CalledOnValidThread()); - rtc_video_decoder_ = NULL; - media_engine_->SetVideoCaptureModule(NULL); - vcm_created_ = false; + video_renderer_ = NULL; peer_connection_handler_ = NULL; + // TODO(grunell): This is a temporary workaround for an error in native + // PeerConnection where added live tracks are not seen on the remote side. + MediaStreamTrackPtrMap::const_iterator it = local_tracks_.begin(); + for (; it != local_tracks_.end(); ++it) + it->second->set_state(webrtc::MediaStreamTrackInterface::kEnded); } -bool MediaStreamImpl::SetVideoCaptureModule(const std::string& label) { +webrtc::MediaStreamTrackInterface* MediaStreamImpl::GetLocalMediaStreamTrack( + const std::string& label) { DCHECK(CalledOnValidThread()); - if (vcm_created_) - return true; - // Set the capture device. - // TODO(grunell): Instead of using the first track, the selected track - // should be used. - int id = media_stream_dispatcher_->video_session_id(label, 0); - if (id == media_stream::StreamDeviceInfo::kNoId) - return false; - webrtc::VideoCaptureModule* vcm = - new VideoCaptureModuleImpl(id, vc_manager_.get()); - vcm_created_ = true; - media_engine_->SetVideoCaptureModule(vcm); - return true; + MediaStreamTrackPtrMap::iterator it = local_tracks_.find(label); + if (it == local_tracks_.end()) + return NULL; + MediaStreamTrackPtr stream = it->second; + return stream.get(); } void MediaStreamImpl::requestUserMedia( @@ -214,6 +189,7 @@ void MediaStreamImpl::requestUserMedia( void MediaStreamImpl::cancelUserMediaRequest( const WebKit::WebUserMediaRequest& user_media_request) { + DCHECK(CalledOnValidThread()); // TODO(grunell): Implement. NOTIMPLEMENTED(); } @@ -226,22 +202,31 @@ scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder( WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url)); if (descriptor.isNull()) return NULL; // This is not a valid stream. + + // We must find out if this is a local or remote stream. We extract the + // MediaStreamManager stream label and if found in the dispatcher we have a + // local stream, otherwise we have a remote stream. There will be changes soon + // so that we don't have to bother about the type of stream here. Hence this + // solution is OK for now. + WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; descriptor.sources(source_vector); - std::string label; + std::string msm_label; for (size_t i = 0; i < source_vector.size(); ++i) { if (source_vector[i].type() == WebKit::WebMediaStreamSource::TypeVideo) { - label = UTF16ToUTF8(source_vector[i].id()); + // We assume there is one video track only. + msm_label = ExtractManagerStreamLabel(UTF16ToUTF8(source_vector[i].id())); break; } } - if (label.empty()) + if (msm_label.empty()) return NULL; scoped_refptr<media::VideoDecoder> decoder; - if (media_stream_dispatcher_->IsStream(label)) { + if (media_stream_dispatcher_->IsStream(msm_label)) { // It's a local stream. - int video_session_id = media_stream_dispatcher_->video_session_id(label, 0); + int video_session_id = + media_stream_dispatcher_->video_session_id(msm_label, 0); media::VideoCapture::VideoCaptureCapability capability; capability.width = kVideoCaptureWidth; capability.height = kVideoCaptureHeight; @@ -256,20 +241,27 @@ scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder( capability); } else { // It's a remote stream. - size_t found = label.rfind("-remote"); - if (found != std::string::npos) - label = label.substr(0, found); - if (rtc_video_decoder_.get()) { + if (!video_renderer_.get()) + video_renderer_ = new talk_base::RefCountedObject<VideoRendererWrapper>(); + if (video_renderer_->renderer()) { // The renderer is used by PeerConnection, release it first. - if (peer_connection_handler_) - peer_connection_handler_->SetVideoRenderer(label, NULL); + if (peer_connection_handler_) { + peer_connection_handler_->SetVideoRenderer( + UTF16ToUTF8(descriptor.label()), + NULL); + } + video_renderer_->SetVideoDecoder(NULL); } - rtc_video_decoder_ = new RTCVideoDecoder( + RTCVideoDecoder* rtc_video_decoder = new RTCVideoDecoder( message_loop_factory->GetMessageLoop("RtcVideoDecoderThread"), url.spec()); - decoder = rtc_video_decoder_; - if (peer_connection_handler_) - peer_connection_handler_->SetVideoRenderer(label, rtc_video_decoder_); + decoder = rtc_video_decoder; + video_renderer_->SetVideoDecoder(rtc_video_decoder); + if (peer_connection_handler_) { + peer_connection_handler_->SetVideoRenderer( + UTF16ToUTF8(descriptor.label()), + video_renderer_); + } } return decoder; } @@ -280,32 +272,46 @@ void MediaStreamImpl::OnStreamGenerated( const media_stream::StreamDeviceInfoArray& audio_array, const media_stream::StreamDeviceInfoArray& video_array) { DCHECK(CalledOnValidThread()); + EnsurePeerConnectionFactory(); - // We only support max one audio track and one video track. If the UI - // for selecting device starts to allow several devices, we must implement - // handling for this. - DCHECK_LE(audio_array.size(), 1u); - DCHECK_LE(video_array.size(), 1u); WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( audio_array.size() + video_array.size()); - WebKit::WebString track_label_audio(UTF8ToUTF16("AudioDevice")); - WebKit::WebString track_label_video(UTF8ToUTF16("VideoCapture")); - size_t track_num = source_vector.size(); - while (track_num--) { - if (track_num < audio_array.size()) { - source_vector[track_num].initialize( - UTF8ToUTF16(label), + // Add audio tracks. + std::string track_label; + for (size_t i = 0; i < audio_array.size(); ++i) { + track_label = CreateTrackLabel(label, audio_array[i].session_id, false); + MediaStreamTrackPtr audio_track( + dependency_factory_->CreateLocalAudioTrack(audio_array[i].name, NULL)); + local_tracks_.insert( + std::pair<std::string, MediaStreamTrackPtr>(track_label, audio_track)); + source_vector[i].initialize( + UTF8ToUTF16(track_label), WebKit::WebMediaStreamSource::TypeAudio, - track_label_audio); - } else { - source_vector[track_num].initialize( - UTF8ToUTF16(label), + UTF8ToUTF16(audio_array[i].name)); + } + + // Add video tracks. + for (size_t i = 0; i < video_array.size(); ++i) { + track_label = CreateTrackLabel(label, video_array[i].session_id, true); + webrtc::VideoCaptureModule* vcm = + new VideoCaptureModuleImpl(video_array[i].session_id, + vc_manager_.get()); + MediaStreamTrackPtr video_track(dependency_factory_->CreateLocalVideoTrack( + video_array[i].name, + // The video capturer takes ownership of |vcm|. + webrtc::CreateVideoCapturer(vcm))); + local_tracks_.insert( + std::pair<std::string, MediaStreamTrackPtr>(track_label, video_track)); + source_vector[audio_array.size() + i].initialize( + UTF8ToUTF16(track_label), WebKit::WebMediaStreamSource::TypeVideo, - track_label_video); - } + UTF8ToUTF16(video_array[i].name)); } + // TODO(grunell): Remove tracks from the map when support to stop is + // added in WebKit. + MediaRequestMap::iterator it = user_media_requests_.find(request_id); if (it == user_media_requests_.end()) { DVLOG(1) << "Request ID not found"; @@ -313,7 +319,6 @@ void MediaStreamImpl::OnStreamGenerated( } WebKit::WebUserMediaRequest user_media_request = it->second; user_media_requests_.erase(it); - stream_labels_.push_back(label); user_media_request.requestSucceeded(source_vector); } @@ -393,3 +398,61 @@ void MediaStreamImpl::DeleteIpcNetworkManager() { delete network_manager_; network_manager_ = NULL; } + +bool MediaStreamImpl::EnsurePeerConnectionFactory() { + DCHECK(CalledOnValidThread()); + if (!signaling_thread_) { + jingle_glue::JingleThreadWrapper::EnsureForCurrentThread(); + jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); + signaling_thread_ = jingle_glue::JingleThreadWrapper::current(); + } + + if (!worker_thread_) { + if (!chrome_worker_thread_.IsRunning()) { + if (!chrome_worker_thread_.Start()) { + LOG(ERROR) << "Could not start worker thread"; + signaling_thread_ = NULL; + return false; + } + } + base::WaitableEvent event(true, false); + chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &MediaStreamImpl::InitializeWorkerThread, + this, + &worker_thread_, + &event)); + event.Wait(); + DCHECK(worker_thread_); + } + + if (!network_manager_) + network_manager_ = new content::IpcNetworkManager(p2p_socket_dispatcher_); + + if (!socket_factory_.get()) { + socket_factory_.reset( + new content::IpcPacketSocketFactory(p2p_socket_dispatcher_)); + } + + if (!dependency_factory_->PeerConnectionFactoryCreated()) { + if (!dependency_factory_->CreatePeerConnectionFactory( + worker_thread_, + signaling_thread_, + p2p_socket_dispatcher_, + network_manager_, + socket_factory_.get())) { + LOG(ERROR) << "Could not initialize PeerConnection factory"; + return false; + } + } + + return true; +} + +MediaStreamImpl::VideoRendererWrapper::VideoRendererWrapper() {} + +MediaStreamImpl::VideoRendererWrapper::~VideoRendererWrapper() {} + +void MediaStreamImpl::VideoRendererWrapper::SetVideoDecoder( + RTCVideoDecoder* decoder) { + rtc_video_decoder_ = decoder; +} diff --git a/content/renderer/media/media_stream_impl.h b/content/renderer/media/media_stream_impl.h index 2aa6be3..503c510 100644 --- a/content/renderer/media/media_stream_impl.h +++ b/content/renderer/media/media_stream_impl.h @@ -19,6 +19,9 @@ #include "base/threading/thread.h" #include "content/common/content_export.h" #include "content/renderer/media/media_stream_dispatcher_eventhandler.h" +#include "content/renderer/media/rtc_video_decoder.h" +#include "third_party/libjingle/source/talk/app/webrtc/mediastream.h" +#include "third_party/libjingle/source/talk/base/scoped_ref_ptr.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebUserMediaClient.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebUserMediaRequest.h" #include "webkit/media/media_stream_client.h" @@ -33,10 +36,6 @@ class IpcPacketSocketFactory; class P2PSocketDispatcher; } -namespace cricket { -class WebRtcMediaEngine; -} - namespace talk_base { class Thread; } @@ -74,9 +73,8 @@ class CONTENT_EXPORT MediaStreamImpl virtual WebKit::WebPeerConnectionHandler* CreatePeerConnectionHandler( WebKit::WebPeerConnectionHandlerClient* client); virtual void ClosePeerConnection(); - - // Returns true if created successfully or already exists, false otherwise. - virtual bool SetVideoCaptureModule(const std::string& label); + virtual webrtc::MediaStreamTrackInterface* GetLocalMediaStreamTrack( + const std::string& label); // WebKit::WebUserMediaClient implementation virtual void requestUserMedia( @@ -117,10 +115,26 @@ class CONTENT_EXPORT MediaStreamImpl private: FRIEND_TEST_ALL_PREFIXES(MediaStreamImplTest, Basic); + class VideoRendererWrapper : public webrtc::VideoRendererWrapperInterface { + public: + VideoRendererWrapper(); + virtual cricket::VideoRenderer* renderer() OVERRIDE { + return rtc_video_decoder_.get(); + } + void SetVideoDecoder(RTCVideoDecoder* decoder); + + protected: + virtual ~VideoRendererWrapper(); + + private: + scoped_refptr<RTCVideoDecoder> rtc_video_decoder_; + }; + void InitializeWorkerThread( talk_base::Thread** thread, base::WaitableEvent* event); void DeleteIpcNetworkManager(); + bool EnsurePeerConnectionFactory(); scoped_ptr<MediaStreamDependencyFactory> dependency_factory_; @@ -128,11 +142,6 @@ class CONTENT_EXPORT MediaStreamImpl // valid for the lifetime of RenderView. MediaStreamDispatcher* media_stream_dispatcher_; - // media_engine_ is owned by PeerConnectionFactory (which is owned by - // dependency_factory_) and is valid for the lifetime of - // PeerConnectionFactory. - cricket::WebRtcMediaEngine* media_engine_; - // p2p_socket_dispatcher_ is a weak reference, owned by RenderView. It's valid // for the lifetime of RenderView. content::P2PSocketDispatcher* p2p_socket_dispatcher_; @@ -149,7 +158,14 @@ class CONTENT_EXPORT MediaStreamImpl // TODO(grunell): Support several PeerConnectionsHandlers. PeerConnectionHandler* peer_connection_handler_; - scoped_refptr<RTCVideoDecoder> rtc_video_decoder_; + // We keep a list of the generated local tracks, so that we can add capture + // devices when generated and also use them for recording. + typedef talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface> + MediaStreamTrackPtr; + typedef std::map<std::string, MediaStreamTrackPtr> MediaStreamTrackPtrMap; + MediaStreamTrackPtrMap local_tracks_; + + talk_base::scoped_refptr<VideoRendererWrapper> video_renderer_; scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; // PeerConnection threads. signaling_thread_ is created from the @@ -162,15 +178,6 @@ class CONTENT_EXPORT MediaStreamImpl typedef std::map<int, WebKit::WebUserMediaRequest> MediaRequestMap; MediaRequestMap user_media_requests_; - std::list<std::string> stream_labels_; - - // Make sure we only create the video capture module once. This is also - // temporary and will be handled differently when several PeerConnections - // and/or streams is supported. - // TODO(grunell): This shall be removed or changed when native PeerConnection - // has been updated to closer follow the specification. - bool vcm_created_; - DISALLOW_COPY_AND_ASSIGN(MediaStreamImpl); }; diff --git a/content/renderer/media/mock_media_stream_dependency_factory.cc b/content/renderer/media/mock_media_stream_dependency_factory.cc index 5cbcbd4..71adfb4 100644 --- a/content/renderer/media/mock_media_stream_dependency_factory.cc +++ b/content/renderer/media/mock_media_stream_dependency_factory.cc @@ -5,7 +5,125 @@ #include "base/logging.h" #include "content/renderer/media/mock_media_stream_dependency_factory.h" #include "content/renderer/media/mock_peer_connection_impl.h" -#include "third_party/libjingle/source/talk/session/phone/webrtcmediaengine.h" +#include "third_party/libjingle/source/talk/app/webrtc/mediastream.h" +#include "third_party/libjingle/source/talk/base/scoped_ref_ptr.h" + +namespace webrtc { + +template <class TrackType> +class MockMediaStreamTrackList + : public MediaStreamTrackListInterface<TrackType> { + public: + virtual size_t count() OVERRIDE { + return tracks_.size(); + } + virtual TrackType* at(size_t index) OVERRIDE { + return tracks_[index]; + } + void AddTrack(TrackType* track) { + tracks_.push_back(track); + } + + protected: + virtual ~MockMediaStreamTrackList() {} + + private: + std::vector<TrackType*> tracks_; +}; + +typedef MockMediaStreamTrackList<AudioTrackInterface> MockAudioTracks; +typedef MockMediaStreamTrackList<VideoTrackInterface> MockVideoTracks; + +class MockLocalMediaStream : public LocalMediaStreamInterface { + public: + explicit MockLocalMediaStream(std::string label) + : label_(label), + audio_tracks_(new talk_base::RefCountedObject<MockAudioTracks>), + video_tracks_(new talk_base::RefCountedObject<MockVideoTracks>) { + } + virtual bool AddTrack(AudioTrackInterface* track) OVERRIDE { + audio_tracks_->AddTrack(track); + return true; + } + virtual bool AddTrack(VideoTrackInterface* track) OVERRIDE { + video_tracks_->AddTrack(track); + return true; + } + virtual std::string label() const OVERRIDE { return label_; } + virtual AudioTracks* audio_tracks() OVERRIDE { + return audio_tracks_; + } + virtual VideoTracks* video_tracks() OVERRIDE { + return video_tracks_; + } + virtual ReadyState ready_state() OVERRIDE { + NOTIMPLEMENTED(); + return kInitializing; + } + virtual void set_ready_state(ReadyState state) OVERRIDE { NOTIMPLEMENTED(); } + virtual void RegisterObserver(ObserverInterface* observer) OVERRIDE { + NOTIMPLEMENTED(); + } + virtual void UnregisterObserver(ObserverInterface* observer) { + NOTIMPLEMENTED(); + } + + protected: + virtual ~MockLocalMediaStream() {} + + private: + std::string label_; + talk_base::scoped_refptr<MockAudioTracks> audio_tracks_; + talk_base::scoped_refptr<MockVideoTracks> video_tracks_; +}; + +cricket::VideoCapturer* MockLocalVideoTrack::GetVideoCapture() { + NOTIMPLEMENTED(); + return NULL; +} + +void MockLocalVideoTrack::SetRenderer(VideoRendererWrapperInterface* renderer) { + renderer_ = renderer; +} + +VideoRendererWrapperInterface* MockLocalVideoTrack::GetRenderer() { + NOTIMPLEMENTED(); + return NULL; +} + +std::string MockLocalVideoTrack::kind() const { + NOTIMPLEMENTED(); + return ""; +} + +std::string MockLocalVideoTrack::label() const { return label_; } + +bool MockLocalVideoTrack::enabled() const { return enabled_; } + +MockLocalVideoTrack::TrackState MockLocalVideoTrack::state() const { + NOTIMPLEMENTED(); + return kInitializing; +} + +bool MockLocalVideoTrack::set_enabled(bool enable) { + enabled_ = enable; + return true; +} + +bool MockLocalVideoTrack::set_state(TrackState new_state) { + NOTIMPLEMENTED(); + return false; +} + +void MockLocalVideoTrack::RegisterObserver(ObserverInterface* observer) { + NOTIMPLEMENTED(); +} + +void MockLocalVideoTrack::UnregisterObserver(ObserverInterface* observer) { + NOTIMPLEMENTED(); +} + +} // namespace webrtc MockMediaStreamDependencyFactory::MockMediaStreamDependencyFactory() : mock_pc_factory_created_(false) { @@ -13,20 +131,17 @@ MockMediaStreamDependencyFactory::MockMediaStreamDependencyFactory() MockMediaStreamDependencyFactory::~MockMediaStreamDependencyFactory() {} -cricket::WebRtcMediaEngine* -MockMediaStreamDependencyFactory::CreateWebRtcMediaEngine() { - return new cricket::WebRtcMediaEngine(NULL, NULL, NULL); -} - bool MockMediaStreamDependencyFactory::CreatePeerConnectionFactory( - cricket::MediaEngineInterface* media_engine, - talk_base::Thread* worker_thread) { + talk_base::Thread* worker_thread, + talk_base::Thread* signaling_thread, + content::P2PSocketDispatcher* socket_dispatcher, + talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory) { mock_pc_factory_created_ = true; - media_engine_.reset(media_engine); return true; } -void MockMediaStreamDependencyFactory::DeletePeerConnectionFactory() { +void MockMediaStreamDependencyFactory::ReleasePeerConnectionFactory() { mock_pc_factory_created_ = false; } @@ -34,17 +149,35 @@ bool MockMediaStreamDependencyFactory::PeerConnectionFactoryCreated() { return mock_pc_factory_created_; } -cricket::PortAllocator* MockMediaStreamDependencyFactory::CreatePortAllocator( - content::P2PSocketDispatcher* socket_dispatcher, - talk_base::NetworkManager* network_manager, - talk_base::PacketSocketFactory* socket_factory, - const webkit_glue::P2PTransport::Config& config) { - return NULL; +talk_base::scoped_refptr<webrtc::PeerConnectionInterface> +MockMediaStreamDependencyFactory::CreatePeerConnection( + const std::string& config, + webrtc::PeerConnectionObserver* observer) { + DCHECK(mock_pc_factory_created_); + return new talk_base::RefCountedObject<webrtc::MockPeerConnectionImpl>(); } -webrtc::PeerConnection* MockMediaStreamDependencyFactory::CreatePeerConnection( - cricket::PortAllocator* port_allocator, - talk_base::Thread* signaling_thread) { - DCHECK(mock_pc_factory_created_); - return new webrtc::MockPeerConnectionImpl(); +talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> +MockMediaStreamDependencyFactory::CreateLocalMediaStream( + const std::string& label) { + talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> stream( + new talk_base::RefCountedObject<webrtc::MockLocalMediaStream>(label)); + return stream; +} + +talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> +MockMediaStreamDependencyFactory::CreateLocalVideoTrack( + const std::string& label, + cricket::VideoCapturer* video_device) { + talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> stream( + new talk_base::RefCountedObject<webrtc::MockLocalVideoTrack>(label)); + return stream; +} + +talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> +MockMediaStreamDependencyFactory::CreateLocalAudioTrack( + const std::string& label, + webrtc::AudioDeviceModule* audio_device) { + NOTIMPLEMENTED(); + return NULL; } diff --git a/content/renderer/media/mock_media_stream_dependency_factory.h b/content/renderer/media/mock_media_stream_dependency_factory.h index 163baab..00c797f 100644 --- a/content/renderer/media/mock_media_stream_dependency_factory.h +++ b/content/renderer/media/mock_media_stream_dependency_factory.h @@ -5,33 +5,77 @@ #ifndef CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_DEPENDENCY_FACTORY_H_ #define CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_DEPENDENCY_FACTORY_H_ +#include <string> +#include <vector> + #include "base/compiler_specific.h" #include "content/renderer/media/media_stream_dependency_factory.h" +namespace webrtc { + +class MockLocalVideoTrack : public LocalVideoTrackInterface { + public: + explicit MockLocalVideoTrack(std::string label) + : enabled_(false), + label_(label), + renderer_(NULL) { + } + virtual cricket::VideoCapturer* GetVideoCapture() OVERRIDE; + virtual void SetRenderer(VideoRendererWrapperInterface* renderer) OVERRIDE; + virtual VideoRendererWrapperInterface* GetRenderer() OVERRIDE; + virtual std::string kind() const OVERRIDE; + virtual std::string label() const OVERRIDE; + virtual bool enabled() const OVERRIDE; + virtual TrackState state() const OVERRIDE; + virtual bool set_enabled(bool enable) OVERRIDE; + virtual bool set_state(TrackState new_state) OVERRIDE; + virtual void RegisterObserver(ObserverInterface* observer) OVERRIDE; + virtual void UnregisterObserver(ObserverInterface* observer) OVERRIDE; + + VideoRendererWrapperInterface* renderer() const { return renderer_; } + + protected: + virtual ~MockLocalVideoTrack() {} + + private: + bool enabled_; + std::string label_; + VideoRendererWrapperInterface* renderer_; +}; + +} // namespace webrtc + // A mock factory for creating different objects for MediaStreamImpl. class MockMediaStreamDependencyFactory : public MediaStreamDependencyFactory { public: MockMediaStreamDependencyFactory(); virtual ~MockMediaStreamDependencyFactory(); - virtual cricket::WebRtcMediaEngine* CreateWebRtcMediaEngine() OVERRIDE; virtual bool CreatePeerConnectionFactory( - cricket::MediaEngineInterface* media_engine, - talk_base::Thread* worker_thread) OVERRIDE; - virtual void DeletePeerConnectionFactory() OVERRIDE; - virtual bool PeerConnectionFactoryCreated() OVERRIDE; - virtual cricket::PortAllocator* CreatePortAllocator( + talk_base::Thread* worker_thread, + talk_base::Thread* signaling_thread, content::P2PSocketDispatcher* socket_dispatcher, talk_base::NetworkManager* network_manager, - talk_base::PacketSocketFactory* socket_factory, - const webkit_glue::P2PTransport::Config& config) OVERRIDE; - virtual webrtc::PeerConnection* CreatePeerConnection( - cricket::PortAllocator* port_allocator, - talk_base::Thread* signaling_thread) OVERRIDE; + talk_base::PacketSocketFactory* socket_factory) OVERRIDE; + virtual void ReleasePeerConnectionFactory() OVERRIDE; + virtual bool PeerConnectionFactoryCreated() OVERRIDE; + virtual talk_base::scoped_refptr<webrtc::PeerConnectionInterface> + CreatePeerConnection( + const std::string& config, + webrtc::PeerConnectionObserver* observer) OVERRIDE; + virtual talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> + CreateLocalMediaStream(const std::string& label) OVERRIDE; + virtual talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> + CreateLocalVideoTrack( + const std::string& label, + cricket::VideoCapturer* video_device) OVERRIDE; + virtual talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> + CreateLocalAudioTrack( + const std::string& label, + webrtc::AudioDeviceModule* audio_device) OVERRIDE; private: bool mock_pc_factory_created_; - scoped_ptr<cricket::MediaEngineInterface> media_engine_; DISALLOW_COPY_AND_ASSIGN(MockMediaStreamDependencyFactory); }; diff --git a/content/renderer/media/mock_media_stream_impl.cc b/content/renderer/media/mock_media_stream_impl.cc index 9109989..4996e95 100644 --- a/content/renderer/media/mock_media_stream_impl.cc +++ b/content/renderer/media/mock_media_stream_impl.cc @@ -4,6 +4,8 @@ #include "content/renderer/media/mock_media_stream_impl.h" +#include <utility> + #include "content/renderer/media/rtc_video_decoder.h" MockMediaStreamImpl::MockMediaStreamImpl() @@ -20,12 +22,15 @@ MockMediaStreamImpl::CreatePeerConnectionHandler( } void MockMediaStreamImpl::ClosePeerConnection() { - video_label_.clear(); } -bool MockMediaStreamImpl::SetVideoCaptureModule(const std::string& label) { - video_label_ = label; - return true; +webrtc::MediaStreamTrackInterface* +MockMediaStreamImpl::GetLocalMediaStreamTrack(const std::string& label) { + MockMediaStreamTrackPtrMap::iterator it = mock_local_tracks_.find(label); + if (it == mock_local_tracks_.end()) + return NULL; + webrtc::MediaStreamTrackInterface* stream = it->second; + return stream; } scoped_refptr<media::VideoDecoder> MockMediaStreamImpl::GetVideoDecoder( @@ -58,3 +63,10 @@ void MockMediaStreamImpl::OnAudioDeviceFailed( int index) { NOTIMPLEMENTED(); } + +void MockMediaStreamImpl::AddTrack( + const std::string& label, + webrtc::MediaStreamTrackInterface* track) { + mock_local_tracks_.insert( + std::pair<std::string, webrtc::MediaStreamTrackInterface*>(label, track)); +} diff --git a/content/renderer/media/mock_media_stream_impl.h b/content/renderer/media/mock_media_stream_impl.h index b297b49..8340b9e 100644 --- a/content/renderer/media/mock_media_stream_impl.h +++ b/content/renderer/media/mock_media_stream_impl.h @@ -5,6 +5,7 @@ #ifndef CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_IMPL_H_ #define CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_IMPL_H_ +#include <map> #include <string> #include "content/renderer/media/media_stream_impl.h" @@ -17,8 +18,8 @@ class MockMediaStreamImpl : public MediaStreamImpl { virtual WebKit::WebPeerConnectionHandler* CreatePeerConnectionHandler( WebKit::WebPeerConnectionHandlerClient* client) OVERRIDE; virtual void ClosePeerConnection() OVERRIDE; - // Returns true if created successfully or already exists, false otherwise. - virtual bool SetVideoCaptureModule(const std::string& label) OVERRIDE; + virtual webrtc::MediaStreamTrackInterface* GetLocalMediaStreamTrack( + const std::string& label) OVERRIDE; // Implement webkit_glue::MediaStreamClient. virtual scoped_refptr<media::VideoDecoder> GetVideoDecoder( @@ -39,10 +40,14 @@ class MockMediaStreamImpl : public MediaStreamImpl { const std::string& label, int index) OVERRIDE; - const std::string& video_label() const { return video_label_; } + void AddTrack( + const std::string& label, + webrtc::MediaStreamTrackInterface* track); private: - std::string video_label_; + typedef std::map<std::string, webrtc::MediaStreamTrackInterface*> + MockMediaStreamTrackPtrMap; + MockMediaStreamTrackPtrMap mock_local_tracks_; DISALLOW_COPY_AND_ASSIGN(MockMediaStreamImpl); }; diff --git a/content/renderer/media/mock_peer_connection_impl.cc b/content/renderer/media/mock_peer_connection_impl.cc index 365f18b..09a164d 100644 --- a/content/renderer/media/mock_peer_connection_impl.cc +++ b/content/renderer/media/mock_peer_connection_impl.cc @@ -4,88 +4,95 @@ #include "content/renderer/media/mock_peer_connection_impl.h" +#include <vector> + #include "base/logging.h" namespace webrtc { +class MockStreamCollection : public StreamCollectionInterface { + public: + virtual size_t count() OVERRIDE { + return streams_.size(); + } + virtual MediaStreamInterface* at(size_t index) OVERRIDE { + return streams_[index]; + } + virtual MediaStreamInterface* find(const std::string& label) OVERRIDE { + for (size_t i = 0; i < streams_.size(); ++i) { + if (streams_[i]->label() == label) + return streams_[i]; + } + return NULL; + } + void AddStream(MediaStreamInterface* stream) { + streams_.push_back(stream); + } + + protected: + virtual ~MockStreamCollection() {} + + private: + std::vector<MediaStreamInterface*> streams_; +}; + MockPeerConnectionImpl::MockPeerConnectionImpl() - : observer_(NULL), - video_stream_(false), - connected_(false), - video_capture_set_(false) { + : stream_changes_committed_(false), + remote_streams_(new talk_base::RefCountedObject<MockStreamCollection>) { } MockPeerConnectionImpl::~MockPeerConnectionImpl() {} -void MockPeerConnectionImpl::RegisterObserver( - PeerConnectionObserver* observer) { - observer_ = observer; +void MockPeerConnectionImpl::ProcessSignalingMessage(const std::string& msg) { + signaling_message_ = msg; } -bool MockPeerConnectionImpl::SignalingMessage( - const std::string& signaling_message) { - signaling_message_ = signaling_message; - return true; +bool MockPeerConnectionImpl::Send(const std::string& msg) { + NOTIMPLEMENTED(); + return false; } -bool MockPeerConnectionImpl::AddStream( - const std::string& stream_id, - bool video) { - stream_id_ = stream_id; - video_stream_ = video; - return true; +talk_base::scoped_refptr<StreamCollectionInterface> +MockPeerConnectionImpl::local_streams() { + NOTIMPLEMENTED(); + return NULL; } -bool MockPeerConnectionImpl::RemoveStream(const std::string& stream_id) { - stream_id_.clear(); - video_stream_ = false; - return true; +talk_base::scoped_refptr<StreamCollectionInterface> +MockPeerConnectionImpl::remote_streams() { + return remote_streams_; } -bool MockPeerConnectionImpl::Connect() { - connected_ = true; - return true; +void MockPeerConnectionImpl::AddStream(LocalMediaStreamInterface* stream) { + stream_label_ = stream->label(); } -bool MockPeerConnectionImpl::Close() { - observer_ = NULL; - signaling_message_.clear(); - stream_id_.clear(); - video_stream_ = false; - connected_ = false; - video_capture_set_ = false; - return true; +void MockPeerConnectionImpl::RemoveStream(LocalMediaStreamInterface* stream) { + stream_label_.clear(); } -bool MockPeerConnectionImpl::SetAudioDevice( - const std::string& wave_in_device, - const std::string& wave_out_device, - int opts) { - NOTIMPLEMENTED(); - return false; +void MockPeerConnectionImpl::CommitStreamChanges() { + stream_changes_committed_ = true; } -bool MockPeerConnectionImpl::SetLocalVideoRenderer( - cricket::VideoRenderer* renderer) { - NOTIMPLEMENTED(); - return false; +void MockPeerConnectionImpl::Close() { + signaling_message_.clear(); + stream_label_.clear(); + stream_changes_committed_ = false; } -bool MockPeerConnectionImpl::SetVideoRenderer( - const std::string& stream_id, - cricket::VideoRenderer* renderer) { - video_renderer_stream_id_ = stream_id; - return true; +MockPeerConnectionImpl::ReadyState MockPeerConnectionImpl::ready_state() { + NOTIMPLEMENTED(); + return kNew; } -bool MockPeerConnectionImpl::SetVideoCapture(const std::string& cam_device) { - video_capture_set_ = true; - return true; +MockPeerConnectionImpl::SdpState MockPeerConnectionImpl::sdp_state() { + NOTIMPLEMENTED(); + return kSdpNew; } -MockPeerConnectionImpl::ReadyState MockPeerConnectionImpl::GetReadyState() { - NOTIMPLEMENTED(); - return NEW; +void MockPeerConnectionImpl::AddRemoteStream(MediaStreamInterface* stream) { + remote_streams_->AddStream(stream); } } // namespace webrtc diff --git a/content/renderer/media/mock_peer_connection_impl.h b/content/renderer/media/mock_peer_connection_impl.h index 4d74355..9f20e8b 100644 --- a/content/renderer/media/mock_peer_connection_impl.h +++ b/content/renderer/media/mock_peer_connection_impl.h @@ -9,50 +9,45 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" -#include "third_party/libjingle/source/talk/app/webrtcv1/peerconnection.h" +#include "third_party/libjingle/source/talk/app/webrtc/peerconnection.h" namespace webrtc { -class MockPeerConnectionImpl : public PeerConnection { +class MockStreamCollection; + +class MockPeerConnectionImpl : public PeerConnectionInterface { public: MockPeerConnectionImpl(); - virtual ~MockPeerConnectionImpl(); - // PeerConnection implementation. - virtual void RegisterObserver(PeerConnectionObserver* observer) OVERRIDE; - virtual bool SignalingMessage(const std::string& msg) OVERRIDE; - virtual bool AddStream(const std::string& stream_id, bool video) OVERRIDE; - virtual bool RemoveStream(const std::string& stream_id) OVERRIDE; - virtual bool Connect() OVERRIDE; - virtual bool Close() OVERRIDE; - virtual bool SetAudioDevice( - const std::string& wave_in_device, - const std::string& wave_out_device, int opts) OVERRIDE; - virtual bool SetLocalVideoRenderer(cricket::VideoRenderer* renderer) OVERRIDE; - virtual bool SetVideoRenderer( - const std::string& stream_id, - cricket::VideoRenderer* renderer) OVERRIDE; - virtual bool SetVideoCapture(const std::string& cam_device) OVERRIDE; - virtual ReadyState GetReadyState() OVERRIDE; - - PeerConnectionObserver* observer() const { return observer_; } + // PeerConnectionInterface implementation. + virtual void ProcessSignalingMessage(const std::string& msg) OVERRIDE; + virtual bool Send(const std::string& msg) OVERRIDE; + virtual talk_base::scoped_refptr<StreamCollectionInterface> + local_streams() OVERRIDE; + virtual talk_base::scoped_refptr<StreamCollectionInterface> + remote_streams() OVERRIDE; + virtual void AddStream(LocalMediaStreamInterface* stream) OVERRIDE; + virtual void RemoveStream(LocalMediaStreamInterface* stream) OVERRIDE; + virtual void CommitStreamChanges() OVERRIDE; + virtual void Close() OVERRIDE; + virtual ReadyState ready_state() OVERRIDE; + virtual SdpState sdp_state() OVERRIDE; + + void AddRemoteStream(MediaStreamInterface* stream); + void ClearStreamChangesCommitted() { stream_changes_committed_ = false; } + const std::string& signaling_message() const { return signaling_message_; } - const std::string& stream_id() const { return stream_id_; } - bool video_stream() const { return video_stream_; } - bool connected() const { return connected_; } - bool video_capture_set() const { return video_capture_set_; } - const std::string& video_renderer_stream_id() const { - return video_renderer_stream_id_; - } + const std::string& stream_label() const { return stream_label_; } + bool stream_changes_committed() const { return stream_changes_committed_; } + + protected: + virtual ~MockPeerConnectionImpl(); private: - PeerConnectionObserver* observer_; std::string signaling_message_; - std::string stream_id_; - bool video_stream_; - bool connected_; - bool video_capture_set_; - std::string video_renderer_stream_id_; + std::string stream_label_; + bool stream_changes_committed_; + talk_base::scoped_refptr<MockStreamCollection> remote_streams_; DISALLOW_COPY_AND_ASSIGN(MockPeerConnectionImpl); }; diff --git a/content/renderer/media/peer_connection_handler.cc b/content/renderer/media/peer_connection_handler.cc index d1729e5..51cfb10 100644 --- a/content/renderer/media/peer_connection_handler.cc +++ b/content/renderer/media/peer_connection_handler.cc @@ -4,21 +4,15 @@ #include "content/renderer/media/peer_connection_handler.h" -#include <stdlib.h> +#include <utility> #include <vector> #include "base/bind.h" #include "base/logging.h" #include "base/string_number_conversions.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" #include "base/utf_string_conversions.h" #include "content/renderer/media/media_stream_dependency_factory.h" #include "content/renderer/media/media_stream_impl.h" -#include "content/renderer/p2p/ipc_network_manager.h" -#include "content/renderer/p2p/ipc_socket_factory.h" -#include "third_party/libjingle/source/talk/base/thread.h" -#include "third_party/libjingle/source/talk/p2p/base/portallocator.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamDescriptor.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamSource.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConnectionHandlerClient.h" @@ -27,108 +21,54 @@ PeerConnectionHandler::PeerConnectionHandler( WebKit::WebPeerConnectionHandlerClient* client, MediaStreamImpl* msi, - MediaStreamDependencyFactory* dependency_factory, - talk_base::Thread* signaling_thread, - content::P2PSocketDispatcher* socket_dispatcher, - content::IpcNetworkManager* network_manager, - content::IpcPacketSocketFactory* socket_factory) + MediaStreamDependencyFactory* dependency_factory) : client_(client), media_stream_impl_(msi), dependency_factory_(dependency_factory), - message_loop_proxy_(base::MessageLoopProxy::current()), - signaling_thread_(signaling_thread), - socket_dispatcher_(socket_dispatcher), - network_manager_(network_manager), - socket_factory_(socket_factory), - call_state_(NOT_STARTED) { + message_loop_proxy_(base::MessageLoopProxy::current()) { } PeerConnectionHandler::~PeerConnectionHandler() { - if (native_peer_connection_.get()) { - native_peer_connection_->RegisterObserver(NULL); - native_peer_connection_->Close(); - } } -bool PeerConnectionHandler::SetVideoRenderer( +void PeerConnectionHandler::SetVideoRenderer( const std::string& stream_label, - cricket::VideoRenderer* renderer) { - return native_peer_connection_->SetVideoRenderer(stream_label, renderer); + webrtc::VideoRendererWrapperInterface* renderer) { + webrtc::MediaStreamInterface* stream = + native_peer_connection_->remote_streams()->find(stream_label); + webrtc::VideoTracks* video_tracks = stream->video_tracks(); + // We assume there is only one enabled video track. + for(size_t i = 0; i < video_tracks->count(); ++i) { + webrtc::VideoTrackInterface* video_track = video_tracks->at(i); + if (video_track->enabled()) { + video_track->SetRenderer(renderer); + return; + } + } + DVLOG(1) << "No enabled video track."; } void PeerConnectionHandler::initialize( const WebKit::WebString& server_configuration, const WebKit::WebSecurityOrigin& security_origin) { - // We support the following server configuration format: - // "STUN <address>:<port>". We only support STUN at the moment. - // TODO(grunell): Support TURN. - - // Strip "STUN ". - std::string strip_string = "STUN "; - std::string config = UTF16ToUTF8(server_configuration); - size_t pos = config.find(strip_string); - if (pos != 0) { - DVLOG(1) << "Invalid configuration string."; - return; - } - config = config.substr(strip_string.length()); - // Parse out port. - pos = config.find(':'); - if (pos == std::string::npos) { - DVLOG(1) << "Invalid configuration string."; - return; - } - int port = 0; - bool success = base::StringToInt(config.substr(pos+1), &port); - if (!success || (port == 0)) { - DVLOG(1) << "Invalid configuration string."; - return; - } - // Get address. - std::string address = config.substr(0, pos); - - webkit_glue::P2PTransport::Config p2p_config; - p2p_config.stun_server = address; - p2p_config.stun_server_port = port; - - port_allocator_.reset(dependency_factory_->CreatePortAllocator( - socket_dispatcher_, - network_manager_, - socket_factory_, - p2p_config)); - - native_peer_connection_.reset(dependency_factory_->CreatePeerConnection( - port_allocator_.get(), - signaling_thread_)); - native_peer_connection_->RegisterObserver(this); + native_peer_connection_ = dependency_factory_->CreatePeerConnection( + UTF16ToUTF8(server_configuration), + this); } void PeerConnectionHandler::produceInitialOffer( const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& pending_add_streams) { - // We currently don't support creating an initial offer without a stream. - // Native PeerConnection will anyway create the initial offer when the first - // (and only) stream is added, so it will be done when processPendingStreams - // is called if not here. - if (pending_add_streams.isEmpty()) { - DVLOG(1) << "Can't produce initial offer with no stream."; - return; - } - // TODO(grunell): Support several streams. - DCHECK_EQ(pending_add_streams.size(), 1u); - WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; - pending_add_streams[0].sources(source_vector); - DCHECK_GT(source_vector.size(), 0u); - std::string label = UTF16ToUTF8(source_vector[0].id()); - AddStream(label); + AddStreams(pending_add_streams); + native_peer_connection_->CommitStreamChanges(); } void PeerConnectionHandler::handleInitialOffer(const WebKit::WebString& sdp) { - native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); + native_peer_connection_->ProcessSignalingMessage(UTF16ToUTF8(sdp)); } void PeerConnectionHandler::processSDP(const WebKit::WebString& sdp) { - native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); + native_peer_connection_->ProcessSignalingMessage(UTF16ToUTF8(sdp)); } void PeerConnectionHandler::processPendingStreams( @@ -136,33 +76,36 @@ void PeerConnectionHandler::processPendingStreams( pending_add_streams, const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& pending_remove_streams) { - // TODO(grunell): Support several streams. - if (!pending_add_streams.isEmpty()) { - DCHECK_EQ(pending_add_streams.size(), 1u); - WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; - pending_add_streams[0].sources(source_vector); - DCHECK_GT(source_vector.size(), 0u); - std::string label = UTF16ToUTF8(source_vector[0].id()); - AddStream(label); - } - // Currently we ignore remove stream, no support in native PeerConnection. + AddStreams(pending_add_streams); + RemoveStreams(pending_remove_streams); + native_peer_connection_->CommitStreamChanges(); } void PeerConnectionHandler::sendDataStreamMessage( const char* data, size_t length) { - // TODO(grunell): Implement. Not supported in native PeerConnection. + // TODO(grunell): Implement. NOTIMPLEMENTED(); } void PeerConnectionHandler::stop() { - if (native_peer_connection_.get()) - native_peer_connection_->RegisterObserver(NULL); - native_peer_connection_.reset(); - // The close function will delete us. + // TODO(ronghuawu): There's an issue with signaling messages being sent during + // close. We need to investigate further. Not calling Close() on native + // PeerConnection is OK for now. + native_peer_connection_ = NULL; media_stream_impl_->ClosePeerConnection(); } +void PeerConnectionHandler::OnError() { + // TODO(grunell): Implement. + NOTIMPLEMENTED(); +} + +void PeerConnectionHandler::OnMessage(const std::string& msg) { + // TODO(grunell): Implement. + NOTIMPLEMENTED(); +} + void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { if (!message_loop_proxy_->BelongsToCurrentThread()) { message_loop_proxy_->PostTask(FROM_HERE, base::Bind( @@ -174,101 +117,134 @@ void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { client_->didGenerateSDP(UTF8ToUTF16(msg)); } -void PeerConnectionHandler::OnAddStream(const std::string& stream_id, - bool video) { - if (!video) +void PeerConnectionHandler::OnStateChange(StateType state_changed) { + // TODO(grunell): Implement. + NOTIMPLEMENTED(); +} + +void PeerConnectionHandler::OnAddStream(webrtc::MediaStreamInterface* stream) { + if (!stream) return; if (!message_loop_proxy_->BelongsToCurrentThread()) { message_loop_proxy_->PostTask(FROM_HERE, base::Bind( &PeerConnectionHandler::OnAddStreamCallback, base::Unretained(this), - stream_id)); + stream)); } else { - OnAddStreamCallback(stream_id); + OnAddStreamCallback(stream); } } void PeerConnectionHandler::OnRemoveStream( - const std::string& stream_id, - bool video) { - if (!video) + webrtc::MediaStreamInterface* stream) { + if (!stream) return; if (!message_loop_proxy_->BelongsToCurrentThread()) { message_loop_proxy_->PostTask(FROM_HERE, base::Bind( &PeerConnectionHandler::OnRemoveStreamCallback, base::Unretained(this), - remote_label_)); + stream)); } else { - OnRemoveStreamCallback(remote_label_); + OnRemoveStreamCallback(stream); } } -void PeerConnectionHandler::AddStream(const std::string label) { - // TODO(grunell): Fix code in this function after a new native PeerConnection - // version has been rolled out. - if (call_state_ == NOT_STARTED) { - // TODO(grunell): Add audio and/or video depending on what's enabled - // in the stream. - std::string audio_label = label; - audio_label.append("-audio"); - native_peer_connection_->AddStream(audio_label, false); // Audio - native_peer_connection_->AddStream(label, true); // Video - call_state_ = INITIATING; - } - if (call_state_ == INITIATING || call_state_ == RECEIVING) { - local_label_ = label; - if (media_stream_impl_->SetVideoCaptureModule(label)) - native_peer_connection_->SetVideoCapture(""); - if (call_state_ == INITIATING) - native_peer_connection_->Connect(); - else if (call_state_ == RECEIVING) - call_state_ = SENDING_AND_RECEIVING; - } else { - DLOG(ERROR) << "Multiple streams not supported"; +void PeerConnectionHandler::AddStreams( + const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams) { + for (size_t i = 0; i < streams.size(); ++i) { + talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> stream = + dependency_factory_->CreateLocalMediaStream( + UTF16ToUTF8(streams[i].label())); + WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; + streams[i].sources(source_vector); + + // Get and add all tracks. + for (size_t j = 0; j < source_vector.size(); ++j) { + webrtc::MediaStreamTrackInterface* track = + media_stream_impl_->GetLocalMediaStreamTrack( + UTF16ToUTF8(source_vector[j].id())); + DCHECK(track); + if (source_vector[j].type() == WebKit::WebMediaStreamSource::TypeVideo) { + stream->AddTrack(static_cast<webrtc::VideoTrackInterface*>(track)); + } else { + stream->AddTrack(static_cast<webrtc::AudioTrackInterface*>(track)); + } + } + + native_peer_connection_->AddStream(stream); } } -void PeerConnectionHandler::OnAddStreamCallback( - const std::string& stream_label) { - // TODO(grunell): Fix code in this function after a new native PeerConnection - // version has been rolled out. - if (call_state_ == NOT_STARTED) { - remote_label_ = stream_label; - call_state_ = RECEIVING; - } else if (call_state_ == INITIATING) { - remote_label_ = local_label_; - remote_label_ += "-remote"; - call_state_ = SENDING_AND_RECEIVING; +void PeerConnectionHandler::RemoveStreams( + const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams) { + for (size_t i = 0; i < streams.size(); ++i) { + webrtc::MediaStreamInterface* stream = + native_peer_connection_->remote_streams()->find( + UTF16ToUTF8(streams[i].label())); + native_peer_connection_->RemoveStream( + static_cast<webrtc::LocalMediaStreamInterface*>(stream)); } +} - // TODO(grunell): Support several tracks. - WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( - static_cast<size_t>(2)); - source_vector[0].initialize(WebKit::WebString::fromUTF8(remote_label_), - WebKit::WebMediaStreamSource::TypeVideo, - WebKit::WebString::fromUTF8("RemoteVideo")); - source_vector[1].initialize(WebKit::WebString::fromUTF8(remote_label_), - WebKit::WebMediaStreamSource::TypeAudio, - WebKit::WebString::fromUTF8("RemoteAudio")); - WebKit::WebMediaStreamDescriptor descriptor; - descriptor.initialize(UTF8ToUTF16(remote_label_), source_vector); +void PeerConnectionHandler::OnAddStreamCallback( + webrtc::MediaStreamInterface* stream) { + 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 PeerConnectionHandler::OnRemoveStreamCallback( - const std::string& stream_label) { - // TODO(grunell): Support several tracks. + webrtc::MediaStreamInterface* stream) { + 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); +} + +WebKit::WebMediaStreamDescriptor +PeerConnectionHandler::CreateWebKitStreamDescriptor( + webrtc::MediaStreamInterface* stream) { + webrtc::AudioTracks* audio_tracks = stream->audio_tracks(); + webrtc::VideoTracks* video_tracks = stream->video_tracks(); WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( - static_cast<size_t>(2)); - source_vector[0].initialize(WebKit::WebString::fromUTF8(stream_label), - WebKit::WebMediaStreamSource::TypeVideo, - WebKit::WebString::fromUTF8("RemoteVideo")); - source_vector[1].initialize(WebKit::WebString::fromUTF8(stream_label), - WebKit::WebMediaStreamSource::TypeAudio, - WebKit::WebString::fromUTF8("RemoteAudio")); + audio_tracks->count() + video_tracks->count()); + + // Add audio tracks. + size_t i = 0; + for (; i < audio_tracks->count(); ++i) { + webrtc::AudioTrackInterface* audio_track = audio_tracks->at(i); + DCHECK(audio_track); + source_vector[i].initialize( + // TODO(grunell): Set id to something unique. + UTF8ToUTF16(audio_track->label()), + WebKit::WebMediaStreamSource::TypeAudio, + UTF8ToUTF16(audio_track->label())); + } + + // Add video tracks. + for (i = 0; i < video_tracks->count(); ++i) { + webrtc::VideoTrackInterface* video_track = video_tracks->at(i); + DCHECK(video_track); + source_vector[audio_tracks->count() + i].initialize( + // TODO(grunell): Set id to something unique. + UTF8ToUTF16(video_track->label()), + WebKit::WebMediaStreamSource::TypeVideo, + UTF8ToUTF16(video_track->label())); + } + WebKit::WebMediaStreamDescriptor descriptor; - descriptor.initialize(UTF8ToUTF16(stream_label), source_vector); - client_->didRemoveRemoteStream(descriptor); + descriptor.initialize(UTF8ToUTF16(stream->label()), source_vector); + + return descriptor; } diff --git a/content/renderer/media/peer_connection_handler.h b/content/renderer/media/peer_connection_handler.h index 589f865..6765ece 100644 --- a/content/renderer/media/peer_connection_handler.h +++ b/content/renderer/media/peer_connection_handler.h @@ -5,6 +5,7 @@ #ifndef CONTENT_RENDERER_MEDIA_PEER_CONNECTION_HANDLER_H_ #define CONTENT_RENDERER_MEDIA_PEER_CONNECTION_HANDLER_H_ +#include <map> #include <string> #include "base/basictypes.h" @@ -13,35 +14,16 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop_proxy.h" #include "content/common/content_export.h" -#include "third_party/libjingle/source/talk/app/webrtcv1/peerconnection.h" -#include "third_party/libjingle/source/talk/base/socketaddress.h" +#include "third_party/libjingle/source/talk/app/webrtc/mediastream.h" +#include "third_party/libjingle/source/talk/app/webrtc/peerconnection.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConnectionHandler.h" -namespace base { -class Thread; -class WaitableEvent; -} - -namespace content { -class IpcNetworkManager; -class IpcPacketSocketFactory; -class P2PSocketDispatcher; -} - -namespace cricket { -class PortAllocator; -} - -namespace talk_base { -class Thread; -} - class MediaStreamDependencyFactory; class MediaStreamImpl; // PeerConnectionHandler is a delegate for the PeerConnection API messages going // between WebKit and native PeerConnection in libjingle. It's owned by -// MediaStreamImpl. +// WebKit. class CONTENT_EXPORT PeerConnectionHandler : NON_EXPORTED_BASE(public WebKit::WebPeerConnectionHandler), NON_EXPORTED_BASE(public webrtc::PeerConnectionObserver) { @@ -49,16 +31,13 @@ class CONTENT_EXPORT PeerConnectionHandler PeerConnectionHandler( WebKit::WebPeerConnectionHandlerClient* client, MediaStreamImpl* msi, - MediaStreamDependencyFactory* dependency_factory, - talk_base::Thread* signaling_thread, - content::P2PSocketDispatcher* socket_dispatcher, - content::IpcNetworkManager* network_manager, - content::IpcPacketSocketFactory* socket_factory); + MediaStreamDependencyFactory* dependency_factory); virtual ~PeerConnectionHandler(); // Set the video renderer for the specified stream. - virtual bool SetVideoRenderer(const std::string& stream_label, - cricket::VideoRenderer* renderer); + virtual void SetVideoRenderer( + const std::string& stream_label, + webrtc::VideoRendererWrapperInterface* renderer); // WebKit::WebPeerConnectionHandler implementation virtual void initialize( @@ -75,21 +54,28 @@ class CONTENT_EXPORT PeerConnectionHandler const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& pending_remove_streams) OVERRIDE; virtual void sendDataStreamMessage(const char* data, size_t length) OVERRIDE; + // We will be deleted by WebKit after stop has been returned. virtual void stop() OVERRIDE; // webrtc::PeerConnectionObserver implementation + virtual void OnError() OVERRIDE; + virtual void OnMessage(const std::string& msg) OVERRIDE; virtual void OnSignalingMessage(const std::string& msg) OVERRIDE; - virtual void OnAddStream(const std::string& stream_id, bool video) OVERRIDE; - virtual void OnRemoveStream( - const std::string& stream_id, - bool video) OVERRIDE; + virtual void OnStateChange(StateType state_changed) OVERRIDE; + virtual void OnAddStream(webrtc::MediaStreamInterface* stream) OVERRIDE; + virtual void OnRemoveStream(webrtc::MediaStreamInterface* stream) OVERRIDE; private: FRIEND_TEST_ALL_PREFIXES(PeerConnectionHandlerTest, Basic); - void AddStream(const std::string label); - void OnAddStreamCallback(const std::string& stream_label); - void OnRemoveStreamCallback(const std::string& stream_label); + void AddStreams( + const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams); + void RemoveStreams( + const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams); + void OnAddStreamCallback(webrtc::MediaStreamInterface* stream); + void OnRemoveStreamCallback(webrtc::MediaStreamInterface* stream); + WebKit::WebMediaStreamDescriptor CreateWebKitStreamDescriptor( + webrtc::MediaStreamInterface* stream); // client_ is a weak pointer, and is valid until stop() has returned. WebKit::WebPeerConnectionHandlerClient* client_; @@ -104,55 +90,14 @@ class CONTENT_EXPORT PeerConnectionHandler // native_peer_connection_ is the native PeerConnection object, // it handles the ICE processing and media engine. - scoped_ptr<webrtc::PeerConnection> native_peer_connection_; + talk_base::scoped_refptr<webrtc::PeerConnectionInterface> + native_peer_connection_; - scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + typedef std::map<webrtc::MediaStreamInterface*, + WebKit::WebMediaStreamDescriptor> RemoteStreamMap; + RemoteStreamMap remote_streams_; - talk_base::Thread* signaling_thread_; - - // socket_dispatcher_ is a weak reference, owned by RenderView. It's valid - // for the lifetime of RenderView. - content::P2PSocketDispatcher* socket_dispatcher_; - - // network_manager_ and socket_factory_ are a weak references, owned by - // MediaStreamImpl. - content::IpcNetworkManager* network_manager_; - content::IpcPacketSocketFactory* socket_factory_; - - scoped_ptr<cricket::PortAllocator> port_allocator_; - - // Currently, a stream in WebKit has audio and/or video and has one label. - // Local and remote streams have different labels. - // In native PeerConnection, a stream has audio or video (not both), and they - // have separate labels. A remote stream has the same label as the - // corresponding local stream. Hence the workarounds in the implementation to - // handle this. It could look like this: - // WebKit: Local, audio and video: label "foo". - // Remote, audio and video: label "foo-remote". - // Native: Local and remote, audio: label "foo-audio". - // Local and remote, video: label "foo". - // TODO(grunell): This shall be removed or changed when native PeerConnection - // has been updated to closer follow the specification. - std::string local_label_; // Label used in WebKit - std::string remote_label_; // Label used in WebKit - - // Call states. Possible transitions: - // NOT_STARTED -> INITIATING -> SENDING_AND_RECEIVING - // NOT_STARTED -> RECEIVING - // RECEIVING -> NOT_STARTED - // RECEIVING -> SENDING_AND_RECEIVING - // SENDING_AND_RECEIVING -> NOT_STARTED - // Note that when in state SENDING_AND_RECEIVING, the other side may or may - // not send media. Thus, this state does not necessarily mean full duplex. - // TODO(grunell): This shall be removed or changed when native PeerConnection - // has been updated to closer follow the specification. - enum CallState { - NOT_STARTED, - INITIATING, - RECEIVING, - SENDING_AND_RECEIVING - }; - CallState call_state_; + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; DISALLOW_COPY_AND_ASSIGN(PeerConnectionHandler); }; diff --git a/content/renderer/media/peer_connection_handler_unittest.cc b/content/renderer/media/peer_connection_handler_unittest.cc index 766db5d..8cb4076 100644 --- a/content/renderer/media/peer_connection_handler_unittest.cc +++ b/content/renderer/media/peer_connection_handler_unittest.cc @@ -15,10 +15,22 @@ #include "content/renderer/media/rtc_video_decoder.h" #include "jingle/glue/thread_wrapper.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/libjingle/source/talk/app/webrtcv1/peerconnection.h" +#include "third_party/libjingle/source/talk/app/webrtc/peerconnection.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamDescriptor.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamSource.h" +namespace webrtc { + +class MockVideoRendererWrapper : public VideoRendererWrapperInterface { + public: + virtual cricket::VideoRenderer* renderer() OVERRIDE { return NULL; } + + protected: + virtual ~MockVideoRendererWrapper() {} +}; + +} // namespace webrtc + TEST(PeerConnectionHandlerTest, Basic) { MessageLoop loop; @@ -27,15 +39,15 @@ TEST(PeerConnectionHandlerTest, Basic) { scoped_refptr<MockMediaStreamImpl> mock_ms_impl(new MockMediaStreamImpl()); scoped_ptr<MockMediaStreamDependencyFactory> mock_dependency_factory( new MockMediaStreamDependencyFactory()); - mock_dependency_factory->CreatePeerConnectionFactory(NULL, NULL); + mock_dependency_factory->CreatePeerConnectionFactory(NULL, + NULL, + NULL, + NULL, + NULL); scoped_ptr<PeerConnectionHandler> pc_handler( new PeerConnectionHandler(mock_client.get(), mock_ms_impl.get(), - mock_dependency_factory.get(), - NULL, - NULL, - NULL, - NULL)); + mock_dependency_factory.get())); WebKit::WebString server_config( WebKit::WebString::fromUTF8("STUN stun.l.google.com:19302")); @@ -45,24 +57,24 @@ TEST(PeerConnectionHandlerTest, Basic) { webrtc::MockPeerConnectionImpl* mock_peer_connection = static_cast<webrtc::MockPeerConnectionImpl*>( pc_handler->native_peer_connection_.get()); - EXPECT_EQ(static_cast<webrtc::PeerConnectionObserver*>(pc_handler.get()), - mock_peer_connection->observer()); - std::string label("label"); + // TODO(grunell): Add an audio track as well. + std::string stream_label("stream-label"); + std::string video_track_label("video-label"); + talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> local_video_track( + mock_dependency_factory->CreateLocalVideoTrack(video_track_label, NULL)); + mock_ms_impl->AddTrack(video_track_label, local_video_track); WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( static_cast<size_t>(1)); - source_vector[0].initialize(WebKit::WebString::fromUTF8(label), + source_vector[0].initialize(WebKit::WebString::fromUTF8(video_track_label), WebKit::WebMediaStreamSource::TypeVideo, WebKit::WebString::fromUTF8("RemoteVideo")); - WebKit::WebVector<WebKit::WebMediaStreamDescriptor> pendingAddStreams( + WebKit::WebVector<WebKit::WebMediaStreamDescriptor> local_streams( static_cast<size_t>(1)); - pendingAddStreams[0].initialize(UTF8ToUTF16(label), source_vector); - pc_handler->produceInitialOffer(pendingAddStreams); - EXPECT_EQ(label, mock_ms_impl->video_label()); - EXPECT_EQ(label, mock_peer_connection->stream_id()); - EXPECT_TRUE(mock_peer_connection->video_stream()); - EXPECT_TRUE(mock_peer_connection->connected()); - EXPECT_TRUE(mock_peer_connection->video_capture_set()); + local_streams[0].initialize(UTF8ToUTF16(stream_label), source_vector); + pc_handler->produceInitialOffer(local_streams); + EXPECT_EQ(stream_label, mock_peer_connection->stream_label()); + EXPECT_TRUE(mock_peer_connection->stream_changes_committed()); std::string message("message1"); pc_handler->handleInitialOffer(WebKit::WebString::fromUTF8(message)); @@ -76,49 +88,47 @@ TEST(PeerConnectionHandlerTest, Basic) { pc_handler->OnSignalingMessage(message); EXPECT_EQ(message, mock_client->sdp()); - std::string remote_label(label); - remote_label.append("-remote"); - pc_handler->OnAddStream(remote_label, true); - EXPECT_EQ(remote_label, mock_client->stream_label()); - - scoped_refptr<RTCVideoDecoder> rtc_video_decoder( - new RTCVideoDecoder(&loop, "")); - pc_handler->SetVideoRenderer(label, rtc_video_decoder.get()); - EXPECT_EQ(label, mock_peer_connection->video_renderer_stream_id()); + std::string remote_stream_label(stream_label); + remote_stream_label += "-remote"; + std::string remote_video_track_label(video_track_label); + remote_video_track_label += "-remote"; + // We use a local stream as a remote since for testing purposes we really + // only need the MediaStreamInterface. + talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> remote_stream( + mock_dependency_factory->CreateLocalMediaStream(remote_stream_label)); + talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> remote_video_track( + mock_dependency_factory->CreateLocalVideoTrack(remote_video_track_label, + NULL)); + remote_video_track->set_enabled(true); + remote_stream->AddTrack(remote_video_track); + mock_peer_connection->AddRemoteStream(remote_stream); + pc_handler->OnAddStream(remote_stream); + EXPECT_EQ(remote_stream_label, mock_client->stream_label()); + + talk_base::scoped_refptr<webrtc::MockVideoRendererWrapper> renderer( + new talk_base::RefCountedObject<webrtc::MockVideoRendererWrapper>()); + pc_handler->SetVideoRenderer(remote_stream_label, renderer); + EXPECT_EQ(renderer, static_cast<webrtc::MockLocalVideoTrack*>( + remote_video_track.get())->renderer()); + + WebKit::WebVector<WebKit::WebMediaStreamDescriptor> empty_streams( + static_cast<size_t>(0)); + pc_handler->processPendingStreams(empty_streams, local_streams); + EXPECT_EQ("", mock_peer_connection->stream_label()); + mock_peer_connection->ClearStreamChangesCommitted(); + EXPECT_TRUE(!mock_peer_connection->stream_changes_committed()); - pc_handler->OnRemoveStream(remote_label, true); + pc_handler->OnRemoveStream(remote_stream); EXPECT_TRUE(mock_client->stream_label().empty()); + pc_handler->processPendingStreams(local_streams, empty_streams); + EXPECT_EQ(stream_label, mock_peer_connection->stream_label()); + EXPECT_TRUE(mock_peer_connection->stream_changes_committed()); + pc_handler->stop(); EXPECT_FALSE(pc_handler->native_peer_connection_.get()); // PC handler is expected to be deleted when stop calls // MediaStreamImpl::ClosePeerConnection. We own and delete it here instead of // in the mock. pc_handler.reset(); - - // processPendingStreams must be tested on a new PC handler since removing - // streams is currently not supported. - pc_handler.reset(new PeerConnectionHandler(mock_client.get(), - mock_ms_impl.get(), - mock_dependency_factory.get(), - NULL, - NULL, - NULL, - NULL)); - pc_handler->initialize(server_config, security_origin); - EXPECT_TRUE(pc_handler->native_peer_connection_.get()); - mock_peer_connection = static_cast<webrtc::MockPeerConnectionImpl*>( - pc_handler->native_peer_connection_.get()); - - WebKit::WebVector<WebKit::WebMediaStreamDescriptor> pendingRemoveStreams( - static_cast<size_t>(0)); - pc_handler->processPendingStreams(pendingAddStreams, pendingRemoveStreams); - EXPECT_EQ(label, mock_ms_impl->video_label()); - EXPECT_EQ(label, mock_peer_connection->stream_id()); - EXPECT_TRUE(mock_peer_connection->video_stream()); - EXPECT_TRUE(mock_peer_connection->connected()); - EXPECT_TRUE(mock_peer_connection->video_capture_set()); - - pc_handler->stop(); - pc_handler.reset(); } diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp index a276e98..7531ae6 100644 --- a/third_party/libjingle/libjingle.gyp +++ b/third_party/libjingle/libjingle.gyp @@ -481,17 +481,45 @@ 'target_name': 'libjingle_peerconnection', 'type': 'static_library', 'sources': [ - 'source/talk/app/webrtcv1/peerconnection.h', - 'source/talk/app/webrtcv1/peerconnectionfactory.cc', - 'source/talk/app/webrtcv1/peerconnectionfactory.h', - 'source/talk/app/webrtcv1/peerconnectionimpl.cc', - 'source/talk/app/webrtcv1/peerconnectionimpl.h', - 'source/talk/app/webrtcv1/peerconnectionproxy.cc', - 'source/talk/app/webrtcv1/peerconnectionproxy.h', - 'source/talk/app/webrtcv1/webrtcsession.cc', - 'source/talk/app/webrtcv1/webrtcsession.h', - 'source/talk/app/webrtcv1/webrtcjson.cc', - 'source/talk/app/webrtcv1/webrtcjson.h', + 'source/talk/app/webrtc/audiotrackimpl.cc', + 'source/talk/app/webrtc/audiotrackimpl.h', + 'source/talk/app/webrtc/mediastream.h', + 'source/talk/app/webrtc/mediastreamhandler.cc', + 'source/talk/app/webrtc/mediastreamhandler.h', + 'source/talk/app/webrtc/mediastreamimpl.cc', + 'source/talk/app/webrtc/mediastreamimpl.h', + 'source/talk/app/webrtc/mediastreamprovider.h', + 'source/talk/app/webrtc/mediastreamproxy.cc', + 'source/talk/app/webrtc/mediastreamproxy.h', + 'source/talk/app/webrtc/mediastreamtrackproxy.cc', + 'source/talk/app/webrtc/mediastreamtrackproxy.h', + 'source/talk/app/webrtc/mediatrackimpl.h', + 'source/talk/app/webrtc/notifierimpl.h', + 'source/talk/app/webrtc/peerconnectionfactoryimpl.cc', + 'source/talk/app/webrtc/peerconnectionfactoryimpl.h', + 'source/talk/app/webrtc/peerconnectionimpl.cc', + 'source/talk/app/webrtc/peerconnectionimpl.h', + 'source/talk/app/webrtc/peerconnectionsignaling.cc', + 'source/talk/app/webrtc/peerconnectionsignaling.h', + 'source/talk/app/webrtc/portallocatorfactory.cc', + 'source/talk/app/webrtc/portallocatorfactory.h', + 'source/talk/app/webrtc/roaperrorcodes.h', + 'source/talk/app/webrtc/roapmessages.cc', + 'source/talk/app/webrtc/roapmessages.h', + 'source/talk/app/webrtc/roapsession.cc', + 'source/talk/app/webrtc/roapsession.h', + 'source/talk/app/webrtc/sessiondescriptionprovider.h', + 'source/talk/app/webrtc/streamcollectionimpl.h', + 'source/talk/app/webrtc/videorendererimpl.cc', + 'source/talk/app/webrtc/videotrackimpl.cc', + 'source/talk/app/webrtc/videotrackimpl.h', + 'source/talk/app/webrtc/webrtcjson.cc', + 'source/talk/app/webrtc/webrtcjson.h', + 'source/talk/app/webrtc/webrtcsdp.cc', + 'source/talk/app/webrtc/webrtcsdp.h', + 'source/talk/app/webrtc/webrtcsession.cc', + 'source/talk/app/webrtc/webrtcsession.h', + 'source/talk/app/webrtc/webrtcsessionobserver.h', 'source/talk/session/phone/audiomonitor.cc', 'source/talk/session/phone/audiomonitor.h', 'source/talk/session/phone/call.cc', |