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