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_impl.h" | 5 #include "content/renderer/media/media_stream_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | |
10 #include "base/logging.h" | 9 #include "base/logging.h" |
11 #include "base/metrics/histogram.h" | |
12 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
13 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
14 #include "base/synchronization/waitable_event.h" | |
15 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
16 #include "content/common/child_thread.h" | |
17 #include "content/renderer/media/capture_video_decoder.h" | 13 #include "content/renderer/media/capture_video_decoder.h" |
18 #include "content/renderer/media/media_stream_extra_data.h" | 14 #include "content/renderer/media/media_stream_extra_data.h" |
15 #include "content/renderer/media/media_stream_source_extra_data.h" | |
19 #include "content/renderer/media/media_stream_dependency_factory.h" | 16 #include "content/renderer/media/media_stream_dependency_factory.h" |
20 #include "content/renderer/media/media_stream_dispatcher.h" | 17 #include "content/renderer/media/media_stream_dispatcher.h" |
21 #include "content/renderer/media/peer_connection_handler_jsep.h" | 18 #include "content/renderer/media/rtc_video_decoder.h" |
22 #include "content/renderer/media/video_capture_impl_manager.h" | 19 #include "content/renderer/media/video_capture_impl_manager.h" |
23 #include "content/renderer/media/webrtc_audio_device_impl.h" | 20 #include "content/renderer/media/webrtc_uma_histograms.h" |
24 #include "content/renderer/p2p/ipc_network_manager.h" | |
25 #include "content/renderer/p2p/ipc_socket_factory.h" | |
26 #include "jingle/glue/thread_wrapper.h" | |
27 #include "media/base/message_loop_factory.h" | 21 #include "media/base/message_loop_factory.h" |
28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamRegistr y.h" | 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamRegistr y.h" |
30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" | 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" |
31 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre amComponent.h" | 25 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre amComponent.h" |
32 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre amDescriptor.h" | 26 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre amDescriptor.h" |
33 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre amSource.h" | 27 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStre amSource.h" |
34 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" | 28 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" |
35 | 29 |
36 namespace { | 30 namespace { |
37 const int kVideoCaptureWidth = 640; | 31 const int kVideoCaptureWidth = 640; |
38 const int kVideoCaptureHeight = 480; | 32 const int kVideoCaptureHeight = 480; |
39 const int kVideoCaptureFramePerSecond = 30; | 33 const int kVideoCaptureFramePerSecond = 30; |
40 | |
41 // Helper enum used for histogramming calls to WebRTC APIs from JavaScript. | |
42 enum JavaScriptAPIName { | |
43 kWebkitGetUserMedia, | |
44 kWebkitPeerConnection, | |
45 kInvalidName | |
46 }; | |
47 } // namespace | 34 } // namespace |
48 | 35 |
49 // Helper method used to collect information about the number of times | |
50 // different WebRTC API:s are called from JavaScript. | |
51 // The histogram can be viewed at chrome://histograms/WebRTC.webkitApiCount. | |
52 static void UpdateWebRTCMethodCount(JavaScriptAPIName api_name) { | |
53 UMA_HISTOGRAM_ENUMERATION("WebRTC.webkitApiCount", api_name, kInvalidName); | |
54 } | |
55 | |
56 static int g_next_request_id = 0; | 36 static int g_next_request_id = 0; |
57 | 37 |
58 // MediaStreamSourceExtraData contains data stored in the | |
59 // WebKit::WebMediaStreamSource extra data field. | |
60 class MediaStreamSourceExtraData | |
61 : public WebKit::WebMediaStreamSource::ExtraData { | |
62 public: | |
63 explicit MediaStreamSourceExtraData( | |
64 const media_stream::StreamDeviceInfo& device_info) | |
65 : device_info_(device_info) { | |
66 } | |
67 // Return device information about the camera or microphone. | |
68 const media_stream::StreamDeviceInfo& device_info() const { | |
69 return device_info_; | |
70 } | |
71 | |
72 private: | |
73 media_stream::StreamDeviceInfo device_info_; | |
74 }; | |
75 | |
76 // Creates a WebKit representation of a stream sources based on | 38 // Creates a WebKit representation of a stream sources based on |
77 // |devices| from the MediaStreamDispatcher. | 39 // |devices| from the MediaStreamDispatcher. |
78 static void CreateWebKitSourceVector( | 40 static void CreateWebKitSourceVector( |
79 const std::string& label, | 41 const std::string& label, |
80 const media_stream::StreamDeviceInfoArray& devices, | 42 const media_stream::StreamDeviceInfoArray& devices, |
81 WebKit::WebMediaStreamSource::Type type, | 43 WebKit::WebMediaStreamSource::Type type, |
82 WebKit::WebVector<WebKit::WebMediaStreamSource>& webkit_sources) { | 44 WebKit::WebVector<WebKit::WebMediaStreamSource>& webkit_sources) { |
83 ASSERT(devices.size() == webkit_sources.size()); | 45 CHECK(devices.size() == webkit_sources.size()); |
tommi (sloooow) - chröme
2012/09/12 13:10:24
CHECK_EQ?
perkj_chrome
2012/09/12 13:54:39
Done.
| |
84 for (size_t i = 0; i < devices.size(); ++i) { | 46 for (size_t i = 0; i < devices.size(); ++i) { |
85 std::string source_id = StringPrintf("%s%d%u", label.c_str(), type, | 47 std::string source_id = StringPrintf("%s%d%u", label.c_str(), type, |
86 static_cast<unsigned int>(i)); | 48 static_cast<unsigned int>(i)); |
87 webkit_sources[i].initialize( | 49 webkit_sources[i].initialize( |
88 UTF8ToUTF16(source_id), | 50 UTF8ToUTF16(source_id), |
89 type, | 51 type, |
90 UTF8ToUTF16(devices[i].name)); | 52 UTF8ToUTF16(devices[i].name)); |
91 webkit_sources[i].setExtraData( | 53 webkit_sources[i].setExtraData( |
92 new MediaStreamSourceExtraData(devices[i])); | 54 new MediaStreamSourceExtraData(devices[i])); |
93 } | 55 } |
94 } | 56 } |
95 | 57 |
96 MediaStreamImpl::MediaStreamImpl( | 58 MediaStreamImpl::MediaStreamImpl( |
97 content::RenderView* render_view, | 59 content::RenderView* render_view, |
98 MediaStreamDispatcher* media_stream_dispatcher, | 60 MediaStreamDispatcher* media_stream_dispatcher, |
99 content::P2PSocketDispatcher* p2p_socket_dispatcher, | |
100 VideoCaptureImplManager* vc_manager, | 61 VideoCaptureImplManager* vc_manager, |
101 MediaStreamDependencyFactory* dependency_factory) | 62 MediaStreamDependencyFactory* dependency_factory) |
102 : content::RenderViewObserver(render_view), | 63 : content::RenderViewObserver(render_view), |
103 dependency_factory_(dependency_factory), | 64 dependency_factory_(dependency_factory), |
104 media_stream_dispatcher_(media_stream_dispatcher), | 65 media_stream_dispatcher_(media_stream_dispatcher), |
105 p2p_socket_dispatcher_(p2p_socket_dispatcher), | 66 vc_manager_(vc_manager) { |
106 network_manager_(NULL), | |
107 vc_manager_(vc_manager), | |
108 signaling_thread_(NULL), | |
109 worker_thread_(NULL), | |
110 chrome_worker_thread_("Chrome_libJingle_WorkerThread") { | |
111 } | 67 } |
112 | 68 |
113 MediaStreamImpl::~MediaStreamImpl() { | 69 MediaStreamImpl::~MediaStreamImpl() { |
114 CleanupPeerConnectionFactory(); | |
115 } | |
116 | |
117 WebKit::WebPeerConnection00Handler* | |
118 MediaStreamImpl::CreatePeerConnectionHandlerJsep( | |
119 WebKit::WebPeerConnection00HandlerClient* client) { | |
120 // Save histogram data so we can see how much PeerConnetion is used. | |
121 // The histogram counts the number of calls to the JS API | |
122 // webKitPeerConnection00. | |
123 UpdateWebRTCMethodCount(kWebkitPeerConnection); | |
124 DCHECK(CalledOnValidThread()); | |
125 if (!EnsurePeerConnectionFactory()) | |
126 return NULL; | |
127 | |
128 PeerConnectionHandlerJsep* pc_handler = new PeerConnectionHandlerJsep( | |
129 client, | |
130 dependency_factory_.get()); | |
131 return pc_handler; | |
132 } | 70 } |
133 | 71 |
134 void MediaStreamImpl::StopLocalMediaStream( | 72 void MediaStreamImpl::StopLocalMediaStream( |
135 const WebKit::WebMediaStreamDescriptor& stream) { | 73 const WebKit::WebMediaStreamDescriptor& stream) { |
136 DVLOG(1) << "MediaStreamImpl::StopLocalMediaStream"; | 74 DVLOG(1) << "MediaStreamImpl::StopLocalMediaStream"; |
137 | 75 |
138 MediaStreamExtraData* extra_data = | 76 MediaStreamExtraData* extra_data = |
139 static_cast<MediaStreamExtraData*>(stream.extraData()); | 77 static_cast<MediaStreamExtraData*>(stream.extraData()); |
140 if (extra_data && extra_data->local_stream()) { | 78 if (extra_data && extra_data->local_stream()) { |
141 media_stream_dispatcher_->StopStream(extra_data->local_stream()->label()); | 79 media_stream_dispatcher_->StopStream(extra_data->local_stream()->label()); |
142 local_media_streams_.erase(extra_data->local_stream()->label()); | 80 local_media_streams_.erase(extra_data->local_stream()->label()); |
143 } else { | 81 } else { |
144 NOTREACHED(); | 82 NOTREACHED(); |
145 } | 83 } |
146 } | 84 } |
147 | 85 |
148 void MediaStreamImpl::CreateMediaStream( | |
149 WebKit::WebFrame* frame, | |
150 WebKit::WebMediaStreamDescriptor* stream) { | |
151 DVLOG(1) << "MediaStreamImpl::CreateMediaStream"; | |
152 | |
153 if (!CreateNativeLocalMediaStream(stream)) { | |
154 DVLOG(1) << "Failed to create native stream in CreateMediaStream."; | |
155 return; | |
156 } | |
157 } | |
158 | |
159 void MediaStreamImpl::requestUserMedia( | 86 void MediaStreamImpl::requestUserMedia( |
160 const WebKit::WebUserMediaRequest& user_media_request, | 87 const WebKit::WebUserMediaRequest& user_media_request, |
161 const WebKit::WebVector<WebKit::WebMediaStreamSource>& audio_sources, | 88 const WebKit::WebVector<WebKit::WebMediaStreamSource>& audio_sources, |
162 const WebKit::WebVector<WebKit::WebMediaStreamSource>& video_sources) { | 89 const WebKit::WebVector<WebKit::WebMediaStreamSource>& video_sources) { |
163 // Save histogram data so we can see how much GetUserMedia is used. | 90 // Save histogram data so we can see how much GetUserMedia is used. |
164 // The histogram counts the number of calls to the JS API | 91 // The histogram counts the number of calls to the JS API |
165 // webGetUserMedia. | 92 // webGetUserMedia. |
166 UpdateWebRTCMethodCount(kWebkitGetUserMedia); | 93 UpdateWebRTCMethodCount(kWebkitGetUserMedia); |
167 DCHECK(CalledOnValidThread()); | 94 DCHECK(CalledOnValidThread()); |
168 int request_id = g_next_request_id++; | 95 int request_id = g_next_request_id++; |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
271 DVLOG(1) << "Request ID not found"; | 198 DVLOG(1) << "Request ID not found"; |
272 media_stream_dispatcher_->StopStream(label); | 199 media_stream_dispatcher_->StopStream(label); |
273 return; | 200 return; |
274 } | 201 } |
275 | 202 |
276 WebKit::WebString webkit_label = UTF8ToUTF16(label); | 203 WebKit::WebString webkit_label = UTF8ToUTF16(label); |
277 WebKit::WebMediaStreamDescriptor description; | 204 WebKit::WebMediaStreamDescriptor description; |
278 description.initialize(webkit_label, audio_source_vector, | 205 description.initialize(webkit_label, audio_source_vector, |
279 video_source_vector); | 206 video_source_vector); |
280 | 207 |
281 if (!CreateNativeLocalMediaStream(&description)) { | 208 if (!dependency_factory_->CreateNativeLocalMediaStream(&description)) { |
282 DVLOG(1) << "Failed to create native stream in OnStreamGenerated."; | 209 DVLOG(1) << "Failed to create native stream in OnStreamGenerated."; |
283 media_stream_dispatcher_->StopStream(label); | 210 media_stream_dispatcher_->StopStream(label); |
284 it->second.request_.requestFailed(); | 211 it->second.request_.requestFailed(); |
285 user_media_requests_.erase(it); | 212 user_media_requests_.erase(it); |
286 return; | 213 return; |
287 } | 214 } |
288 local_media_streams_[label] = it->second.frame_; | 215 local_media_streams_[label] = it->second.frame_; |
289 CompleteGetUserMediaRequest(description, &it->second.request_); | 216 CompleteGetUserMediaRequest(description, &it->second.request_); |
290 user_media_requests_.erase(it); | 217 user_media_requests_.erase(it); |
291 } | 218 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 << "Stopping stream " << it->first; | 304 << "Stopping stream " << it->first; |
378 media_stream_dispatcher_->StopStream(it->first); | 305 media_stream_dispatcher_->StopStream(it->first); |
379 local_media_streams_.erase(it); | 306 local_media_streams_.erase(it); |
380 it = local_media_streams_.begin(); | 307 it = local_media_streams_.begin(); |
381 } else { | 308 } else { |
382 ++it; | 309 ++it; |
383 } | 310 } |
384 } | 311 } |
385 } | 312 } |
386 | 313 |
387 void MediaStreamImpl::InitializeWorkerThread(talk_base::Thread** thread, | |
388 base::WaitableEvent* event) { | |
389 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | |
390 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); | |
391 *thread = jingle_glue::JingleThreadWrapper::current(); | |
392 event->Signal(); | |
393 } | |
394 | |
395 void MediaStreamImpl::CreateIpcNetworkManagerOnWorkerThread( | |
396 base::WaitableEvent* event) { | |
397 DCHECK_EQ(MessageLoop::current(), chrome_worker_thread_.message_loop()); | |
398 network_manager_ = new content::IpcNetworkManager(p2p_socket_dispatcher_); | |
399 event->Signal(); | |
400 } | |
401 | |
402 void MediaStreamImpl::DeleteIpcNetworkManager() { | |
403 DCHECK_EQ(MessageLoop::current(), chrome_worker_thread_.message_loop()); | |
404 delete network_manager_; | |
405 network_manager_ = NULL; | |
406 } | |
407 | |
408 bool MediaStreamImpl::EnsurePeerConnectionFactory() { | |
409 DCHECK(CalledOnValidThread()); | |
410 if (!signaling_thread_) { | |
411 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | |
412 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); | |
413 signaling_thread_ = jingle_glue::JingleThreadWrapper::current(); | |
414 } | |
415 | |
416 if (!worker_thread_) { | |
417 if (!chrome_worker_thread_.IsRunning()) { | |
418 if (!chrome_worker_thread_.Start()) { | |
419 LOG(ERROR) << "Could not start worker thread"; | |
420 signaling_thread_ = NULL; | |
421 return false; | |
422 } | |
423 } | |
424 base::WaitableEvent event(true, false); | |
425 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | |
426 &MediaStreamImpl::InitializeWorkerThread, | |
427 base::Unretained(this), | |
428 &worker_thread_, | |
429 &event)); | |
430 event.Wait(); | |
431 DCHECK(worker_thread_); | |
432 } | |
433 | |
434 if (!network_manager_) { | |
435 base::WaitableEvent event(true, false); | |
436 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | |
437 &MediaStreamImpl::CreateIpcNetworkManagerOnWorkerThread, | |
438 base::Unretained(this), | |
439 &event)); | |
440 event.Wait(); | |
441 } | |
442 | |
443 if (!socket_factory_.get()) { | |
444 socket_factory_.reset( | |
445 new content::IpcPacketSocketFactory(p2p_socket_dispatcher_)); | |
446 } | |
447 | |
448 if (!dependency_factory_->PeerConnectionFactoryCreated()) { | |
449 if (!dependency_factory_->CreatePeerConnectionFactory( | |
450 worker_thread_, | |
451 signaling_thread_, | |
452 p2p_socket_dispatcher_, | |
453 network_manager_, | |
454 socket_factory_.get())) { | |
455 LOG(ERROR) << "Could not create PeerConnection factory"; | |
456 return false; | |
457 } | |
458 } | |
459 | |
460 return true; | |
461 } | |
462 | |
463 void MediaStreamImpl::CleanupPeerConnectionFactory() { | |
464 if (dependency_factory_.get()) | |
465 dependency_factory_->ReleasePeerConnectionFactory(); | |
466 if (network_manager_) { | |
467 // The network manager needs to free its resources on the thread they were | |
468 // created, which is the worked thread. | |
469 if (chrome_worker_thread_.IsRunning()) { | |
470 chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | |
471 &MediaStreamImpl::DeleteIpcNetworkManager, | |
472 base::Unretained(this))); | |
473 // Stopping the thread will wait until all tasks have been | |
474 // processed before returning. We wait for the above task to finish before | |
475 // letting the the function continue to avoid any potential race issues. | |
476 chrome_worker_thread_.Stop(); | |
477 } else { | |
478 NOTREACHED() << "Worker thread not running."; | |
479 } | |
480 } | |
481 } | |
482 | |
483 scoped_refptr<media::VideoDecoder> MediaStreamImpl::CreateLocalVideoDecoder( | 314 scoped_refptr<media::VideoDecoder> MediaStreamImpl::CreateLocalVideoDecoder( |
484 webrtc::MediaStreamInterface* stream, | 315 webrtc::MediaStreamInterface* stream, |
485 media::MessageLoopFactory* message_loop_factory) { | 316 media::MessageLoopFactory* message_loop_factory) { |
486 if (!stream->video_tracks() || stream->video_tracks()->count() == 0) | 317 if (!stream->video_tracks() || stream->video_tracks()->count() == 0) |
487 return NULL; | 318 return NULL; |
488 | 319 |
489 int video_session_id = | 320 int video_session_id = |
490 media_stream_dispatcher_->video_session_id(stream->label(), 0); | 321 media_stream_dispatcher_->video_session_id(stream->label(), 0); |
491 media::VideoCaptureCapability capability; | 322 media::VideoCaptureCapability capability; |
492 capability.width = kVideoCaptureWidth; | 323 capability.width = kVideoCaptureWidth; |
(...skipping 22 matching lines...) Expand all Loading... | |
515 | 346 |
516 DVLOG(1) << "MediaStreamImpl::CreateRemoteVideoDecoder label:" | 347 DVLOG(1) << "MediaStreamImpl::CreateRemoteVideoDecoder label:" |
517 << stream->label(); | 348 << stream->label(); |
518 | 349 |
519 return new RTCVideoDecoder( | 350 return new RTCVideoDecoder( |
520 message_loop_factory->GetMessageLoop(media::MessageLoopFactory::kDecoder), | 351 message_loop_factory->GetMessageLoop(media::MessageLoopFactory::kDecoder), |
521 base::MessageLoopProxy::current(), | 352 base::MessageLoopProxy::current(), |
522 stream->video_tracks()->at(0)); | 353 stream->video_tracks()->at(0)); |
523 } | 354 } |
524 | 355 |
525 bool MediaStreamImpl::CreateNativeLocalMediaStream( | |
526 WebKit::WebMediaStreamDescriptor* description) { | |
527 // Creating the peer connection factory can fail if for example the audio | |
528 // (input or output) or video device cannot be opened. Handling such cases | |
529 // better is a higher level design discussion which involves the media | |
530 // manager, webrtc and libjingle. We cannot create any native | |
531 // track objects however, so we'll just have to skip that. Furthermore, | |
532 // creating a peer connection later on will fail if we don't have a factory. | |
533 if (!EnsurePeerConnectionFactory()) | |
534 return false; | |
535 | |
536 std::string label = UTF16ToUTF8(description->label()); | |
537 LocalNativeStreamPtr native_stream = | |
538 dependency_factory_->CreateLocalMediaStream(label); | |
539 | |
540 // Add audio tracks. | |
541 WebKit::WebVector<WebKit::WebMediaStreamComponent> audio_components; | |
542 description->audioSources(audio_components); | |
543 for (size_t i = 0; i < audio_components.size(); ++i) { | |
544 const WebKit::WebMediaStreamSource& source = audio_components[i].source(); | |
545 MediaStreamSourceExtraData* source_data = | |
546 static_cast<MediaStreamSourceExtraData*>(source.extraData()); | |
547 if (!source_data) { | |
548 // TODO(perkj): Implement support for sources from remote MediaStreams. | |
549 NOTIMPLEMENTED(); | |
550 continue; | |
551 } | |
552 // TODO(perkj): Refactor the creation of audio tracks to use a proper | |
553 // interface for receiving audio input data. Currently NULL is passed since | |
554 // the |audio_device| is the wrong class and is unused. | |
555 talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface> audio_track( | |
556 dependency_factory_->CreateLocalAudioTrack( | |
557 UTF16ToUTF8(source.id()), NULL)); | |
558 native_stream->AddTrack(audio_track); | |
559 audio_track->set_enabled(audio_components[i].isEnabled()); | |
560 // TODO(xians): This set the source of all audio tracks to the same | |
561 // microphone. Implement support for setting the source per audio track | |
562 // instead. | |
563 dependency_factory_->SetAudioDeviceSessionId( | |
564 source_data->device_info().session_id); | |
565 } | |
566 | |
567 // Add video tracks. | |
568 WebKit::WebVector<WebKit::WebMediaStreamComponent> video_components; | |
569 description->videoSources(video_components); | |
570 for (size_t i = 0; i < video_components.size(); ++i) { | |
571 const WebKit::WebMediaStreamSource& source = video_components[i].source(); | |
572 MediaStreamSourceExtraData* source_data = | |
573 static_cast<MediaStreamSourceExtraData*>(source.extraData()); | |
574 if (!source_data) { | |
575 // TODO(perkj): Implement support for sources from remote MediaStreams. | |
576 NOTIMPLEMENTED(); | |
577 continue; | |
578 } | |
579 talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> video_track( | |
580 dependency_factory_->CreateLocalVideoTrack( | |
581 UTF16ToUTF8(source.id()), source_data->device_info().session_id)); | |
582 native_stream->AddTrack(video_track); | |
583 video_track->set_enabled(video_components[i].isEnabled()); | |
584 } | |
585 | |
586 description->setExtraData(new MediaStreamExtraData(native_stream)); | |
587 | |
588 return true; | |
589 } | |
590 | |
591 MediaStreamExtraData::MediaStreamExtraData( | 356 MediaStreamExtraData::MediaStreamExtraData( |
592 webrtc::MediaStreamInterface* remote_stream) | 357 webrtc::MediaStreamInterface* remote_stream) |
593 : remote_stream_(remote_stream) { | 358 : remote_stream_(remote_stream) { |
594 } | 359 } |
595 MediaStreamExtraData::MediaStreamExtraData( | 360 MediaStreamExtraData::MediaStreamExtraData( |
596 webrtc::LocalMediaStreamInterface* local_stream) | 361 webrtc::LocalMediaStreamInterface* local_stream) |
597 : local_stream_(local_stream) { | 362 : local_stream_(local_stream) { |
598 } | 363 } |
599 MediaStreamExtraData::~MediaStreamExtraData() { | 364 MediaStreamExtraData::~MediaStreamExtraData() { |
600 } | 365 } |
OLD | NEW |