| 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/browser/renderer_host/media/media_stream_manager.h" | 5 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <string.h> | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 #include <cctype> | 11 #include <cctype> |
| 12 #include <list> | 12 #include <list> |
| 13 #include <utility> | |
| 14 #include <vector> | |
| 15 | 13 |
| 16 #include "base/bind.h" | 14 #include "base/bind.h" |
| 17 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 18 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
| 19 #include "base/logging.h" | 17 #include "base/logging.h" |
| 20 #include "base/macros.h" | 18 #include "base/macros.h" |
| 21 #include "base/power_monitor/power_monitor.h" | 19 #include "base/power_monitor/power_monitor.h" |
| 22 #include "base/profiler/scoped_tracker.h" | 20 #include "base/profiler/scoped_tracker.h" |
| 23 #include "base/rand_util.h" | 21 #include "base/rand_util.h" |
| 24 #include "base/run_loop.h" | |
| 25 #include "base/strings/string_number_conversions.h" | 22 #include "base/strings/string_number_conversions.h" |
| 26 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 27 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
| 28 #include "base/task_runner_util.h" | 25 #include "base/task_runner_util.h" |
| 29 #include "base/threading/thread.h" | 26 #include "base/threading/thread.h" |
| 30 #include "base/threading/thread_local.h" | 27 #include "base/threading/thread_local.h" |
| 31 #include "build/build_config.h" | 28 #include "build/build_config.h" |
| 32 #include "content/browser/browser_main_loop.h" | |
| 33 #include "content/browser/child_process_security_policy_impl.h" | 29 #include "content/browser/child_process_security_policy_impl.h" |
| 34 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 30 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 35 #include "content/browser/renderer_host/media/audio_output_device_enumerator.h" | |
| 36 #include "content/browser/renderer_host/media/media_capture_devices_impl.h" | 31 #include "content/browser/renderer_host/media/media_capture_devices_impl.h" |
| 32 #include "content/browser/renderer_host/media/media_devices_manager.h" |
| 37 #include "content/browser/renderer_host/media/media_stream_requester.h" | 33 #include "content/browser/renderer_host/media/media_stream_requester.h" |
| 38 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | 34 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
| 39 #include "content/browser/renderer_host/media/video_capture_manager.h" | 35 #include "content/browser/renderer_host/media/video_capture_manager.h" |
| 40 #include "content/browser/renderer_host/render_process_host_impl.h" | 36 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 41 #include "content/public/browser/browser_thread.h" | 37 #include "content/public/browser/browser_thread.h" |
| 42 #include "content/public/browser/content_browser_client.h" | 38 #include "content/public/browser/content_browser_client.h" |
| 43 #include "content/public/browser/desktop_media_id.h" | 39 #include "content/public/browser/desktop_media_id.h" |
| 44 #include "content/public/browser/media_observer.h" | 40 #include "content/public/browser/media_observer.h" |
| 45 #include "content/public/browser/media_request_state.h" | |
| 46 #include "content/public/browser/render_process_host.h" | 41 #include "content/public/browser/render_process_host.h" |
| 47 #include "content/public/browser/web_contents_media_capture_id.h" | 42 #include "content/public/browser/web_contents_media_capture_id.h" |
| 48 #include "content/public/common/content_client.h" | 43 #include "content/public/common/content_client.h" |
| 49 #include "content/public/common/content_switches.h" | 44 #include "content/public/common/content_switches.h" |
| 50 #include "content/public/common/media_stream_request.h" | 45 #include "content/public/common/media_stream_request.h" |
| 51 #include "crypto/hmac.h" | 46 #include "crypto/hmac.h" |
| 52 #include "media/audio/audio_device_description.h" | 47 #include "media/audio/audio_device_description.h" |
| 53 #include "media/audio/audio_manager.h" | 48 #include "media/audio/audio_manager.h" |
| 54 #include "media/base/audio_parameters.h" | 49 #include "media/base/audio_parameters.h" |
| 55 #include "media/base/channel_layout.h" | 50 #include "media/base/channel_layout.h" |
| 56 #include "media/base/media_switches.h" | 51 #include "media/base/media_switches.h" |
| 57 #include "media/capture/video/video_capture_device_factory.h" | 52 #include "media/capture/video/video_capture_device_factory.h" |
| 58 #include "url/gurl.h" | 53 #include "url/gurl.h" |
| 59 #include "url/origin.h" | 54 #include "url/origin.h" |
| 60 | 55 |
| 61 #if defined(OS_WIN) | 56 #if defined(OS_WIN) |
| 62 #include "base/win/scoped_com_initializer.h" | 57 #include "base/win/scoped_com_initializer.h" |
| 63 #endif | 58 #endif |
| 64 | 59 |
| 65 #if defined(OS_CHROMEOS) | 60 #if defined(OS_CHROMEOS) |
| 66 #include "chromeos/audio/cras_audio_handler.h" | 61 #include "chromeos/audio/cras_audio_handler.h" |
| 67 #endif | 62 #endif |
| 68 | 63 |
| 69 #if defined(OS_MACOSX) | |
| 70 #include "media/device_monitors/device_monitor_mac.h" | |
| 71 #endif | |
| 72 | |
| 73 namespace content { | 64 namespace content { |
| 74 | 65 |
| 75 base::LazyInstance<base::ThreadLocalPointer<MediaStreamManager>>::Leaky | 66 base::LazyInstance<base::ThreadLocalPointer<MediaStreamManager>>::Leaky |
| 76 g_media_stream_manager_tls_ptr = LAZY_INSTANCE_INITIALIZER; | 67 g_media_stream_manager_tls_ptr = LAZY_INSTANCE_INITIALIZER; |
| 77 | 68 |
| 78 namespace { | 69 namespace { |
| 79 // Creates a random label used to identify requests. | 70 // Creates a random label used to identify requests. |
| 80 std::string RandomLabel() { | 71 std::string RandomLabel() { |
| 81 // An earlier PeerConnection spec [1] defined MediaStream::label alphabet as | 72 // An earlier PeerConnection spec [1] defined MediaStream::label alphabet as |
| 82 // an uuid with characters from range: U+0021, U+0023 to U+0027, U+002A to | 73 // an uuid with characters from range: U+0021, U+0023 to U+0027, U+002A to |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 for (const chromeos::AudioDevice& device : devices) { | 148 for (const chromeos::AudioDevice& device : devices) { |
| 158 if (device.type == chromeos::AUDIO_TYPE_HOTWORD) { | 149 if (device.type == chromeos::AUDIO_TYPE_HOTWORD) { |
| 159 DCHECK(device.is_input); | 150 DCHECK(device.is_input); |
| 160 *effects |= media::AudioParameters::HOTWORD; | 151 *effects |= media::AudioParameters::HOTWORD; |
| 161 } | 152 } |
| 162 } | 153 } |
| 163 #endif | 154 #endif |
| 164 } | 155 } |
| 165 } | 156 } |
| 166 | 157 |
| 167 // Private helper method to generate a string for the log message that lists the | |
| 168 // human readable names of |devices|. | |
| 169 std::string GetLogMessageString(MediaStreamType stream_type, | |
| 170 const StreamDeviceInfoArray& device_infos) { | |
| 171 std::string output_string = | |
| 172 base::StringPrintf("Getting devices for stream type %d:\n", stream_type); | |
| 173 if (device_infos.empty()) | |
| 174 return output_string + "No devices found."; | |
| 175 for (const content::StreamDeviceInfo& device_info : device_infos) | |
| 176 output_string += " " + device_info.device.name + "\n"; | |
| 177 return output_string; | |
| 178 } | |
| 179 | |
| 180 // Clears the MediaStreamDevice.name from all devices in |devices|. | 158 // Clears the MediaStreamDevice.name from all devices in |devices|. |
| 181 void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) { | 159 void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) { |
| 182 for (content::StreamDeviceInfo& device_info : *devices) | 160 for (content::StreamDeviceInfo& device_info : *devices) |
| 183 device_info.device.name.clear(); | 161 device_info.device.name.clear(); |
| 184 } | 162 } |
| 185 | 163 |
| 186 bool CalledOnIOThread() { | 164 bool CalledOnIOThread() { |
| 187 // Check if this function call is on the IO thread, except for unittests where | 165 // Check if this function call is on the IO thread, except for unittests where |
| 188 // an IO thread might not have been created. | 166 // an IO thread might not have been created. |
| 189 return BrowserThread::CurrentlyOn(BrowserThread::IO) || | 167 return BrowserThread::CurrentlyOn(BrowserThread::IO) || |
| 190 !BrowserThread::IsMessageLoopValid(BrowserThread::IO); | 168 !BrowserThread::IsMessageLoopValid(BrowserThread::IO); |
| 191 } | 169 } |
| 192 | 170 |
| 193 GURL ConvertToGURL(const url::Origin& origin) { | 171 GURL ConvertToGURL(const url::Origin& origin) { |
| 194 return origin.unique() ? GURL() : GURL(origin.Serialize()); | 172 return origin.unique() ? GURL() : GURL(origin.Serialize()); |
| 195 } | 173 } |
| 196 | 174 |
| 175 bool GetDeviceIDFromHMAC(const std::string& salt, |
| 176 const url::Origin& security_origin, |
| 177 const std::string& hmac_device_id, |
| 178 const MediaDeviceInfoArray& devices, |
| 179 std::string* device_id) { |
| 180 // The source_id can be empty if the constraint is set but empty. |
| 181 if (hmac_device_id.empty()) |
| 182 return false; |
| 183 |
| 184 for (const auto& device_info : devices) { |
| 185 if (MediaStreamManager::DoesMediaDeviceIDMatchHMAC( |
| 186 salt, security_origin, hmac_device_id, device_info.device_id)) { |
| 187 *device_id = device_info.device_id; |
| 188 return true; |
| 189 } |
| 190 } |
| 191 return false; |
| 192 } |
| 193 |
| 194 MediaStreamType ConvertToMediaStreamType(MediaDeviceType type) { |
| 195 switch (type) { |
| 196 case MEDIA_DEVICE_TYPE_AUDIO_INPUT: |
| 197 return MEDIA_DEVICE_AUDIO_CAPTURE; |
| 198 case MEDIA_DEVICE_TYPE_VIDEO_INPUT: |
| 199 return MEDIA_DEVICE_VIDEO_CAPTURE; |
| 200 case MEDIA_DEVICE_TYPE_AUDIO_OUTPUT: |
| 201 return MEDIA_DEVICE_AUDIO_OUTPUT; |
| 202 default: |
| 203 NOTREACHED(); |
| 204 } |
| 205 |
| 206 return MEDIA_NO_SERVICE; |
| 207 } |
| 208 |
| 209 MediaDeviceType ConvertToMediaDeviceType(MediaStreamType stream_type) { |
| 210 switch (stream_type) { |
| 211 case MEDIA_DEVICE_AUDIO_CAPTURE: |
| 212 return MEDIA_DEVICE_TYPE_AUDIO_INPUT; |
| 213 case MEDIA_DEVICE_VIDEO_CAPTURE: |
| 214 return MEDIA_DEVICE_TYPE_VIDEO_INPUT; |
| 215 case MEDIA_DEVICE_AUDIO_OUTPUT: |
| 216 return MEDIA_DEVICE_TYPE_AUDIO_OUTPUT; |
| 217 default: |
| 218 NOTREACHED(); |
| 219 } |
| 220 |
| 221 return NUM_MEDIA_DEVICE_TYPES; |
| 222 } |
| 223 |
| 224 StreamDeviceInfoArray ConvertToStreamDeviceInfoArray( |
| 225 MediaStreamType stream_type, |
| 226 const MediaDeviceInfoArray& device_infos) { |
| 227 StreamDeviceInfoArray stream_devices; |
| 228 for (const auto& info : device_infos) { |
| 229 stream_devices.emplace_back(stream_type, info.label, info.device_id, |
| 230 info.group_id); |
| 231 } |
| 232 |
| 233 return stream_devices; |
| 234 } |
| 235 |
| 236 MediaStreamDevices ConvertToMediaStreamDevices( |
| 237 MediaStreamType stream_type, |
| 238 const MediaDeviceInfoArray& device_infos) { |
| 239 MediaStreamDevices devices; |
| 240 for (const auto& info : device_infos) { |
| 241 devices.emplace_back(stream_type, info.device_id, info.label, |
| 242 info.group_id); |
| 243 } |
| 244 |
| 245 return devices; |
| 246 } |
| 247 |
| 197 } // namespace | 248 } // namespace |
| 198 | 249 |
| 199 | 250 |
| 200 // MediaStreamManager::DeviceRequest represents a request to either enumerate | 251 // MediaStreamManager::DeviceRequest represents a request to either enumerate |
| 201 // available devices or open one or more devices. | 252 // available devices or open one or more devices. |
| 202 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create | 253 // TODO(perkj): MediaStreamManager still needs refactoring. I propose we create |
| 203 // several subclasses of DeviceRequest and move some of the responsibility of | 254 // several subclasses of DeviceRequest and move some of the responsibility of |
| 204 // the MediaStreamManager to the subclasses to get rid of the way too many if | 255 // the MediaStreamManager to the subclasses to get rid of the way too many if |
| 205 // statements in MediaStreamManager. | 256 // statements in MediaStreamManager. |
| 206 class MediaStreamManager::DeviceRequest { | 257 class MediaStreamManager::DeviceRequest { |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 | 407 |
| 357 private: | 408 private: |
| 358 std::vector<MediaRequestState> state_; | 409 std::vector<MediaRequestState> state_; |
| 359 std::unique_ptr<MediaStreamRequest> ui_request_; | 410 std::unique_ptr<MediaStreamRequest> ui_request_; |
| 360 MediaStreamType audio_type_; | 411 MediaStreamType audio_type_; |
| 361 MediaStreamType video_type_; | 412 MediaStreamType video_type_; |
| 362 int target_process_id_; | 413 int target_process_id_; |
| 363 int target_frame_id_; | 414 int target_frame_id_; |
| 364 }; | 415 }; |
| 365 | 416 |
| 366 MediaStreamManager::EnumerationCache::EnumerationCache() | |
| 367 : valid(false) { | |
| 368 } | |
| 369 | |
| 370 MediaStreamManager::EnumerationCache::~EnumerationCache() { | |
| 371 } | |
| 372 | |
| 373 // static | 417 // static |
| 374 void MediaStreamManager::SendMessageToNativeLog(const std::string& message) { | 418 void MediaStreamManager::SendMessageToNativeLog(const std::string& message) { |
| 375 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 419 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 376 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 420 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 377 base::Bind(&MediaStreamManager::SendMessageToNativeLog, message)); | 421 base::Bind(&MediaStreamManager::SendMessageToNativeLog, message)); |
| 378 return; | 422 return; |
| 379 } | 423 } |
| 380 | 424 |
| 381 MediaStreamManager* msm = g_media_stream_manager_tls_ptr.Pointer()->Get(); | 425 MediaStreamManager* msm = g_media_stream_manager_tls_ptr.Pointer()->Get(); |
| 382 if (!msm) { | 426 if (!msm) { |
| 383 DLOG(ERROR) << "No MediaStreamManager on the IO thread. " << message; | 427 DLOG(ERROR) << "No MediaStreamManager on the IO thread. " << message; |
| 384 return; | 428 return; |
| 385 } | 429 } |
| 386 | 430 |
| 387 msm->AddLogMessageOnIOThread(message); | 431 msm->AddLogMessageOnIOThread(message); |
| 388 } | 432 } |
| 389 | 433 |
| 390 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) | 434 MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) |
| 391 : audio_manager_(audio_manager), | 435 : audio_manager_(audio_manager), |
| 392 #if defined(OS_WIN) | 436 #if defined(OS_WIN) |
| 393 video_capture_thread_("VideoCaptureThread"), | 437 video_capture_thread_("VideoCaptureThread"), |
| 394 #endif | 438 #endif |
| 395 monitoring_started_(false), | |
| 396 use_fake_ui_(base::CommandLine::ForCurrentProcess()->HasSwitch( | 439 use_fake_ui_(base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 397 switches::kUseFakeUIForMediaStream)) { | 440 switches::kUseFakeUIForMediaStream)) { |
| 398 DCHECK(audio_manager_); | 441 DCHECK(audio_manager_); |
| 399 memset(active_enumeration_ref_count_, 0, | |
| 400 sizeof(active_enumeration_ref_count_)); | |
| 401 | 442 |
| 402 // Some unit tests create the MSM in the IO thread and assumes the | 443 // Some unit tests create the MSM in the IO thread and assumes the |
| 403 // initialization is done synchronously. | 444 // initialization is done synchronously. |
| 404 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 445 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 405 InitializeDeviceManagersOnIOThread(); | 446 InitializeDeviceManagersOnIOThread(); |
| 406 } else { | 447 } else { |
| 407 BrowserThread::PostTask( | 448 BrowserThread::PostTask( |
| 408 BrowserThread::IO, FROM_HERE, | 449 BrowserThread::IO, FROM_HERE, |
| 409 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread, | 450 base::Bind(&MediaStreamManager::InitializeDeviceManagersOnIOThread, |
| 410 base::Unretained(this))); | 451 base::Unretained(this))); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 return audio_input_device_manager_.get(); | 484 return audio_input_device_manager_.get(); |
| 444 } | 485 } |
| 445 | 486 |
| 446 AudioOutputDeviceEnumerator* | 487 AudioOutputDeviceEnumerator* |
| 447 MediaStreamManager::audio_output_device_enumerator() { | 488 MediaStreamManager::audio_output_device_enumerator() { |
| 448 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 489 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 449 DCHECK(audio_output_device_enumerator_.get()); | 490 DCHECK(audio_output_device_enumerator_.get()); |
| 450 return audio_output_device_enumerator_.get(); | 491 return audio_output_device_enumerator_.get(); |
| 451 } | 492 } |
| 452 | 493 |
| 494 MediaDevicesManager* MediaStreamManager::media_devices_manager() { |
| 495 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 496 DCHECK(media_devices_manager_.get()); |
| 497 return media_devices_manager_.get(); |
| 498 } |
| 499 |
| 453 std::string MediaStreamManager::MakeMediaAccessRequest( | 500 std::string MediaStreamManager::MakeMediaAccessRequest( |
| 454 int render_process_id, | 501 int render_process_id, |
| 455 int render_frame_id, | 502 int render_frame_id, |
| 456 int page_request_id, | 503 int page_request_id, |
| 457 const StreamControls& controls, | 504 const StreamControls& controls, |
| 458 const url::Origin& security_origin, | 505 const url::Origin& security_origin, |
| 459 const MediaRequestResponseCallback& callback) { | 506 const MediaRequestResponseCallback& callback) { |
| 460 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 507 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 461 | 508 |
| 462 // TODO(perkj): The argument list with NULL parameters to DeviceRequest | 509 // TODO(perkj): The argument list with NULL parameters to DeviceRequest |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 } | 761 } |
| 715 | 762 |
| 716 void MediaStreamManager::DoEnumerateDevices(const std::string& label) { | 763 void MediaStreamManager::DoEnumerateDevices(const std::string& label) { |
| 717 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 764 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 718 DeviceRequest* request = FindRequest(label); | 765 DeviceRequest* request = FindRequest(label); |
| 719 if (!request) | 766 if (!request) |
| 720 return; // This can happen if the request has been canceled. | 767 return; // This can happen if the request has been canceled. |
| 721 | 768 |
| 722 if (request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) { | 769 if (request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) { |
| 723 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type()); | 770 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type()); |
| 724 DCHECK_GE(active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT], 0); | |
| 725 request->SetState(MEDIA_DEVICE_AUDIO_OUTPUT, MEDIA_REQUEST_STATE_REQUESTED); | 771 request->SetState(MEDIA_DEVICE_AUDIO_OUTPUT, MEDIA_REQUEST_STATE_REQUESTED); |
| 726 if (active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT] == 0) { | 772 media_devices_manager_->EnumerateDevices( |
| 727 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT]; | 773 {{false /* audio input */, false /* video input*/, |
| 728 DCHECK(audio_output_device_enumerator_); | 774 true /* audio output */}}, |
| 729 audio_output_device_enumerator_->Enumerate( | 775 base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated, |
| 730 base::Bind(&MediaStreamManager::AudioOutputDevicesEnumerated, | 776 base::Unretained(this), label)); |
| 731 base::Unretained(this))); | |
| 732 } | |
| 733 return; | 777 return; |
| 734 } | 778 } |
| 735 | 779 |
| 736 MediaStreamType type; | 780 StartEnumeration(request, label); |
| 737 EnumerationCache* cache; | |
| 738 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) { | |
| 739 DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type()); | |
| 740 type = MEDIA_DEVICE_AUDIO_CAPTURE; | |
| 741 cache = &audio_enumeration_cache_; | |
| 742 } else { | |
| 743 DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type()); | |
| 744 DCHECK_EQ(MEDIA_NO_SERVICE, request->audio_type()); | |
| 745 type = MEDIA_DEVICE_VIDEO_CAPTURE; | |
| 746 cache = &video_enumeration_cache_; | |
| 747 } | |
| 748 | |
| 749 if (!EnumerationRequired(cache, type)) { | |
| 750 // Cached device list of this type exists. Just send it out. | |
| 751 request->SetState(type, MEDIA_REQUEST_STATE_REQUESTED); | |
| 752 request->devices = cache->devices; | |
| 753 FinalizeEnumerateDevices(label, request); | |
| 754 } else { | |
| 755 StartEnumeration(request); | |
| 756 } | |
| 757 DVLOG(1) << "Enumerate Devices ({label = " << label << "})"; | 781 DVLOG(1) << "Enumerate Devices ({label = " << label << "})"; |
| 758 } | 782 } |
| 759 | 783 |
| 760 void MediaStreamManager::AudioOutputDevicesEnumerated( | 784 void MediaStreamManager::AudioOutputDevicesEnumerated( |
| 761 const AudioOutputDeviceEnumeration& device_enumeration) { | 785 const std::string& label, |
| 786 const MediaDeviceEnumeration& enumeration) { |
| 762 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 787 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 763 DVLOG(1) << "AudioOutputDevicesEnumerated()"; | |
| 764 StreamDeviceInfoArray device_infos; | |
| 765 | 788 |
| 766 if (device_enumeration.has_actual_devices) { | 789 DeviceRequest* request = FindRequest(label); |
| 767 for (const auto& entry : device_enumeration.devices) { | 790 if (!request) |
| 768 device_infos.emplace_back(MEDIA_DEVICE_AUDIO_OUTPUT, entry.device_name, | 791 return; |
| 769 entry.unique_id, entry.group_id); | |
| 770 } | |
| 771 } | |
| 772 | 792 |
| 773 const std::string log_message = | 793 DCHECK_EQ(MEDIA_DEVICE_AUDIO_OUTPUT, request->audio_type()); |
| 774 "New device enumeration result:\n" + | 794 DCHECK_EQ(MEDIA_REQUEST_STATE_REQUESTED, |
| 775 GetLogMessageString(MEDIA_DEVICE_AUDIO_OUTPUT, device_infos); | 795 request->state(MEDIA_DEVICE_AUDIO_OUTPUT)); |
| 776 SendMessageToNativeLog(log_message); | 796 DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, request->request_type); |
| 777 | 797 DCHECK(!request->ui_proxy.get()); |
| 778 // Publish the result for all requests waiting for device list(s). | 798 StreamDeviceInfoArray device_infos = ConvertToStreamDeviceInfoArray( |
| 779 for (const LabeledDeviceRequest& request : requests_) { | 799 MEDIA_DEVICE_AUDIO_OUTPUT, enumeration[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]); |
| 780 if (request.second->state(MEDIA_DEVICE_AUDIO_OUTPUT) == | 800 request->devices = device_infos; |
| 781 MEDIA_REQUEST_STATE_REQUESTED && | 801 FinalizeEnumerateDevices(label, request); |
| 782 request.second->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) { | |
| 783 DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, request.second->request_type); | |
| 784 request.second->SetState(MEDIA_DEVICE_AUDIO_OUTPUT, | |
| 785 MEDIA_REQUEST_STATE_PENDING_APPROVAL); | |
| 786 request.second->devices = device_infos; | |
| 787 FinalizeEnumerateDevices(request.first, request.second); | |
| 788 } | |
| 789 } | |
| 790 | |
| 791 --active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT]; | |
| 792 DCHECK_GE(active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_OUTPUT], 0); | |
| 793 } | 802 } |
| 794 | 803 |
| 795 void MediaStreamManager::OpenDevice(MediaStreamRequester* requester, | 804 void MediaStreamManager::OpenDevice(MediaStreamRequester* requester, |
| 796 int render_process_id, | 805 int render_process_id, |
| 797 int render_frame_id, | 806 int render_frame_id, |
| 798 const std::string& salt, | 807 const std::string& salt, |
| 799 int page_request_id, | 808 int page_request_id, |
| 800 const std::string& device_id, | 809 const std::string& device_id, |
| 801 MediaStreamType type, | 810 MediaStreamType type, |
| 802 const url::Origin& security_origin) { | 811 const url::Origin& security_origin) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 const std::string& salt, | 846 const std::string& salt, |
| 838 const url::Origin& security_origin, | 847 const url::Origin& security_origin, |
| 839 const std::string& source_id, | 848 const std::string& source_id, |
| 840 std::string* device_id) const { | 849 std::string* device_id) const { |
| 841 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || | 850 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 842 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); | 851 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); |
| 843 // The source_id can be empty if the constraint is set but empty. | 852 // The source_id can be empty if the constraint is set but empty. |
| 844 if (source_id.empty()) | 853 if (source_id.empty()) |
| 845 return false; | 854 return false; |
| 846 | 855 |
| 847 const EnumerationCache* cache = | 856 // TODO(guidou): Change to use MediaDevicesManager::EnumerateDevices. |
| 848 stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? | 857 // See http://crbug.com/648155. |
| 849 &audio_enumeration_cache_ : &video_enumeration_cache_; | 858 MediaDeviceInfoArray cached_devices = |
| 850 | 859 media_devices_manager_->GetCachedDeviceInfo( |
| 851 // If device monitoring hasn't started, the |device_guid| is not valid. | 860 ConvertToMediaDeviceType(stream_type)); |
| 852 if (!cache->valid) | 861 return GetDeviceIDFromHMAC(salt, security_origin, source_id, cached_devices, |
| 853 return false; | 862 device_id); |
| 854 | |
| 855 for (const StreamDeviceInfo& device_info : cache->devices) { | |
| 856 if (DoesMediaDeviceIDMatchHMAC(salt, security_origin, source_id, | |
| 857 device_info.device.id)) { | |
| 858 *device_id = device_info.device.id; | |
| 859 return true; | |
| 860 } | |
| 861 } | |
| 862 return false; | |
| 863 } | 863 } |
| 864 | 864 |
| 865 void MediaStreamManager::EnsureDeviceMonitorStarted() { | 865 void MediaStreamManager::EnsureDeviceMonitorStarted() { |
| 866 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 866 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 867 StartMonitoring(); | 867 media_devices_manager_->StartMonitoring(); |
| 868 } | 868 } |
| 869 | 869 |
| 870 void MediaStreamManager::StopRemovedDevices( | 870 void MediaStreamManager::StopRemovedDevice(MediaDeviceType type, |
| 871 const StreamDeviceInfoArray& old_devices, | 871 const MediaDeviceInfo& device) { |
| 872 const StreamDeviceInfoArray& new_devices) { | 872 DCHECK(type == MEDIA_DEVICE_TYPE_AUDIO_INPUT || |
| 873 DVLOG(1) << "StopRemovedDevices(" | 873 type == MEDIA_DEVICE_TYPE_VIDEO_INPUT); |
| 874 << "{#old_devices = " << old_devices.size() << "} " | 874 MediaStreamType stream_type = ConvertToMediaStreamType(type); |
| 875 << "{#new_devices = " << new_devices.size() << "})"; | |
| 876 for (const StreamDeviceInfo& old_device_info : old_devices) { | |
| 877 bool device_found = false; | |
| 878 for (const StreamDeviceInfo& new_device_info : new_devices) { | |
| 879 if (old_device_info.device.id == new_device_info.device.id) { | |
| 880 device_found = true; | |
| 881 break; | |
| 882 } | |
| 883 } | |
| 884 | |
| 885 if (!device_found) { | |
| 886 // A device has been removed. We need to check if it is used by a | |
| 887 // MediaStream and in that case cleanup and notify the render process. | |
| 888 StopRemovedDevice(old_device_info.device); | |
| 889 } | |
| 890 } | |
| 891 } | |
| 892 | |
| 893 void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) { | |
| 894 std::vector<int> session_ids; | 875 std::vector<int> session_ids; |
| 895 for (const LabeledDeviceRequest& labeled_request : requests_) { | 876 for (const LabeledDeviceRequest& labeled_request : requests_) { |
| 896 const DeviceRequest* request = labeled_request.second; | 877 const DeviceRequest* request = labeled_request.second; |
| 897 for (const StreamDeviceInfo& device_info : request->devices) { | 878 for (const StreamDeviceInfo& device_info : request->devices) { |
| 898 const std::string source_id = GetHMACForMediaDeviceID( | 879 const std::string source_id = GetHMACForMediaDeviceID( |
| 899 request->salt, request->security_origin, device.id); | 880 request->salt, request->security_origin, device.device_id); |
| 900 if (device_info.device.id == source_id && | 881 if (device_info.device.id == source_id && |
| 901 device_info.device.type == device.type) { | 882 device_info.device.type == stream_type) { |
| 902 session_ids.push_back(device_info.session_id); | 883 session_ids.push_back(device_info.session_id); |
| 903 if (labeled_request.second->requester) { | 884 if (labeled_request.second->requester) { |
| 904 labeled_request.second->requester->DeviceStopped( | 885 labeled_request.second->requester->DeviceStopped( |
| 905 labeled_request.second->requesting_frame_id, | 886 labeled_request.second->requesting_frame_id, |
| 906 labeled_request.first, device_info); | 887 labeled_request.first, device_info); |
| 907 } | 888 } |
| 908 } | 889 } |
| 909 } | 890 } |
| 910 } | 891 } |
| 911 for (const int session_id : session_ids) | 892 for (const int session_id : session_ids) |
| 912 StopDevice(device.type, session_id); | 893 StopDevice(stream_type, session_id); |
| 913 | 894 |
| 914 AddLogMessageOnIOThread( | 895 AddLogMessageOnIOThread( |
| 915 base::StringPrintf( | 896 base::StringPrintf( |
| 916 "Media input device removed: type = %s, id = %s, name = %s ", | 897 "Media input device removed: type=%s, id=%s, name=%s ", |
| 917 (device.type == MEDIA_DEVICE_AUDIO_CAPTURE ? "audio" : "video"), | 898 (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ? "audio" : "video"), |
| 918 device.id.c_str(), device.name.c_str()).c_str()); | 899 device.device_id.c_str(), device.label.c_str()) |
| 900 .c_str()); |
| 919 } | 901 } |
| 920 | 902 |
| 921 void MediaStreamManager::StartMonitoring() { | 903 bool MediaStreamManager::PickDeviceId(const std::string& salt, |
| 922 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 923 if (monitoring_started_) | |
| 924 return; | |
| 925 | |
| 926 if (!base::SystemMonitor::Get()) | |
| 927 return; | |
| 928 | |
| 929 monitoring_started_ = true; | |
| 930 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); | |
| 931 | |
| 932 // Enumerate both the audio and video input devices to cache the device lists | |
| 933 // and send them to media observer. | |
| 934 ++active_enumeration_ref_count_[MEDIA_DEVICE_AUDIO_CAPTURE]; | |
| 935 audio_input_device_manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE); | |
| 936 ++active_enumeration_ref_count_[MEDIA_DEVICE_VIDEO_CAPTURE]; | |
| 937 video_capture_manager_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); | |
| 938 | |
| 939 #if defined(OS_MACOSX) | |
| 940 BrowserThread::PostTask( | |
| 941 BrowserThread::UI, FROM_HERE, | |
| 942 base::Bind(&MediaStreamManager::StartMonitoringOnUIThread, | |
| 943 base::Unretained(this))); | |
| 944 #endif | |
| 945 } | |
| 946 | |
| 947 void MediaStreamManager::StopMonitoring() { | |
| 948 DCHECK(CalledOnIOThread()); | |
| 949 if (!monitoring_started_) | |
| 950 return; | |
| 951 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); | |
| 952 monitoring_started_ = false; | |
| 953 ClearEnumerationCache(&audio_enumeration_cache_); | |
| 954 ClearEnumerationCache(&video_enumeration_cache_); | |
| 955 audio_output_device_enumerator_->SetCachePolicy( | |
| 956 AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING); | |
| 957 } | |
| 958 | |
| 959 #if defined(OS_MACOSX) | |
| 960 void MediaStreamManager::StartMonitoringOnUIThread() { | |
| 961 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 962 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is fixed. | |
| 963 tracked_objects::ScopedTracker tracking_profile1( | |
| 964 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 965 "458404 MediaStreamManager::GetBrowserMainLoop")); | |
| 966 BrowserMainLoop* browser_main_loop = content::BrowserMainLoop::GetInstance(); | |
| 967 if (!browser_main_loop) | |
| 968 return; | |
| 969 | |
| 970 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is | |
| 971 // fixed. | |
| 972 tracked_objects::ScopedTracker tracking_profile2( | |
| 973 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 974 "458404 MediaStreamManager::GetTaskRunner")); | |
| 975 const scoped_refptr<base::SingleThreadTaskRunner> task_runner = | |
| 976 audio_manager_->GetTaskRunner(); | |
| 977 // TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is | |
| 978 // fixed. | |
| 979 tracked_objects::ScopedTracker tracking_profile3( | |
| 980 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 981 "458404 MediaStreamManager::DeviceMonitorMac::StartMonitoring")); | |
| 982 browser_main_loop->device_monitor_mac()->StartMonitoring(task_runner); | |
| 983 } | |
| 984 #endif | |
| 985 | |
| 986 // Pick the first valid (translatable) device ID from lists of required | |
| 987 // and optional IDs. | |
| 988 bool MediaStreamManager::PickDeviceId(MediaStreamType type, | |
| 989 const std::string& salt, | |
| 990 const url::Origin& security_origin, | 904 const url::Origin& security_origin, |
| 991 const TrackControls& controls, | 905 const TrackControls& controls, |
| 906 const MediaDeviceInfoArray& devices, |
| 992 std::string* device_id) const { | 907 std::string* device_id) const { |
| 993 if (!controls.device_ids.empty()) { | 908 if (!controls.device_ids.empty()) { |
| 994 if (controls.device_ids.size() > 1) { | 909 if (controls.device_ids.size() > 1) { |
| 995 LOG(ERROR) << "Only one required device ID is supported"; | 910 LOG(ERROR) << "Only one required device ID is supported"; |
| 996 return false; | 911 return false; |
| 997 } | 912 } |
| 998 const std::string& candidate_id = controls.device_ids[0]; | 913 const std::string& candidate_id = controls.device_ids[0]; |
| 999 if (!TranslateSourceIdToDeviceId(type, salt, security_origin, candidate_id, | 914 if (!GetDeviceIDFromHMAC(salt, security_origin, candidate_id, devices, |
| 1000 device_id)) { | 915 device_id)) { |
| 1001 LOG(WARNING) << "Invalid mandatory capture ID = " << candidate_id; | 916 LOG(WARNING) << "Invalid mandatory capture ID = " << candidate_id; |
| 1002 return false; | 917 return false; |
| 1003 } | 918 } |
| 1004 return true; | 919 return true; |
| 1005 } | 920 } |
| 1006 // We don't have a required ID. Look at the alternates. | 921 // We don't have a required ID. Look at the alternates. |
| 1007 for (const std::string& candidate_id : controls.alternate_device_ids) { | 922 for (const std::string& candidate_id : controls.alternate_device_ids) { |
| 1008 if (TranslateSourceIdToDeviceId(type, salt, security_origin, candidate_id, | 923 if (GetDeviceIDFromHMAC(salt, security_origin, candidate_id, devices, |
| 1009 device_id)) { | 924 device_id)) { |
| 1010 return true; | 925 return true; |
| 1011 } else { | 926 } else { |
| 1012 LOG(WARNING) << "Invalid optional capture ID = " << candidate_id; | 927 LOG(WARNING) << "Invalid optional capture ID = " << candidate_id; |
| 1013 } | 928 } |
| 1014 } | 929 } |
| 1015 return true; // If we get here, device_id is empty. | 930 return true; // If we get here, device_id is empty. |
| 1016 } | 931 } |
| 1017 | 932 |
| 1018 bool MediaStreamManager::GetRequestedDeviceCaptureId( | 933 bool MediaStreamManager::GetRequestedDeviceCaptureId( |
| 1019 const DeviceRequest* request, | 934 const DeviceRequest* request, |
| 1020 MediaStreamType type, | 935 MediaStreamType type, |
| 936 const MediaDeviceInfoArray& devices, |
| 1021 std::string* device_id) const { | 937 std::string* device_id) const { |
| 1022 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) { | 938 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) { |
| 1023 return PickDeviceId(type, request->salt, request->security_origin, | 939 return PickDeviceId(request->salt, request->security_origin, |
| 1024 request->controls.audio, device_id); | 940 request->controls.audio, devices, device_id); |
| 1025 } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) { | 941 } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) { |
| 1026 return PickDeviceId(type, request->salt, request->security_origin, | 942 return PickDeviceId(request->salt, request->security_origin, |
| 1027 request->controls.video, device_id); | 943 request->controls.video, devices, device_id); |
| 1028 } else { | 944 } else { |
| 1029 NOTREACHED(); | 945 NOTREACHED(); |
| 1030 } | 946 } |
| 1031 return false; | 947 return false; |
| 1032 } | 948 } |
| 1033 | 949 |
| 1034 void MediaStreamManager::TranslateDeviceIdToSourceId( | 950 void MediaStreamManager::TranslateDeviceIdToSourceId( |
| 1035 DeviceRequest* request, | 951 DeviceRequest* request, |
| 1036 MediaStreamDevice* device) { | 952 MediaStreamDevice* device) { |
| 1037 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || | 953 if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 1038 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT || | 954 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT || |
| 1039 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) { | 955 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) { |
| 1040 device->id = GetHMACForMediaDeviceID(request->salt, | 956 device->id = GetHMACForMediaDeviceID(request->salt, |
| 1041 request->security_origin, device->id); | 957 request->security_origin, device->id); |
| 1042 if (!device->group_id.empty()) | 958 if (!device->group_id.empty()) |
| 1043 device->group_id = GetHMACForMediaDeviceID( | 959 device->group_id = GetHMACForMediaDeviceID( |
| 1044 request->salt, request->security_origin, device->group_id); | 960 request->salt, request->security_origin, device->group_id); |
| 1045 } | 961 } |
| 1046 } | 962 } |
| 1047 | 963 |
| 1048 void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) { | 964 void MediaStreamManager::StartEnumeration(DeviceRequest* request, |
| 1049 DCHECK(CalledOnIOThread()); | 965 const std::string& label) { |
| 1050 cache->valid = false; | |
| 1051 } | |
| 1052 | |
| 1053 bool MediaStreamManager::EnumerationRequired(EnumerationCache* cache, | |
| 1054 MediaStreamType stream_type) { | |
| 1055 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 1056 if (stream_type == MEDIA_NO_SERVICE) | |
| 1057 return false; | |
| 1058 | |
| 1059 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || | |
| 1060 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); | |
| 1061 | |
| 1062 #if defined(OS_ANDROID) | |
| 1063 // There's no SystemMonitor on Android that notifies us when devices are | |
| 1064 // added or removed, so we need to populate the cache on every request. | |
| 1065 // Fortunately, there is an already up-to-date cache in the browser side | |
| 1066 // audio manager that we can rely on, so the performance impact of | |
| 1067 // invalidating the cache like this, is minimal. | |
| 1068 if (stream_type == MEDIA_DEVICE_AUDIO_CAPTURE) { | |
| 1069 // Make sure the cache is marked as invalid so that FinalizeEnumerateDevices | |
| 1070 // will be called at the end of the enumeration. | |
| 1071 ClearEnumerationCache(cache); | |
| 1072 } | |
| 1073 #endif | |
| 1074 // If the cache isn't valid, we need to start a full enumeration. | |
| 1075 return !cache->valid; | |
| 1076 } | |
| 1077 | |
| 1078 void MediaStreamManager::StartEnumeration(DeviceRequest* request) { | |
| 1079 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 966 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1080 | 967 |
| 1081 // Start monitoring the devices when doing the first enumeration. | 968 // Start monitoring the devices when doing the first enumeration. |
| 1082 StartMonitoring(); | 969 media_devices_manager_->StartMonitoring(); |
| 1083 | 970 |
| 1084 // Start enumeration for devices of all requested device types. | 971 // Start enumeration for devices of all requested device types. |
| 1085 const MediaStreamType stream_types[] = {request->audio_type(), | 972 bool request_audio_input = request->audio_type() != MEDIA_NO_SERVICE; |
| 1086 request->video_type()}; | 973 if (request_audio_input) |
| 1087 for (const MediaStreamType stream_type : stream_types) { | 974 request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_REQUESTED); |
| 1088 if (stream_type == MEDIA_NO_SERVICE) | 975 |
| 1089 continue; | 976 bool request_video_input = request->video_type() != MEDIA_NO_SERVICE; |
| 1090 request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED); | 977 if (request_video_input) |
| 1091 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); | 978 request->SetState(request->video_type(), MEDIA_REQUEST_STATE_REQUESTED); |
| 1092 if (active_enumeration_ref_count_[stream_type] == 0) { | 979 |
| 1093 ++active_enumeration_ref_count_[stream_type]; | 980 // base::Unretained is safe here because MediaStreamManager is deleted on the |
| 1094 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); | 981 // UI thread, after the IO thread has been stopped. |
| 1095 } | 982 DCHECK(request_audio_input || request_video_input); |
| 1096 } | 983 media_devices_manager_->EnumerateDevices( |
| 984 {{request_audio_input, request_video_input, false /* no audio output */}}, |
| 985 base::Bind(&MediaStreamManager::DevicesEnumerated, base::Unretained(this), |
| 986 request_audio_input, request_video_input, label)); |
| 1097 } | 987 } |
| 1098 | 988 |
| 1099 std::string MediaStreamManager::AddRequest(DeviceRequest* request) { | 989 std::string MediaStreamManager::AddRequest(DeviceRequest* request) { |
| 1100 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 990 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1101 | 991 |
| 1102 // Create a label for this request and verify it is unique. | 992 // Create a label for this request and verify it is unique. |
| 1103 std::string unique_label; | 993 std::string unique_label; |
| 1104 do { | 994 do { |
| 1105 unique_label = RandomLabel(); | 995 unique_label = RandomLabel(); |
| 1106 } while (FindRequest(unique_label) != NULL); | 996 } while (FindRequest(unique_label) != NULL); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1127 std::unique_ptr<DeviceRequest> request(request_it->second); | 1017 std::unique_ptr<DeviceRequest> request(request_it->second); |
| 1128 requests_.erase(request_it); | 1018 requests_.erase(request_it); |
| 1129 return; | 1019 return; |
| 1130 } | 1020 } |
| 1131 } | 1021 } |
| 1132 NOTREACHED(); | 1022 NOTREACHED(); |
| 1133 } | 1023 } |
| 1134 | 1024 |
| 1135 void MediaStreamManager::ReadOutputParamsAndPostRequestToUI( | 1025 void MediaStreamManager::ReadOutputParamsAndPostRequestToUI( |
| 1136 const std::string& label, | 1026 const std::string& label, |
| 1137 DeviceRequest* request) { | 1027 DeviceRequest* request, |
| 1028 const MediaDeviceEnumeration& enumeration) { |
| 1138 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1029 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1139 | 1030 |
| 1140 // Actual audio parameters are required only for MEDIA_TAB_AUDIO_CAPTURE. | 1031 // Actual audio parameters are required only for MEDIA_TAB_AUDIO_CAPTURE. |
| 1141 // TODO(guidou): MEDIA_TAB_AUDIO_CAPTURE should not be a special case. See | 1032 // TODO(guidou): MEDIA_TAB_AUDIO_CAPTURE should not be a special case. See |
| 1142 // crbug.com/584287. | 1033 // crbug.com/584287. |
| 1143 if (request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE) { | 1034 if (request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE) { |
| 1144 // Read output parameters on the correct thread for native audio OS calls. | 1035 // Read output parameters on the correct thread for native audio OS calls. |
| 1145 // Using base::Unretained is safe since |audio_manager_| is deleted after | 1036 // Using base::Unretained is safe since |audio_manager_| is deleted after |
| 1146 // its task runner, and MediaStreamManager is deleted on the UI thread, | 1037 // its task runner, and MediaStreamManager is deleted on the UI thread, |
| 1147 // after the IO thread has been stopped. | 1038 // after the IO thread has been stopped. |
| 1148 base::PostTaskAndReplyWithResult( | 1039 base::PostTaskAndReplyWithResult( |
| 1149 audio_manager_->GetTaskRunner(), FROM_HERE, | 1040 audio_manager_->GetTaskRunner(), FROM_HERE, |
| 1150 base::Bind(&media::AudioManager::GetDefaultOutputStreamParameters, | 1041 base::Bind(&media::AudioManager::GetDefaultOutputStreamParameters, |
| 1151 base::Unretained(audio_manager_)), | 1042 base::Unretained(audio_manager_)), |
| 1152 base::Bind(&MediaStreamManager::PostRequestToUI, base::Unretained(this), | 1043 base::Bind(&MediaStreamManager::PostRequestToUI, base::Unretained(this), |
| 1153 label, request)); | 1044 label, request, enumeration)); |
| 1154 } else { | 1045 } else { |
| 1155 PostRequestToUI(label, request, media::AudioParameters()); | 1046 PostRequestToUI(label, request, enumeration, media::AudioParameters()); |
| 1156 } | 1047 } |
| 1157 } | 1048 } |
| 1158 | 1049 |
| 1159 void MediaStreamManager::PostRequestToUI( | 1050 void MediaStreamManager::PostRequestToUI( |
| 1160 const std::string& label, | 1051 const std::string& label, |
| 1161 DeviceRequest* request, | 1052 DeviceRequest* request, |
| 1053 const MediaDeviceEnumeration& enumeration, |
| 1162 const media::AudioParameters& output_parameters) { | 1054 const media::AudioParameters& output_parameters) { |
| 1163 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1055 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1164 DCHECK(request->HasUIRequest()); | 1056 DCHECK(request->HasUIRequest()); |
| 1165 DVLOG(1) << "PostRequestToUI({label= " << label << "})"; | 1057 DVLOG(1) << "PostRequestToUI({label= " << label << "})"; |
| 1166 | 1058 |
| 1167 const MediaStreamType audio_type = request->audio_type(); | 1059 const MediaStreamType audio_type = request->audio_type(); |
| 1168 const MediaStreamType video_type = request->video_type(); | 1060 const MediaStreamType video_type = request->video_type(); |
| 1169 | 1061 |
| 1170 // Post the request to UI and set the state. | 1062 // Post the request to UI and set the state. |
| 1171 if (IsAudioInputMediaType(audio_type)) | 1063 if (IsAudioInputMediaType(audio_type)) |
| 1172 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); | 1064 request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); |
| 1173 if (IsVideoMediaType(video_type)) | 1065 if (IsVideoMediaType(video_type)) |
| 1174 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); | 1066 request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); |
| 1175 | 1067 |
| 1176 // If using the fake UI, it will just auto-select from the available devices. | 1068 // If using the fake UI, it will just auto-select from the available devices. |
| 1177 // The fake UI doesn't work for desktop sharing requests since we can't see | 1069 // The fake UI doesn't work for desktop sharing requests since we can't see |
| 1178 // its devices from here; always use the real UI for such requests. | 1070 // its devices from here; always use the real UI for such requests. |
| 1179 if (use_fake_ui_ && request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE) { | 1071 if (use_fake_ui_ && request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE) { |
| 1180 if (!fake_ui_) | 1072 if (!fake_ui_) |
| 1181 fake_ui_.reset(new FakeMediaStreamUIProxy()); | 1073 fake_ui_.reset(new FakeMediaStreamUIProxy()); |
| 1182 | 1074 |
| 1183 MediaStreamDevices devices; | 1075 MediaStreamDevices devices; |
| 1184 if (audio_enumeration_cache_.valid) { | 1076 for (const auto& info : enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT]) { |
| 1185 for (const StreamDeviceInfo& device_info : | 1077 devices.emplace_back(audio_type, info.device_id, info.label, |
| 1186 audio_enumeration_cache_.devices) { | 1078 info.group_id); |
| 1187 devices.push_back(device_info.device); | |
| 1188 } | |
| 1189 } | 1079 } |
| 1190 if (video_enumeration_cache_.valid) { | 1080 for (const auto& info : enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT]) { |
| 1191 for (const StreamDeviceInfo& device_info : | 1081 devices.emplace_back(video_type, info.device_id, info.label, |
| 1192 video_enumeration_cache_.devices) { | 1082 info.group_id); |
| 1193 devices.push_back(device_info.device); | |
| 1194 } | |
| 1195 } | 1083 } |
| 1196 | 1084 |
| 1197 fake_ui_->SetAvailableDevices(devices); | 1085 fake_ui_->SetAvailableDevices(devices); |
| 1198 | 1086 |
| 1199 request->ui_proxy = std::move(fake_ui_); | 1087 request->ui_proxy = std::move(fake_ui_); |
| 1200 } else { | 1088 } else { |
| 1201 request->ui_proxy = MediaStreamUIProxy::Create(); | 1089 request->ui_proxy = MediaStreamUIProxy::Create(); |
| 1202 } | 1090 } |
| 1203 | 1091 |
| 1204 request->ui_proxy->RequestAccess( | 1092 request->ui_proxy->RequestAccess( |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1232 | 1120 |
| 1233 const bool is_screen_capture = video_type == MEDIA_DESKTOP_VIDEO_CAPTURE; | 1121 const bool is_screen_capture = video_type == MEDIA_DESKTOP_VIDEO_CAPTURE; |
| 1234 if (is_screen_capture && !SetupScreenCaptureRequest(request)) { | 1122 if (is_screen_capture && !SetupScreenCaptureRequest(request)) { |
| 1235 FinalizeRequestFailed(label, | 1123 FinalizeRequestFailed(label, |
| 1236 request, | 1124 request, |
| 1237 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE); | 1125 MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE); |
| 1238 return; | 1126 return; |
| 1239 } | 1127 } |
| 1240 | 1128 |
| 1241 if (!is_web_contents_capture && !is_screen_capture) { | 1129 if (!is_web_contents_capture && !is_screen_capture) { |
| 1242 if (EnumerationRequired(&audio_enumeration_cache_, audio_type) || | 1130 if (audio_type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 1243 EnumerationRequired(&video_enumeration_cache_, video_type)) { | 1131 video_type == MEDIA_DEVICE_VIDEO_CAPTURE) { |
| 1244 // Enumerate the devices if there is no valid device lists to be used. | 1132 StartEnumeration(request, label); |
| 1245 StartEnumeration(request); | |
| 1246 return; | 1133 return; |
| 1247 } else { | |
| 1248 // Cache is valid, so log the cached devices for MediaStream requests. | |
| 1249 if (request->request_type == MEDIA_GENERATE_STREAM) { | |
| 1250 std::string log_message("Using cached devices for request.\n"); | |
| 1251 if (audio_type != MEDIA_NO_SERVICE) { | |
| 1252 log_message += | |
| 1253 GetLogMessageString(audio_type, audio_enumeration_cache_.devices); | |
| 1254 } | |
| 1255 if (video_type != MEDIA_NO_SERVICE) { | |
| 1256 log_message += | |
| 1257 GetLogMessageString(video_type, video_enumeration_cache_.devices); | |
| 1258 } | |
| 1259 SendMessageToNativeLog(log_message); | |
| 1260 } | |
| 1261 } | 1134 } |
| 1262 | 1135 // If no actual device capture is requested, set up the request with an |
| 1263 if (!SetupDeviceCaptureRequest(request)) { | 1136 // empty device list. |
| 1137 if (!SetupDeviceCaptureRequest(request, MediaDeviceEnumeration())) { |
| 1264 FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); | 1138 FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); |
| 1265 return; | 1139 return; |
| 1266 } | 1140 } |
| 1267 } | 1141 } |
| 1268 ReadOutputParamsAndPostRequestToUI(label, request); | 1142 ReadOutputParamsAndPostRequestToUI(label, request, MediaDeviceEnumeration()); |
| 1269 } | 1143 } |
| 1270 | 1144 |
| 1271 bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) { | 1145 bool MediaStreamManager::SetupDeviceCaptureRequest( |
| 1146 DeviceRequest* request, |
| 1147 const MediaDeviceEnumeration& enumeration) { |
| 1272 DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || | 1148 DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 1273 request->audio_type() == MEDIA_NO_SERVICE) && | 1149 request->audio_type() == MEDIA_NO_SERVICE) && |
| 1274 (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE || | 1150 (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE || |
| 1275 request->video_type() == MEDIA_NO_SERVICE)); | 1151 request->video_type() == MEDIA_NO_SERVICE)); |
| 1276 std::string audio_device_id; | 1152 std::string audio_device_id; |
| 1277 if (request->controls.audio.requested && | 1153 if (request->controls.audio.requested && |
| 1278 !GetRequestedDeviceCaptureId(request, request->audio_type(), | 1154 !GetRequestedDeviceCaptureId(request, request->audio_type(), |
| 1155 enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT], |
| 1279 &audio_device_id)) { | 1156 &audio_device_id)) { |
| 1280 return false; | 1157 return false; |
| 1281 } | 1158 } |
| 1282 | 1159 |
| 1283 std::string video_device_id; | 1160 std::string video_device_id; |
| 1284 if (request->controls.video.requested && | 1161 if (request->controls.video.requested && |
| 1285 !GetRequestedDeviceCaptureId(request, request->video_type(), | 1162 !GetRequestedDeviceCaptureId(request, request->video_type(), |
| 1163 enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT], |
| 1286 &video_device_id)) { | 1164 &video_device_id)) { |
| 1287 return false; | 1165 return false; |
| 1288 } | 1166 } |
| 1289 request->CreateUIRequest(audio_device_id, video_device_id); | 1167 request->CreateUIRequest(audio_device_id, video_device_id); |
| 1290 DVLOG(3) << "Audio requested " << request->controls.audio.requested | 1168 DVLOG(3) << "Audio requested " << request->controls.audio.requested |
| 1291 << " device id = " << audio_device_id << "Video requested " | 1169 << " device id = " << audio_device_id << "Video requested " |
| 1292 << request->controls.video.requested | 1170 << request->controls.video.requested |
| 1293 << " device id = " << video_device_id; | 1171 << " device id = " << video_device_id; |
| 1294 return true; | 1172 return true; |
| 1295 } | 1173 } |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1465 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE)); | 1343 request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE)); |
| 1466 | 1344 |
| 1467 for (StreamDeviceInfo& device_info : request->devices) | 1345 for (StreamDeviceInfo& device_info : request->devices) |
| 1468 TranslateDeviceIdToSourceId(request, &device_info.device); | 1346 TranslateDeviceIdToSourceId(request, &device_info.device); |
| 1469 | 1347 |
| 1470 if (use_fake_ui_) { | 1348 if (use_fake_ui_) { |
| 1471 if (!fake_ui_) | 1349 if (!fake_ui_) |
| 1472 fake_ui_.reset(new FakeMediaStreamUIProxy()); | 1350 fake_ui_.reset(new FakeMediaStreamUIProxy()); |
| 1473 request->ui_proxy = std::move(fake_ui_); | 1351 request->ui_proxy = std::move(fake_ui_); |
| 1474 } else { | 1352 } else { |
| 1353 DCHECK(!request->ui_proxy); |
| 1475 request->ui_proxy = MediaStreamUIProxy::Create(); | 1354 request->ui_proxy = MediaStreamUIProxy::Create(); |
| 1476 } | 1355 } |
| 1477 | 1356 |
| 1478 // Output label permissions are based on input permission. | 1357 // Output label permissions are based on input permission. |
| 1479 const MediaStreamType type = | 1358 const MediaStreamType type = |
| 1480 request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || | 1359 request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 1481 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT | 1360 request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT |
| 1482 ? MEDIA_DEVICE_AUDIO_CAPTURE | 1361 ? MEDIA_DEVICE_AUDIO_CAPTURE |
| 1483 : MEDIA_DEVICE_VIDEO_CAPTURE; | 1362 : MEDIA_DEVICE_VIDEO_CAPTURE; |
| 1484 | 1363 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1506 | 1385 |
| 1507 if (!have_access) | 1386 if (!have_access) |
| 1508 ClearDeviceLabels(&request->devices); | 1387 ClearDeviceLabels(&request->devices); |
| 1509 | 1388 |
| 1510 request->requester->DevicesEnumerated( | 1389 request->requester->DevicesEnumerated( |
| 1511 request->requesting_frame_id, | 1390 request->requesting_frame_id, |
| 1512 request->page_request_id, | 1391 request->page_request_id, |
| 1513 label, | 1392 label, |
| 1514 request->devices); | 1393 request->devices); |
| 1515 | 1394 |
| 1516 // TODO(tommi): | 1395 // TODO(guidou): |
| 1517 // Ideally enumeration requests should be deleted once they have been served | 1396 // Ideally enumeration requests should be deleted once they have been served |
| 1518 // (as any request). However, this implementation mixes requests and | 1397 // (as any request). However, this implementation mixes requests and |
| 1519 // notifications together so enumeration requests are kept open by some | 1398 // notifications together so enumeration requests are kept open by some |
| 1520 // implementations (only Pepper?) and enumerations are done again when | 1399 // implementations (only Pepper?) and enumerations are done again when |
| 1521 // device notifications are fired. | 1400 // device notifications are fired. |
| 1522 // Implementations that just want to request the device list and be done | 1401 // Implementations that just want to request the device list and be done |
| 1523 // (e.g. DeviceRequestMessageFilter), they must (confusingly) call | 1402 // (e.g. DeviceRequestMessageFilter), they must (confusingly) call |
| 1524 // CancelRequest() after the request has been fulfilled. This is not | 1403 // CancelRequest() after the request has been fulfilled. This is not |
| 1525 // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest) | 1404 // obvious, not consistent in this class (see e.g. FinalizeMediaAccessRequest) |
| 1526 // and can lead to subtle bugs (requests not deleted at all deleted too | 1405 // and can lead to subtle bugs (requests not deleted at all deleted too |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1582 | 1461 |
| 1583 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is | 1462 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is |
| 1584 // fixed. | 1463 // fixed. |
| 1585 tracked_objects::ScopedTracker tracking_profile3( | 1464 tracked_objects::ScopedTracker tracking_profile3( |
| 1586 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1465 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 1587 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 3")); | 1466 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 3")); |
| 1588 // We want to be notified of IO message loop destruction to delete the thread | 1467 // We want to be notified of IO message loop destruction to delete the thread |
| 1589 // and the device managers. | 1468 // and the device managers. |
| 1590 base::MessageLoop::current()->AddDestructionObserver(this); | 1469 base::MessageLoop::current()->AddDestructionObserver(this); |
| 1591 | 1470 |
| 1592 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1593 switches::kUseFakeDeviceForMediaStream)) { | |
| 1594 audio_input_device_manager()->UseFakeDevice(); | |
| 1595 } | |
| 1596 | |
| 1597 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is | 1471 // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is |
| 1598 // fixed. | 1472 // fixed. |
| 1599 tracked_objects::ScopedTracker tracking_profile4( | 1473 tracked_objects::ScopedTracker tracking_profile4( |
| 1600 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1474 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 1601 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 4")); | 1475 "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 4")); |
| 1602 video_capture_manager_ = | 1476 video_capture_manager_ = |
| 1603 new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory( | 1477 new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory( |
| 1604 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI))); | 1478 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI))); |
| 1605 #if defined(OS_WIN) | 1479 #if defined(OS_WIN) |
| 1606 // Use an STA Video Capture Thread to try to avoid crashes on enumeration of | 1480 // Use an STA Video Capture Thread to try to avoid crashes on enumeration of |
| 1607 // buggy third party Direct Show modules, http://crbug.com/428958. | 1481 // buggy third party Direct Show modules, http://crbug.com/428958. |
| 1608 video_capture_thread_.init_com_with_mta(false); | 1482 video_capture_thread_.init_com_with_mta(false); |
| 1609 CHECK(video_capture_thread_.Start()); | 1483 CHECK(video_capture_thread_.Start()); |
| 1610 video_capture_manager_->Register(this, video_capture_thread_.task_runner()); | 1484 video_capture_manager_->Register(this, video_capture_thread_.task_runner()); |
| 1611 #else | 1485 #else |
| 1612 video_capture_manager_->Register(this, device_task_runner_); | 1486 video_capture_manager_->Register(this, device_task_runner_); |
| 1613 #endif | 1487 #endif |
| 1614 | 1488 |
| 1615 audio_output_device_enumerator_.reset(new AudioOutputDeviceEnumerator( | 1489 audio_output_device_enumerator_.reset(new AudioOutputDeviceEnumerator( |
| 1616 audio_manager_, AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING)); | 1490 audio_manager_, AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING)); |
| 1491 |
| 1492 media_devices_manager_.reset( |
| 1493 new MediaDevicesManager(audio_manager_, video_capture_manager_, this)); |
| 1617 } | 1494 } |
| 1618 | 1495 |
| 1619 void MediaStreamManager::Opened(MediaStreamType stream_type, | 1496 void MediaStreamManager::Opened(MediaStreamType stream_type, |
| 1620 int capture_session_id) { | 1497 int capture_session_id) { |
| 1621 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1498 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1622 DVLOG(1) << "Opened({stream_type = " << stream_type << "} " | 1499 DVLOG(1) << "Opened({stream_type = " << stream_type << "} " |
| 1623 << "{capture_session_id = " << capture_session_id << "})"; | 1500 << "{capture_session_id = " << capture_session_id << "})"; |
| 1624 // Find the request(s) containing this device and mark it as used. | 1501 // Find the request(s) containing this device and mark it as used. |
| 1625 // It can be used in several requests since the same device can be | 1502 // It can be used in several requests since the same device can be |
| 1626 // requested from the same web page. | 1503 // requested from the same web page. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1695 request->devices)); | 1572 request->devices)); |
| 1696 } | 1573 } |
| 1697 } | 1574 } |
| 1698 | 1575 |
| 1699 void MediaStreamManager::Closed(MediaStreamType stream_type, | 1576 void MediaStreamManager::Closed(MediaStreamType stream_type, |
| 1700 int capture_session_id) { | 1577 int capture_session_id) { |
| 1701 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1578 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1702 } | 1579 } |
| 1703 | 1580 |
| 1704 void MediaStreamManager::DevicesEnumerated( | 1581 void MediaStreamManager::DevicesEnumerated( |
| 1705 MediaStreamType stream_type, const StreamDeviceInfoArray& devices) { | 1582 bool requested_audio_input, |
| 1583 bool requested_video_input, |
| 1584 const std::string& label, |
| 1585 const MediaDeviceEnumeration& enumeration) { |
| 1706 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1586 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1707 DVLOG(1) << "DevicesEnumerated(" | |
| 1708 << "{stream_type = " << stream_type << "})"; | |
| 1709 | 1587 |
| 1710 std::string log_message = "New device enumeration result:\n" + | 1588 DeviceRequest* request = FindRequest(label); |
| 1711 GetLogMessageString(stream_type, devices); | 1589 if (!request) |
| 1712 SendMessageToNativeLog(log_message); | 1590 return; |
| 1713 | 1591 |
| 1714 // Only cache the device list when the device list has been changed. | 1592 bool requested[] = {requested_audio_input, requested_video_input}; |
| 1715 bool need_update_clients = false; | 1593 MediaStreamType stream_types[] = {MEDIA_DEVICE_AUDIO_CAPTURE, |
| 1716 bool need_update_device_change_subscribers = false; | 1594 MEDIA_DEVICE_VIDEO_CAPTURE}; |
| 1717 EnumerationCache* cache = stream_type == MEDIA_DEVICE_AUDIO_CAPTURE | 1595 MediaDeviceType device_types[] = {MEDIA_DEVICE_TYPE_AUDIO_INPUT, |
| 1718 ? &audio_enumeration_cache_ | 1596 MEDIA_DEVICE_TYPE_VIDEO_INPUT}; |
| 1719 : &video_enumeration_cache_; | |
| 1720 if (!cache->valid || devices.size() != cache->devices.size() || | |
| 1721 !std::equal(devices.begin(), devices.end(), cache->devices.begin(), | |
| 1722 StreamDeviceInfo::IsEqual)) { | |
| 1723 StopRemovedDevices(cache->devices, devices); | |
| 1724 need_update_clients = true; | |
| 1725 // Device-change subscribers should not be notified the first time the cache | |
| 1726 // is loaded , as this is not a change in the set of devices. The same | |
| 1727 // applies to enumerations listing no devices when the cache is empty. | |
| 1728 need_update_device_change_subscribers = | |
| 1729 cache->valid && (devices.size() != 0 || cache->devices.size() != 0); | |
| 1730 cache->devices = devices; | |
| 1731 | 1597 |
| 1732 // The device might not be able to be enumerated when it is not warmed up, | 1598 for (size_t i = 0; i < arraysize(requested); ++i) { |
| 1733 // for example, when the machine just wakes up from sleep. We set the cache | 1599 if (!requested[i]) |
| 1734 // to be invalid so that the next media request will trigger the | 1600 continue; |
| 1735 // enumeration again. See issue/317673. | |
| 1736 cache->valid = !devices.empty(); | |
| 1737 } | |
| 1738 | 1601 |
| 1739 if (need_update_clients && monitoring_started_) | 1602 DCHECK(request->audio_type() == stream_types[i] || |
| 1740 NotifyDevicesChanged(stream_type, devices); | 1603 request->video_type() == stream_types[i]); |
| 1741 | 1604 if (request->state(stream_types[i]) == MEDIA_REQUEST_STATE_REQUESTED) { |
| 1742 if (need_update_device_change_subscribers) | 1605 if (request->request_type == MEDIA_ENUMERATE_DEVICES) { |
| 1743 NotifyDeviceChangeSubscribers(stream_type); | 1606 // MEDIA_ENUMERATE_DEVICES requests are always for a single type, so it |
| 1744 | 1607 // is OK to ignore any remaining iteration in this loop. |
| 1745 // Publish the result for all requests waiting for device list(s). | 1608 ProcessEnumerationRequest(label, request, stream_types[i], |
| 1746 // Find the requests waiting for this device list, store their labels and | 1609 enumeration[device_types[i]]); |
| 1747 // release the iterator before calling device settings. We might get a call | 1610 return; |
| 1748 // back from device_settings that will need to iterate through devices. | 1611 } |
| 1749 std::list<std::string> label_list; | 1612 // Not a MEDIA_ENUMERATE_DEVICES request. |
| 1750 for (const LabeledDeviceRequest& labeled_request : requests_) { | 1613 request->SetState(stream_types[i], MEDIA_REQUEST_STATE_PENDING_APPROVAL); |
| 1751 DeviceRequest* const request = labeled_request.second; | |
| 1752 if (request->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && | |
| 1753 (request->audio_type() == stream_type || | |
| 1754 request->video_type() == stream_type)) { | |
| 1755 if (request->request_type != MEDIA_ENUMERATE_DEVICES) | |
| 1756 request->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL); | |
| 1757 label_list.push_back(labeled_request.first); | |
| 1758 } | 1614 } |
| 1759 } | 1615 } |
| 1760 | 1616 |
| 1761 for (const std::string& label : label_list) { | 1617 if (!SetupDeviceCaptureRequest(request, enumeration)) |
| 1762 DeviceRequest* const request = FindRequest(label); | 1618 FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); |
| 1763 switch (request->request_type) { | 1619 else |
| 1764 case MEDIA_ENUMERATE_DEVICES: | 1620 ReadOutputParamsAndPostRequestToUI(label, request, enumeration); |
| 1765 if (need_update_clients && request->requester) { | |
| 1766 request->devices = devices; | |
| 1767 FinalizeEnumerateDevices(label, request); | |
| 1768 } | |
| 1769 break; | |
| 1770 default: | |
| 1771 if (request->state(request->audio_type()) == | |
| 1772 MEDIA_REQUEST_STATE_REQUESTED || | |
| 1773 request->state(request->video_type()) == | |
| 1774 MEDIA_REQUEST_STATE_REQUESTED) { | |
| 1775 // We are doing enumeration for other type of media, wait until it is | |
| 1776 // all done before posting the request to UI because UI needs | |
| 1777 // the device lists to handle the request. | |
| 1778 break; | |
| 1779 } | |
| 1780 if (!SetupDeviceCaptureRequest(request)) | |
| 1781 FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE); | |
| 1782 else | |
| 1783 ReadOutputParamsAndPostRequestToUI(label, request); | |
| 1784 break; | |
| 1785 } | |
| 1786 } | |
| 1787 label_list.clear(); | |
| 1788 --active_enumeration_ref_count_[stream_type]; | |
| 1789 DCHECK_GE(active_enumeration_ref_count_[stream_type], 0); | |
| 1790 } | 1621 } |
| 1791 | 1622 |
| 1792 void MediaStreamManager::Aborted(MediaStreamType stream_type, | 1623 void MediaStreamManager::Aborted(MediaStreamType stream_type, |
| 1793 int capture_session_id) { | 1624 int capture_session_id) { |
| 1794 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1625 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1795 DVLOG(1) << "Aborted({stream_type = " << stream_type << "} " | 1626 DVLOG(1) << "Aborted({stream_type = " << stream_type << "} " |
| 1796 << "{capture_session_id = " << capture_session_id << "})"; | 1627 << "{capture_session_id = " << capture_session_id << "})"; |
| 1797 StopDevice(stream_type, capture_session_id); | 1628 StopDevice(stream_type, capture_session_id); |
| 1798 } | 1629 } |
| 1799 | 1630 |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1950 } | 1781 } |
| 1951 | 1782 |
| 1952 CancelRequest(label); | 1783 CancelRequest(label); |
| 1953 } | 1784 } |
| 1954 | 1785 |
| 1955 void MediaStreamManager::WillDestroyCurrentMessageLoop() { | 1786 void MediaStreamManager::WillDestroyCurrentMessageLoop() { |
| 1956 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()"; | 1787 DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()"; |
| 1957 DCHECK(CalledOnIOThread()); | 1788 DCHECK(CalledOnIOThread()); |
| 1958 DCHECK(requests_.empty()); | 1789 DCHECK(requests_.empty()); |
| 1959 if (device_task_runner_.get()) { | 1790 if (device_task_runner_.get()) { |
| 1960 StopMonitoring(); | 1791 media_devices_manager_->StopMonitoring(); |
| 1961 | 1792 |
| 1962 video_capture_manager_->Unregister(); | 1793 video_capture_manager_->Unregister(); |
| 1963 audio_input_device_manager_->Unregister(); | 1794 audio_input_device_manager_->Unregister(); |
| 1964 device_task_runner_ = NULL; | 1795 device_task_runner_ = NULL; |
| 1965 } | 1796 } |
| 1966 | 1797 |
| 1967 audio_input_device_manager_ = NULL; | 1798 audio_input_device_manager_ = NULL; |
| 1968 video_capture_manager_ = NULL; | 1799 video_capture_manager_ = NULL; |
| 1969 audio_output_device_enumerator_ = NULL; | 1800 audio_output_device_enumerator_ = NULL; |
| 1801 media_devices_manager_ = NULL; |
| 1970 g_media_stream_manager_tls_ptr.Pointer()->Set(NULL); | 1802 g_media_stream_manager_tls_ptr.Pointer()->Set(NULL); |
| 1971 } | 1803 } |
| 1972 | 1804 |
| 1973 void MediaStreamManager::NotifyDevicesChanged( | 1805 void MediaStreamManager::NotifyDevicesChanged( |
| 1974 MediaStreamType stream_type, | 1806 MediaDeviceType device_type, |
| 1975 const StreamDeviceInfoArray& devices) { | 1807 const MediaDeviceInfoArray& devices) { |
| 1976 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1808 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1977 MediaObserver* media_observer = | 1809 MediaObserver* media_observer = |
| 1978 GetContentClient()->browser()->GetMediaObserver(); | 1810 GetContentClient()->browser()->GetMediaObserver(); |
| 1979 | 1811 |
| 1980 // Map the devices to MediaStreamDevices. | 1812 MediaStreamType stream_type = ConvertToMediaStreamType(device_type); |
| 1981 MediaStreamDevices new_devices; | 1813 MediaStreamDevices new_devices = |
| 1982 for (const StreamDeviceInfo& device_info : devices) | 1814 ConvertToMediaStreamDevices(stream_type, devices); |
| 1983 new_devices.push_back(device_info.device); | |
| 1984 | 1815 |
| 1985 if (IsAudioInputMediaType(stream_type)) { | 1816 if (IsAudioInputMediaType(stream_type)) { |
| 1986 MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged( | 1817 MediaCaptureDevicesImpl::GetInstance()->OnAudioCaptureDevicesChanged( |
| 1987 new_devices); | 1818 new_devices); |
| 1988 if (media_observer) | 1819 if (media_observer) |
| 1989 media_observer->OnAudioCaptureDevicesChanged(); | 1820 media_observer->OnAudioCaptureDevicesChanged(); |
| 1990 } else if (IsVideoMediaType(stream_type)) { | 1821 } else if (IsVideoMediaType(stream_type)) { |
| 1991 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged( | 1822 MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged( |
| 1992 new_devices); | 1823 new_devices); |
| 1993 if (media_observer) | 1824 if (media_observer) |
| 1994 media_observer->OnVideoCaptureDevicesChanged(); | 1825 media_observer->OnVideoCaptureDevicesChanged(); |
| 1995 } else { | 1826 } else { |
| 1996 NOTREACHED(); | 1827 NOTREACHED(); |
| 1997 } | 1828 } |
| 1829 |
| 1830 ProcessOpenEnumerationRequests(stream_type, devices); |
| 1998 } | 1831 } |
| 1999 | 1832 |
| 2000 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { | 1833 bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { |
| 2001 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1834 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 2002 | 1835 |
| 2003 const bool requested_audio = IsAudioInputMediaType(request.audio_type()); | 1836 const bool requested_audio = IsAudioInputMediaType(request.audio_type()); |
| 2004 const bool requested_video = IsVideoMediaType(request.video_type()); | 1837 const bool requested_video = IsVideoMediaType(request.video_type()); |
| 2005 | 1838 |
| 2006 const bool audio_done = | 1839 const bool audio_done = |
| 2007 !requested_audio || | 1840 !requested_audio || |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2023 MediaStreamProvider* MediaStreamManager::GetDeviceManager( | 1856 MediaStreamProvider* MediaStreamManager::GetDeviceManager( |
| 2024 MediaStreamType stream_type) { | 1857 MediaStreamType stream_type) { |
| 2025 if (IsVideoMediaType(stream_type)) | 1858 if (IsVideoMediaType(stream_type)) |
| 2026 return video_capture_manager(); | 1859 return video_capture_manager(); |
| 2027 else if (IsAudioInputMediaType(stream_type)) | 1860 else if (IsAudioInputMediaType(stream_type)) |
| 2028 return audio_input_device_manager(); | 1861 return audio_input_device_manager(); |
| 2029 NOTREACHED(); | 1862 NOTREACHED(); |
| 2030 return NULL; | 1863 return NULL; |
| 2031 } | 1864 } |
| 2032 | 1865 |
| 2033 void MediaStreamManager::OnDevicesChanged( | |
| 2034 base::SystemMonitor::DeviceType device_type) { | |
| 2035 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 2036 | |
| 2037 // NOTE: This method is only called in response to physical audio/video device | |
| 2038 // changes (from the operating system). | |
| 2039 | |
| 2040 MediaStreamType stream_type; | |
| 2041 if (device_type == base::SystemMonitor::DEVTYPE_AUDIO) { | |
| 2042 stream_type = MEDIA_DEVICE_AUDIO_CAPTURE; | |
| 2043 } else if (device_type == base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) { | |
| 2044 stream_type = MEDIA_DEVICE_VIDEO_CAPTURE; | |
| 2045 } else { | |
| 2046 return; // Uninteresting device change. | |
| 2047 } | |
| 2048 | |
| 2049 // Always do enumeration even though some enumeration is in progress, because | |
| 2050 // those enumeration commands could be sent before these devices change. | |
| 2051 ++active_enumeration_ref_count_[stream_type]; | |
| 2052 GetDeviceManager(stream_type)->EnumerateDevices(stream_type); | |
| 2053 } | |
| 2054 | |
| 2055 void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type, | 1866 void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type, |
| 2056 StreamDeviceInfoArray devices, | 1867 StreamDeviceInfoArray devices, |
| 2057 gfx::NativeViewId window_id) { | 1868 gfx::NativeViewId window_id) { |
| 2058 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1869 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 2059 if (!window_id) | 1870 if (!window_id) |
| 2060 return; | 1871 return; |
| 2061 | 1872 |
| 2062 if (video_type != MEDIA_DESKTOP_VIDEO_CAPTURE) | 1873 if (video_type != MEDIA_DESKTOP_VIDEO_CAPTURE) |
| 2063 return; | 1874 return; |
| 2064 | 1875 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2166 } | 1977 } |
| 2167 | 1978 |
| 2168 return true; | 1979 return true; |
| 2169 } | 1980 } |
| 2170 | 1981 |
| 2171 void MediaStreamManager::SetCapturingLinkSecured(int render_process_id, | 1982 void MediaStreamManager::SetCapturingLinkSecured(int render_process_id, |
| 2172 int session_id, | 1983 int session_id, |
| 2173 content::MediaStreamType type, | 1984 content::MediaStreamType type, |
| 2174 bool is_secure) { | 1985 bool is_secure) { |
| 2175 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1986 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 2176 | |
| 2177 for (LabeledDeviceRequest& labeled_request : requests_) { | 1987 for (LabeledDeviceRequest& labeled_request : requests_) { |
| 2178 DeviceRequest* request = labeled_request.second; | 1988 DeviceRequest* request = labeled_request.second; |
| 2179 if (request->requesting_process_id != render_process_id) | 1989 if (request->requesting_process_id != render_process_id) |
| 2180 continue; | 1990 continue; |
| 2181 | 1991 |
| 2182 for (const StreamDeviceInfo& device_info : request->devices) { | 1992 for (const StreamDeviceInfo& device_info : request->devices) { |
| 2183 if (device_info.session_id == session_id && | 1993 if (device_info.session_id == session_id && |
| 2184 device_info.device.type == type) { | 1994 device_info.device.type == type) { |
| 2185 request->SetCapturingLinkSecured(is_secure); | 1995 request->SetCapturingLinkSecured(is_secure); |
| 2186 return; | 1996 return; |
| 2187 } | 1997 } |
| 2188 } | 1998 } |
| 2189 } | 1999 } |
| 2190 } | 2000 } |
| 2191 | 2001 |
| 2002 void MediaStreamManager::ProcessEnumerationRequest( |
| 2003 const std::string& label, |
| 2004 DeviceRequest* request, |
| 2005 MediaStreamType stream_type, |
| 2006 const MediaDeviceInfoArray& device_infos) { |
| 2007 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 2008 DCHECK_EQ(MEDIA_REQUEST_STATE_REQUESTED, request->state(stream_type)); |
| 2009 DCHECK(request->audio_type() == stream_type || |
| 2010 request->video_type() == stream_type); |
| 2011 DCHECK(request->audio_type() == MEDIA_NO_SERVICE || |
| 2012 request->video_type() == MEDIA_NO_SERVICE); |
| 2013 DCHECK_EQ(MEDIA_ENUMERATE_DEVICES, request->request_type); |
| 2014 |
| 2015 if (request->requester && !request->ui_proxy) { |
| 2016 request->devices = |
| 2017 ConvertToStreamDeviceInfoArray(stream_type, device_infos); |
| 2018 FinalizeEnumerateDevices(label, request); |
| 2019 } |
| 2020 } |
| 2021 |
| 2022 // This function is intended to support subscription-style device enumerations. |
| 2023 // It is only supported for media capture devices and will be removed once |
| 2024 // handling of enumeration requests and device-change notifications is migrated |
| 2025 // out of MediaStreamManager. |
| 2026 void MediaStreamManager::ProcessOpenEnumerationRequests( |
| 2027 MediaStreamType stream_type, |
| 2028 const MediaDeviceInfoArray& device_infos) { |
| 2029 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 2030 DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 2031 stream_type == MEDIA_DEVICE_VIDEO_CAPTURE); |
| 2032 |
| 2033 for (const LabeledDeviceRequest& labeled_request : requests_) { |
| 2034 DeviceRequest* request = labeled_request.second; |
| 2035 if (request->request_type == MEDIA_ENUMERATE_DEVICES && |
| 2036 request->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED && |
| 2037 (request->audio_type() == stream_type || |
| 2038 request->video_type() == stream_type)) { |
| 2039 ProcessEnumerationRequest(labeled_request.first, request, stream_type, |
| 2040 device_infos); |
| 2041 } |
| 2042 } |
| 2043 } |
| 2044 |
| 2192 } // namespace content | 2045 } // namespace content |
| OLD | NEW |