OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/media_stream_dependency_factory.h" | 5 #include "content/renderer/media/media_stream_dependency_factory.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
| 9 #include "base/synchronization/waitable_event.h" |
| 10 #include "base/utf_string_conversions.h" |
| 11 #include "content/renderer/media/media_stream_extra_data.h" |
| 12 #include "content/renderer/media/media_stream_source_extra_data.h" |
9 #include "content/renderer/media/rtc_video_capturer.h" | 13 #include "content/renderer/media/rtc_video_capturer.h" |
| 14 #include "content/renderer/media/peer_connection_handler_jsep.h" |
10 #include "content/renderer/media/video_capture_impl_manager.h" | 15 #include "content/renderer/media/video_capture_impl_manager.h" |
11 #include "content/renderer/media/webrtc_audio_device_impl.h" | 16 #include "content/renderer/media/webrtc_audio_device_impl.h" |
| 17 #include "content/renderer/media/webrtc_uma_histograms.h" |
12 #include "content/renderer/p2p/ipc_network_manager.h" | 18 #include "content/renderer/p2p/ipc_network_manager.h" |
13 #include "content/renderer/p2p/ipc_socket_factory.h" | 19 #include "content/renderer/p2p/ipc_socket_factory.h" |
14 #include "content/renderer/p2p/port_allocator.h" | 20 #include "content/renderer/p2p/port_allocator.h" |
15 #include "jingle/glue/thread_wrapper.h" | 21 #include "jingle/glue/thread_wrapper.h" |
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre
amComponent.h" |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre
amDescriptor.h" |
| 25 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre
amSource.h" |
17 | 26 |
18 class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface { | 27 class P2PPortAllocatorFactory : public webrtc::PortAllocatorFactoryInterface { |
19 public: | 28 public: |
20 P2PPortAllocatorFactory( | 29 P2PPortAllocatorFactory( |
21 content::P2PSocketDispatcher* socket_dispatcher, | 30 content::P2PSocketDispatcher* socket_dispatcher, |
22 talk_base::NetworkManager* network_manager, | 31 talk_base::NetworkManager* network_manager, |
23 talk_base::PacketSocketFactory* socket_factory) | 32 talk_base::PacketSocketFactory* socket_factory) |
24 : socket_dispatcher_(socket_dispatcher), | 33 : socket_dispatcher_(socket_dispatcher), |
25 network_manager_(network_manager), | 34 network_manager_(network_manager), |
26 socket_factory_(socket_factory) { | 35 socket_factory_(socket_factory) { |
(...skipping 23 matching lines...) Expand all Loading... |
50 socket_dispatcher_, | 59 socket_dispatcher_, |
51 network_manager_, | 60 network_manager_, |
52 socket_factory_, | 61 socket_factory_, |
53 config); | 62 config); |
54 } | 63 } |
55 | 64 |
56 protected: | 65 protected: |
57 virtual ~P2PPortAllocatorFactory() {} | 66 virtual ~P2PPortAllocatorFactory() {} |
58 | 67 |
59 private: | 68 private: |
60 // socket_dispatcher_ is a weak reference, owned by RenderView. It's valid | 69 scoped_refptr<content::P2PSocketDispatcher> socket_dispatcher_; |
61 // for the lifetime of RenderView. | 70 // |network_manager_| and |socket_factory_| are a weak references, owned by |
62 content::P2PSocketDispatcher* socket_dispatcher_; | 71 // MediaStreamDependencyFactory. |
63 // network_manager_ and socket_factory_ are a weak references, owned by | |
64 // MediaStreamImpl. | |
65 talk_base::NetworkManager* network_manager_; | 72 talk_base::NetworkManager* network_manager_; |
66 talk_base::PacketSocketFactory* socket_factory_; | 73 talk_base::PacketSocketFactory* socket_factory_; |
67 }; | 74 }; |
68 | 75 |
69 MediaStreamDependencyFactory::MediaStreamDependencyFactory( | 76 MediaStreamDependencyFactory::MediaStreamDependencyFactory( |
70 VideoCaptureImplManager* vc_manager) | 77 VideoCaptureImplManager* vc_manager, |
71 : vc_manager_(vc_manager) { | 78 content::P2PSocketDispatcher* p2p_socket_dispatcher) |
| 79 : network_manager_(NULL), |
| 80 vc_manager_(vc_manager), |
| 81 p2p_socket_dispatcher_(p2p_socket_dispatcher), |
| 82 signaling_thread_(NULL), |
| 83 worker_thread_(NULL), |
| 84 chrome_worker_thread_("Chrome_libJingle_WorkerThread") { |
72 } | 85 } |
73 | 86 |
74 MediaStreamDependencyFactory::~MediaStreamDependencyFactory() {} | 87 MediaStreamDependencyFactory::~MediaStreamDependencyFactory() { |
| 88 CleanupPeerConnectionFactory(); |
| 89 } |
| 90 |
| 91 WebKit::WebPeerConnection00Handler* |
| 92 MediaStreamDependencyFactory::CreatePeerConnectionHandlerJsep( |
| 93 WebKit::WebPeerConnection00HandlerClient* client) { |
| 94 // Save histogram data so we can see how much PeerConnetion is used. |
| 95 // The histogram counts the number of calls to the JS API |
| 96 // webKitPeerConnection00. |
| 97 UpdateWebRTCMethodCount(WEBKIT_PEER_CONNECTION); |
| 98 |
| 99 if (!EnsurePeerConnectionFactory()) { |
| 100 return NULL; |
| 101 } |
| 102 |
| 103 return new PeerConnectionHandlerJsep(client, this); |
| 104 } |
| 105 |
| 106 bool MediaStreamDependencyFactory::CreateNativeLocalMediaStream( |
| 107 WebKit::WebMediaStreamDescriptor* description) { |
| 108 // Creating the peer connection factory can fail if for example the audio |
| 109 // (input or output) or video device cannot be opened. Handling such cases |
| 110 // better is a higher level design discussion which involves the media |
| 111 // manager, webrtc and libjingle. We cannot create any native |
| 112 // track objects however, so we'll just have to skip that. Furthermore, |
| 113 // creating a peer connection later on will fail if we don't have a factory. |
| 114 if (!EnsurePeerConnectionFactory()) |
| 115 return false; |
| 116 |
| 117 std::string label = UTF16ToUTF8(description->label()); |
| 118 talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> native_stream = |
| 119 CreateLocalMediaStream(label); |
| 120 |
| 121 // Add audio tracks. |
| 122 WebKit::WebVector<WebKit::WebMediaStreamComponent> audio_components; |
| 123 description->audioSources(audio_components); |
| 124 for (size_t i = 0; i < audio_components.size(); ++i) { |
| 125 const WebKit::WebMediaStreamSource& source = audio_components[i].source(); |
| 126 MediaStreamSourceExtraData* source_data = |
| 127 static_cast<MediaStreamSourceExtraData*>(source.extraData()); |
| 128 if (!source_data) { |
| 129 // TODO(perkj): Implement support for sources from remote MediaStreams. |
| 130 NOTIMPLEMENTED(); |
| 131 continue; |
| 132 } |
| 133 // TODO(perkj): Refactor the creation of audio tracks to use a proper |
| 134 // interface for receiving audio input data. Currently NULL is passed since |
| 135 // the |audio_device| is the wrong class and is unused. |
| 136 talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> audio_track( |
| 137 CreateLocalAudioTrack(UTF16ToUTF8(source.id()), NULL)); |
| 138 native_stream->AddTrack(audio_track); |
| 139 audio_track->set_enabled(audio_components[i].isEnabled()); |
| 140 // TODO(xians): This set the source of all audio tracks to the same |
| 141 // microphone. Implement support for setting the source per audio track |
| 142 // instead. |
| 143 SetAudioDeviceSessionId(source_data->device_info().session_id); |
| 144 } |
| 145 |
| 146 // Add video tracks. |
| 147 WebKit::WebVector<WebKit::WebMediaStreamComponent> video_components; |
| 148 description->videoSources(video_components); |
| 149 for (size_t i = 0; i < video_components.size(); ++i) { |
| 150 const WebKit::WebMediaStreamSource& source = video_components[i].source(); |
| 151 MediaStreamSourceExtraData* source_data = |
| 152 static_cast<MediaStreamSourceExtraData*>(source.extraData()); |
| 153 if (!source_data) { |
| 154 // TODO(perkj): Implement support for sources from remote MediaStreams. |
| 155 NOTIMPLEMENTED(); |
| 156 continue; |
| 157 } |
| 158 talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> video_track( |
| 159 CreateLocalVideoTrack(UTF16ToUTF8(source.id()), |
| 160 source_data->device_info().session_id)); |
| 161 native_stream->AddTrack(video_track); |
| 162 video_track->set_enabled(video_components[i].isEnabled()); |
| 163 } |
| 164 |
| 165 description->setExtraData(new MediaStreamExtraData(native_stream)); |
| 166 return true; |
| 167 } |
75 | 168 |
76 bool MediaStreamDependencyFactory::CreatePeerConnectionFactory( | 169 bool MediaStreamDependencyFactory::CreatePeerConnectionFactory( |
77 talk_base::Thread* worker_thread, | 170 talk_base::Thread* worker_thread, |
78 talk_base::Thread* signaling_thread, | 171 talk_base::Thread* signaling_thread, |
79 content::P2PSocketDispatcher* socket_dispatcher, | 172 content::P2PSocketDispatcher* socket_dispatcher, |
80 talk_base::NetworkManager* network_manager, | 173 talk_base::NetworkManager* network_manager, |
81 talk_base::PacketSocketFactory* socket_factory) { | 174 talk_base::PacketSocketFactory* socket_factory) { |
82 if (!pc_factory_.get()) { | 175 if (!pc_factory_.get()) { |
83 talk_base::scoped_refptr<P2PPortAllocatorFactory> pa_factory = | 176 talk_base::scoped_refptr<P2PPortAllocatorFactory> pa_factory = |
84 new talk_base::RefCountedObject<P2PPortAllocatorFactory>( | 177 new talk_base::RefCountedObject<P2PPortAllocatorFactory>( |
85 socket_dispatcher, | 178 socket_dispatcher, |
86 network_manager, | 179 network_manager, |
87 socket_factory); | 180 socket_factory); |
88 | 181 |
89 DCHECK(!audio_device_); | 182 DCHECK(!audio_device_); |
90 audio_device_ = new WebRtcAudioDeviceImpl(); | 183 audio_device_ = new WebRtcAudioDeviceImpl(); |
91 talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory( | 184 talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory( |
92 webrtc::CreatePeerConnectionFactory(worker_thread, | 185 webrtc::CreatePeerConnectionFactory(worker_thread, |
93 signaling_thread, | 186 signaling_thread, |
94 pa_factory.release(), | 187 pa_factory.release(), |
95 audio_device_)); | 188 audio_device_)); |
96 if (factory.get()) | 189 if (factory.get()) |
97 pc_factory_ = factory.release(); | 190 pc_factory_ = factory.release(); |
98 } | 191 } |
99 return pc_factory_.get() != NULL; | 192 return pc_factory_.get() != NULL; |
100 } | 193 } |
101 | 194 |
102 void MediaStreamDependencyFactory::ReleasePeerConnectionFactory() { | |
103 if (pc_factory_.get()) | |
104 pc_factory_ = NULL; | |
105 } | |
106 | |
107 bool MediaStreamDependencyFactory::PeerConnectionFactoryCreated() { | 195 bool MediaStreamDependencyFactory::PeerConnectionFactoryCreated() { |
108 return pc_factory_.get() != NULL; | 196 return pc_factory_.get() != NULL; |
109 } | 197 } |
110 | 198 |
111 talk_base::scoped_refptr<webrtc::PeerConnectionInterface> | 199 talk_base::scoped_refptr<webrtc::PeerConnectionInterface> |
112 MediaStreamDependencyFactory::CreatePeerConnection( | 200 MediaStreamDependencyFactory::CreatePeerConnection( |
113 const std::string& config, | 201 const std::string& config, |
114 webrtc::PeerConnectionObserver* observer) { | 202 webrtc::PeerConnectionObserver* observer) { |
115 return pc_factory_->CreatePeerConnection(config, observer); | 203 return pc_factory_->CreatePeerConnection(config, observer); |
116 } | 204 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 webrtc::IceCandidateInterface* MediaStreamDependencyFactory::CreateIceCandidate( | 236 webrtc::IceCandidateInterface* MediaStreamDependencyFactory::CreateIceCandidate( |
149 const std::string& sdp_mid, | 237 const std::string& sdp_mid, |
150 int sdp_mline_index, | 238 int sdp_mline_index, |
151 const std::string& sdp) { | 239 const std::string& sdp) { |
152 return webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, sdp); | 240 return webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, sdp); |
153 } | 241 } |
154 | 242 |
155 void MediaStreamDependencyFactory::SetAudioDeviceSessionId(int session_id) { | 243 void MediaStreamDependencyFactory::SetAudioDeviceSessionId(int session_id) { |
156 audio_device_->SetSessionId(session_id); | 244 audio_device_->SetSessionId(session_id); |
157 } | 245 } |
| 246 |
| 247 void MediaStreamDependencyFactory::InitializeWorkerThread( |
| 248 talk_base::Thread** thread, |
| 249 base::WaitableEvent* event) { |
| 250 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
| 251 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); |
| 252 *thread = jingle_glue::JingleThreadWrapper::current(); |
| 253 event->Signal(); |
| 254 } |
| 255 |
| 256 void MediaStreamDependencyFactory::CreateIpcNetworkManagerOnWorkerThread( |
| 257 base::WaitableEvent* event) { |
| 258 DCHECK_EQ(MessageLoop::current(), chrome_worker_thread_.message_loop()); |
| 259 network_manager_ = new content::IpcNetworkManager(p2p_socket_dispatcher_); |
| 260 event->Signal(); |
| 261 } |
| 262 |
| 263 void MediaStreamDependencyFactory::DeleteIpcNetworkManager() { |
| 264 DCHECK_EQ(MessageLoop::current(), chrome_worker_thread_.message_loop()); |
| 265 delete network_manager_; |
| 266 network_manager_ = NULL; |
| 267 } |
| 268 |
| 269 bool MediaStreamDependencyFactory::EnsurePeerConnectionFactory() { |
| 270 DCHECK(CalledOnValidThread()); |
| 271 if(PeerConnectionFactoryCreated()) |
| 272 return true; |
| 273 |
| 274 if (!signaling_thread_) { |
| 275 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
| 276 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); |
| 277 signaling_thread_ = jingle_glue::JingleThreadWrapper::current(); |
| 278 CHECK(signaling_thread_); |
| 279 } |
| 280 |
| 281 if (!worker_thread_) { |
| 282 if (!chrome_worker_thread_.IsRunning()) { |
| 283 if (!chrome_worker_thread_.Start()) { |
| 284 LOG(ERROR) << "Could not start worker thread"; |
| 285 signaling_thread_ = NULL; |
| 286 return false; |
| 287 } |
| 288 } |
| 289 base::WaitableEvent event(true, false); |
| 290 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 291 &MediaStreamDependencyFactory::InitializeWorkerThread, |
| 292 base::Unretained(this), |
| 293 &worker_thread_, |
| 294 &event)); |
| 295 event.Wait(); |
| 296 DCHECK(worker_thread_); |
| 297 } |
| 298 |
| 299 if (!network_manager_) { |
| 300 base::WaitableEvent event(true, false); |
| 301 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 302 &MediaStreamDependencyFactory::CreateIpcNetworkManagerOnWorkerThread, |
| 303 base::Unretained(this), |
| 304 &event)); |
| 305 event.Wait(); |
| 306 } |
| 307 |
| 308 if (!socket_factory_.get()) { |
| 309 socket_factory_.reset( |
| 310 new content::IpcPacketSocketFactory(p2p_socket_dispatcher_)); |
| 311 } |
| 312 |
| 313 if (!CreatePeerConnectionFactory( |
| 314 worker_thread_, |
| 315 signaling_thread_, |
| 316 p2p_socket_dispatcher_, |
| 317 network_manager_, |
| 318 socket_factory_.get())) { |
| 319 LOG(ERROR) << "Could not create PeerConnection factory"; |
| 320 return false; |
| 321 } |
| 322 return true; |
| 323 } |
| 324 |
| 325 void MediaStreamDependencyFactory::CleanupPeerConnectionFactory() { |
| 326 pc_factory_ = NULL; |
| 327 if (network_manager_) { |
| 328 // The network manager needs to free its resources on the thread they were |
| 329 // created, which is the worked thread. |
| 330 if (chrome_worker_thread_.IsRunning()) { |
| 331 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 332 &MediaStreamDependencyFactory::DeleteIpcNetworkManager, |
| 333 base::Unretained(this))); |
| 334 // Stopping the thread will wait until all tasks have been |
| 335 // processed before returning. We wait for the above task to finish before |
| 336 // letting the the function continue to avoid any potential race issues. |
| 337 chrome_worker_thread_.Stop(); |
| 338 } else { |
| 339 NOTREACHED() << "Worker thread not running."; |
| 340 } |
| 341 } |
| 342 } |
OLD | NEW |