Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: content/renderer/media/media_stream_impl.cc

Issue 8060055: Adding support for MediaStream and PeerConnection functionality (Closed) Base URL: http://git.chromium.org/chromium/chromium.git@trunk
Patch Set: Code review, adding changed gyp files. It also includes all changes in patch 4 which didn't get in. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_impl.h" 5 #include "content/renderer/media/media_stream_impl.h"
6 6
7 #include "base/string_util.h" 7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/utf_string_conversions.h"
13 #include "content/common/media/media_stream_options.h"
8 #include "content/renderer/media/capture_video_decoder.h" 14 #include "content/renderer/media/capture_video_decoder.h"
15 #include "content/renderer/media/media_stream_dependency_factory.h"
16 #include "content/renderer/media/media_stream_dispatcher.h"
17 #include "content/renderer/media/rtc_video_decoder.h"
9 #include "content/renderer/media/video_capture_impl_manager.h" 18 #include "content/renderer/media/video_capture_impl_manager.h"
10 #include "googleurl/src/gurl.h" 19 #include "content/renderer/media/video_capture_module_impl.h"
20 #include "content/renderer/media/webrtc_audio_device_impl.h"
21 #include "content/renderer/p2p/ipc_network_manager.h"
22 #include "content/renderer/p2p/ipc_socket_factory.h"
23 #include "content/renderer/p2p/socket_dispatcher.h"
24 #include "jingle/glue/thread_wrapper.h"
11 #include "media/base/message_loop_factory.h" 25 #include "media/base/message_loop_factory.h"
12 #include "media/base/pipeline.h" 26 #include "third_party/libjingle/source/talk/p2p/client/httpportallocator.h"
27 #include "third_party/libjingle/source/talk/session/phone/dummydevicemanager.h"
28 #include "third_party/libjingle/source/talk/session/phone/webrtcmediaengine.h"
29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebLocalMediaStream.h "
31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStream.h"
32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamControl ler.h"
33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamRegistr y.h"
34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamTrack.h "
35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamTrackLi st.h"
36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h"
13 39
14 namespace { 40 namespace {
15 41
16 static const int kVideoCaptureWidth = 352; 42 static const int kVideoCaptureWidth = 352;
17 static const int kVideoCaptureHeight = 288; 43 static const int kVideoCaptureHeight = 288;
18 static const int kVideoCaptureFramePerSecond = 30; 44 static const int kVideoCaptureFramePerSecond = 30;
19 45
20 static const int kStartOpenSessionId = 1;
21
22 // TODO(wjia): remove this string when full media stream code is checked in.
23 static const char kRawMediaScheme[] = "mediastream";
24
25 } // namespace 46 } // namespace
26 47
27 MediaStreamImpl::MediaStreamImpl(VideoCaptureImplManager* vc_manager) 48 MediaStreamImpl::MediaStreamImpl(
28 : vc_manager_(vc_manager) { 49 MediaStreamDispatcher* media_stream_dispatcher,
29 } 50 content::P2PSocketDispatcher* p2p_socket_dispatcher,
30 51 VideoCaptureImplManager* vc_manager,
31 MediaStreamImpl::~MediaStreamImpl() {} 52 MediaStreamDependencyFactory* dependency_factory)
53 : dependency_factory_(dependency_factory),
54 media_stream_dispatcher_(media_stream_dispatcher),
55 media_engine_(NULL),
56 p2p_socket_dispatcher_(p2p_socket_dispatcher),
57 vc_manager_(vc_manager),
58 message_loop_proxy_(base::MessageLoopProxy::current()),
59 signaling_thread_(NULL),
60 worker_thread_(NULL),
61 chrome_worker_thread_("Chrome_libJingle_WorkerThread"),
62 call_state_(NOT_STARTED),
63 vcm_created_(false) {
64 }
65
66 MediaStreamImpl::~MediaStreamImpl() {
67 if (native_peer_connection_.get()) {
68 native_peer_connection_->RegisterObserver(NULL);
69 native_peer_connection_->Close();
70 }
71 dependency_factory_->DeletePeerConnectionFactory();
72 }
73
74 void MediaStreamImpl::setController(
75 WebKit::WebMediaStreamController* controller) {
76 controller_.reset(controller);
77 }
78
79 void MediaStreamImpl::shutdown() {
80 controller_.reset();
81 }
82
83 void MediaStreamImpl::generateStream(
84 int request_id,
85 WebKit::WebGenerateStreamOptionFlags flags,
86 const WebKit::WebSecurityOrigin& web_security_origin) {
87 bool audio = (flags & WebKit::WebGenerateStreamRequestAudio) != 0;
88 media_stream::StreamOptions::VideoOption video_option =
89 media_stream::StreamOptions::kNoCamera;
90 if ((flags & WebKit::WebGenerateStreamRequestVideoFacingUser) &&
91 (flags & WebKit::WebGenerateStreamRequestVideoFacingEnvironment)) {
92 video_option = media_stream::StreamOptions::kFacingBoth;
93 } else {
94 if (flags & WebKit::WebGenerateStreamRequestVideoFacingEnvironment)
95 video_option = media_stream::StreamOptions::kFacingEnvironment;
96 if (flags & WebKit::WebGenerateStreamRequestVideoFacingUser)
97 video_option = media_stream::StreamOptions::kFacingUser;
98 }
99 DVLOG(1) << "MediaStreamImpl::generateStream("
100 << request_id << ", [ "
101 << (audio ? "audio " : "")
102 << ((flags & WebKit::WebGenerateStreamRequestVideoFacingUser) ?
103 "video_facing_user " : "")
104 << ((flags &
105 WebKit::WebGenerateStreamRequestVideoFacingEnvironment) ?
106 "video_facing_environment " : "")
107 << "], "
108 << static_cast<string16>(web_security_origin.toString()) << ")";
109
110 media_stream_dispatcher_->GenerateStream(request_id, this,
111 media_stream::StreamOptions(audio, video_option),
112 UTF16ToUTF8(web_security_origin.toString()));
113 }
114
115 void MediaStreamImpl::stopGeneratedStream(
116 const WebKit::WebLocalMediaStream& stream) {
117 std::string label = UTF16ToUTF8(stream.label());
118 media_stream_dispatcher_->StopStream(label);
119 }
120
121 void MediaStreamImpl::recordStream(
122 const WebKit::WebMediaStreamRecorder& recorder) {
123 // TODO(grunell): Implement.
124 NOTIMPLEMENTED();
125 }
126
127 void MediaStreamImpl::getRecordedData(
128 const WebKit::WebMediaStreamRecorder& recorder,
129 int request_id) {
130 // TODO(grunell): Implement.
131 NOTIMPLEMENTED();
132 }
133
134 void MediaStreamImpl::disposeRecordedData(
135 const WebKit::WebMediaStreamRecorder& recorder) {
136 // TODO(grunell): Implement.
137 NOTIMPLEMENTED();
138 }
139
140 void MediaStreamImpl::setMediaStreamTrackEnabled(
141 const WebKit::WebMediaStreamTrack& track) {
142 // TODO(grunell): Implement.
143 NOTIMPLEMENTED();
144 }
145
146 void MediaStreamImpl::processSignalingMessage(
147 const WebKit::WebPeerConnection& web_peer_connection,
148 const WebKit::WebString& message) {
149 if (web_peer_connection != web_peer_connection_) {
150 NOTREACHED();
151 return;
152 }
153 native_peer_connection_->SignalingMessage(UTF16ToUTF8(message));
154 }
155
156 void MediaStreamImpl::message(
157 const WebKit::WebPeerConnection& web_peer_connection,
158 const WebKit::WebString& message) {
159 if (web_peer_connection != web_peer_connection_) {
160 NOTREACHED();
161 return;
162 }
163 // TODO(grunell): Implement.
164 NOTIMPLEMENTED();
165 }
166
167 void MediaStreamImpl::addStream(
168 const WebKit::WebPeerConnection& web_peer_connection,
169 const WebKit::WebMediaStream& stream) {
170 if (web_peer_connection != web_peer_connection_) {
171 NOTREACHED();
172 return;
173 }
174 // TODO(grunell): Fix code in this function after a new native PeerConnection
175 // version has been rolled out.
176 std::string label = UTF16ToUTF8(stream.label());
177 if (call_state_ == NOT_STARTED) {
178 // TODO(grunell): Add audio and/or video depending on what's enabled
179 // in the stream.
180 std::string audio_label = label;
181 audio_label.append("-audio");
182 native_peer_connection_->AddStream(audio_label, false); // Audio
183 native_peer_connection_->AddStream(label, true); // Video
184 call_state_ = INITIATING;
185 }
186 if (call_state_ == INITIATING || call_state_ == RECEIVING) {
187 local_label_ = label;
188 if (!vcm_created_) {
189 // Set the capture device.
190 // TODO(grunell): Instead of using the first track, the selected track
191 // should be used.
192 int id = media_stream_dispatcher_->video_session_id(local_label_, 0);
193 if (id != media_stream::StreamDeviceInfo::kNoId) {
194 webrtc::VideoCaptureModule* vcm =
195 new VideoCaptureModuleImpl(id, vc_manager_.get());
196 vcm_created_ = true;
197 media_engine_->SetVideoCaptureModule(vcm);
198 native_peer_connection_->SetVideoCapture("");
199 }
200 }
201 if (call_state_ == INITIATING)
202 native_peer_connection_->Connect();
203 else if (call_state_ == RECEIVING)
204 call_state_ = SENDING_AND_RECEIVING;
205 } else {
206 DLOG(ERROR) << "Multiple calls not supported";
207 }
208 }
209
210 void MediaStreamImpl::newPeerConnection(
211 const WebKit::WebPeerConnection& web_peer_connection,
212 const WebKit::WebString& configuration) {
213 if (native_peer_connection_.get()) {
214 LOG(WARNING) << "A PeerConnection already exists";
215 return;
216 }
217
218 if (!media_engine_) {
219 media_engine_ = dependency_factory_->CreateWebRtcMediaEngine();
220 }
221
222 if (!signaling_thread_) {
223 jingle_glue::JingleThreadWrapper::EnsureForCurrentThread();
224 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
225 signaling_thread_ = jingle_glue::JingleThreadWrapper::current();
226 }
227
228 if (!worker_thread_) {
229 if (!chrome_worker_thread_.IsRunning()) {
230 if (!chrome_worker_thread_.Start()) {
231 LOG(ERROR) << "Could not start worker thread";
232 return;
233 }
234 }
235 base::WaitableEvent event(true, false);
236 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
237 &MediaStreamImpl::InitializeWorkerThread,
238 this,
239 &worker_thread_,
240 &event));
241 event.Wait();
242 DCHECK(worker_thread_);
243 }
244
245 if (!dependency_factory_->PeerConnectionFactoryCreated()) {
246 ipc_network_manager_.reset(
247 new content::IpcNetworkManager(p2p_socket_dispatcher_));
248 ipc_socket_factory_.reset(
249 new content::IpcPacketSocketFactory(p2p_socket_dispatcher_));
250 cricket::HttpPortAllocator* port_allocator =
251 new cricket::HttpPortAllocator(ipc_network_manager_.get(),
252 ipc_socket_factory_.get(),
253 "PeerConnection");
254 // TODO(mallinath): The following flags were added to solve a crash in
255 // HttpClient, we should probably remove them after that issue has been
256 // investigated.
257 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
258 cricket::PORTALLOCATOR_DISABLE_RELAY);
259
260 // TODO(mallinath): PeerConnectionFactory constructor changed in latest
261 // code and it no more accepts config string. Config string must be parsed
262 // here and set in HttpPortAllocator. Now using standard google STUN server
263 // address.
264 std::vector<talk_base::SocketAddress> stun_hosts;
265 stun_hosts.push_back(talk_base::SocketAddress("stun.l.google.com", 19302));
266 port_allocator->SetStunHosts(stun_hosts);
267
268 if (!dependency_factory_->CreatePeerConnectionFactory(
269 port_allocator,
270 media_engine_,
271 worker_thread_)) {
272 LOG(ERROR) << __FUNCTION__
273 << ": Could not initialize PeerConnection factory";
274 return;
275 }
276 }
277
278 native_peer_connection_.reset(dependency_factory_->CreatePeerConnection(
279 signaling_thread_));
280 web_peer_connection_ = web_peer_connection;
281 native_peer_connection_->RegisterObserver(this);
282 }
283
284 void MediaStreamImpl::closePeerConnection(
285 const WebKit::WebPeerConnection& web_peer_connection) {
286 if (web_peer_connection != web_peer_connection_) {
287 NOTREACHED();
288 return;
289 }
290 if (native_peer_connection_.get())
291 native_peer_connection_->RegisterObserver(NULL);
292 native_peer_connection_.reset();
293 web_peer_connection_.reset();
294 rtc_video_decoder_ = NULL;
295 media_engine_->SetVideoCaptureModule(NULL);
296 vcm_created_ = false;
297 call_state_ = NOT_STARTED;
298 }
299
300 void MediaStreamImpl::startNegotiation(
301 const WebKit::WebPeerConnection& web_peer_connection) {
302 if (web_peer_connection != web_peer_connection_) {
303 NOTREACHED();
304 return;
305 }
306 // TODO(grunell): Implement. Currently not supported in native PeerConnection.
307 NOTIMPLEMENTED();
308 }
309
310 void MediaStreamImpl::removeStream(
311 const WebKit::WebPeerConnection& web_peer_connection,
312 const WebKit::WebMediaStream& stream) {
313 if (web_peer_connection != web_peer_connection_) {
314 NOTREACHED();
315 return;
316 }
317 // TODO(grunell): Implement. Currently not supported in native PeerConnection.
318 NOTIMPLEMENTED();
319 }
320
321 void MediaStreamImpl::commitStreamChanges(
322 const WebKit::WebPeerConnection& web_peer_connection) {
323 if (web_peer_connection != web_peer_connection_) {
324 NOTREACHED();
325 return;
326 }
327 // TODO(grunell): Implement. Currently not supported in native PeerConnection.
328 NOTIMPLEMENTED();
329 }
32 330
33 scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder( 331 scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder(
34 const GURL& url, media::MessageLoopFactory* message_loop_factory) { 332 const GURL& url,
35 bool raw_media = (url.spec().find(kRawMediaScheme) == 0); 333 media::MessageLoopFactory* message_loop_factory) {
36 media::VideoDecoder* decoder = NULL; 334 std::string label =
37 if (raw_media) { 335 UTF16ToUTF8(WebKit::WebMediaStreamRegistry::mediaStreamLabel(url));
336 if (label.empty())
337 return NULL; // This is not a valid stream.
338
339 scoped_refptr<media::VideoDecoder> decoder;
340 if (media_stream_dispatcher_->IsStream(label)) {
341 // It's a local stream.
342 int video_session_id = media_stream_dispatcher_->video_session_id(label, 0);
38 media::VideoCapture::VideoCaptureCapability capability; 343 media::VideoCapture::VideoCaptureCapability capability;
39 capability.width = kVideoCaptureWidth; 344 capability.width = kVideoCaptureWidth;
40 capability.height = kVideoCaptureHeight; 345 capability.height = kVideoCaptureHeight;
41 capability.max_fps = kVideoCaptureFramePerSecond; 346 capability.max_fps = kVideoCaptureFramePerSecond;
42 capability.expected_capture_delay = 0; 347 capability.expected_capture_delay = 0;
43 capability.raw_type = media::VideoFrame::I420; 348 capability.raw_type = media::VideoFrame::I420;
44 capability.interlaced = false; 349 capability.interlaced = false;
45 capability.resolution_fixed = false; 350 capability.resolution_fixed = false;
46
47 decoder = new CaptureVideoDecoder( 351 decoder = new CaptureVideoDecoder(
48 message_loop_factory->GetMessageLoopProxy("CaptureVideoDecoder").get(), 352 message_loop_factory->GetMessageLoopProxy("CaptureVideoDecoderThread"),
49 kStartOpenSessionId, vc_manager_.get(), capability); 353 video_session_id,
354 vc_manager_.get(),
355 capability);
356 } else {
357 // It's a remote stream.
358 size_t found = label.rfind("-remote");
359 if (found != std::string::npos)
360 label = label.substr(0, found);
361 if (rtc_video_decoder_.get()) {
362 // The renderer is used by PeerConnection, release it first.
363 if (native_peer_connection_.get())
364 native_peer_connection_->SetVideoRenderer(label, NULL);
365 }
366 rtc_video_decoder_ = new RTCVideoDecoder(
367 message_loop_factory->GetMessageLoop("RtcVideoDecoderThread"),
368 url.spec());
369 decoder = rtc_video_decoder_;
370 if (native_peer_connection_.get())
371 native_peer_connection_->SetVideoRenderer(label, rtc_video_decoder_);
50 } 372 }
51 return decoder; 373 return decoder;
52 } 374 }
375
376 void MediaStreamImpl::OnStreamGenerated(
377 int request_id,
378 const std::string& label,
379 const media_stream::StreamDeviceInfoArray& audio_array,
380 const media_stream::StreamDeviceInfoArray& video_array) {
381 WebKit::WebVector<WebKit::WebMediaStreamTrack> web_track_vector(
382 audio_array.size() + video_array.size());
383
384 WebKit::WebString track_id(WebKit::WebString::fromUTF8(""));
385 WebKit::WebString track_kind(WebKit::WebString::fromUTF8("main"));
386 WebKit::WebString track_label_audio(
387 WebKit::WebString::fromUTF8("AudioDevice"));
388 WebKit::WebString track_label_video(
389 WebKit::WebString::fromUTF8("VideoCapture"));
390 size_t track_num = web_track_vector.size();
391 while (track_num--) {
392 if (track_num < audio_array.size()) {
393 web_track_vector[track_num].initialize(track_id,
394 track_kind,
395 track_label_audio);
396 } else {
397 web_track_vector[track_num].initialize(track_id,
398 track_kind,
399 track_label_video);
400 }
401 }
402
403 WebKit::WebMediaStreamTrackList web_track_list;
404 web_track_list.initialize(web_track_vector);
405
406 WebKit::WebLocalMediaStream web_local_media_stream;
407 web_local_media_stream.initialize(UTF8ToUTF16(label), web_track_list);
408
409 controller_->streamGenerated(request_id, web_local_media_stream);
410 }
411
412 void MediaStreamImpl::OnStreamGenerationFailed(int request_id) {
413 DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed("
414 << request_id << ")";
415 controller_->streamGenerationFailed(
416 request_id,
417 WebKit::WebMediaStreamController::ErrorPermissionDenied);
418 }
419
420 void MediaStreamImpl::OnVideoDeviceFailed(const std::string& label,
421 int index) {
422 DVLOG(1) << "MediaStreamImpl::OnVideoDeviceFailed("
423 << label << ", " << index << ")";
424 controller_->streamFailed(UTF8ToUTF16(label));
425 }
426
427 void MediaStreamImpl::OnAudioDeviceFailed(const std::string& label,
428 int index) {
429 DVLOG(1) << "MediaStreamImpl::OnAudioDeviceFailed("
430 << label << ", " << index << ")";
431 controller_->streamFailed(UTF8ToUTF16(label));
432 }
433
434 void MediaStreamImpl::OnSignalingMessage(const std::string& msg) {
435 if (!message_loop_proxy_->BelongsToCurrentThread()) {
436 message_loop_proxy_->PostTask(
437 FROM_HERE,
438 base::Bind(&MediaStreamImpl::OnSignalingMessage, this, msg));
439 return;
440 }
441 controller_->onSignalingMessage(web_peer_connection_, UTF8ToUTF16(msg));
442 }
443
444 void MediaStreamImpl::OnAddStream(const std::string& stream_id, bool video) {
445 if (!video)
446 return;
447
448 if (!message_loop_proxy_->BelongsToCurrentThread()) {
449 message_loop_proxy_->PostTask(
450 FROM_HERE,
451 base::Bind(&MediaStreamImpl::OnAddStreamCallback, this, stream_id));
452 } else {
453 OnAddStreamCallback(stream_id);
454 }
455 }
456
457 void MediaStreamImpl::OnRemoveStream(const std::string& stream_id, bool video) {
458 if (!video)
459 return;
460
461 if (!message_loop_proxy_->BelongsToCurrentThread()) {
462 message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
463 &MediaStreamImpl::OnRemoveStreamCallback,
464 this,
465 remote_label_));
466 } else {
467 OnRemoveStreamCallback(remote_label_);
468 }
469 }
470
471 void MediaStreamImpl::OnAddStreamCallback(const std::string& stream_label) {
472 // TODO(grunell): Fix code in this function after a new native PeerConnection
473 // version has been rolled out.
474 if (call_state_ == NOT_STARTED) {
475 remote_label_ = stream_label;
476 call_state_ = RECEIVING;
477 } else if (call_state_ == INITIATING) {
478 remote_label_ = local_label_;
479 remote_label_ += "-remote";
480 call_state_ = SENDING_AND_RECEIVING;
481 }
482
483 // TODO(grunell): Currently only support for one track. Add support for
484 // several tracks.
485 WebKit::WebVector<WebKit::WebMediaStreamTrack> web_track_vector(
486 static_cast<size_t>(1));
487 web_track_vector[0].initialize(WebKit::WebString::fromUTF8(""),
488 WebKit::WebString::fromUTF8("main"),
489 WebKit::WebString::fromUTF8(remote_label_));
490 WebKit::WebMediaStreamTrackList web_track_list;
491 web_track_list.initialize(web_track_vector);
492
493 WebKit::WebMediaStream web_media_stream;
494 web_media_stream.initialize(UTF8ToUTF16(remote_label_), web_track_list);
495
496 controller_->onAddStream(web_peer_connection_, web_media_stream);
497 }
498
499 void MediaStreamImpl::OnRemoveStreamCallback(const std::string& stream_label) {
500 controller_->onRemoveStream(web_peer_connection_, UTF8ToUTF16(stream_label));
501 }
502
503 void MediaStreamImpl::InitializeWorkerThread(talk_base::Thread** thread,
504 base::WaitableEvent* event) {
505 jingle_glue::JingleThreadWrapper::EnsureForCurrentThread();
506 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
507 *thread = jingle_glue::JingleThreadWrapper::current();
508 event->Signal();
509 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698