#include "content/browser/renderer_host/media/media_devices_manager.h"
#include <stddef.h>
#include <stdint.h>
#include <functional>
#include <map>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/ranges/algorithm.h"
#include "base/sequence_checker.h"
#include "base/strings/stringprintf.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/media/media_devices_permission_checker.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/common/features.h"
#include "content/public/browser/audio_service.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/audio_system.h"
#include "media/base/media_switches.h"
#include "media/capture/capture_switches.h"
#include "media/capture/mojom/video_capture_types.mojom-shared.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/audio/public/mojom/device_notifications.mojom.h"
#include "services/video_capture/public/cpp/features.h"
#include "third_party/blink/public/common/mediastream/media_devices.h"
#include "third_party/blink/public/mojom/mediastream/media_devices.mojom.h"
#if BUILDFLAG(IS_MAC)
#include "base/functional/callback_helpers.h"
#include "base/task/single_thread_task_runner.h"
#include "content/browser/browser_main_loop.h"
#include "media/device_monitors/device_monitor_mac.h"
#endif
namespace content {
namespace {
DeviceEnumerationResult;
struct { … } const kFallbackVideoResolutions[] = …;
const uint16_t kFallbackVideoFrameRates[] = …;
void SendLogMessage(const std::string& message) { … }
const char* DeviceTypeToString(MediaDeviceType device_type) { … }
std::string GetDevicesEnumeratedLogString(
MediaDeviceType device_type,
const blink::WebMediaDeviceInfoArray& device_infos) { … }
blink::WebMediaDeviceInfoArray GetFakeAudioDevices(bool is_input) { … }
std::string VideoLabelWithoutModelID(const std::string& label) { … }
bool LabelHasUSBModel(const std::string& label) { … }
std::string GetUSBModelFromLabel(const std::string& label) { … }
bool IsRealAudioDeviceID(const std::string& device_id) { … }
bool EqualDeviceExcludingGroupID(const blink::WebMediaDeviceInfo& lhs,
const blink::WebMediaDeviceInfo& rhs) { … }
bool EqualDeviceIncludingGroupID(const blink::WebMediaDeviceInfo& lhs,
const blink::WebMediaDeviceInfo& rhs) { … }
void ReplaceInvalidFrameRatesWithFallback(media::VideoCaptureFormats* formats) { … }
void BindDeviceNotifierFromUIThread(
mojo::PendingReceiver<audio::mojom::DeviceNotifier> receiver) { … }
void ReportVideoEnumerationStart() { … }
void ReportVideoEnumerationResult(DeviceEnumerationResult result_code) { … }
BrowserContext* GetBrowserContextOnUIThread(
GlobalRenderFrameHostId render_frame_host_id) { … }
void RankDevices(
GlobalRenderFrameHostId render_frame_host_id,
const MediaDevicesManager::BoolDeviceTypes& requested_types,
base::OnceCallback<void(const MediaDeviceEnumeration&)> callback,
const MediaDeviceEnumeration& enumeration) { … }
}
std::string GuessVideoGroupID(const blink::WebMediaDeviceInfoArray& audio_infos,
const blink::WebMediaDeviceInfo& video_info) { … }
struct MediaDevicesManager::EnumerationRequest { … };
class MediaDevicesManager::CacheInfo { … };
MediaDevicesManager::SubscriptionRequest::SubscriptionRequest(
GlobalRenderFrameHostId render_frame_host_id,
const BoolDeviceTypes& subscribe_types,
mojo::Remote<blink::mojom::MediaDevicesListener> listener)
: … { … }
MediaDevicesManager::SubscriptionRequest::SubscriptionRequest(
SubscriptionRequest&&) = default;
MediaDevicesManager::SubscriptionRequest::~SubscriptionRequest() = default;
MediaDevicesManager::SubscriptionRequest&
MediaDevicesManager::SubscriptionRequest::operator=(SubscriptionRequest&&) =
default;
class MediaDevicesManager::AudioServiceDeviceListener
: public audio::mojom::DeviceListener { … };
MediaDevicesManager::MediaDevicesManager(
media::AudioSystem* audio_system,
const scoped_refptr<VideoCaptureManager>& video_capture_manager,
StopRemovedInputDeviceCallback stop_removed_input_device_cb,
UIInputDeviceChangeCallback ui_input_device_change_cb)
: … { … }
MediaDevicesManager::~MediaDevicesManager() { … }
void MediaDevicesManager::EnumerateDevices(
const BoolDeviceTypes& requested_types,
EnumerationCallback callback) { … }
void MediaDevicesManager::EnumerateAndRankDevices(
GlobalRenderFrameHostId render_frame_host_id,
const BoolDeviceTypes& requested_types,
EnumerationCallback callback) { … }
void MediaDevicesManager::EnumerateAndRankDevices(
GlobalRenderFrameHostId render_frame_host_id,
const BoolDeviceTypes& requested_types,
bool request_video_input_capabilities,
bool request_audio_input_capabilities,
EnumerateDevicesCallback callback) { … }
uint32_t MediaDevicesManager::SubscribeDeviceChangeNotifications(
GlobalRenderFrameHostId render_frame_host_id,
const BoolDeviceTypes& subscribe_types,
mojo::PendingRemote<blink::mojom::MediaDevicesListener> listener) { … }
void MediaDevicesManager::SetSubscriptionLastSeenDeviceIdSalt(
uint32_t subscription_id,
const MediaDeviceSaltAndOrigin& salt_and_origin) { … }
void MediaDevicesManager::UnsubscribeDeviceChangeNotifications(
uint32_t subscription_id) { … }
void MediaDevicesManager::SetCachePolicy(MediaDeviceType type,
CachePolicy policy) { … }
void MediaDevicesManager::StartMonitoring() { … }
void MediaDevicesManager::StopMonitoring() { … }
void MediaDevicesManager::OnDevicesChanged(
base::SystemMonitor::DeviceType device_type) { … }
media::VideoCaptureFormats MediaDevicesManager::GetVideoInputFormats(
const std::string& device_id,
bool try_in_use_first) { … }
blink::WebMediaDeviceInfoArray MediaDevicesManager::GetCachedDeviceInfo(
MediaDeviceType type) const { … }
void MediaDevicesManager::RegisterDispatcherHost(
std::unique_ptr<blink::mojom::MediaDevicesDispatcherHost> dispatcher_host,
mojo::PendingReceiver<blink::mojom::MediaDevicesDispatcherHost> receiver) { … }
void MediaDevicesManager::SetPermissionChecker(
std::unique_ptr<MediaDevicesPermissionChecker> permission_checker) { … }
void MediaDevicesManager::CheckPermissionsForEnumerateDevices(
GlobalRenderFrameHostId render_frame_host_id,
const BoolDeviceTypes& requested_types,
bool request_video_input_capabilities,
bool request_audio_input_capabilities,
EnumerateDevicesCallback callback,
const MediaDeviceSaltAndOrigin& salt_and_origin) { … }
void MediaDevicesManager::OnPermissionsCheckDone(
GlobalRenderFrameHostId render_frame_host_id,
const MediaDevicesManager::BoolDeviceTypes& requested_types,
bool request_video_input_capabilities,
bool request_audio_input_capabilities,
EnumerateDevicesCallback callback,
const MediaDeviceSaltAndOrigin& salt_and_origin,
const MediaDevicesManager::BoolDeviceTypes& has_permissions) { … }
void MediaDevicesManager::OnDevicesEnumerated(
const MediaDevicesManager::BoolDeviceTypes& requested_types,
bool request_video_input_capabilities,
bool request_audio_input_capabilities,
EnumerateDevicesCallback callback,
const MediaDeviceSaltAndOrigin& salt_and_origin,
const MediaDevicesManager::BoolDeviceTypes& has_permissions,
const MediaDeviceEnumeration& enumeration) { … }
void MediaDevicesManager::GetAudioInputCapabilities(
bool request_video_input_capabilities,
bool request_audio_input_capabilities,
EnumerateDevicesCallback callback,
const MediaDeviceEnumeration& raw_enumeration_results,
const std::vector<blink::WebMediaDeviceInfoArray>&
hashed_enumeration_results) { … }
void MediaDevicesManager::GotAudioInputCapabilities(
size_t state_id,
size_t capabilities_index,
const std::optional<media::AudioParameters>& parameters) { … }
void MediaDevicesManager::FinalizeDevicesEnumerated(
EnumerationState enumeration_state) { … }
std::vector<VideoInputDeviceCapabilitiesPtr>
MediaDevicesManager::ComputeVideoInputCapabilities(
const blink::WebMediaDeviceInfoArray& raw_device_infos,
const blink::WebMediaDeviceInfoArray& translated_device_infos) { … }
void MediaDevicesManager::DoEnumerateDevices(MediaDeviceType type) { … }
void MediaDevicesManager::EnumerateAudioDevices(bool is_input) { … }
void MediaDevicesManager::VideoInputDevicesEnumerated(
DeviceEnumerationResult result_code,
const media::VideoCaptureDeviceDescriptors& descriptors) { … }
void MediaDevicesManager::AudioDevicesEnumerated(
MediaDeviceType type,
media::AudioDeviceDescriptions device_descriptions) { … }
void MediaDevicesManager::DevicesEnumerated(
MediaDeviceType type,
const blink::WebMediaDeviceInfoArray& snapshot) { … }
void MediaDevicesManager::UpdateSnapshot(
MediaDeviceType type,
const blink::WebMediaDeviceInfoArray& new_snapshot,
bool ignore_group_id) { … }
void MediaDevicesManager::ProcessRequests() { … }
bool MediaDevicesManager::IsEnumerationRequestReady(
const EnumerationRequest& request_info) { … }
void MediaDevicesManager::HandleDevicesChanged(MediaDeviceType type) { … }
void MediaDevicesManager::MaybeStopRemovedInputDevices(
MediaDeviceType type,
const blink::WebMediaDeviceInfoArray& new_snapshot) { … }
void MediaDevicesManager::OnSaltAndOriginForSubscription(
uint32_t subscription_id,
GlobalRenderFrameHostId render_frame_host_id,
MediaDeviceType type,
const blink::WebMediaDeviceInfoArray& device_infos,
bool devices_changed,
const MediaDeviceSaltAndOrigin& salt_and_origin) { … }
void MediaDevicesManager::CheckPermissionForDeviceChange(
uint32_t subscription_id,
GlobalRenderFrameHostId render_frame_host_id,
MediaDeviceType type,
const blink::WebMediaDeviceInfoArray& device_infos,
const MediaDeviceSaltAndOrigin& salt_and_origin) { … }
void MediaDevicesManager::OnCheckedPermissionForDeviceChange(
uint32_t subscription_id,
GlobalRenderFrameHostId render_frame_host_id,
MediaDeviceType type,
const blink::WebMediaDeviceInfoArray& device_infos,
const MediaDeviceSaltAndOrigin& salt_and_origin,
bool has_permission) { … }
void MediaDevicesManager::NotifyDeviceChange(
uint32_t subscription_id,
MediaDeviceType type,
const MediaDeviceSaltAndOrigin& salt_and_origin,
bool has_permission,
const MediaDeviceEnumeration& enumeration) { … }
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
void MediaDevicesManager::RegisterVideoCaptureDevicesChangedObserver() {
CHECK(!video_capture_service_device_changed_observer_);
if (base::FeatureList::IsEnabled(
features::kRunVideoCaptureServiceInBrowserProcess)) {
return;
}
video_capture_service_device_changed_observer_ =
std::make_unique<VideoCaptureDevicesChangedObserver>(
base::BindRepeating(
&MediaDevicesManager::HandleDevicesChanged,
base::Unretained(this), MediaDeviceType::kMediaVideoInput),
base::BindRepeating([] {
if (auto* monitor = base::SystemMonitor::Get()) {
monitor->ProcessDevicesChanged(
base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
}
}));
video_capture_service_device_changed_observer_->ConnectToService();
}
#endif
MediaDevicesManager::EnumerationState::EnumerationState() = default;
MediaDevicesManager::EnumerationState::EnumerationState(
EnumerationState&& other) = default;
MediaDevicesManager::EnumerationState::~EnumerationState() = default;
MediaDevicesManager::EnumerationState& MediaDevicesManager::EnumerationState::
operator=(EnumerationState&& other) = default;
}