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/hash.h" 10 #include "base/logging.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "content/renderer/media/media_stream.h" 16 #include "content/renderer/media/media_stream_audio_source.h" 17 #include "content/renderer/media/media_stream_dispatcher.h" 18 #include "content/renderer/media/media_stream_video_capturer_source.h" 19 #include "content/renderer/media/media_stream_video_track.h" 20 #include "content/renderer/media/peer_connection_tracker.h" 21 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" 22 #include "content/renderer/media/webrtc_audio_capturer.h" 23 #include "content/renderer/media/webrtc_logging.h" 24 #include "content/renderer/media/webrtc_uma_histograms.h" 25 #include "content/renderer/render_thread_impl.h" 26 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 27 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h" 28 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 29 #include "third_party/WebKit/public/web/WebDocument.h" 30 #include "third_party/WebKit/public/web/WebLocalFrame.h" 31 32 namespace content { 33 namespace { 34 35 void CopyStreamConstraints(const blink::WebMediaConstraints& constraints, 36 StreamOptions::Constraints* mandatory, 37 StreamOptions::Constraints* optional) { 38 blink::WebVector<blink::WebMediaConstraint> mandatory_constraints; 39 constraints.getMandatoryConstraints(mandatory_constraints); 40 for (size_t i = 0; i < mandatory_constraints.size(); i++) { 41 mandatory->push_back(StreamOptions::Constraint( 42 mandatory_constraints[i].m_name.utf8(), 43 mandatory_constraints[i].m_value.utf8())); 44 } 45 46 blink::WebVector<blink::WebMediaConstraint> optional_constraints; 47 constraints.getOptionalConstraints(optional_constraints); 48 for (size_t i = 0; i < optional_constraints.size(); i++) { 49 optional->push_back(StreamOptions::Constraint( 50 optional_constraints[i].m_name.utf8(), 51 optional_constraints[i].m_value.utf8())); 52 } 53 } 54 55 static int g_next_request_id = 0; 56 57 } // namespace 58 59 struct MediaStreamImpl::MediaDevicesRequestInfo { 60 MediaDevicesRequestInfo(const blink::WebMediaDevicesRequest& request, 61 int audio_input_request_id, 62 int video_input_request_id, 63 int audio_output_request_id) 64 : request(request), 65 audio_input_request_id(audio_input_request_id), 66 video_input_request_id(video_input_request_id), 67 audio_output_request_id(audio_output_request_id), 68 has_audio_input_returned(false), 69 has_video_input_returned(false), 70 has_audio_output_returned(false) {} 71 72 blink::WebMediaDevicesRequest request; 73 int audio_input_request_id; 74 int video_input_request_id; 75 int audio_output_request_id; 76 bool has_audio_input_returned; 77 bool has_video_input_returned; 78 bool has_audio_output_returned; 79 StreamDeviceInfoArray audio_input_devices; 80 StreamDeviceInfoArray video_input_devices; 81 StreamDeviceInfoArray audio_output_devices; 82 }; 83 84 MediaStreamImpl::MediaStreamImpl( 85 RenderView* render_view, 86 MediaStreamDispatcher* media_stream_dispatcher, 87 PeerConnectionDependencyFactory* dependency_factory) 88 : RenderViewObserver(render_view), 89 dependency_factory_(dependency_factory), 90 media_stream_dispatcher_(media_stream_dispatcher) { 91 } 92 93 MediaStreamImpl::~MediaStreamImpl() { 94 } 95 96 void MediaStreamImpl::requestUserMedia( 97 const blink::WebUserMediaRequest& user_media_request) { 98 // Save histogram data so we can see how much GetUserMedia is used. 99 // The histogram counts the number of calls to the JS API 100 // webGetUserMedia. 101 UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA); 102 DCHECK(CalledOnValidThread()); 103 104 if (RenderThreadImpl::current()) { 105 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia( 106 user_media_request); 107 } 108 109 int request_id = g_next_request_id++; 110 StreamOptions options; 111 blink::WebLocalFrame* frame = NULL; 112 GURL security_origin; 113 bool enable_automatic_output_device_selection = false; 114 115 // |user_media_request| can't be mocked. So in order to test at all we check 116 // if it isNull. 117 if (user_media_request.isNull()) { 118 // We are in a test. 119 options.audio_requested = true; 120 options.video_requested = true; 121 } else { 122 if (user_media_request.audio()) { 123 options.audio_requested = true; 124 CopyStreamConstraints(user_media_request.audioConstraints(), 125 &options.mandatory_audio, 126 &options.optional_audio); 127 128 // Check if this input device should be used to select a matching output 129 // device for audio rendering. 130 std::string enable; 131 if (options.GetFirstAudioConstraintByName( 132 kMediaStreamRenderToAssociatedSink, &enable, NULL) && 133 LowerCaseEqualsASCII(enable, "true")) { 134 enable_automatic_output_device_selection = true; 135 } 136 } 137 if (user_media_request.video()) { 138 options.video_requested = true; 139 CopyStreamConstraints(user_media_request.videoConstraints(), 140 &options.mandatory_video, 141 &options.optional_video); 142 } 143 144 security_origin = GURL(user_media_request.securityOrigin().toString()); 145 // Get the WebFrame that requested a MediaStream. 146 // The frame is needed to tell the MediaStreamDispatcher when a stream goes 147 // out of scope. 148 frame = user_media_request.ownerDocument().frame(); 149 DCHECK(frame); 150 } 151 152 DVLOG(1) << "MediaStreamImpl::requestUserMedia(" << request_id << ", [ " 153 << "audio=" << (options.audio_requested) 154 << " select associated sink: " 155 << enable_automatic_output_device_selection 156 << ", video=" << (options.video_requested) << " ], " 157 << security_origin.spec() << ")"; 158 159 std::string audio_device_id; 160 bool mandatory_audio; 161 options.GetFirstAudioConstraintByName(kMediaStreamSourceInfoId, 162 &audio_device_id, &mandatory_audio); 163 std::string video_device_id; 164 bool mandatory_video; 165 options.GetFirstVideoConstraintByName(kMediaStreamSourceInfoId, 166 &video_device_id, &mandatory_video); 167 168 WebRtcLogMessage(base::StringPrintf( 169 "MSI::requestUserMedia. request_id=%d" 170 ", audio source id=%s mandatory= %s " 171 ", video source id=%s mandatory= %s", 172 request_id, 173 audio_device_id.c_str(), 174 mandatory_audio ? "true":"false", 175 video_device_id.c_str(), 176 mandatory_video ? "true":"false")); 177 178 user_media_requests_.push_back( 179 new UserMediaRequestInfo(request_id, frame, user_media_request, 180 enable_automatic_output_device_selection)); 181 182 media_stream_dispatcher_->GenerateStream( 183 request_id, 184 AsWeakPtr(), 185 options, 186 security_origin); 187 } 188 189 void MediaStreamImpl::cancelUserMediaRequest( 190 const blink::WebUserMediaRequest& user_media_request) { 191 DCHECK(CalledOnValidThread()); 192 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request); 193 if (request) { 194 // We can't abort the stream generation process. 195 // Instead, erase the request. Once the stream is generated we will stop the 196 // stream if the request does not exist. 197 DeleteUserMediaRequestInfo(request); 198 } 199 } 200 201 void MediaStreamImpl::requestMediaDevices( 202 const blink::WebMediaDevicesRequest& media_devices_request) { 203 UpdateWebRTCMethodCount(WEBKIT_GET_MEDIA_DEVICES); 204 DCHECK(CalledOnValidThread()); 205 206 int audio_input_request_id = g_next_request_id++; 207 int video_input_request_id = g_next_request_id++; 208 int audio_output_request_id = g_next_request_id++; 209 210 // |media_devices_request| can't be mocked, so in tests it will be empty (the 211 // underlying pointer is null). In order to use this function in a test we 212 // need to check if it isNull. 213 GURL security_origin; 214 if (!media_devices_request.isNull()) 215 security_origin = GURL(media_devices_request.securityOrigin().toString()); 216 217 DVLOG(1) << "MediaStreamImpl::requestMediaDevices(" << audio_input_request_id 218 << ", " << video_input_request_id << ", " << audio_output_request_id 219 << ", " << security_origin.spec() << ")"; 220 221 media_devices_requests_.push_back(new MediaDevicesRequestInfo( 222 media_devices_request, 223 audio_input_request_id, 224 video_input_request_id, 225 audio_output_request_id)); 226 227 media_stream_dispatcher_->EnumerateDevices( 228 audio_input_request_id, 229 AsWeakPtr(), 230 MEDIA_DEVICE_AUDIO_CAPTURE, 231 security_origin, 232 true); 233 234 media_stream_dispatcher_->EnumerateDevices( 235 video_input_request_id, 236 AsWeakPtr(), 237 MEDIA_DEVICE_VIDEO_CAPTURE, 238 security_origin, 239 true); 240 241 media_stream_dispatcher_->EnumerateDevices( 242 audio_output_request_id, 243 AsWeakPtr(), 244 MEDIA_DEVICE_AUDIO_OUTPUT, 245 security_origin, 246 true); 247 } 248 249 void MediaStreamImpl::cancelMediaDevicesRequest( 250 const blink::WebMediaDevicesRequest& media_devices_request) { 251 DCHECK(CalledOnValidThread()); 252 MediaDevicesRequestInfo* request = 253 FindMediaDevicesRequestInfo(media_devices_request); 254 if (!request) 255 return; 256 257 // Cancel device enumeration. 258 media_stream_dispatcher_->StopEnumerateDevices( 259 request->audio_input_request_id, 260 AsWeakPtr()); 261 media_stream_dispatcher_->StopEnumerateDevices( 262 request->video_input_request_id, 263 AsWeakPtr()); 264 media_stream_dispatcher_->StopEnumerateDevices( 265 request->audio_output_request_id, 266 AsWeakPtr()); 267 DeleteMediaDevicesRequestInfo(request); 268 } 269 270 // Callback from MediaStreamDispatcher. 271 // The requested stream have been generated by the MediaStreamDispatcher. 272 void MediaStreamImpl::OnStreamGenerated( 273 int request_id, 274 const std::string& label, 275 const StreamDeviceInfoArray& audio_array, 276 const StreamDeviceInfoArray& video_array) { 277 DCHECK(CalledOnValidThread()); 278 DVLOG(1) << "MediaStreamImpl::OnStreamGenerated stream:" << label; 279 280 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id); 281 if (!request_info) { 282 // This can happen if the request is canceled or the frame reloads while 283 // MediaStreamDispatcher is processing the request. 284 // Only stop the device if the device is not used in another MediaStream. 285 for (StreamDeviceInfoArray::const_iterator device_it = audio_array.begin(); 286 device_it != audio_array.end(); ++device_it) { 287 if (!FindLocalSource(*device_it)) 288 media_stream_dispatcher_->StopStreamDevice(*device_it); 289 } 290 291 for (StreamDeviceInfoArray::const_iterator device_it = video_array.begin(); 292 device_it != video_array.end(); ++device_it) { 293 if (!FindLocalSource(*device_it)) 294 media_stream_dispatcher_->StopStreamDevice(*device_it); 295 } 296 297 DVLOG(1) << "Request ID not found"; 298 return; 299 } 300 request_info->generated = true; 301 302 // WebUserMediaRequest don't have an implementation in unit tests. 303 // Therefore we need to check for isNull here and initialize the 304 // constraints. 305 blink::WebUserMediaRequest* request = &(request_info->request); 306 blink::WebMediaConstraints audio_constraints; 307 blink::WebMediaConstraints video_constraints; 308 if (request->isNull()) { 309 audio_constraints.initialize(); 310 video_constraints.initialize(); 311 } else { 312 audio_constraints = request->audioConstraints(); 313 video_constraints = request->videoConstraints(); 314 } 315 316 blink::WebVector<blink::WebMediaStreamTrack> audio_track_vector( 317 audio_array.size()); 318 CreateAudioTracks(audio_array, audio_constraints, &audio_track_vector, 319 request_info); 320 321 blink::WebVector<blink::WebMediaStreamTrack> video_track_vector( 322 video_array.size()); 323 CreateVideoTracks(video_array, video_constraints, &video_track_vector, 324 request_info); 325 326 blink::WebString webkit_id = base::UTF8ToUTF16(label); 327 blink::WebMediaStream* web_stream = &(request_info->web_stream); 328 329 web_stream->initialize(webkit_id, audio_track_vector, 330 video_track_vector); 331 web_stream->setExtraData( 332 new MediaStream( 333 *web_stream)); 334 335 // Wait for the tracks to be started successfully or to fail. 336 request_info->CallbackOnTracksStarted( 337 base::Bind(&MediaStreamImpl::OnCreateNativeTracksCompleted, AsWeakPtr())); 338 } 339 340 // Callback from MediaStreamDispatcher. 341 // The requested stream failed to be generated. 342 void MediaStreamImpl::OnStreamGenerationFailed( 343 int request_id, 344 content::MediaStreamRequestResult result) { 345 DCHECK(CalledOnValidThread()); 346 DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed(" 347 << request_id << ")"; 348 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id); 349 if (!request_info) { 350 // This can happen if the request is canceled or the frame reloads while 351 // MediaStreamDispatcher is processing the request. 352 DVLOG(1) << "Request ID not found"; 353 return; 354 } 355 356 GetUserMediaRequestFailed(&request_info->request, result); 357 DeleteUserMediaRequestInfo(request_info); 358 } 359 360 // Callback from MediaStreamDispatcher. 361 // The browser process has stopped a device used by a MediaStream. 362 void MediaStreamImpl::OnDeviceStopped( 363 const std::string& label, 364 const StreamDeviceInfo& device_info) { 365 DCHECK(CalledOnValidThread()); 366 DVLOG(1) << "MediaStreamImpl::OnDeviceStopped(" 367 << "{device_id = " << device_info.device.id << "})"; 368 369 const blink::WebMediaStreamSource* source_ptr = FindLocalSource(device_info); 370 if (!source_ptr) { 371 // This happens if the same device is used in several guM requests or 372 // if a user happen stop a track from JS at the same time 373 // as the underlying media device is unplugged from the system. 374 return; 375 } 376 // By creating |source| it is guaranteed that the blink::WebMediaStreamSource 377 // object is valid during the cleanup. 378 blink::WebMediaStreamSource source(*source_ptr); 379 StopLocalSource(source, false); 380 381 for (LocalStreamSources::iterator device_it = local_sources_.begin(); 382 device_it != local_sources_.end(); ++device_it) { 383 if (device_it->source.id() == source.id()) { 384 local_sources_.erase(device_it); 385 break; 386 } 387 } 388 } 389 390 void MediaStreamImpl::InitializeSourceObject( 391 const StreamDeviceInfo& device, 392 blink::WebMediaStreamSource::Type type, 393 const blink::WebMediaConstraints& constraints, 394 blink::WebFrame* frame, 395 blink::WebMediaStreamSource* webkit_source) { 396 const blink::WebMediaStreamSource* existing_source = 397 FindLocalSource(device); 398 if (existing_source) { 399 *webkit_source = *existing_source; 400 DVLOG(1) << "Source already exist. Reusing source with id " 401 << webkit_source->id().utf8(); 402 return; 403 } 404 405 webkit_source->initialize( 406 base::UTF8ToUTF16(device.device.id), 407 type, 408 base::UTF8ToUTF16(device.device.name)); 409 410 DVLOG(1) << "Initialize source object :" 411 << "id = " << webkit_source->id().utf8() 412 << ", name = " << webkit_source->name().utf8(); 413 414 if (type == blink::WebMediaStreamSource::TypeVideo) { 415 webkit_source->setExtraData( 416 CreateVideoSource( 417 device, 418 base::Bind(&MediaStreamImpl::OnLocalSourceStopped, AsWeakPtr()))); 419 } else { 420 DCHECK_EQ(blink::WebMediaStreamSource::TypeAudio, type); 421 MediaStreamAudioSource* audio_source( 422 new MediaStreamAudioSource( 423 RenderViewObserver::routing_id(), 424 device, 425 base::Bind(&MediaStreamImpl::OnLocalSourceStopped, AsWeakPtr()), 426 dependency_factory_)); 427 webkit_source->setExtraData(audio_source); 428 } 429 local_sources_.push_back(LocalStreamSource(frame, *webkit_source)); 430 } 431 432 MediaStreamVideoSource* MediaStreamImpl::CreateVideoSource( 433 const StreamDeviceInfo& device, 434 const MediaStreamSource::SourceStoppedCallback& stop_callback) { 435 return new content::MediaStreamVideoCapturerSource( 436 device, 437 stop_callback, 438 new VideoCapturerDelegate(device)); 439 } 440 441 void MediaStreamImpl::CreateVideoTracks( 442 const StreamDeviceInfoArray& devices, 443 const blink::WebMediaConstraints& constraints, 444 blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks, 445 UserMediaRequestInfo* request) { 446 DCHECK_EQ(devices.size(), webkit_tracks->size()); 447 448 for (size_t i = 0; i < devices.size(); ++i) { 449 blink::WebMediaStreamSource webkit_source; 450 InitializeSourceObject(devices[i], 451 blink::WebMediaStreamSource::TypeVideo, 452 constraints, 453 request->frame, 454 &webkit_source); 455 (*webkit_tracks)[i] = 456 request->CreateAndStartVideoTrack(webkit_source, constraints); 457 } 458 } 459 460 void MediaStreamImpl::CreateAudioTracks( 461 const StreamDeviceInfoArray& devices, 462 const blink::WebMediaConstraints& constraints, 463 blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks, 464 UserMediaRequestInfo* request) { 465 DCHECK_EQ(devices.size(), webkit_tracks->size()); 466 467 // Log the device names for this request. 468 for (StreamDeviceInfoArray::const_iterator it = devices.begin(); 469 it != devices.end(); ++it) { 470 WebRtcLogMessage(base::StringPrintf( 471 "Generated media stream for request id %d contains audio device name" 472 " \"%s\"", 473 request->request_id, 474 it->device.name.c_str())); 475 } 476 477 StreamDeviceInfoArray overridden_audio_array = devices; 478 if (!request->enable_automatic_output_device_selection) { 479 // If the GetUserMedia request did not explicitly set the constraint 480 // kMediaStreamRenderToAssociatedSink, the output device parameters must 481 // be removed. 482 for (StreamDeviceInfoArray::iterator it = overridden_audio_array.begin(); 483 it != overridden_audio_array.end(); ++it) { 484 it->device.matched_output_device_id = ""; 485 it->device.matched_output = MediaStreamDevice::AudioDeviceParameters(); 486 } 487 } 488 489 for (size_t i = 0; i < overridden_audio_array.size(); ++i) { 490 blink::WebMediaStreamSource webkit_source; 491 InitializeSourceObject(overridden_audio_array[i], 492 blink::WebMediaStreamSource::TypeAudio, 493 constraints, 494 request->frame, 495 &webkit_source); 496 (*webkit_tracks)[i].initialize(webkit_source); 497 request->StartAudioTrack((*webkit_tracks)[i], constraints); 498 } 499 } 500 501 void MediaStreamImpl::OnCreateNativeTracksCompleted( 502 UserMediaRequestInfo* request, 503 content::MediaStreamRequestResult result) { 504 DVLOG(1) << "MediaStreamImpl::OnCreateNativeTracksComplete(" 505 << "{request_id = " << request->request_id << "} " 506 << "{result = " << result << "})"; 507 if (result == content::MEDIA_DEVICE_OK) 508 GetUserMediaRequestSucceeded(request->web_stream, &request->request); 509 else 510 GetUserMediaRequestFailed(&request->request, result); 511 512 DeleteUserMediaRequestInfo(request); 513 } 514 515 void MediaStreamImpl::OnDevicesEnumerated( 516 int request_id, 517 const StreamDeviceInfoArray& device_array) { 518 DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerated(" << request_id << ")"; 519 520 MediaDevicesRequestInfo* request = FindMediaDevicesRequestInfo(request_id); 521 DCHECK(request); 522 523 if (request_id == request->audio_input_request_id) { 524 request->has_audio_input_returned = true; 525 DCHECK(request->audio_input_devices.empty()); 526 request->audio_input_devices = device_array; 527 } else if (request_id == request->video_input_request_id) { 528 request->has_video_input_returned = true; 529 DCHECK(request->video_input_devices.empty()); 530 request->video_input_devices = device_array; 531 } else { 532 DCHECK_EQ(request->audio_output_request_id, request_id); 533 request->has_audio_output_returned = true; 534 DCHECK(request->audio_output_devices.empty()); 535 request->audio_output_devices = device_array; 536 } 537 538 if (!request->has_audio_input_returned || 539 !request->has_video_input_returned || 540 !request->has_audio_output_returned) { 541 // Wait for the rest of the devices to complete. 542 return; 543 } 544 545 // All devices are ready for copying. We use a hashed audio output device id 546 // as the group id for input and output audio devices. If an input device 547 // doesn't have an associated output device, we use the input device's own id. 548 // We don't support group id for video devices, that's left empty. 549 blink::WebVector<blink::WebMediaDeviceInfo> 550 devices(request->audio_input_devices.size() + 551 request->video_input_devices.size() + 552 request->audio_output_devices.size()); 553 for (size_t i = 0; i < request->audio_input_devices.size(); ++i) { 554 const MediaStreamDevice& device = request->audio_input_devices[i].device; 555 DCHECK_EQ(device.type, MEDIA_DEVICE_AUDIO_CAPTURE); 556 std::string group_id = base::UintToString(base::Hash( 557 !device.matched_output_device_id.empty() ? 558 device.matched_output_device_id : 559 device.id)); 560 devices[i].initialize( 561 blink::WebString::fromUTF8(device.id), 562 blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput, 563 blink::WebString::fromUTF8(device.name), 564 blink::WebString::fromUTF8(group_id)); 565 } 566 size_t offset = request->audio_input_devices.size(); 567 for (size_t i = 0; i < request->video_input_devices.size(); ++i) { 568 const MediaStreamDevice& device = request->video_input_devices[i].device; 569 DCHECK_EQ(device.type, MEDIA_DEVICE_VIDEO_CAPTURE); 570 devices[offset + i].initialize( 571 blink::WebString::fromUTF8(device.id), 572 blink::WebMediaDeviceInfo::MediaDeviceKindVideoInput, 573 blink::WebString::fromUTF8(device.name), 574 blink::WebString()); 575 } 576 offset += request->video_input_devices.size(); 577 for (size_t i = 0; i < request->audio_output_devices.size(); ++i) { 578 const MediaStreamDevice& device = request->audio_output_devices[i].device; 579 DCHECK_EQ(device.type, MEDIA_DEVICE_AUDIO_OUTPUT); 580 devices[offset + i].initialize( 581 blink::WebString::fromUTF8(device.id), 582 blink::WebMediaDeviceInfo::MediaDeviceKindAudioOutput, 583 blink::WebString::fromUTF8(device.name), 584 blink::WebString::fromUTF8(base::UintToString(base::Hash(device.id)))); 585 } 586 587 EnumerateDevicesSucceded(&request->request, devices); 588 589 // Cancel device enumeration. 590 media_stream_dispatcher_->StopEnumerateDevices( 591 request->audio_input_request_id, 592 AsWeakPtr()); 593 media_stream_dispatcher_->StopEnumerateDevices( 594 request->video_input_request_id, 595 AsWeakPtr()); 596 media_stream_dispatcher_->StopEnumerateDevices( 597 request->audio_output_request_id, 598 AsWeakPtr()); 599 600 DeleteMediaDevicesRequestInfo(request); 601 } 602 603 void MediaStreamImpl::OnDeviceOpened( 604 int request_id, 605 const std::string& label, 606 const StreamDeviceInfo& video_device) { 607 DVLOG(1) << "MediaStreamImpl::OnDeviceOpened(" 608 << request_id << ", " << label << ")"; 609 NOTIMPLEMENTED(); 610 } 611 612 void MediaStreamImpl::OnDeviceOpenFailed(int request_id) { 613 DVLOG(1) << "MediaStreamImpl::VideoDeviceOpenFailed(" 614 << request_id << ")"; 615 NOTIMPLEMENTED(); 616 } 617 618 void MediaStreamImpl::GetUserMediaRequestSucceeded( 619 const blink::WebMediaStream& stream, 620 blink::WebUserMediaRequest* request_info) { 621 DVLOG(1) << "MediaStreamImpl::GetUserMediaRequestSucceeded"; 622 request_info->requestSucceeded(stream); 623 } 624 625 void MediaStreamImpl::GetUserMediaRequestFailed( 626 blink::WebUserMediaRequest* request_info, 627 content::MediaStreamRequestResult result) { 628 switch (result) { 629 case MEDIA_DEVICE_OK: 630 NOTREACHED(); 631 break; 632 case MEDIA_DEVICE_PERMISSION_DENIED: 633 request_info->requestDenied(); 634 break; 635 case MEDIA_DEVICE_PERMISSION_DISMISSED: 636 request_info->requestFailedUASpecific("PermissionDismissedError"); 637 break; 638 case MEDIA_DEVICE_INVALID_STATE: 639 request_info->requestFailedUASpecific("InvalidStateError"); 640 break; 641 case MEDIA_DEVICE_NO_HARDWARE: 642 request_info->requestFailedUASpecific("DevicesNotFoundError"); 643 break; 644 case MEDIA_DEVICE_INVALID_SECURITY_ORIGIN: 645 request_info->requestFailedUASpecific("InvalidSecurityOriginError"); 646 break; 647 case MEDIA_DEVICE_TAB_CAPTURE_FAILURE: 648 request_info->requestFailedUASpecific("TabCaptureError"); 649 break; 650 case MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE: 651 request_info->requestFailedUASpecific("ScreenCaptureError"); 652 break; 653 case MEDIA_DEVICE_CAPTURE_FAILURE: 654 request_info->requestFailedUASpecific("DeviceCaptureError"); 655 break; 656 case MEDIA_DEVICE_TRACK_START_FAILURE: 657 request_info->requestFailedUASpecific("TrackStartError"); 658 break; 659 default: 660 request_info->requestFailed(); 661 break; 662 } 663 } 664 665 void MediaStreamImpl::EnumerateDevicesSucceded( 666 blink::WebMediaDevicesRequest* request, 667 blink::WebVector<blink::WebMediaDeviceInfo>& devices) { 668 request->requestSucceeded(devices); 669 } 670 671 const blink::WebMediaStreamSource* MediaStreamImpl::FindLocalSource( 672 const StreamDeviceInfo& device) const { 673 for (LocalStreamSources::const_iterator it = local_sources_.begin(); 674 it != local_sources_.end(); ++it) { 675 MediaStreamSource* source = 676 static_cast<MediaStreamSource*>(it->source.extraData()); 677 const StreamDeviceInfo& active_device = source->device_info(); 678 if (active_device.device.id == device.device.id && 679 active_device.device.type == device.device.type && 680 active_device.session_id == device.session_id) { 681 return &it->source; 682 } 683 } 684 return NULL; 685 } 686 687 MediaStreamImpl::UserMediaRequestInfo* 688 MediaStreamImpl::FindUserMediaRequestInfo(int request_id) { 689 UserMediaRequests::iterator it = user_media_requests_.begin(); 690 for (; it != user_media_requests_.end(); ++it) { 691 if ((*it)->request_id == request_id) 692 return (*it); 693 } 694 return NULL; 695 } 696 697 MediaStreamImpl::UserMediaRequestInfo* 698 MediaStreamImpl::FindUserMediaRequestInfo( 699 const blink::WebUserMediaRequest& request) { 700 UserMediaRequests::iterator it = user_media_requests_.begin(); 701 for (; it != user_media_requests_.end(); ++it) { 702 if ((*it)->request == request) 703 return (*it); 704 } 705 return NULL; 706 } 707 708 void MediaStreamImpl::DeleteUserMediaRequestInfo( 709 UserMediaRequestInfo* request) { 710 UserMediaRequests::iterator it = user_media_requests_.begin(); 711 for (; it != user_media_requests_.end(); ++it) { 712 if ((*it) == request) { 713 user_media_requests_.erase(it); 714 return; 715 } 716 } 717 NOTREACHED(); 718 } 719 720 MediaStreamImpl::MediaDevicesRequestInfo* 721 MediaStreamImpl::FindMediaDevicesRequestInfo( 722 int request_id) { 723 MediaDevicesRequests::iterator it = media_devices_requests_.begin(); 724 for (; it != media_devices_requests_.end(); ++it) { 725 if ((*it)->audio_input_request_id == request_id || 726 (*it)->video_input_request_id == request_id || 727 (*it)->audio_output_request_id == request_id) { 728 return (*it); 729 } 730 } 731 return NULL; 732 } 733 734 MediaStreamImpl::MediaDevicesRequestInfo* 735 MediaStreamImpl::FindMediaDevicesRequestInfo( 736 const blink::WebMediaDevicesRequest& request) { 737 MediaDevicesRequests::iterator it = media_devices_requests_.begin(); 738 for (; it != media_devices_requests_.end(); ++it) { 739 if ((*it)->request == request) 740 return (*it); 741 } 742 return NULL; 743 } 744 745 void MediaStreamImpl::DeleteMediaDevicesRequestInfo( 746 MediaDevicesRequestInfo* request) { 747 MediaDevicesRequests::iterator it = media_devices_requests_.begin(); 748 for (; it != media_devices_requests_.end(); ++it) { 749 if ((*it) == request) { 750 media_devices_requests_.erase(it); 751 return; 752 } 753 } 754 NOTREACHED(); 755 } 756 757 void MediaStreamImpl::FrameDetached(blink::WebFrame* frame) { 758 // Do same thing as FrameWillClose. 759 FrameWillClose(frame); 760 } 761 762 void MediaStreamImpl::FrameWillClose(blink::WebFrame* frame) { 763 // Loop through all UserMediaRequests and find the requests that belong to the 764 // frame that is being closed. 765 UserMediaRequests::iterator request_it = user_media_requests_.begin(); 766 while (request_it != user_media_requests_.end()) { 767 if ((*request_it)->frame == frame) { 768 DVLOG(1) << "MediaStreamImpl::FrameWillClose: " 769 << "Cancel user media request " << (*request_it)->request_id; 770 // If the request is not generated, it means that a request 771 // has been sent to the MediaStreamDispatcher to generate a stream 772 // but MediaStreamDispatcher has not yet responded and we need to cancel 773 // the request. 774 if (!(*request_it)->generated) { 775 media_stream_dispatcher_->CancelGenerateStream( 776 (*request_it)->request_id, AsWeakPtr()); 777 } 778 request_it = user_media_requests_.erase(request_it); 779 } else { 780 ++request_it; 781 } 782 } 783 784 // Loop through all current local sources and stop the sources that were 785 // created by the frame that will be closed. 786 LocalStreamSources::iterator sources_it = local_sources_.begin(); 787 while (sources_it != local_sources_.end()) { 788 if (sources_it->frame == frame) { 789 StopLocalSource(sources_it->source, true); 790 sources_it = local_sources_.erase(sources_it); 791 } else { 792 ++sources_it; 793 } 794 } 795 } 796 797 void MediaStreamImpl::OnLocalSourceStopped( 798 const blink::WebMediaStreamSource& source) { 799 DCHECK(CalledOnValidThread()); 800 DVLOG(1) << "MediaStreamImpl::OnLocalSourceStopped"; 801 802 bool device_found = false; 803 for (LocalStreamSources::iterator device_it = local_sources_.begin(); 804 device_it != local_sources_.end(); ++device_it) { 805 if (device_it->source.id() == source.id()) { 806 device_found = true; 807 local_sources_.erase(device_it); 808 break; 809 } 810 } 811 CHECK(device_found); 812 813 MediaStreamSource* source_impl = 814 static_cast<MediaStreamSource*> (source.extraData()); 815 media_stream_dispatcher_->StopStreamDevice(source_impl->device_info()); 816 } 817 818 void MediaStreamImpl::StopLocalSource( 819 const blink::WebMediaStreamSource& source, 820 bool notify_dispatcher) { 821 MediaStreamSource* source_impl = 822 static_cast<MediaStreamSource*> (source.extraData()); 823 DVLOG(1) << "MediaStreamImpl::StopLocalSource(" 824 << "{device_id = " << source_impl->device_info().device.id << "})"; 825 826 if (notify_dispatcher) 827 media_stream_dispatcher_->StopStreamDevice(source_impl->device_info()); 828 829 source_impl->ResetSourceStoppedCallback(); 830 source_impl->StopSource(); 831 } 832 833 MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo( 834 int request_id, 835 blink::WebFrame* frame, 836 const blink::WebUserMediaRequest& request, 837 bool enable_automatic_output_device_selection) 838 : request_id(request_id), 839 generated(false), 840 enable_automatic_output_device_selection( 841 enable_automatic_output_device_selection), 842 frame(frame), 843 request(request), 844 request_failed_(false) { 845 } 846 847 MediaStreamImpl::UserMediaRequestInfo::~UserMediaRequestInfo() { 848 DVLOG(1) << "~UserMediaRequestInfo"; 849 } 850 851 void MediaStreamImpl::UserMediaRequestInfo::StartAudioTrack( 852 const blink::WebMediaStreamTrack& track, 853 const blink::WebMediaConstraints& constraints) { 854 DCHECK(track.source().type() == blink::WebMediaStreamSource::TypeAudio); 855 MediaStreamAudioSource* native_source = 856 static_cast <MediaStreamAudioSource*>(track.source().extraData()); 857 DCHECK(native_source); 858 859 sources_.push_back(track.source()); 860 sources_waiting_for_callback_.push_back(native_source); 861 native_source->AddTrack( 862 track, constraints, base::Bind( 863 &MediaStreamImpl::UserMediaRequestInfo::OnTrackStarted, 864 AsWeakPtr())); 865 } 866 867 blink::WebMediaStreamTrack 868 MediaStreamImpl::UserMediaRequestInfo::CreateAndStartVideoTrack( 869 const blink::WebMediaStreamSource& source, 870 const blink::WebMediaConstraints& constraints) { 871 DCHECK(source.type() == blink::WebMediaStreamSource::TypeVideo); 872 MediaStreamVideoSource* native_source = 873 MediaStreamVideoSource::GetVideoSource(source); 874 DCHECK(native_source); 875 sources_.push_back(source); 876 sources_waiting_for_callback_.push_back(native_source); 877 return MediaStreamVideoTrack::CreateVideoTrack( 878 native_source, constraints, base::Bind( 879 &MediaStreamImpl::UserMediaRequestInfo::OnTrackStarted, 880 AsWeakPtr()), 881 true); 882 } 883 884 void MediaStreamImpl::UserMediaRequestInfo::CallbackOnTracksStarted( 885 const ResourcesReady& callback) { 886 DCHECK(ready_callback_.is_null()); 887 ready_callback_ = callback; 888 CheckAllTracksStarted(); 889 } 890 891 void MediaStreamImpl::UserMediaRequestInfo::OnTrackStarted( 892 MediaStreamSource* source, bool success) { 893 DVLOG(1) << "OnTrackStarted result " << success; 894 std::vector<MediaStreamSource*>::iterator it = 895 std::find(sources_waiting_for_callback_.begin(), 896 sources_waiting_for_callback_.end(), 897 source); 898 DCHECK(it != sources_waiting_for_callback_.end()); 899 sources_waiting_for_callback_.erase(it); 900 // All tracks must be started successfully. Otherwise the request is a 901 // failure. 902 if (!success) 903 request_failed_ = true; 904 CheckAllTracksStarted(); 905 } 906 907 void MediaStreamImpl::UserMediaRequestInfo::CheckAllTracksStarted() { 908 if (!ready_callback_.is_null() && sources_waiting_for_callback_.empty()) { 909 ready_callback_.Run( 910 this, 911 request_failed_ ? MEDIA_DEVICE_TRACK_START_FAILURE : MEDIA_DEVICE_OK); 912 } 913 } 914 915 bool MediaStreamImpl::UserMediaRequestInfo::IsSourceUsed( 916 const blink::WebMediaStreamSource& source) const { 917 for (std::vector<blink::WebMediaStreamSource>::const_iterator source_it = 918 sources_.begin(); 919 source_it != sources_.end(); ++source_it) { 920 if (source_it->id() == source.id()) 921 return true; 922 } 923 return false; 924 } 925 926 void MediaStreamImpl::UserMediaRequestInfo::RemoveSource( 927 const blink::WebMediaStreamSource& source) { 928 for (std::vector<blink::WebMediaStreamSource>::iterator it = 929 sources_.begin(); 930 it != sources_.end(); ++it) { 931 if (source.id() == it->id()) { 932 sources_.erase(it); 933 return; 934 } 935 } 936 } 937 938 } // namespace content 939