blob: df60f9a0639854a8b255dd26f9c0d1ff58eabb97 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// MediaStreamManager is used to open media capture devices.
//
// If either user or test harness selects --use-fake-device-for-media-stream,
// a fake video device or devices are used instead of real ones.
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/task/current_thread.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/bad_message.h"
#include "content/browser/media/capture_handle_manager.h"
#include "content/browser/media/media_devices_util.h"
#include "content/browser/renderer_host/media/media_devices_manager.h"
#include "content/browser/renderer_host/media/media_stream_power_logger.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/common/content_export.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/media_request_state.h"
#include "content/public/browser/media_stream_request.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/common/buildflags.h"
#include "media/base/video_facing.h"
#include "media/capture/mojom/video_capture.mojom.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
#include "third_party/blink/public/common/mediastream/media_devices.h"
#include "third_party/blink/public/common/mediastream/media_stream_controls.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#include "content/browser/media/captured_surface_controller.h"
#endif
namespace media {
class AudioSystem;
#if BUILDFLAG(IS_CHROMEOS)
class JpegAcceleratorProviderImpl;
class SystemEventMonitorImpl;
#endif
}
namespace url {
class Origin;
}
namespace content {
class AudioInputDeviceManager;
class AudioServiceListener;
class FakeMediaStreamUIProxy;
class MediaStreamUIProxy;
class PermissionControllerImpl;
class PreferredAudioOutputDeviceManager;
class VideoCaptureManager;
class VideoCaptureProvider;
enum TransferState { KEPT_ALIVE, GOT_OPEN_DEVICE };
struct TransferStatus {
TransferState state;
base::TimeTicks start_time;
};
typedef std::map<const base::UnguessableToken, TransferStatus> TransferMap;
// MediaStreamManager is used to generate and close new media devices, not to
// start the media flow. The classes requesting new media streams are answered
// using callbacks.
class CONTENT_EXPORT MediaStreamManager
: public MediaStreamProviderListener,
public base::CurrentThread::DestructionObserver {
public:
// Callback to deliver the result of a media access request.
using MediaAccessRequestCallback = base::OnceCallback<void(
const blink::mojom::StreamDevicesSet& stream_devices_set,
std::unique_ptr<MediaStreamUIProxy> ui)>;
using GenerateStreamsCallback = base::OnceCallback<void(
blink::mojom::MediaStreamRequestResult result,
const std::string& label,
blink::mojom::StreamDevicesSetPtr stream_devices_set,
bool pan_tilt_zoom_allowed)>;
using OpenDeviceCallback =
base::OnceCallback<void(bool success,
const std::string& label,
const blink::MediaStreamDevice& device)>;
using DeviceStoppedCallback =
base::RepeatingCallback<void(const std::string& label,
const blink::MediaStreamDevice& device)>;
using DeviceChangedCallback =
base::RepeatingCallback<void(const std::string& label,
const blink::MediaStreamDevice& old_device,
const blink::MediaStreamDevice& new_device)>;
using DeviceRequestStateChangeCallback = base::RepeatingCallback<void(
const std::string& label,
const blink::MediaStreamDevice& device,
const blink::mojom::MediaStreamStateChange new_state)>;
using DeviceCaptureConfigurationChangeCallback =
base::RepeatingCallback<void(const std::string& label,
const blink::MediaStreamDevice& device)>;
using DeviceCaptureHandleChangeCallback =
base::RepeatingCallback<void(const std::string& label,
const blink::MediaStreamDevice& device)>;
using ZoomLevelChangeCallback =
base::RepeatingCallback<void(const std::string& label,
const blink::MediaStreamDevice& device,
int zoom_level)>;
using GetOpenDeviceCallback =
base::OnceCallback<void(blink::mojom::MediaStreamRequestResult result,
blink::mojom::GetOpenDeviceResponsePtr response)>;
// Callback for testing.
using GenerateStreamTestCallback =
base::OnceCallback<bool(const blink::StreamControls&)>;
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Callback for creating a CapturedSurfaceController. Used to override the
// default CapturedSurfaceController in tests.
using CapturedSurfaceControllerFactoryCallback =
::base::RepeatingCallback<std::unique_ptr<CapturedSurfaceController>(
GlobalRenderFrameHostId,
WebContentsMediaCaptureId,
base::RepeatingCallback<void(int)> on_zoom_level_change_callback)>;
#endif
// Adds |message| to native logs for outstanding device requests, for use by
// render processes hosts whose corresponding render processes are requesting
// logging from webrtcLoggingPrivate API. Safe to call from any thread.
static void SendMessageToNativeLog(const std::string& message);
// Returns the current MediaStreamManager instance. This is used to get access
// to the getters that return objects owned by MediaStreamManager.
// Must be called on the IO thread.
static MediaStreamManager* GetInstance();
explicit MediaStreamManager(media::AudioSystem* audio_system);
// |audio_system| is required but defaults will be used if either
// |video_capture_system| or |device_task_runner| are null.
MediaStreamManager(
media::AudioSystem* audio_system,
std::unique_ptr<VideoCaptureProvider> video_capture_provider);
MediaStreamManager(const MediaStreamManager&) = delete;
MediaStreamManager& operator=(const MediaStreamManager&) = delete;
~MediaStreamManager() override;
// Used to access VideoCaptureManager.
VideoCaptureManager* video_capture_manager() const;
// Used to access AudioInputDeviceManager.
AudioInputDeviceManager* audio_input_device_manager() const;
// Used to access AudioServiceListener, must be called on UI thread.
AudioServiceListener* audio_service_listener();
// Used to access MediaDevicesManager.
MediaDevicesManager* media_devices_manager();
// Used to access AudioSystem.
media::AudioSystem* audio_system();
// Used to access PreferredAudioOutputDeviceManager.
PreferredAudioOutputDeviceManager* preferred_audio_output_device_manager();
// AddVideoCaptureObserver() and RemoveAllVideoCaptureObservers() must be
// called after InitializeDeviceManagersOnIOThread() and before
// WillDestroyCurrentMessageLoop(). They can be called more than once and it's
// ok to not call at all if the client is not interested in receiving
// media::VideoCaptureObserver callbacks.
// The methods must be called on BrowserThread::IO threads. The callbacks of
// media::VideoCaptureObserver also arrive on BrowserThread::IO threads.
void AddVideoCaptureObserver(media::VideoCaptureObserver* capture_observer);
void RemoveAllVideoCaptureObservers();
// Creates a new media access request which is identified by a unique string
// that's returned to the caller. This will trigger the infobar and ask users
// for access to the device. `render_frame_host_id` is used to determine where
// the infobar will appear to the user. |callback| is used to send the
// selected device to the clients. An empty list of device will be returned if
// the users deny the access.
std::string MakeMediaAccessRequest(
GlobalRenderFrameHostId render_frame_host_id,
int requester_id,
int page_request_id,
const blink::StreamControls& controls,
const url::Origin& security_origin,
MediaAccessRequestCallback callback);
// GenerateStream opens new media devices according to |controls|. It creates
// a new request which is identified by a unique string that's returned to the
// caller. `render_frame_host_id` is used to determine where the infobar will
// appear to the user. |device_stopped_callback| is set to receive device
// stopped notifications. |device_changed_callback| is set to receive device
// changed notifications. |device_request_state_change_callback| is used to
// notify clients about request state changes. TODO(crbug.com/40058526):
// Package device-related callbacks into a single struct.
void GenerateStreams(
GlobalRenderFrameHostId render_frame_host_id,
int requester_id,
int page_request_id,
const blink::StreamControls& controls,
MediaDeviceSaltAndOrigin salt_and_origin,
bool user_gesture,
blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
GenerateStreamsCallback generate_stream_callback,
DeviceStoppedCallback device_stopped_callback,
DeviceChangedCallback device_changed_callback,
DeviceRequestStateChangeCallback device_request_state_change_callback,
DeviceCaptureConfigurationChangeCallback
device_capture_configuration_change_callback,
DeviceCaptureHandleChangeCallback device_capture_handle_change_callback,
ZoomLevelChangeCallback zoom_level_change_callback);
// Accesses an existing open device, identified by |device_session_id|,
// and associates it with a new DeviceRequest. This device is then returned by
// invoking |get_open_device_callback| asynchronously.
void GetOpenDevice(
const base::UnguessableToken& device_session_id,
const base::UnguessableToken& transfer_id,
GlobalRenderFrameHostId requesting_render_frame_host_id,
int requester_id,
int page_request_id,
MediaDeviceSaltAndOrigin salt_and_origin,
GetOpenDeviceCallback get_open_device_callback,
DeviceStoppedCallback device_stopped_callback,
DeviceChangedCallback device_changed_callback,
DeviceRequestStateChangeCallback device_request_state_change_callback,
DeviceCaptureConfigurationChangeCallback
device_capture_configuration_change_callback,
DeviceCaptureHandleChangeCallback device_capture_handle_change_callback,
ZoomLevelChangeCallback zoom_level_change_callback);
// Cancel an open request identified by |page_request_id| for the given frame.
// Must be called on the IO thread.
void CancelRequest(GlobalRenderFrameHostId render_frame_host_id,
int requester_id,
int page_request_id);
// Cancel an open request identified by |label|. Must be called on the IO
// thread.
void CancelRequest(const std::string& label);
// Cancel all requests for the given `render_frame_host_id`. Must be called on
// the IO thread.
void CancelAllRequests(GlobalRenderFrameHostId render_frame_host_id,
int requester_id);
// Closes the stream device for a certain render frame. The stream must have
// been opened by a call to GenerateStream or GetOpenDevice. Must be called on
// the IO thread. Closing a cloned MediaStreamDevice, created by
// GetOpenDevice, doesn't affect the original MediaStreamDevice it was created
// from. Similarly, closing the original MediaStreamDevice, created by
// GenerateStream, doesn't affect the cloned device.
void StopStreamDevice(GlobalRenderFrameHostId render_frame_host_id,
int requester_id,
const std::string& device_id,
const base::UnguessableToken& session_id);
// Open a device identified by |device_id|. |type| must be either
// MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
// |device_stopped_callback| is set to receive device stopped notifications.
// The request is identified using string returned to the caller.
void OpenDevice(GlobalRenderFrameHostId render_frame_host_id,
int requester_id,
int page_request_id,
const std::string& device_id,
blink::mojom::MediaStreamType type,
MediaDeviceSaltAndOrigin salt_and_origin,
OpenDeviceCallback open_device_callback,
DeviceStoppedCallback device_stopped_callback);
// Find |device_id| in the list of |requests_|, and returns its session id,
// or an empty base::UnguessableToken if not found. Must be called on the IO
// thread.
base::UnguessableToken VideoDeviceIdToSessionId(
const std::string& device_id) const;
// Called by UI to make sure the device monitor is started so that UI receive
// notifications about device changes.
void EnsureDeviceMonitorStarted();
// Implements MediaStreamProviderListener.
void Opened(blink::mojom::MediaStreamType stream_type,
const base::UnguessableToken& capture_session_id) override;
void Closed(blink::mojom::MediaStreamType stream_type,
const base::UnguessableToken& capture_session_id) override;
void Aborted(blink::mojom::MediaStreamType stream_type,
const base::UnguessableToken& capture_session_id) override;
// Returns all devices currently opened by a request with label |label|.
// If no request with |label| exist, an empty array is returned.
blink::MediaStreamDevices GetDevicesOpenedByRequest(
const std::string& label) const;
using GetRawDeviceIdsOpenedForFrameCallback =
base::OnceCallback<void(std::vector<std::string> active_device_ids)>;
// Returns all device IDs currently opened for `render_frame_host_id` and its
// descendants with `type`. If no request exists that matches the constraints,
// an empty array is returned.
void GetRawDeviceIdsOpenedForFrame(
RenderFrameHost* render_frame_host,
blink::mojom::MediaStreamType type,
GetRawDeviceIdsOpenedForFrameCallback) const;
// This object gets deleted on the UI thread after the IO thread has been
// destroyed. So we need to know when IO thread is being destroyed so that
// we can delete VideoCaptureManager and AudioInputDeviceManager.
// Note: In tests it is sometimes necessary to invoke this explicitly when
// using BrowserTaskEnvironment because the notification happens too late.
// (see http://crbug.com/247525#c14).
void WillDestroyCurrentMessageLoop() override;
// Sends log messages to the render process hosts whose corresponding render
// processes are making device requests, to be used by the
// webrtcLoggingPrivate API if requested.
void AddLogMessageOnIOThread(const std::string& message);
// Called by the tests to specify a factory for creating
// FakeMediaStreamUIProxys to be used for generated streams.
void UseFakeUIFactoryForTests(
base::RepeatingCallback<std::unique_ptr<FakeMediaStreamUIProxy>(void)>
fake_ui_factory,
bool use_for_gum_desktop_capture = true,
std::optional<WebContentsMediaCaptureId> captured_tab_id = std::nullopt);
// Register and unregister a new callback for receiving native log entries.
// Called on the IO thread.
static void RegisterNativeLogCallback(
int renderer_host_id,
base::RepeatingCallback<void(const std::string&)> callback);
static void UnregisterNativeLogCallback(int renderer_host_id);
// Returns true if the renderer process identified with |render_process_id|
// is allowed to access |origin|.
static bool IsOriginAllowed(int render_process_id, const url::Origin& origin);
// Returns internal single instance of PreferredAudioOutputDeviceManager
// object instance. The client should not take ownership of the returned
// object.
static PreferredAudioOutputDeviceManager* GetPreferredOutputManagerInstance();
// Set whether the capturing is secure for the capturing session with given
// |session_id|, |render_process_id|, and the MediaStreamType |type|.
// Must be called on the IO thread.
void SetCapturingLinkSecured(int render_process_id,
const base::UnguessableToken& session_id,
blink::mojom::MediaStreamType type,
bool is_secure);
// Helper for sending up-to-date device lists to media observer when a
// capture device is plugged in or unplugged.
void NotifyDevicesChanged(blink::mojom::MediaDeviceType stream_type,
const blink::WebMediaDeviceInfoArray& devices);
// This method is called when an audio or video device is removed. It makes
// sure all MediaStreams that use a removed device are stopped and that the
// render process is notified. Must be called on the IO thread.
void StopRemovedDevice(blink::mojom::MediaDeviceType type,
const blink::WebMediaDeviceInfo& media_device_info);
void SetGenerateStreamsCallbackForTesting(
GenerateStreamTestCallback test_callback);
void SetStateForTesting(size_t request_index,
blink::mojom::MediaStreamType stream_type,
MediaRequestState new_state);
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void SetConditionalFocusWindowForTesting(base::TimeDelta window);
void SetCapturedSurfaceControllerFactoryForTesting(
CapturedSurfaceControllerFactoryCallback factory);
#endif
void SetPreferredAudioOutputDeviceManagerForTesting(
std::unique_ptr<PreferredAudioOutputDeviceManager> manager);
// This method is called when all tracks are started.
void OnStreamStarted(const std::string& label);
// Keeps MediaStreamDevice alive to allow transferred tracks to successfully
// find and clone it. Returns whether the specified device was found and
// successfully kept alive.
bool KeepDeviceAliveForTransfer(GlobalRenderFrameHostId render_frame_host_id,
int requester_id,
const base::UnguessableToken& session_id,
const base::UnguessableToken& transfer_id);
void OnCaptureConfigurationChanged(const base::UnguessableToken& session_id);
void OnRegionCaptureRectChanged(
const base::UnguessableToken& session_id,
const std::optional<gfx::Rect>& region_capture_rect);
#if BUILDFLAG(ENABLE_SCREEN_CAPTURE)
// Determines whether the captured surface (tab/window) should be focused.
// This can be called at most once, and only within the first 1s of the
// capture session being initiated. If a call with |focus=false| is not
// executed within this time period, the captured surface *is* focused.
//
// |is_from_microtask| and |is_from_timer| are used to distinguish:
// a. Explicit calls from the Web-application.
// b. Implicit calls resulting from the focusability-window-closing microtask.
// c. The browser-side timer.
// This distinction is reflected by UMA.
void SetCapturedDisplaySurfaceFocus(const std::string& label,
bool focus,
bool is_from_microtask,
bool is_from_timer);
#endif // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Captured Surface Control APIs.
void SendWheel(
GlobalRenderFrameHostId capturer_rfh_id,
const base::UnguessableToken& session_id,
blink::mojom::CapturedWheelActionPtr action,
base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
callback);
void UpdateZoomLevel(
GlobalRenderFrameHostId capturer_rfh_id,
const base::UnguessableToken& session_id,
blink::mojom::ZoomLevelAction action,
base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
callback);
void RequestCapturedSurfaceControlPermission(
GlobalRenderFrameHostId capturer_rfh_id,
const base::UnguessableToken& session_id,
base::OnceCallback<void(blink::mojom::CapturedSurfaceControlResult)>
callback);
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void RegisterDispatcherHost(
std::unique_ptr<blink::mojom::MediaStreamDispatcherHost> host,
mojo::PendingReceiver<blink::mojom::MediaStreamDispatcherHost> receiver);
size_t num_dispatcher_hosts() const { return dispatcher_hosts_.size(); }
void RegisterVideoCaptureHost(
std::unique_ptr<media::mojom::VideoCaptureHost> host,
mojo::PendingReceiver<media::mojom::VideoCaptureHost> receiver);
size_t num_video_capture_hosts() const { return video_capture_hosts_.size(); }
std::optional<url::Origin> GetOriginByVideoSessionId(
const base::UnguessableToken& session_id);
private:
friend class MediaStreamManagerTest;
FRIEND_TEST_ALL_PREFIXES(MediaStreamManagerTest, DesktopCaptureDeviceStopped);
FRIEND_TEST_ALL_PREFIXES(MediaStreamManagerTest, DesktopCaptureDeviceChanged);
FRIEND_TEST_ALL_PREFIXES(MediaStreamManagerTest,
MultiCaptureOnMediaStreamUIWindowId);
FRIEND_TEST_ALL_PREFIXES(MediaStreamManagerTest,
MultiCaptureAllDevicesOpened);
FRIEND_TEST_ALL_PREFIXES(MediaStreamManagerTest,
MultiCaptureNotAllDevicesOpened);
FRIEND_TEST_ALL_PREFIXES(MediaStreamManagerTest,
MultiCaptureIntermediateErrorOnOpening);
// Contains common data needed to keep track of requests.
class DeviceRequest;
// Contains data specific for MediaDeviceAccess requests
class MediaAccessRequest;
// Contains common data between GenerateStreams and GetOpenDevice requests
class CreateDeviceRequest;
// Contains data specific for GenerateStreams requests
class GenerateStreamsRequest;
// Contains data specific for GetOpenDevice requests
class GetOpenDeviceRequest;
// Contains data specific for OpenDevice requests
class OpenDeviceRequest;
// |DeviceRequests| is a list to ensure requests are processed in the order
// they arrive. The first member of the pair is the label of the
// |DeviceRequest|.
using LabeledDeviceRequest =
std::pair<std::string, std::unique_ptr<DeviceRequest>>;
using DeviceRequests = std::list<LabeledDeviceRequest>;
// Sets the |device| to the right audio / video field in |target_devices|.
static void SetRequestDevice(blink::mojom::StreamDevices& target_devices,
const blink::MediaStreamDevice& device);
void InitializeMaybeAsync(
std::unique_ptr<VideoCaptureProvider> video_capture_provider);
// |output_parameters| contains real values only if the request requires it.
void HandleAccessRequestResponse(
const std::string& label,
const media::AudioParameters& output_parameters,
const blink::mojom::StreamDevicesSet& stream_devices_set,
blink::mojom::MediaStreamRequestResult result);
void HandleChangeSourceRequestResponse(
const std::string& label,
DeviceRequest* request,
const blink::mojom::StreamDevicesSet& stream_devices_set);
void StopMediaStreamFromBrowser(const std::string& label);
void ChangeMediaStreamSourceFromBrowser(const std::string& label,
const DesktopMediaID& media_id,
bool captured_surface_control_active);
void OnRequestStateChangeFromBrowser(
const std::string& label,
const DesktopMediaID& media_id,
blink::mojom::MediaStreamStateChange new_state);
// Checks if all devices that was requested in the request identififed by
// |label| has been opened and set the request state accordingly.
void HandleRequestDone(const std::string& label, DeviceRequest* request);
// Stop the use of the device associated with |session_id| of type |type| in
// all |requests_|. The device is removed from the request. If a request
// doesn't use any devices as a consequence, the request is deleted.
void StopDevice(blink::mojom::MediaStreamType type,
const base::UnguessableToken& session_id);
// Calls the correct capture manager and closes the device with |session_id|.
// All requests that use the device are updated.
void CloseDevice(blink::mojom::MediaStreamType type,
const base::UnguessableToken& session_id);
// Returns true if a request for devices has been completed and the devices
// has either been opened or an error has occurred.
bool RequestDone(const DeviceRequest& request) const;
MediaStreamProvider* GetDeviceManager(
blink::mojom::MediaStreamType stream_type) const;
void StartEnumeration(DeviceRequest* request, const std::string& label);
// Adds a new request. Returns an iterator to that request, as stored
// in requests_.
DeviceRequests::const_iterator AddRequest(
std::unique_ptr<DeviceRequest> request);
DeviceRequests::const_iterator FindRequestIterator(
const std::string& label) const;
DeviceRequest* FindRequest(const std::string& label) const;
// Find a request by the session-ID of its video device.
// (In case of multiple video devices - any of them would fit.)
// TOOD(crbug.com/1466247): Remove this after making the Captured Surface
// Control APIs pass the label instead.
DeviceRequest* FindRequestByVideoSessionId(
const base::UnguessableToken& session_id) const;
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
CapturedSurfaceController* GetCapturedSurfaceController(
GlobalRenderFrameHostId capturer_rfh_id,
const base::UnguessableToken& session_id,
blink::mojom::CapturedSurfaceControlResult& result);
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Clones an existing device identified by |existing_device_session_id| and
// returns it. If no such device is found, it returns std::nullopt.
std::optional<blink::MediaStreamDevice> CloneExistingOpenDevice(
const base::UnguessableToken& existing_device_session_id,
const base::UnguessableToken& transfer_id,
const std::string& new_label);
void UpdateDeviceTransferStatus(DeviceRequest* request,
const blink::MediaStreamDevice* const device,
const base::UnguessableToken& transfer_id,
TransferState transfer_state);
void CancelRequest(DeviceRequests::const_iterator request_it);
void DeleteRequest(DeviceRequests::const_iterator request_it);
// Prepare the request with label |label| by starting device enumeration if
// needed.
void SetUpRequest(const std::string& label);
// Prepare |request| of type MEDIA_DEVICE_AUDIO_CAPTURE and/or
// MEDIA_DEVICE_VIDEO_CAPTURE for being posted to the UI by parsing
// StreamControls for requested device IDs.
bool SetUpDeviceCaptureRequest(DeviceRequest* request,
const MediaDeviceEnumeration& enumeration);
// Prepare |request| of type MEDIA_DISPLAY_CAPTURE.
bool SetUpDisplayCaptureRequest(DeviceRequest* request);
// Prepare |request| of type MEDIA_GUM_DESKTOP_AUDIO_CAPTURE and/or
// MEDIA_GUM_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
// StreamControls for the requested desktop ID.
bool SetUpScreenCaptureRequest(DeviceRequest* request);
// Resolve the random device ID of tab capture on UI thread before proceeding
// with the tab capture UI request.
bool SetUpTabCaptureRequest(DeviceRequest* request, const std::string& label);
// Prepare |request| for being posted to the UI to bring up the picker again
// to change the desktop capture source.
void SetUpDesktopCaptureChangeSourceRequest(DeviceRequest* request,
const std::string& label,
const DesktopMediaID& media_id);
DesktopMediaID ResolveTabCaptureDeviceIdOnUIThread(
const std::string& capture_device_id,
GlobalRenderFrameHostId render_frame_host_id,
const GURL& origin);
// Prepare |request| of type MEDIA_GUM_TAB_AUDIO_CAPTURE and/or
// MEDIA_GUM_TAB_VIDEO_CAPTURE for being posted to the UI after the
// requested tab capture IDs are resolved from registry.
void FinishTabCaptureRequestSetupWithDeviceId(
const std::string& label,
const DesktopMediaID& device_id);
// Called when a request has been setup and devices have been enumerated if
// needed.
void ReadOutputParamsAndPostRequestToUI(
const std::string& label,
DeviceRequest* request,
const MediaDeviceEnumeration& enumeration);
// Called when audio output parameters have been read if needed.
void PostRequestToUI(
const std::string& label,
const MediaDeviceEnumeration& enumeration,
const std::optional<media::AudioParameters>& output_parameters);
// Returns true if a device with |device_id| has already been requested with
// a render_frame_host_id and type equal to the the values
// in |request|. If it has been requested, |device_info| contain information
// about the device.
bool FindExistingRequestedDevice(
const DeviceRequest& new_request,
const blink::MediaStreamDevice& new_device,
blink::MediaStreamDevice* existing_device,
MediaRequestState* existing_request_state) const;
void FinalizeGenerateStreams(const std::string& label,
DeviceRequest* request);
void FinalizeGetOpenDevice(const std::string& label, DeviceRequest* request);
void PanTiltZoomPermissionChecked(
const std::string& label,
const std::optional<blink::MediaStreamDevice>& video_device,
bool pan_tilt_zoom_allowed);
void FinalizeRequestFailed(DeviceRequests::const_iterator request_it,
blink::mojom::MediaStreamRequestResult result);
void FinalizeChangeDevice(const std::string& label, DeviceRequest* request);
void FinalizeMediaAccessRequest(
DeviceRequests::const_iterator request_it,
const blink::mojom::StreamDevicesSet& stream_devices_set);
void HandleCheckMediaAccessResponse(const std::string& label,
bool have_access);
// Picks a device ID from a list of required and alternate device IDs,
// presented as part of a TrackControls structure.
// Either the required device ID is picked (if present), or the first
// valid alternate device ID.
// Returns false if the required device ID is present and invalid.
// Otherwise, if no valid device is found, device_id is unchanged.
bool RemoveInvalidDeviceIds(const MediaDeviceSaltAndOrigin& salt_and_origin,
const blink::TrackControls& controls,
const blink::WebMediaDeviceInfoArray& devices,
std::vector<std::string>* device_id) const;
// Finds the requested device id from request. The requested device type
// must be MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
bool GetEligibleCaptureDeviceids(
const DeviceRequest* request,
blink::mojom::MediaStreamType type,
const blink::WebMediaDeviceInfoArray& devices,
std::vector<std::string>* device_id) const;
void TranslateDeviceIdToSourceId(const DeviceRequest* request,
blink::MediaStreamDevice* device) const;
// Handles the callback from MediaStreamUIProxy to receive the UI window id,
// used for excluding the notification window in desktop capturing.
void OnMediaStreamUIWindowId(
blink::mojom::MediaStreamType video_type,
blink::mojom::StreamDevicesSetPtr stream_devices_set,
gfx::NativeViewId window_id);
// Runs on the IO thread and does the actual [un]registration of callbacks.
void DoNativeLogCallbackRegistration(
int renderer_host_id,
base::RepeatingCallback<void(const std::string&)> callback);
void DoNativeLogCallbackUnregistration(int renderer_host_id);
// Callback to handle the reply to a low-level enumeration request.
void DevicesEnumerated(bool requested_audio_input,
bool requested_video_input,
const std::string& label,
const MediaDeviceEnumeration& enumeration);
// Creates blink::MediaStreamDevices for |devices_infos| of |stream_type|. For
// video capture device it also uses cached content from
// |video_capture_manager_| to set the MediaStreamDevice fields.
blink::MediaStreamDevices ConvertToMediaStreamDevices(
blink::mojom::MediaStreamType stream_type,
const blink::WebMediaDeviceInfoArray& device_infos);
// Activate the specified tab and bring it to the front.
void ActivateTabOnUIThread(const DesktopMediaID source);
// Get the permission controller for a particular RFH. Must be called on the
// UI thread.
static PermissionControllerImpl* GetPermissionController(
GlobalRenderFrameHostId render_frame_host_id);
void SubscribeToPermissionController(const std::string& label,
const DeviceRequest* request);
// Subscribe to the permission controller in order to monitor camera/mic
// permission updates for a particular DeviceRequest. All the additional
// information is needed because `FindRequest` can't be called on the UI
// thread.
void SubscribeToPermissionControllerOnUIThread(
const std::string& label,
GlobalRenderFrameHostId requesting_render_frame_host_id,
int requester_id,
int page_request_id,
bool is_audio_request,
bool is_video_request,
const GURL& origin);
// Store the subscription ids on a DeviceRequest in order to allow
// unsubscribing when the request is deleted.
void SetPermissionSubscriptionIDs(
const std::string& label,
GlobalRenderFrameHostId requesting_render_frame_host_id,
PermissionController::SubscriptionId audio_subscription_id,
PermissionController::SubscriptionId video_subscription_id);
// Unsubscribe from following permission updates for the two specified
// subscription IDs. Called when a request is deleted.
static void UnsubscribeFromPermissionControllerOnUIThread(
GlobalRenderFrameHostId requesting_render_frame_host_id,
PermissionController::SubscriptionId audio_subscription_id,
PermissionController::SubscriptionId video_subscription_id);
// Callback that the PermissionController calls when a permission is updated.
void PermissionChangedCallback(
GlobalRenderFrameHostId requesting_render_frame_host_id,
int requester_id,
int page_request_id,
blink::mojom::PermissionStatus status);
// Start tracking capture-handle changes for tab-capture.
void MaybeStartTrackingCaptureHandleConfig(
const std::string& label,
const blink::MediaStreamDevice& captured_device,
DeviceRequest& request);
// Stop tracking capture-handle changes for tab-capture.
void MaybeStopTrackingCaptureHandleConfig(
const std::string& label,
const blink::MediaStreamDevice& captured_device);
// When device changes, update which tabs' capture-handles are tracked.
void MaybeUpdateTrackedCaptureHandleConfigs(
const std::string& label,
const blink::mojom::StreamDevicesSet& new_stream_devices_set,
DeviceRequest& request);
bool ShouldUseFakeUIProxy(const DeviceRequest& request) const;
std::unique_ptr<MediaStreamUIProxy> MakeFakeUIProxy(
const std::string& label,
const MediaDeviceEnumeration& enumeration,
DeviceRequest* request);
void GetRawDeviceIdsOpenedForFrameIds(
blink::mojom::MediaStreamType type,
GetRawDeviceIdsOpenedForFrameCallback callback,
base::flat_set<GlobalRenderFrameHostId> render_frame_host_ids) const;
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
void OnVideoCaptureHostConnectionError();
#endif
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Defines a window of opportunity for the Web-application to decide
// whether a display-surface which it's capturing should be focused.
// After |kConditionalFocusWindow| past the beginning of the capture,
// the browser makes its own decision and ignores further instructions
// from Web-applications, thereby preventing applications from changing
// focus at an arbitrary time.
base::TimeDelta conditional_focus_window_ = base::Seconds(1);
CapturedSurfaceControllerFactoryCallback captured_surface_controller_factory_;
#endif
const raw_ptr<media::AudioSystem, DanglingUntriaged>
audio_system_; // not owned
scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_;
scoped_refptr<VideoCaptureManager> video_capture_manager_;
std::optional<base::Thread> video_capture_thread_;
std::unique_ptr<MediaDevicesManager> media_devices_manager_;
std::unique_ptr<PreferredAudioOutputDeviceManager>
preferred_audio_output_device_manager_;
// All non-closed request. Must be accessed on IO thread.
DeviceRequests requests_;
// A fake UI factory allows bypassing the user interaction with permission and
// capture selection dialogs, immediately starting capture with a default
// selection.
// Set in unit tests via UseFakeUIFactoryForTests(), and enabled in browser
// tests / web tests via the command line flag --use-fake-ui-for-media-stream.
base::RepeatingCallback<std::unique_ptr<FakeMediaStreamUIProxy>(void)>
fake_ui_factory_;
// The fake UI doesn't work for getUserMedia desktop captures, so in general
// we won't use it for them, even if fake_ui_factory_ is set (see
// crbug.com/919485).
// Some unittests do still require the fake ui to be used for all captures, so
// set this indicator to true.
bool use_fake_ui_for_gum_desktop_capture_ = false;
// If `true`, the fake UI factory is used only for cameras and microphones,
// and NOT for any form of screen-capture, regardless if that screen-capture
// is getDisplayMedia-driven or getUserMedia-driven.
bool use_fake_ui_only_for_camera_and_microphone_ = false;
// If `fake_ui_factory_` is set, then when its use results in tab-capture:
// * If `fake_ui_factory_captured_tab_id_` is also set, it determines the ID
// of the tab that will be captured.
// * Otherwise, the capturing tab will capture itself.
std::optional<WebContentsMediaCaptureId> fake_ui_factory_captured_tab_id_;
// Observes changes of captured tabs' CaptureHandleConfig and reports
// this changes back to their capturers. This object lives on the UI thread
// and must be accessed on it and torn down from it.
CaptureHandleManager capture_handle_manager_;
// Maps render process hosts to log callbacks. Used on the IO thread.
std::map<int, base::RepeatingCallback<void(const std::string&)>>
log_callbacks_;
std::unique_ptr<AudioServiceListener> audio_service_listener_;
// Provider of system power change logging to the WebRTC logs.
MediaStreamPowerLogger power_logger_;
mojo::UniqueReceiverSet<blink::mojom::MediaStreamDispatcherHost>
dispatcher_hosts_;
mojo::UniqueReceiverSet<media::mojom::VideoCaptureHost> video_capture_hosts_;
GenerateStreamTestCallback generate_stream_test_callback_;
#if BUILDFLAG(IS_CHROMEOS)
std::unique_ptr<media::JpegAcceleratorProviderImpl>
jpeg_accelerator_provider_;
std::unique_ptr<media::SystemEventMonitorImpl> system_event_monitor_;
#endif
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_MANAGER_H_