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_; |
tommi (sloooow) - chröme
2012/09/12 13:10:24
can this now be a scoped_refptr?
perkj_chrome
2012/09/12 13:54:39
Done.
| |
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(); | |
tommi (sloooow) - chröme
2012/09/12 13:10:24
should we CHECK that this isn't NULL?
perkj_chrome
2012/09/12 13:54:39
Done.
| |
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, | |
tommi (sloooow) - chröme
2012/09/12 13:10:24
fix indent
perkj_chrome
2012/09/12 13:54:39
Done.
| |
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()) { | |
tommi (sloooow) - chröme
2012/09/12 13:10:24
could you have this check at the top and return ea
perkj_chrome
2012/09/12 13:54:39
Done.
| |
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 |