| 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_EQ(devices.size(), webkit_sources.size()); |
| 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(WEBKIT_GET_USER_MEDIA); |
| 167 DCHECK(CalledOnValidThread()); | 94 DCHECK(CalledOnValidThread()); |
| 168 int request_id = g_next_request_id++; | 95 int request_id = g_next_request_id++; |
| 169 bool audio = false; | 96 bool audio = false; |
| 170 bool video = false; | 97 bool video = false; |
| 171 WebKit::WebFrame* frame = NULL; | 98 WebKit::WebFrame* frame = NULL; |
| 172 GURL security_origin; | 99 GURL security_origin; |
| 173 | 100 |
| 174 // |user_media_request| can't be mocked. So in order to test at all we check | 101 // |user_media_request| can't be mocked. So in order to test at all we check |
| 175 // if it isNull. | 102 // if it isNull. |
| 176 if (user_media_request.isNull()) { | 103 if (user_media_request.isNull()) { |
| (...skipping 94 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 |