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 3 // found in the LICENSE file. 4 5 #include "content/renderer/media/media_stream_impl.h" 6 7 #include <utility> 8 9 #include "base/logging.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "content/public/common/desktop_media_id.h" 14 #include "content/renderer/media/media_stream_audio_renderer.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/media_stream_extra_data.h" 18 #include "content/renderer/media/media_stream_source_extra_data.h" 19 #include "content/renderer/media/rtc_video_renderer.h" 20 #include "content/renderer/media/webrtc_audio_capturer.h" 21 #include "content/renderer/media/webrtc_audio_renderer.h" 22 #include "content/renderer/media/webrtc_local_audio_renderer.h" 23 #include "content/renderer/media/webrtc_uma_histograms.h" 24 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 25 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 26 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 27 #include "third_party/WebKit/public/platform/WebVector.h" 28 #include "third_party/WebKit/public/web/WebDocument.h" 29 #include "third_party/WebKit/public/web/WebFrame.h" 30 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" 31 32 namespace content { 33 namespace { 34 35 std::string GetStreamConstraint( 36 const WebKit::WebMediaConstraints& constraints, const std::string& key, 37 bool is_mandatory) { 38 if (constraints.isNull()) 39 return std::string(); 40 41 WebKit::WebString value; 42 if (is_mandatory) { 43 constraints.getMandatoryConstraintValue(UTF8ToUTF16(key), value); 44 } else { 45 constraints.getOptionalConstraintValue(UTF8ToUTF16(key), value); 46 } 47 return UTF16ToUTF8(value); 48 } 49 50 void UpdateRequestOptions( 51 const WebKit::WebUserMediaRequest& user_media_request, 52 StreamOptions* options) { 53 if (options->audio_type != content::MEDIA_NO_SERVICE) { 54 std::string audio_stream_source = GetStreamConstraint( 55 user_media_request.audioConstraints(), kMediaStreamSource, true); 56 if (audio_stream_source == kMediaStreamSourceTab) { 57 options->audio_type = content::MEDIA_TAB_AUDIO_CAPTURE; 58 options->audio_device_id = GetStreamConstraint( 59 user_media_request.audioConstraints(), 60 kMediaStreamSourceId, true); 61 } else if (audio_stream_source == kMediaStreamSourceSystem) { 62 options->audio_type = content::MEDIA_SYSTEM_AUDIO_CAPTURE; 63 } 64 } 65 66 if (options->video_type != content::MEDIA_NO_SERVICE) { 67 std::string video_stream_source = GetStreamConstraint( 68 user_media_request.videoConstraints(), kMediaStreamSource, true); 69 if (video_stream_source == kMediaStreamSourceTab) { 70 options->video_type = content::MEDIA_TAB_VIDEO_CAPTURE; 71 options->video_device_id = GetStreamConstraint( 72 user_media_request.videoConstraints(), 73 kMediaStreamSourceId, true); 74 } else if (video_stream_source == kMediaStreamSourceScreen) { 75 options->video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE; 76 options->video_device_id = 77 DesktopMediaID(DesktopMediaID::TYPE_SCREEN, 0).ToString(); 78 } 79 } 80 } 81 82 static int g_next_request_id = 0; 83 84 // Creates a WebKit representation of a stream sources based on 85 // |devices| from the MediaStreamDispatcher. 86 void CreateWebKitSourceVector( 87 const std::string& label, 88 const StreamDeviceInfoArray& devices, 89 WebKit::WebMediaStreamSource::Type type, 90 WebKit::WebVector<WebKit::WebMediaStreamSource>& webkit_sources) { 91 CHECK_EQ(devices.size(), webkit_sources.size()); 92 for (size_t i = 0; i < devices.size(); ++i) { 93 const char* track_type = 94 (type == WebKit::WebMediaStreamSource::TypeAudio) ? "a" : "v"; 95 std::string source_id = base::StringPrintf("%s%s%u", label.c_str(), 96 track_type, 97 static_cast<unsigned int>(i)); 98 webkit_sources[i].initialize( 99 UTF8ToUTF16(source_id), 100 type, 101 UTF8ToUTF16(devices[i].device.name)); 102 webkit_sources[i].setExtraData( 103 new content::MediaStreamSourceExtraData(devices[i], webkit_sources[i])); 104 webkit_sources[i].setDeviceId(UTF8ToUTF16( 105 base::IntToString(devices[i].session_id))); 106 } 107 } 108 109 webrtc::MediaStreamInterface* GetNativeMediaStream( 110 const WebKit::WebMediaStream& web_stream) { 111 content::MediaStreamExtraData* extra_data = 112 static_cast<content::MediaStreamExtraData*>(web_stream.extraData()); 113 if (!extra_data) 114 return NULL; 115 return extra_data->stream().get(); 116 } 117 118 } // namespace 119 120 MediaStreamImpl::MediaStreamImpl( 121 RenderView* render_view, 122 MediaStreamDispatcher* media_stream_dispatcher, 123 MediaStreamDependencyFactory* dependency_factory) 124 : RenderViewObserver(render_view), 125 dependency_factory_(dependency_factory), 126 media_stream_dispatcher_(media_stream_dispatcher) { 127 } 128 129 MediaStreamImpl::~MediaStreamImpl() { 130 } 131 132 void MediaStreamImpl::OnLocalMediaStreamStop( 133 const std::string& label) { 134 DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop(" << label << ")"; 135 136 UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label); 137 if (user_media_request) { 138 StopLocalAudioTrack(user_media_request->web_stream); 139 media_stream_dispatcher_->StopStream(label); 140 DeleteUserMediaRequestInfo(user_media_request); 141 } else { 142 DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop: the stream has " 143 << "already been stopped."; 144 } 145 } 146 147 void MediaStreamImpl::requestUserMedia( 148 const WebKit::WebUserMediaRequest& user_media_request) { 149 // Save histogram data so we can see how much GetUserMedia is used. 150 // The histogram counts the number of calls to the JS API 151 // webGetUserMedia. 152 UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA); 153 DCHECK(CalledOnValidThread()); 154 int request_id = g_next_request_id++; 155 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_NO_SERVICE); 156 WebKit::WebFrame* frame = NULL; 157 GURL security_origin; 158 159 // |user_media_request| can't be mocked. So in order to test at all we check 160 // if it isNull. 161 if (user_media_request.isNull()) { 162 // We are in a test. 163 options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE; 164 options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE; 165 } else { 166 if (user_media_request.audio()) { 167 options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE; 168 options.audio_device_id = GetStreamConstraint( 169 user_media_request.audioConstraints(), 170 kMediaStreamSourceInfoId, false); 171 } 172 if (user_media_request.video()) { 173 options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE; 174 options.video_device_id = GetStreamConstraint( 175 user_media_request.videoConstraints(), 176 kMediaStreamSourceInfoId, false); 177 } 178 179 security_origin = GURL(user_media_request.securityOrigin().toString()); 180 // Get the WebFrame that requested a MediaStream. 181 // The frame is needed to tell the MediaStreamDispatcher when a stream goes 182 // out of scope. 183 frame = user_media_request.ownerDocument().frame(); 184 DCHECK(frame); 185 186 UpdateRequestOptions(user_media_request, &options); 187 } 188 189 DVLOG(1) << "MediaStreamImpl::requestUserMedia(" << request_id << ", [ " 190 << "audio=" << (options.audio_type) 191 << ", video=" << (options.video_type) << " ], " 192 << security_origin.spec() << ")"; 193 194 user_media_requests_.push_back( 195 new UserMediaRequestInfo(request_id, frame, user_media_request)); 196 197 media_stream_dispatcher_->GenerateStream( 198 request_id, 199 AsWeakPtr(), 200 options, 201 security_origin); 202 } 203 204 void MediaStreamImpl::cancelUserMediaRequest( 205 const WebKit::WebUserMediaRequest& user_media_request) { 206 DCHECK(CalledOnValidThread()); 207 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request); 208 if (request) { 209 // We can't abort the stream generation process. 210 // Instead, erase the request. Once the stream is generated we will stop the 211 // stream if the request does not exist. 212 DeleteUserMediaRequestInfo(request); 213 } 214 } 215 216 WebKit::WebMediaStream MediaStreamImpl::GetMediaStream( 217 const GURL& url) { 218 return WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url); 219 } 220 221 bool MediaStreamImpl::IsMediaStream(const GURL& url) { 222 WebKit::WebMediaStream web_stream( 223 WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url)); 224 225 if (web_stream.isNull() || !web_stream.extraData()) 226 return false; // This is not a valid stream. 227 228 webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream); 229 return (stream && 230 (!stream->GetVideoTracks().empty() || !stream->GetAudioTracks().empty())); 231 } 232 233 scoped_refptr<VideoFrameProvider> 234 MediaStreamImpl::GetVideoFrameProvider( 235 const GURL& url, 236 const base::Closure& error_cb, 237 const VideoFrameProvider::RepaintCB& repaint_cb) { 238 DCHECK(CalledOnValidThread()); 239 WebKit::WebMediaStream web_stream(GetMediaStream(url)); 240 241 if (web_stream.isNull() || !web_stream.extraData()) 242 return NULL; // This is not a valid stream. 243 244 DVLOG(1) << "MediaStreamImpl::GetVideoFrameProvider stream:" 245 << UTF16ToUTF8(web_stream.id()); 246 247 webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream); 248 if (stream) 249 return CreateVideoFrameProvider(stream, error_cb, repaint_cb); 250 NOTREACHED(); 251 return NULL; 252 } 253 254 scoped_refptr<MediaStreamAudioRenderer> 255 MediaStreamImpl::GetAudioRenderer(const GURL& url) { 256 DCHECK(CalledOnValidThread()); 257 WebKit::WebMediaStream web_stream(GetMediaStream(url)); 258 259 if (web_stream.isNull() || !web_stream.extraData()) 260 return NULL; // This is not a valid stream. 261 262 DVLOG(1) << "MediaStreamImpl::GetAudioRenderer stream:" 263 << UTF16ToUTF8(web_stream.id()); 264 265 MediaStreamExtraData* extra_data = 266 static_cast<MediaStreamExtraData*>(web_stream.extraData()); 267 268 if (extra_data->is_local()) { 269 // Create the local audio renderer if the stream contains audio tracks. 270 return CreateLocalAudioRenderer(extra_data->stream().get()); 271 } 272 273 webrtc::MediaStreamInterface* stream = extra_data->stream().get(); 274 if (!stream || stream->GetAudioTracks().empty()) 275 return NULL; 276 277 // This is a remote media stream. 278 WebRtcAudioDeviceImpl* audio_device = 279 dependency_factory_->GetWebRtcAudioDevice(); 280 281 // Share the existing renderer if any, otherwise create a new one. 282 scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer()); 283 if (!renderer.get()) { 284 renderer = CreateRemoteAudioRenderer(extra_data->stream().get()); 285 286 if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get())) 287 renderer = NULL; 288 } 289 return renderer; 290 } 291 292 // Callback from MediaStreamDispatcher. 293 // The requested stream have been generated by the MediaStreamDispatcher. 294 void MediaStreamImpl::OnStreamGenerated( 295 int request_id, 296 const std::string& label, 297 const StreamDeviceInfoArray& audio_array, 298 const StreamDeviceInfoArray& video_array) { 299 DCHECK(CalledOnValidThread()); 300 DVLOG(1) << "MediaStreamImpl::OnStreamGenerated stream:" << label; 301 302 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id); 303 if (!request_info) { 304 // This can happen if the request is canceled or the frame reloads while 305 // MediaStreamDispatcher is processing the request. 306 // We need to tell the dispatcher to stop the stream. 307 media_stream_dispatcher_->StopStream(label); 308 DVLOG(1) << "Request ID not found"; 309 return; 310 } 311 request_info->generated = true; 312 313 WebKit::WebVector<WebKit::WebMediaStreamSource> audio_source_vector( 314 audio_array.size()); 315 CreateWebKitSourceVector(label, audio_array, 316 WebKit::WebMediaStreamSource::TypeAudio, 317 audio_source_vector); 318 request_info->audio_sources.assign(audio_source_vector); 319 WebKit::WebVector<WebKit::WebMediaStreamSource> video_source_vector( 320 video_array.size()); 321 CreateWebKitSourceVector(label, video_array, 322 WebKit::WebMediaStreamSource::TypeVideo, 323 video_source_vector); 324 request_info->video_sources.assign(video_source_vector); 325 326 WebKit::WebUserMediaRequest* request = &(request_info->request); 327 WebKit::WebString webkit_id = UTF8ToUTF16(label); 328 WebKit::WebMediaStream* web_stream = &(request_info->web_stream); 329 330 WebKit::WebVector<WebKit::WebMediaStreamTrack> audio_track_vector( 331 audio_array.size()); 332 for (size_t i = 0; i < audio_track_vector.size(); ++i) { 333 audio_track_vector[i].initialize(audio_source_vector[i].id(), 334 audio_source_vector[i]); 335 } 336 337 WebKit::WebVector<WebKit::WebMediaStreamTrack> video_track_vector( 338 video_array.size()); 339 for (size_t i = 0; i < video_track_vector.size(); ++i) { 340 video_track_vector[i].initialize(video_source_vector[i].id(), 341 video_source_vector[i]); 342 } 343 344 web_stream->initialize(webkit_id, audio_track_vector, 345 video_track_vector); 346 347 // WebUserMediaRequest don't have an implementation in unit tests. 348 // Therefore we need to check for isNull here. 349 WebKit::WebMediaConstraints audio_constraints = request->isNull() ? 350 WebKit::WebMediaConstraints() : request->audioConstraints(); 351 WebKit::WebMediaConstraints video_constraints = request->isNull() ? 352 WebKit::WebMediaConstraints() : request->videoConstraints(); 353 354 dependency_factory_->CreateNativeMediaSources( 355 RenderViewObserver::routing_id(), 356 audio_constraints, video_constraints, web_stream, 357 base::Bind(&MediaStreamImpl::OnCreateNativeSourcesComplete, AsWeakPtr())); 358 } 359 360 // Callback from MediaStreamDispatcher. 361 // The requested stream failed to be generated. 362 void MediaStreamImpl::OnStreamGenerationFailed(int request_id) { 363 DCHECK(CalledOnValidThread()); 364 DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed(" 365 << request_id << ")"; 366 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id); 367 if (!request_info) { 368 // This can happen if the request is canceled or the frame reloads while 369 // MediaStreamDispatcher is processing the request. 370 DVLOG(1) << "Request ID not found"; 371 return; 372 } 373 CompleteGetUserMediaRequest(request_info->web_stream, 374 &request_info->request, 375 false); 376 DeleteUserMediaRequestInfo(request_info); 377 } 378 379 // Callback from MediaStreamDispatcher. 380 // The user has requested to stop the media stream. 381 void MediaStreamImpl::OnStopGeneratedStream(const std::string& label) { 382 DCHECK(CalledOnValidThread()); 383 DVLOG(1) << "MediaStreamImpl::OnStopGeneratedStream(" << label << ")"; 384 385 UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label); 386 if (user_media_request) { 387 // No need to call media_stream_dispatcher_->StopStream() because the 388 // request has come from the browser process. 389 StopLocalAudioTrack(user_media_request->web_stream); 390 DeleteUserMediaRequestInfo(user_media_request); 391 } else { 392 DVLOG(1) << "MediaStreamImpl::OnStopGeneratedStream: the stream has " 393 << "already been stopped."; 394 } 395 } 396 397 // Callback from MediaStreamDependencyFactory when the sources in |web_stream| 398 // have been generated. 399 void MediaStreamImpl::OnCreateNativeSourcesComplete( 400 WebKit::WebMediaStream* web_stream, 401 bool request_succeeded) { 402 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(web_stream); 403 if (!request_info) { 404 // This can happen if the request is canceled or the frame reloads while 405 // MediaStreamDependencyFactory is creating the sources. 406 DVLOG(1) << "Request ID not found"; 407 return; 408 } 409 410 // Create a native representation of the stream. 411 if (request_succeeded) { 412 dependency_factory_->CreateNativeLocalMediaStream( 413 web_stream, 414 base::Bind(&MediaStreamImpl::OnLocalMediaStreamStop, AsWeakPtr())); 415 } 416 CompleteGetUserMediaRequest(request_info->web_stream, &request_info->request, 417 request_succeeded); 418 if (!request_succeeded) { 419 OnLocalMediaStreamStop(UTF16ToUTF8(web_stream->id())); 420 } 421 } 422 423 void MediaStreamImpl::OnDevicesEnumerated( 424 int request_id, 425 const StreamDeviceInfoArray& device_array) { 426 DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerated(" 427 << request_id << ")"; 428 NOTIMPLEMENTED(); 429 } 430 431 void MediaStreamImpl::OnDevicesEnumerationFailed(int request_id) { 432 DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerationFailed(" 433 << request_id << ")"; 434 NOTIMPLEMENTED(); 435 } 436 437 void MediaStreamImpl::OnDeviceOpened( 438 int request_id, 439 const std::string& label, 440 const StreamDeviceInfo& video_device) { 441 DVLOG(1) << "MediaStreamImpl::OnDeviceOpened(" 442 << request_id << ", " << label << ")"; 443 NOTIMPLEMENTED(); 444 } 445 446 void MediaStreamImpl::OnDeviceOpenFailed(int request_id) { 447 DVLOG(1) << "MediaStreamImpl::VideoDeviceOpenFailed(" 448 << request_id << ")"; 449 NOTIMPLEMENTED(); 450 } 451 452 void MediaStreamImpl::CompleteGetUserMediaRequest( 453 const WebKit::WebMediaStream& stream, 454 WebKit::WebUserMediaRequest* request_info, 455 bool request_succeeded) { 456 if (request_succeeded) { 457 request_info->requestSucceeded(stream); 458 } else { 459 request_info->requestFailed(); 460 } 461 } 462 463 MediaStreamImpl::UserMediaRequestInfo* 464 MediaStreamImpl::FindUserMediaRequestInfo(int request_id) { 465 UserMediaRequests::iterator it = user_media_requests_.begin(); 466 for (; it != user_media_requests_.end(); ++it) { 467 if ((*it)->request_id == request_id) 468 return (*it); 469 } 470 return NULL; 471 } 472 473 MediaStreamImpl::UserMediaRequestInfo* 474 MediaStreamImpl::FindUserMediaRequestInfo( 475 const WebKit::WebUserMediaRequest& request) { 476 UserMediaRequests::iterator it = user_media_requests_.begin(); 477 for (; it != user_media_requests_.end(); ++it) { 478 if ((*it)->request == request) 479 return (*it); 480 } 481 return NULL; 482 } 483 484 MediaStreamImpl::UserMediaRequestInfo* 485 MediaStreamImpl::FindUserMediaRequestInfo(const std::string& label) { 486 UserMediaRequests::iterator it = user_media_requests_.begin(); 487 for (; it != user_media_requests_.end(); ++it) { 488 if ((*it)->generated && (*it)->web_stream.id() == UTF8ToUTF16(label)) 489 return (*it); 490 } 491 return NULL; 492 } 493 494 MediaStreamImpl::UserMediaRequestInfo* 495 MediaStreamImpl::FindUserMediaRequestInfo( 496 WebKit::WebMediaStream* web_stream) { 497 UserMediaRequests::iterator it = user_media_requests_.begin(); 498 for (; it != user_media_requests_.end(); ++it) { 499 if (&((*it)->web_stream) == web_stream) 500 return (*it); 501 } 502 return NULL; 503 } 504 505 void MediaStreamImpl::DeleteUserMediaRequestInfo( 506 UserMediaRequestInfo* request) { 507 UserMediaRequests::iterator it = user_media_requests_.begin(); 508 for (; it != user_media_requests_.end(); ++it) { 509 if ((*it) == request) { 510 user_media_requests_.erase(it); 511 return; 512 } 513 } 514 NOTREACHED(); 515 } 516 517 void MediaStreamImpl::FrameDetached(WebKit::WebFrame* frame) { 518 // Do same thing as FrameWillClose. 519 FrameWillClose(frame); 520 } 521 522 void MediaStreamImpl::FrameWillClose(WebKit::WebFrame* frame) { 523 // Loop through all UserMediaRequests and find the requests that belong to the 524 // frame that is being closed. 525 UserMediaRequests::iterator request_it = user_media_requests_.begin(); 526 527 while (request_it != user_media_requests_.end()) { 528 if ((*request_it)->frame == frame) { 529 DVLOG(1) << "MediaStreamImpl::FrameWillClose: " 530 << "Cancel user media request " << (*request_it)->request_id; 531 // If the request is generated, it means that the MediaStreamDispatcher 532 // has generated a stream for us and we need to let the 533 // MediaStreamDispatcher know that the stream is no longer wanted. 534 // If not, we cancel the request and delete the request object. 535 if ((*request_it)->generated) { 536 // Stop the local audio track before closing the device in the browser. 537 StopLocalAudioTrack((*request_it)->web_stream); 538 539 media_stream_dispatcher_->StopStream( 540 UTF16ToUTF8((*request_it)->web_stream.id())); 541 } else { 542 media_stream_dispatcher_->CancelGenerateStream( 543 (*request_it)->request_id, AsWeakPtr()); 544 } 545 request_it = user_media_requests_.erase(request_it); 546 } else { 547 ++request_it; 548 } 549 } 550 } 551 552 scoped_refptr<VideoFrameProvider> 553 MediaStreamImpl::CreateVideoFrameProvider( 554 webrtc::MediaStreamInterface* stream, 555 const base::Closure& error_cb, 556 const VideoFrameProvider::RepaintCB& repaint_cb) { 557 if (stream->GetVideoTracks().empty()) 558 return NULL; 559 560 DVLOG(1) << "MediaStreamImpl::CreateRemoteVideoFrameProvider label:" 561 << stream->label(); 562 563 return new RTCVideoRenderer( 564 stream->GetVideoTracks()[0], 565 error_cb, 566 repaint_cb); 567 } 568 569 scoped_refptr<WebRtcAudioRenderer> MediaStreamImpl::CreateRemoteAudioRenderer( 570 webrtc::MediaStreamInterface* stream) { 571 if (stream->GetAudioTracks().empty()) 572 return NULL; 573 574 DVLOG(1) << "MediaStreamImpl::CreateRemoteAudioRenderer label:" 575 << stream->label(); 576 577 return new WebRtcAudioRenderer(RenderViewObserver::routing_id()); 578 } 579 580 scoped_refptr<WebRtcLocalAudioRenderer> 581 MediaStreamImpl::CreateLocalAudioRenderer( 582 webrtc::MediaStreamInterface* stream) { 583 if (stream->GetAudioTracks().empty()) 584 return NULL; 585 586 DVLOG(1) << "MediaStreamImpl::CreateLocalAudioRenderer label:" 587 << stream->label(); 588 589 webrtc::AudioTrackVector audio_tracks = stream->GetAudioTracks(); 590 DCHECK_EQ(audio_tracks.size(), 1u); 591 webrtc::AudioTrackInterface* audio_track = audio_tracks[0]; 592 DVLOG(1) << "audio_track.kind : " << audio_track->kind() 593 << "audio_track.id : " << audio_track->id() 594 << "audio_track.enabled: " << audio_track->enabled(); 595 596 // Create a new WebRtcLocalAudioRenderer instance and connect it to the 597 // existing WebRtcAudioCapturer so that the renderer can use it as source. 598 return new WebRtcLocalAudioRenderer( 599 static_cast<WebRtcLocalAudioTrack*>(audio_track), 600 RenderViewObserver::routing_id()); 601 } 602 603 void MediaStreamImpl::StopLocalAudioTrack( 604 const WebKit::WebMediaStream& web_stream) { 605 MediaStreamExtraData* extra_data = static_cast<MediaStreamExtraData*>( 606 web_stream.extraData()); 607 if (extra_data && extra_data->is_local() && extra_data->stream().get() && 608 !extra_data->stream()->GetAudioTracks().empty()) { 609 webrtc::AudioTrackVector audio_tracks = 610 extra_data->stream()->GetAudioTracks(); 611 for (size_t i = 0; i < audio_tracks.size(); ++i) { 612 WebRtcLocalAudioTrack* audio_track = static_cast<WebRtcLocalAudioTrack*>( 613 audio_tracks[i].get()); 614 // Remove the WebRtcAudioDevice as the sink to the local audio track. 615 audio_track->RemoveSink(dependency_factory_->GetWebRtcAudioDevice()); 616 // Stop the audio track. This will unhook the audio track from the 617 // capturer and will shutdown the source of the capturer if it is the 618 // last audio track connecting to the capturer. 619 audio_track->Stop(); 620 } 621 } 622 } 623 624 MediaStreamSourceExtraData::MediaStreamSourceExtraData( 625 const StreamDeviceInfo& device_info, 626 const WebKit::WebMediaStreamSource& webkit_source) 627 : device_info_(device_info), 628 webkit_source_(webkit_source) { 629 } 630 631 MediaStreamSourceExtraData::MediaStreamSourceExtraData( 632 media::AudioCapturerSource* source) 633 : audio_source_(source) { 634 } 635 636 MediaStreamSourceExtraData::~MediaStreamSourceExtraData() {} 637 638 MediaStreamExtraData::MediaStreamExtraData( 639 webrtc::MediaStreamInterface* stream, bool is_local) 640 : stream_(stream), 641 is_local_(is_local) { 642 } 643 644 MediaStreamExtraData::~MediaStreamExtraData() { 645 } 646 647 void MediaStreamExtraData::SetLocalStreamStopCallback( 648 const StreamStopCallback& stop_callback) { 649 stream_stop_callback_ = stop_callback; 650 } 651 652 void MediaStreamExtraData::OnLocalStreamStop() { 653 if (!stream_stop_callback_.is_null()) 654 stream_stop_callback_.Run(stream_->label()); 655 } 656 657 MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo() 658 : request_id(0), generated(false), frame(NULL), request() { 659 } 660 661 MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo( 662 int request_id, 663 WebKit::WebFrame* frame, 664 const WebKit::WebUserMediaRequest& request) 665 : request_id(request_id), generated(false), frame(frame), 666 request(request) { 667 } 668 669 MediaStreamImpl::UserMediaRequestInfo::~UserMediaRequestInfo() { 670 // Release the extra data field of all sources created by 671 // MediaStreamImpl for this request. This breaks the circular reference to 672 // WebKit::MediaStreamSource. 673 // TODO(tommyw): Remove this once WebKit::MediaStreamSource::Owner has been 674 // implemented to fully avoid a circular dependency. 675 for (size_t i = 0; i < audio_sources.size(); ++i) { 676 audio_sources[i].setReadyState( 677 WebKit::WebMediaStreamSource::ReadyStateEnded); 678 audio_sources[i].setExtraData(NULL); 679 } 680 681 for (size_t i = 0; i < video_sources.size(); ++i) { 682 video_sources[i].setReadyState( 683 WebKit::WebMediaStreamSource::ReadyStateEnded); 684 video_sources[i].setExtraData(NULL); 685 } 686 } 687 688 } // namespace content 689