| Index: content/renderer/media/media_stream_dependency_factory.cc
|
| diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc
|
| index e44ecd8edb49411ad47fe6bfb7c686c5efd9f6cb..a793a3a52bc76c6838d97fbfe2d5762742a1d619 100644
|
| --- a/content/renderer/media/media_stream_dependency_factory.cc
|
| +++ b/content/renderer/media/media_stream_dependency_factory.cc
|
| @@ -6,14 +6,23 @@
|
|
|
| #include <vector>
|
|
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "content/renderer/media/media_stream_extra_data.h"
|
| +#include "content/renderer/media/media_stream_source_extra_data.h"
|
| #include "content/renderer/media/rtc_video_capturer.h"
|
| +#include "content/renderer/media/peer_connection_handler_jsep.h"
|
| #include "content/renderer/media/video_capture_impl_manager.h"
|
| #include "content/renderer/media/webrtc_audio_device_impl.h"
|
| +#include "content/renderer/media/webrtc_uma_histograms.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/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamComponent.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamDescriptor.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamSource.h"
|
|
|
| class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface {
|
| public:
|
| @@ -57,21 +66,110 @@ class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface {
|
| virtual ~P2PPortAllocatorFactory() {}
|
|
|
| private:
|
| - // socket_dispatcher_ is a weak reference, owned by RenderView. It's valid
|
| - // for the lifetime of RenderView.
|
| + // |socket_dispatcher_| is a weak reference, owned by RenderThreadImpl.
|
| + // It's valid for the lifetime of RenderThreadImpl.
|
| content::P2PSocketDispatcher* socket_dispatcher_;
|
| - // network_manager_ and socket_factory_ are a weak references, owned by
|
| - // MediaStreamImpl.
|
| + // |network_manager_| and |socket_factory_| are a weak references, owned by
|
| + // MediaStreamDependencyFactory.
|
| talk_base::NetworkManager* network_manager_;
|
| talk_base::PacketSocketFactory* socket_factory_;
|
| };
|
|
|
| MediaStreamDependencyFactory::MediaStreamDependencyFactory(
|
| - VideoCaptureImplManager* vc_manager)
|
| - : vc_manager_(vc_manager) {
|
| + VideoCaptureImplManager* vc_manager,
|
| + content::P2PSocketDispatcher* p2p_socket_dispatcher)
|
| + : network_manager_(NULL),
|
| + vc_manager_(vc_manager),
|
| + p2p_socket_dispatcher_(p2p_socket_dispatcher),
|
| + signaling_thread_(NULL),
|
| + worker_thread_(NULL),
|
| + chrome_worker_thread_("Chrome_libJingle_WorkerThread") {
|
| }
|
|
|
| -MediaStreamDependencyFactory::~MediaStreamDependencyFactory() {}
|
| +MediaStreamDependencyFactory::~MediaStreamDependencyFactory() {
|
| + CleanupPeerConnectionFactory();
|
| +}
|
| +
|
| +WebKit::WebPeerConnection00Handler*
|
| +MediaStreamDependencyFactory::CreatePeerConnectionHandlerJsep(
|
| + WebKit::WebPeerConnection00HandlerClient* client) {
|
| + // Save histogram data so we can see how much PeerConnetion is used.
|
| + // The histogram counts the number of calls to the JS API
|
| + // webKitPeerConnection00.
|
| + UpdateWebRTCMethodCount(kWebkitPeerConnection);
|
| +
|
| + if (!EnsurePeerConnectionFactory()) {
|
| + return NULL;
|
| + }
|
| +
|
| + PeerConnectionHandlerJsep* pc_handler = new PeerConnectionHandlerJsep(
|
| + client,
|
| + this);
|
| + return pc_handler;
|
| +}
|
| +
|
| +bool MediaStreamDependencyFactory::CreateNativeLocalMediaStream(
|
| + WebKit::WebMediaStreamDescriptor* description) {
|
| + // Creating the peer connection factory can fail if for example the audio
|
| + // (input or output) or video device cannot be opened. Handling such cases
|
| + // better is a higher level design discussion which involves the media
|
| + // manager, webrtc and libjingle. We cannot create any native
|
| + // track objects however, so we'll just have to skip that. Furthermore,
|
| + // creating a peer connection later on will fail if we don't have a factory.
|
| + if (!EnsurePeerConnectionFactory())
|
| + return false;
|
| +
|
| + std::string label = UTF16ToUTF8(description->label());
|
| + talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> native_stream =
|
| + CreateLocalMediaStream(label);
|
| +
|
| + // Add audio tracks.
|
| + WebKit::WebVector<WebKit::WebMediaStreamComponent> audio_components;
|
| + description->audioSources(audio_components);
|
| + for (size_t i = 0; i < audio_components.size(); ++i) {
|
| + const WebKit::WebMediaStreamSource& source = audio_components[i].source();
|
| + MediaStreamSourceExtraData* source_data =
|
| + static_cast<MediaStreamSourceExtraData*>(source.extraData());
|
| + if (!source_data) {
|
| + // TODO(perkj): Implement support for sources from remote MediaStreams.
|
| + NOTIMPLEMENTED();
|
| + continue;
|
| + }
|
| + // TODO(perkj): Refactor the creation of audio tracks to use a proper
|
| + // interface for receiving audio input data. Currently NULL is passed since
|
| + // the |audio_device| is the wrong class and is unused.
|
| + talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> audio_track(
|
| + CreateLocalAudioTrack(UTF16ToUTF8(source.id()), NULL));
|
| + native_stream->AddTrack(audio_track);
|
| + audio_track->set_enabled(audio_components[i].isEnabled());
|
| + // TODO(xians): This set the source of all audio tracks to the same
|
| + // microphone. Implement support for setting the source per audio track
|
| + // instead.
|
| + SetAudioDeviceSessionId(source_data->device_info().session_id);
|
| + }
|
| +
|
| + // Add video tracks.
|
| + WebKit::WebVector<WebKit::WebMediaStreamComponent> video_components;
|
| + description->videoSources(video_components);
|
| + for (size_t i = 0; i < video_components.size(); ++i) {
|
| + const WebKit::WebMediaStreamSource& source = video_components[i].source();
|
| + MediaStreamSourceExtraData* source_data =
|
| + static_cast<MediaStreamSourceExtraData*>(source.extraData());
|
| + if (!source_data) {
|
| + // TODO(perkj): Implement support for sources from remote MediaStreams.
|
| + NOTIMPLEMENTED();
|
| + continue;
|
| + }
|
| + talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> video_track(
|
| + CreateLocalVideoTrack(UTF16ToUTF8(source.id()),
|
| + source_data->device_info().session_id));
|
| + native_stream->AddTrack(video_track);
|
| + video_track->set_enabled(video_components[i].isEnabled());
|
| + }
|
| +
|
| + description->setExtraData(new MediaStreamExtraData(native_stream));
|
| + return true;
|
| +}
|
|
|
| bool MediaStreamDependencyFactory::CreatePeerConnectionFactory(
|
| talk_base::Thread* worker_thread,
|
| @@ -99,11 +197,6 @@ bool MediaStreamDependencyFactory::CreatePeerConnectionFactory(
|
| return pc_factory_.get() != NULL;
|
| }
|
|
|
| -void MediaStreamDependencyFactory::ReleasePeerConnectionFactory() {
|
| - if (pc_factory_.get())
|
| - pc_factory_ = NULL;
|
| -}
|
| -
|
| bool MediaStreamDependencyFactory::PeerConnectionFactoryCreated() {
|
| return pc_factory_.get() != NULL;
|
| }
|
| @@ -155,3 +248,99 @@ webrtc::IceCandidateInterface* MediaStreamDependencyFactory::CreateIceCandidate(
|
| void MediaStreamDependencyFactory::SetAudioDeviceSessionId(int session_id) {
|
| audio_device_->SetSessionId(session_id);
|
| }
|
| +
|
| +void MediaStreamDependencyFactory::InitializeWorkerThread(
|
| + talk_base::Thread** thread,
|
| + base::WaitableEvent* event) {
|
| + jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
|
| + jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
|
| + *thread = jingle_glue::JingleThreadWrapper::current();
|
| + event->Signal();
|
| +}
|
| +
|
| +void MediaStreamDependencyFactory::CreateIpcNetworkManagerOnWorkerThread(
|
| + base::WaitableEvent* event) {
|
| + DCHECK_EQ(MessageLoop::current(), chrome_worker_thread_.message_loop());
|
| + network_manager_ = new content::IpcNetworkManager(p2p_socket_dispatcher_);
|
| + event->Signal();
|
| +}
|
| +
|
| +void MediaStreamDependencyFactory::DeleteIpcNetworkManager() {
|
| + DCHECK_EQ(MessageLoop::current(), chrome_worker_thread_.message_loop());
|
| + delete network_manager_;
|
| + network_manager_ = NULL;
|
| +}
|
| +
|
| +bool MediaStreamDependencyFactory::EnsurePeerConnectionFactory() {
|
| + DCHECK(CalledOnValidThread());
|
| + if (!signaling_thread_) {
|
| + jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
|
| + 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(
|
| + &MediaStreamDependencyFactory::InitializeWorkerThread,
|
| + base::Unretained(this),
|
| + &worker_thread_,
|
| + &event));
|
| + event.Wait();
|
| + DCHECK(worker_thread_);
|
| + }
|
| +
|
| + if (!network_manager_) {
|
| + base::WaitableEvent event(true, false);
|
| + chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
|
| + &MediaStreamDependencyFactory::CreateIpcNetworkManagerOnWorkerThread,
|
| + base::Unretained(this),
|
| + &event));
|
| + event.Wait();
|
| + }
|
| +
|
| + if (!socket_factory_.get()) {
|
| + socket_factory_.reset(
|
| + new content::IpcPacketSocketFactory(p2p_socket_dispatcher_));
|
| + }
|
| +
|
| + if (!PeerConnectionFactoryCreated()) {
|
| + if (!CreatePeerConnectionFactory(
|
| + worker_thread_,
|
| + signaling_thread_,
|
| + p2p_socket_dispatcher_,
|
| + network_manager_,
|
| + socket_factory_.get())) {
|
| + LOG(ERROR) << "Could not create PeerConnection factory";
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void MediaStreamDependencyFactory::CleanupPeerConnectionFactory() {
|
| + pc_factory_ = NULL;
|
| + if (network_manager_) {
|
| + // The network manager needs to free its resources on the thread they were
|
| + // created, which is the worked thread.
|
| + if (chrome_worker_thread_.IsRunning()) {
|
| + chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
|
| + &MediaStreamDependencyFactory::DeleteIpcNetworkManager,
|
| + base::Unretained(this)));
|
| + // Stopping the thread will wait until all tasks have been
|
| + // processed before returning. We wait for the above task to finish before
|
| + // letting the the function continue to avoid any potential race issues.
|
| + chrome_worker_thread_.Stop();
|
| + } else {
|
| + NOTREACHED() << "Worker thread not running.";
|
| + }
|
| + }
|
| +}
|
|
|