0

[CSC] Correct lifetime for the CSC indicator when changing source

When STTI (share-this-tab-instead) is used, a new infobar is created.
This appears to the user as the indicator being removed.
By seeding the correct state of the CSC indicator after STTI, we ensure
the indicator appears persistent to the user.

We perform two changes:
* The source-change callback is extended with a bool,
  allowing TabSharingUIViews to report back to the MediaStreamManager
  whether CSC was active at the time when STTI was invoked.
* Subsequently constructed TabSharingUIViews objects (for the current
  capture-session) are seeded with the knowledge of whether CSC is
  already active.

For the second of these, we extend content::MediaStreamRequest.
This is not ideal, since the CSC activation status is associated with
the capture-session rather with the request. The alternatives considered
thus far have all been less appealing; for example, extending
MediaAccessHandler::HandleRequest() to accept additional parameters
would have affected a large number of sub-classes for whom this
parameter is meaningless.

Bug: 1466247, 324468211, 332555474
Change-Id: I40cdeeb3b1bb0caafd5b728d9b1acbaee29f68ec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5435458
Reviewed-by: Nico Weber <thakis@chromium.org>
Reviewed-by: Peter Conn <peconn@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Commit-Queue: Elad Alon <eladalon@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Auto-Submit: Elad Alon <eladalon@chromium.org>
Reviewed-by: Sergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1284561}
This commit is contained in:
Elad Alon
2024-04-09 17:30:21 +00:00
committed by Chromium LUCI CQ
parent 7ae7c390eb
commit 71a9e11e9d
35 changed files with 289 additions and 125 deletions

@ -70,7 +70,8 @@ class MediaAccessPermissionRequestTest : public testing::Test {
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
false /* disable_local_echo */,
false /* request_pan_tilt_zoom_permission */);
false /* request_pan_tilt_zoom_permission */,
false /* captured_surface_control_active */);
std::unique_ptr<TestMediaAccessPermissionRequest> permission_request;
permission_request = std::make_unique<TestMediaAccessPermissionRequest>(

@ -31,9 +31,11 @@ gfx::NativeViewId ScreenCaptureNotificationUIAsh::OnStarted(
base::BindRepeating(
&ScreenCaptureNotificationUIAsh::ProcessStopRequestFromUI,
weak_ptr_factory_.GetWeakPtr()),
source_callback ? base::BindRepeating(std::move(source_callback),
content::DesktopMediaID())
: base::RepeatingClosure(),
source_callback
? base::BindRepeating(std::move(source_callback),
content::DesktopMediaID(),
/*captured_surface_control_active=*/false)
: base::RepeatingClosure(),
text_);
return 0;
}

@ -126,7 +126,8 @@ content::MediaStreamRequest CreateMediaStreamRequest(
/*requested_audio_device_id=*/{}, {requested_video_device_id},
blink::mojom::MediaStreamType::NO_SERVICE, video_type,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
}
} // namespace
@ -1337,7 +1338,9 @@ IN_PROC_BROWSER_TEST_F(DlpContentManagerAshScreenShareBrowserTest,
new_web_contents->GetPrimaryMainFrame()->GetProcess()->GetID(),
new_web_contents->GetPrimaryMainFrame()->GetRoutingID()));
// Simulate changing the source to another tab.
manager->OnScreenShareSourceChanging(kLabel, media_id, new_media_id);
manager->OnScreenShareSourceChanging(
kLabel, media_id, new_media_id,
/*captured_surface_control_active=*/false);
EXPECT_FALSE(display_service_tester.GetNotification(
kScreenShareResumedNotificationId));
manager->OnScreenShareStopped(kLabel, media_id);

@ -377,11 +377,13 @@ void DlpContentManager::ScreenShareInfo::Resume() {
web_contents_ && source_callback_) {
content::RenderFrameHost* main_frame = web_contents_->GetPrimaryMainFrame();
DCHECK(main_frame);
source_callback_.Run(content::DesktopMediaID(
content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID())));
source_callback_.Run(
content::DesktopMediaID(
content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(
main_frame->GetProcess()->GetID(), main_frame->GetRoutingID())),
captured_surface_control_active_);
// Start after source will be changed and notified.
pending_start_on_source_change_ = true;
} else {
@ -434,6 +436,10 @@ bool DlpContentManager::ScreenShareInfo::HasOpenDialogWidget() {
return dialog_widget_ && !dialog_widget_->IsClosed();
}
void DlpContentManager::ScreenShareInfo::SetCapturedSurfaceControlActive() {
captured_surface_control_active_ = true;
}
base::WeakPtr<DlpContentManager::ScreenShareInfo>
DlpContentManager::ScreenShareInfo::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
@ -475,13 +481,18 @@ void DlpContentManager::AddObserver(DlpContentManagerObserver* observer,
void DlpContentManager::OnScreenShareSourceChanging(
const std::string& label,
const content::DesktopMediaID& old_media_id,
const content::DesktopMediaID& new_media_id) {
const content::DesktopMediaID& new_media_id,
bool captured_surface_control_active) {
for (auto& screen_share : running_screen_shares_) {
if (screen_share->label() == label &&
screen_share->media_id() == old_media_id &&
screen_share->new_media_id() != new_media_id) {
screen_share->ChangeStateBeforeSourceChange();
screen_share->set_new_media_id(new_media_id);
screen_share->media_id() == old_media_id) {
if (captured_surface_control_active) {
screen_share->SetCapturedSurfaceControlActive();
}
if (screen_share->new_media_id() != new_media_id) {
screen_share->ChangeStateBeforeSourceChange();
screen_share->set_new_media_id(new_media_id);
}
}
}
}

@ -128,7 +128,8 @@ class DlpContentManager : public DlpContentObserver,
virtual void OnScreenShareSourceChanging(
const std::string& label,
const content::DesktopMediaID& old_media_id,
const content::DesktopMediaID& new_media_id);
const content::DesktopMediaID& new_media_id,
bool captured_surface_control_active);
void AddObserver(DlpContentManagerObserver* observer,
DlpContentRestriction restriction);
@ -246,6 +247,10 @@ class DlpContentManager : public DlpContentObserver,
// otherwise.
bool HasOpenDialogWidget();
// Records that Captured Surface Control was active at some point during
// the capture.
void SetCapturedSurfaceControlActive();
base::WeakPtr<ScreenShareInfo> GetWeakPtr();
private:
@ -284,6 +289,9 @@ class DlpContentManager : public DlpContentObserver,
// Set only for tab shares.
base::WeakPtr<content::WebContents> web_contents_;
// Only meaningful for tab-shares.
bool captured_surface_control_active_ = false;
base::WeakPtrFactory<ScreenShareInfo> weak_factory_{this};
};

@ -547,7 +547,8 @@ void CastMirroringServiceHost::ShowTabSharingUI(
TabSharingUI::Create(capturer_id, source_media_id_, sink_name_,
/*favicons_used_for_switch_to_tab_button=*/false,
/*app_preferred_current_tab=*/false,
TabSharingInfoBarDelegate::TabShareType::CAST);
TabSharingInfoBarDelegate::TabShareType::CAST,
/*captured_surface_control_active=*/false);
media_stream_ui_ = MediaCaptureDevicesDispatcher::GetInstance()
->GetMediaStreamCaptureIndicator()
@ -567,7 +568,10 @@ void CastMirroringServiceHost::ShowTabSharingUI(
}
void CastMirroringServiceHost::SwitchMirroringSourceTab(
const content::DesktopMediaID& media_id) {
const content::DesktopMediaID& media_id,
bool captured_surface_control_active) {
DCHECK(!captured_surface_control_active) << "CSC not supported for casting.";
source_media_id_ = media_id;
source_media_id_.web_contents_id.disable_local_echo = true;

@ -122,7 +122,10 @@ class CastMirroringServiceHost final : public MirroringServiceHost,
// indicator icon on the tabstrip.
void ShowTabSharingUI(const blink::mojom::StreamDevices& devices);
void SwitchMirroringSourceTab(const content::DesktopMediaID& media_id);
// `captured_surface_control_active` is ignored because CSC is not supported
// for mirroring. It is only here to make the callback's signature line up.
void SwitchMirroringSourceTab(const content::DesktopMediaID& media_id,
bool captured_surface_control_active);
// Records metrics about the usage of Tab Switcher UI, and resets data members
// used for metrics collection.

@ -277,7 +277,8 @@ class CastMirroringServiceHostBrowserTest
ASSERT_NE(host_->GetTabSourceId(), web_contents_source_tab_id);
ASSERT_NE(host_->web_contents(), web_contents);
host_->SwitchMirroringSourceTab(BuildMediaIdForTabMirroring(web_contents));
host_->SwitchMirroringSourceTab(BuildMediaIdForTabMirroring(web_contents),
/*captured_surface_control_active=*/false);
ASSERT_EQ(host_->web_contents(), web_contents);
ASSERT_EQ(host_->GetTabSourceId(), web_contents_source_tab_id);
}

@ -694,7 +694,8 @@ void DesktopCaptureAccessHandler::AcceptRequest(
// DesktopCaptureAccessHandler and DisplayMediaAccessHandler, that's fine.
/*suppress_local_audio_playback=*/false,
pending_request->should_display_notification,
pending_request->application_title, stream_devices);
pending_request->application_title,
pending_request->request.captured_surface_control_active, stream_devices);
DCHECK(stream_devices.audio_device.has_value() ||
stream_devices.video_device.has_value());

@ -78,7 +78,8 @@ class DesktopCaptureAccessHandlerTest : public ChromeRenderViewHostTestHarness {
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
base::RunLoop wait_loop;
content::MediaResponseCallback callback = base::BindOnce(
[](base::RunLoop* wait_loop, bool expect_result,
@ -130,7 +131,8 @@ class DesktopCaptureAccessHandlerTest : public ChromeRenderViewHostTestHarness {
/*requested_video_device_ids=*/{}, audio_type,
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
base::RunLoop wait_loop;
content::MediaResponseCallback callback = base::BindOnce(
@ -238,7 +240,8 @@ TEST_F(DesktopCaptureAccessHandlerTest,
url::Origin::Create(GURL(kOrigin)), false, blink::MEDIA_DEVICE_UPDATE,
/*requested_audio_device_ids=*/{}, /*requested_video_device_ids=*/{},
blink::mojom::MediaStreamType::NO_SERVICE, stream_type,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
access_handler_->HandleRequest(web_contents(), request, std::move(callback),
nullptr /* extension */);
@ -272,7 +275,8 @@ TEST_F(DesktopCaptureAccessHandlerTest, ChangeSourceWebContentsDestroyed) {
/*requested_video_device_ids=*/{},
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
access_handler_->HandleRequest(web_contents(), request, std::move(callback),
nullptr /* extension */);
@ -315,7 +319,8 @@ TEST_F(DesktopCaptureAccessHandlerTest, ChangeSourceMultipleRequests) {
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback = base::BindOnce(
[](base::RunLoop* wait_loop,
blink::mojom::MediaStreamRequestResult* request_result,

@ -258,6 +258,7 @@ std::unique_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
bool suppress_local_audio_playback,
bool display_notification,
const std::u16string& application_title,
bool captured_surface_control_active,
blink::mojom::StreamDevices& out_devices) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@ -321,11 +322,12 @@ std::unique_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
const bool app_preferred_current_tab =
request.video_type ==
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB;
notification_ui = TabSharingUI::Create(
capturer_id, media_id, application_title,
/*favicons_used_for_switch_to_tab_button=*/false,
app_preferred_current_tab,
TabSharingInfoBarDelegate::TabShareType::CAPTURE);
notification_ui =
TabSharingUI::Create(capturer_id, media_id, application_title,
/*favicons_used_for_switch_to_tab_button=*/false,
app_preferred_current_tab,
TabSharingInfoBarDelegate::TabShareType::CAPTURE,
captured_surface_control_active);
} else {
notification_ui = ScreenCaptureNotificationUI::Create(
GetNotificationText(application_title, capture_audio, media_id.type),

@ -30,6 +30,7 @@ std::unique_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
bool suppress_local_audio_playback,
bool display_notification,
const std::u16string& application_title,
bool captured_surface_control_active,
blink::mojom::StreamDevices& out_devices);
#endif // CHROME_BROWSER_MEDIA_WEBRTC_DESKTOP_CAPTURE_DEVICES_UTIL_H_

@ -434,7 +434,8 @@ void DisplayMediaAccessHandler::AcceptRequest(
std::unique_ptr<content::MediaStreamUI> ui = GetDevicesForDesktopCapture(
pending_request.request, web_contents, media_id, media_id.audio_share,
disable_local_echo, pending_request.request.suppress_local_audio_playback,
display_notification_, GetApplicationTitle(web_contents), stream_devices);
display_notification_, GetApplicationTitle(web_contents),
pending_request.request.captured_surface_control_active, stream_devices);
UpdateTarget(pending_request.request, media_id);
std::move(pending_request.callback)

@ -81,7 +81,8 @@ class DisplayMediaAccessHandlerTest : public ChromeRenderViewHostTestHarness {
: blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
}
content::MediaStreamRequest MakeMediaDeviceUpdateRequest(bool request_audio) {
@ -409,7 +410,8 @@ TEST_F(DisplayMediaAccessHandlerTest, UpdateMediaRequestStateWithClosing) {
url::Origin::Create(GURL("http://origin/")), false,
blink::MEDIA_GENERATE_STREAM, /*requested_audio_device_ids=*/{},
/*requested_video_device_ids=*/{}, audio_stream_type, video_stream_type,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
access_handler_->HandleRequest(web_contents(), request, std::move(callback),
nullptr /* extension */);
@ -448,7 +450,8 @@ TEST_F(DisplayMediaAccessHandlerTest, CorrectHostAsksForPermissions) {
url::Origin::Create(GURL("http://origin/")), false,
blink::MEDIA_GENERATE_STREAM, /*requested_audio_device_ids=*/{},
/*requested_video_device_ids=*/{}, audio_stream_type, video_stream_type,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
content::WebContents* test_web_contents = web_contents();
std::unique_ptr<content::NavigationSimulator> navigation =
@ -484,7 +487,8 @@ TEST_F(DisplayMediaAccessHandlerTest, CorrectHostAsksForPermissionsNormalURLs) {
url::Origin::Create(GURL("http://origin/")), false,
blink::MEDIA_GENERATE_STREAM, /*requested_audio_device_ids=*/{},
/*requested_video_device_ids=*/{}, audio_stream_type, video_stream_type,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
content::WebContents* test_web_contents = web_contents();
std::unique_ptr<content::NavigationSimulator> navigation =
@ -529,7 +533,8 @@ TEST_F(DisplayMediaAccessHandlerTest, IsolatedWebAppNameAsksForPermissions) {
url::Origin::Create(GURL("http://origin/")), false,
blink::MEDIA_GENERATE_STREAM, /*requested_audio_device_ids=*/{},
/*requested_video_device_ids=*/{}, audio_stream_type, video_stream_type,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
content::WebContents* test_web_contents = web_contents();
std::unique_ptr<content::NavigationSimulator> navigation =
@ -559,7 +564,8 @@ TEST_F(DisplayMediaAccessHandlerTest, WebContentsDestroyed) {
/*requested_video_device_ids=*/{},
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback;
access_handler_->HandleRequest(web_contents(), request, std::move(callback),
nullptr /* extension */);
@ -601,7 +607,8 @@ TEST_F(DisplayMediaAccessHandlerTest, MultipleRequests) {
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
content::MediaResponseCallback callback = base::BindOnce(
[](base::RunLoop* wait_loop,
blink::mojom::MediaStreamRequestResult* request_result,

@ -270,10 +270,11 @@ class MediaStreamCaptureIndicator::UIDelegate : public content::MediaStreamUI {
void OnDeviceStoppedForSourceChange(
const std::string& label,
const content::DesktopMediaID& old_media_id,
const content::DesktopMediaID& new_media_id) override {
const content::DesktopMediaID& new_media_id,
bool captured_surface_control_active) override {
#if BUILDFLAG(IS_CHROMEOS)
policy::DlpContentManager::Get()->OnScreenShareSourceChanging(
label, old_media_id, new_media_id);
label, old_media_id, new_media_id, captured_surface_control_active);
#endif
}

@ -339,11 +339,13 @@ TEST_P(MediaStreamCaptureIndicatorStreamTypeTest,
/*requested_video_device_ids=*/{"fake_device"},
blink::mojom::MediaStreamType::NO_SERVICE, video_stream_type,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false),
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false),
source, content::DesktopMediaID(media_type, /*id=*/0),
/*capture_audio=*/false, /*disable_local_echo=*/false,
/*suppress_local_audio_playback=*/false,
/*display_notification=*/false, /*application_title=*/u"", devices);
/*display_notification=*/false, /*application_title=*/u"",
/*captured_surface_control_active=*/false, devices);
ASSERT_EQ(devices.video_device->type, video_stream_type);
(observer()->*(GetParam().observer_method))(source, 2);

@ -188,7 +188,8 @@ class MediaStreamDevicesControllerTest : public WebRtcTestBase {
url::Origin::Create(example_url()), false, request_type,
/*requested_audio_device_ids=*/{audio_id},
/*requested_video_device_ids=*/{video_id}, audio_type, video_type,
/*disable_local_echo=*/false, request_pan_tilt_zoom_permission);
/*disable_local_echo=*/false, request_pan_tilt_zoom_permission,
/*captured_surface_control_active=*/false);
}
content::MediaStreamRequest CreateRequest(

@ -59,7 +59,8 @@ class TabCaptureAccessHandlerTest : public ChromeRenderViewHostTestHarness {
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
base::RunLoop wait_loop;
content::MediaResponseCallback callback = base::BindOnce(

@ -75,7 +75,8 @@ class MediaStreamDevicesControllerBrowserTest
/*requested_audio_device_ids=*/{}, /*requested_video_device_ids=*/{},
audio_request_type, video_request_type,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
}
// Configure a given policy map. The |policy_name| is the name of either the

@ -26,7 +26,8 @@ class TabSharingUI : public MediaStreamUI {
const std::u16string& capturer_name,
bool favicons_used_for_switch_to_tab_button,
bool app_preferred_current_tab,
TabSharingInfoBarDelegate::TabShareType capture_type);
TabSharingInfoBarDelegate::TabShareType capture_type,
bool captured_surface_control_active);
virtual void StartSharing(infobars::InfoBar* infobar) = 0;
virtual void StopSharing() = 0;

@ -313,7 +313,11 @@ void ScreenCaptureNotificationUIViews::OnViewBoundsChanged(
void ScreenCaptureNotificationUIViews::NotifySourceChange() {
if (!source_callback_.is_null())
source_callback_.Run(content::DesktopMediaID());
// CSC is only supported for tab-capture, so setting it to `false` is the
// correct behavior so long as we don't support cross-surface-type
// switching.
source_callback_.Run(content::DesktopMediaID(),
/*captured_surface_control_active=*/false);
}
void ScreenCaptureNotificationUIViews::NotifyStopped() {

@ -138,10 +138,11 @@ std::unique_ptr<TabSharingUI> TabSharingUI::Create(
const std::u16string& capturer_name,
bool favicons_used_for_switch_to_tab_button,
bool app_preferred_current_tab,
TabSharingInfoBarDelegate::TabShareType capture_type) {
TabSharingInfoBarDelegate::TabShareType capture_type,
bool captured_surface_control_active) {
return std::make_unique<TabSharingUIViews>(
capturer, media_id, capturer_name, favicons_used_for_switch_to_tab_button,
app_preferred_current_tab, capture_type);
app_preferred_current_tab, capture_type, captured_surface_control_active);
}
TabSharingUIViews::TabSharingUIViews(
@ -150,7 +151,8 @@ TabSharingUIViews::TabSharingUIViews(
const std::u16string& capturer_name,
bool favicons_used_for_switch_to_tab_button,
bool app_preferred_current_tab,
TabSharingInfoBarDelegate::TabShareType capture_type)
TabSharingInfoBarDelegate::TabShareType capture_type,
bool captured_surface_control_active)
: capture_session_id_(next_capture_session_id_++),
profile_(ProfileManager::GetLastUsedProfileAllowedByPolicy()),
capturer_(capturer),
@ -167,7 +169,8 @@ TabSharingUIViews::TabSharingUIViews(
favicons_used_for_switch_to_tab_button_(
favicons_used_for_switch_to_tab_button),
app_preferred_current_tab_(app_preferred_current_tab),
capture_type_(capture_type) {
capture_type_(capture_type),
captured_surface_control_active_(captured_surface_control_active) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Observe(shared_tab_);
@ -245,11 +248,13 @@ void TabSharingUIViews::StartSharing(infobars::InfoBar* infobar) {
RenderFrameHost* main_frame = shared_tab->GetPrimaryMainFrame();
DCHECK(main_frame);
source_callback_.Run(content::DesktopMediaID(
content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID())));
source_callback_.Run(
content::DesktopMediaID(
content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID())),
captured_surface_control_active_);
}
void TabSharingUIViews::StopSharing() {
@ -680,10 +685,6 @@ void TabSharingUIViews::OnCapturedSurfaceControlByCapturer() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!captured_surface_control_active_) {
// TODO(crbug.com/332555474): Set `captured_surface_control_active_` to true
// in the ctor if this `TabSharingUIViews` object was constructed in
// response to a share-this-tab-instead call for a capture-session where CSC
// was previously used.
captured_surface_control_active_ = true;
content::WebContents* const capturer_wc = WebContentsFromId(capturer_);

@ -52,7 +52,8 @@ class TabSharingUIViews : public TabSharingUI,
const std::u16string& capturer_name,
bool favicons_used_for_switch_to_tab_button,
bool app_preferred_current_tab,
TabSharingInfoBarDelegate::TabShareType capture_type);
TabSharingInfoBarDelegate::TabShareType capture_type,
bool captured_surface_control_active);
~TabSharingUIViews() override;
// MediaStreamUI:

@ -54,6 +54,7 @@
namespace {
using ::testing::_;
using ::testing::Not;
content::WebContents* GetWebContents(Browser* browser, int tab) {
@ -241,7 +242,8 @@ class TabSharingUIViewsBrowserTest
GetDesktopMediaID(browser, captured_tab), u"example-sharing.com",
favicons_used_for_switch_to_tab_button_,
/*app_preferred_current_tab=*/false,
TabSharingInfoBarDelegate::TabShareType::CAPTURE);
TabSharingInfoBarDelegate::TabShareType::CAPTURE,
/*captured_surface_control_active=*/false);
if (favicons_used_for_switch_to_tab_button_) {
for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
@ -255,7 +257,7 @@ class TabSharingUIViewsBrowserTest
tab_sharing_ui_->OnStarted(
base::OnceClosure(),
base::BindRepeating(&TabSharingUIViewsBrowserTest::OnStartSharing,
base::BindRepeating(&TabSharingUIViewsBrowserTest::OnSourceChange,
base::Unretained(this)),
std::vector<content::DesktopMediaID>{});
@ -425,15 +427,13 @@ class TabSharingUIViewsBrowserTest
}
#endif // BUILDFLAG(IS_CHROMEOS)
private:
void OnStartSharing(const content::DesktopMediaID& media_id) {
tab_sharing_ui_->OnStarted(
base::OnceClosure(),
base::BindRepeating(&TabSharingUIViewsBrowserTest::OnStartSharing,
base::Unretained(this)),
std::vector<content::DesktopMediaID>{});
}
MOCK_METHOD(void,
OnSourceChange,
(const content::DesktopMediaID& media_id,
bool captured_surface_control_active),
());
private:
base::test::ScopedFeatureList features_;
const bool favicons_used_for_switch_to_tab_button_;
@ -733,7 +733,7 @@ IN_PROC_BROWSER_TEST_P(TabSharingUIViewsBrowserTest,
constexpr int kCapturedTab = 1;
constexpr int kCapturingTab = 2;
// Set up a screen-capture session.
// Set up a tab-capture session.
AddTabs(browser(), 2);
ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
@ -754,6 +754,45 @@ IN_PROC_BROWSER_TEST_P(TabSharingUIViewsBrowserTest,
VerifyUi(expectations);
}
IN_PROC_BROWSER_TEST_P(TabSharingUIViewsBrowserTest,
SourceChangesRemembersIfCapturedSurfaceControlInactive) {
constexpr int kOtherTab = 0;
constexpr int kCapturedTab = 1;
constexpr int kCapturingTab = 2;
// Set up a tab-capture session.
AddTabs(browser(), 2);
ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
CreateUiAndStartSharing(browser(), kCapturingTab, kCapturedTab);
// Note that DidCapturedSurfaceControlForTesting() is *not* called before
// the source-change.
EXPECT_CALL(*this,
OnSourceChange(_, /*captured_surface_control_active=*/false));
GetDelegate(browser(), kOtherTab)->ShareThisTabInstead();
}
IN_PROC_BROWSER_TEST_P(TabSharingUIViewsBrowserTest,
SourceChangesRemembersIfCapturedSurfaceControlActive) {
constexpr int kOtherTab = 0;
constexpr int kCapturedTab = 1;
constexpr int kCapturingTab = 2;
// Set up a tab-capture session.
AddTabs(browser(), 2);
ASSERT_EQ(browser()->tab_strip_model()->count(), 3);
CreateUiAndStartSharing(browser(), kCapturingTab, kCapturedTab);
// Simulate a call to a Captured Surface Control API.
DidCapturedSurfaceControlForTesting(GetWebContents(browser(), kCapturingTab));
EXPECT_CALL(*this,
OnSourceChange(_, /*captured_surface_control_active=*/true));
GetDelegate(browser(), kOtherTab)->ShareThisTabInstead();
}
#if BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(TabSharingUIViewsBrowserTest,
@ -842,7 +881,8 @@ class MultipleTabSharingUIViewsBrowserTest : public InProcessBrowserTest {
GetDesktopMediaID(browser, captured_tab), u"example-sharing.com",
/*favicons_used_for_switch_to_tab_button=*/false,
/*app_preferred_current_tab=*/false,
TabSharingInfoBarDelegate::TabShareType::CAPTURE));
TabSharingInfoBarDelegate::TabShareType::CAPTURE,
/*captured_surface_control_active=*/false));
tab_sharing_ui_views_[tab_sharing_ui_views_.size() - 1]->OnStarted(
base::OnceClosure(), content::MediaStreamUI::SourceCallback(),
std::vector<content::DesktopMediaID>{});
@ -1090,7 +1130,8 @@ class TabSharingUIViewsPreferCurrentTabBrowserTest
GetDesktopMediaID(browser(), captured_tab), u"example-sharing.com",
/*favicons_used_for_switch_to_tab_button=*/false,
/*app_preferred_current_tab=*/true,
TabSharingInfoBarDelegate::TabShareType::CAPTURE);
TabSharingInfoBarDelegate::TabShareType::CAPTURE,
/*captured_surface_control_active=*/false);
tab_sharing_ui_views_->OnStarted(base::OnceClosure(), source_change_cb,
std::vector<content::DesktopMediaID>{});
}
@ -1100,7 +1141,8 @@ class TabSharingUIViewsPreferCurrentTabBrowserTest
AddBlankTabAndShow(browser);
}
void SourceChange(const content::DesktopMediaID& media_id) {}
void SourceChange(const content::DesktopMediaID& media_id,
bool captured_surface_control_active) {}
protected:
const int kTab0 = 0;

@ -170,7 +170,8 @@ TEST_F(BackgroundLoaderContentsTest, DoesNotGiveMediaAccessPermission) {
blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE /* audio_type */,
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE /* video_type */,
false /* disable_local_echo */,
false /* request_pan_tilt_zoom_permission */);
false /* request_pan_tilt_zoom_permission */,
false /* captured_surface_control_active */);
contents()->RequestMediaAccessPermission(
nullptr /* contents */, request /* request */,
base::BindRepeating(&BackgroundLoaderContentsTest::MediaAccessCallback,

@ -192,7 +192,8 @@ class MediaStreamDevicesControllerTest : public testing::Test {
content::MediaStreamRequest{
/*render_process_id=*/render_frame_host_id_.child_id,
/*render_frame_id=*/render_frame_host_id_.frame_routing_id,
/*page_request_id=*/0, /*url_origin=*/origin_,
/*page_request_id=*/0,
/*url_origin=*/origin_,
/*user_gesture=*/false,
/*request_type=*/
request_type,
@ -203,7 +204,9 @@ class MediaStreamDevicesControllerTest : public testing::Test {
request_video ? blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE
: blink::mojom::MediaStreamType::NO_SERVICE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false},
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false,
},
&enumerator_,
base::BindLambdaForTesting(
[&](const blink::mojom::StreamDevicesSet& stream_devices_set,

@ -669,7 +669,8 @@ class MediaStreamManager::DeviceRequest {
salt_and_origin.origin(), user_gesture, request_type_,
requested_audio_device_ids, requested_video_device_ids, audio_type_,
video_type_, stream_controls_.disable_local_echo,
stream_controls_.request_pan_tilt_zoom_permission);
stream_controls_.request_pan_tilt_zoom_permission,
captured_surface_control_active_);
ui_request_->suppress_local_audio_playback =
stream_controls_.suppress_local_audio_playback;
ui_request_->exclude_system_audio = stream_controls_.exclude_system_audio;
@ -693,7 +694,8 @@ class MediaStreamManager::DeviceRequest {
salt_and_origin.origin(), user_gesture, request_type_,
std::vector<std::string>{}, std::vector<std::string>{}, audio_type_,
video_type_, stream_controls_.disable_local_echo,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
captured_surface_control_active_);
ui_request_->exclude_system_audio = stream_controls_.exclude_system_audio;
}
@ -917,6 +919,15 @@ class MediaStreamManager::DeviceRequest {
virtual void OnZoomLevelChange(const std::string& label, int zoom_level) {}
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Marks that CSC was used at least once during this capture-session.
void SetCapturedSurfaceControlActive() {
captured_surface_control_active_ = true;
}
bool captured_surface_control_active() const {
return captured_surface_control_active_;
}
// The render frame host id that requested this stream to be generated and
// that will receive a handle to the MediaStream. This may be different from
// MediaStreamRequest::render_process_id which in the tab capture case
@ -1018,10 +1029,9 @@ class MediaStreamManager::DeviceRequest {
GlobalRenderFrameHostId target_render_frame_host_id_;
std::string label_;
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// If an attempt to access any of the Captured Surface Control APIs is made,
// a controller is instantiated to manage state.
std::unique_ptr<CapturedSurfaceController> captured_surface_controller_;
#endif
bool captured_surface_control_active_ = false;
};
class MediaStreamManager::MediaAccessRequest
@ -3754,7 +3764,8 @@ void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
void MediaStreamManager::ChangeMediaStreamSourceFromBrowser(
const std::string& label,
const DesktopMediaID& media_id) {
const DesktopMediaID& media_id,
bool captured_surface_control_active) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DeviceRequest* request = FindRequest(label);
@ -3766,6 +3777,10 @@ void MediaStreamManager::ChangeMediaStreamSourceFromBrowser(
const blink::mojom::StreamDevices& devices =
*request->stream_devices_set.stream_devices[0];
if (captured_surface_control_active) {
request->SetCapturedSurfaceControlActive();
}
if (request->ui_proxy) {
for (const std::optional<blink::MediaStreamDevice>* device_ptr :
{&devices.audio_device, &devices.video_device}) {
@ -3775,8 +3790,9 @@ void MediaStreamManager::ChangeMediaStreamSourceFromBrowser(
const blink::MediaStreamDevice& device = device_ptr->value();
const DesktopMediaID old_media_id = DesktopMediaID::Parse(device.id);
if (!old_media_id.is_null()) {
request->ui_proxy->OnDeviceStoppedForSourceChange(label, old_media_id,
media_id);
request->ui_proxy->OnDeviceStoppedForSourceChange(
label, old_media_id, media_id,
request->captured_surface_control_active());
}
}
}

@ -504,7 +504,8 @@ class CONTENT_EXPORT MediaStreamManager
const blink::mojom::StreamDevicesSet& stream_devices_set);
void StopMediaStreamFromBrowser(const std::string& label);
void ChangeMediaStreamSourceFromBrowser(const std::string& label,
const DesktopMediaID& media_id);
const DesktopMediaID& media_id,
bool captured_surface_control_active);
void OnRequestStateChangeFromBrowser(
const std::string& label,
const DesktopMediaID& media_id,

@ -1187,8 +1187,9 @@ TEST_F(MediaStreamManagerTest, DesktopCaptureDeviceChanged) {
// |request_label| is cached in the |device.name| for testing purpose.
std::string request_label = video_device.name;
media_stream_manager_->ChangeMediaStreamSourceFromBrowser(request_label,
DesktopMediaID());
media_stream_manager_->ChangeMediaStreamSourceFromBrowser(
request_label, DesktopMediaID(),
/*captured_surface_control_active=*/false);
// Wait to check callbacks before stopping the device.
base::RunLoop().RunUntilIdle();

@ -60,7 +60,8 @@ class MediaStreamUIProxy::Core {
const DesktopMediaID& media_id);
void OnDeviceStoppedForSourceChange(const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id);
const DesktopMediaID& new_media_id,
bool captured_surface_control_active);
void OnRegionCaptureRectChanged(
const std::optional<gfx::Rect>& region_capture_rect);
@ -101,7 +102,8 @@ class MediaStreamUIProxy::Core {
private:
friend class FakeMediaStreamUIProxy;
void ProcessStopRequestFromUI();
void ProcessChangeSourceRequestFromUI(const DesktopMediaID& media_id);
void ProcessChangeSourceRequestFromUI(const DesktopMediaID& media_id,
bool captured_surface_control_active);
void ProcessStateChangeFromUI(const DesktopMediaID& media,
blink::mojom::MediaStreamStateChange);
RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id,
@ -194,10 +196,12 @@ void MediaStreamUIProxy::Core::OnDeviceStopped(const std::string& label,
void MediaStreamUIProxy::Core::OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id) {
const DesktopMediaID& new_media_id,
bool captured_surface_control_active) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (ui_) {
ui_->OnDeviceStoppedForSourceChange(label, old_media_id, new_media_id);
ui_->OnDeviceStoppedForSourceChange(label, old_media_id, new_media_id,
captured_surface_control_active);
ui_->OnDeviceStopped(label, old_media_id);
}
}
@ -313,13 +317,14 @@ void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
}
void MediaStreamUIProxy::Core::ProcessChangeSourceRequestFromUI(
const DesktopMediaID& media_id) {
const DesktopMediaID& media_id,
bool captured_surface_control_active) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&MediaStreamUIProxy::ProcessChangeSourceRequestFromUI,
proxy_, media_id));
proxy_, media_id, captured_surface_control_active));
}
void MediaStreamUIProxy::Core::ProcessStateChangeFromUI(
@ -412,13 +417,14 @@ void MediaStreamUIProxy::OnDeviceStopped(const std::string& label,
void MediaStreamUIProxy::OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id) {
const DesktopMediaID& new_media_id,
bool captured_surface_control_active) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&Core::OnDeviceStoppedForSourceChange, core_->GetWeakPtr(),
label, old_media_id, new_media_id));
FROM_HERE, base::BindOnce(&Core::OnDeviceStoppedForSourceChange,
core_->GetWeakPtr(), label, old_media_id,
new_media_id, captured_surface_control_active));
}
void MediaStreamUIProxy::OnRegionCaptureRectChanged(
@ -462,11 +468,12 @@ void MediaStreamUIProxy::ProcessStopRequestFromUI() {
}
void MediaStreamUIProxy::ProcessChangeSourceRequestFromUI(
const DesktopMediaID& media_id) {
const DesktopMediaID& media_id,
bool captured_surface_control_active) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (source_callback_)
source_callback_.Run(media_id);
source_callback_.Run(media_id, captured_surface_control_active);
}
void MediaStreamUIProxy::ProcessStateChangeFromUI(
@ -598,6 +605,7 @@ void FakeMediaStreamUIProxy::OnDeviceStopped(const std::string& label,
void FakeMediaStreamUIProxy::OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id) {}
const DesktopMediaID& new_media_id,
bool captured_surface_control_active) {}
} // namespace content

@ -86,7 +86,8 @@ class CONTENT_EXPORT MediaStreamUIProxy {
virtual void OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id);
const DesktopMediaID& new_media_id,
bool captured_surface_control_active);
virtual void OnRegionCaptureRectChanged(
const std::optional<gfx::Rect>& region_capture_rect);
@ -120,7 +121,8 @@ class CONTENT_EXPORT MediaStreamUIProxy {
blink::mojom::StreamDevicesSetPtr stream_devices_set,
blink::mojom::MediaStreamRequestResult result);
void ProcessStopRequestFromUI();
void ProcessChangeSourceRequestFromUI(const DesktopMediaID& media_id);
void ProcessChangeSourceRequestFromUI(const DesktopMediaID& media_id,
bool captured_surface_control_active);
void ProcessStateChangeFromUI(const DesktopMediaID& media_id,
blink::mojom::MediaStreamStateChange new_state);
void OnWindowId(WindowIdCallback window_id_callback,
@ -167,7 +169,8 @@ class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy {
void OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id) override;
const DesktopMediaID& new_media_id,
bool captured_surface_control_active) override;
private:
// This is used for RequestAccess().

@ -82,7 +82,8 @@ class MockMediaStreamUI : public MediaStreamUI {
void OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id) override {}
const DesktopMediaID& new_media_id,
bool captured_surface_control_active) override {}
void OnDeviceStopped(const std::string& label,
const DesktopMediaID& media_id) override {}
@ -100,7 +101,9 @@ class MockStopStreamHandler {
class MockChangeSourceStreamHandler {
public:
MOCK_METHOD1(OnChangeSource, void(const DesktopMediaID& media_id));
MOCK_METHOD2(OnChangeSource,
void(const DesktopMediaID& media_id,
bool captured_surface_control_active));
};
} // namespace
@ -145,7 +148,8 @@ TEST_F(MediaStreamUIProxyTest, Deny) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -186,7 +190,8 @@ TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -239,7 +244,8 @@ TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -273,7 +279,8 @@ TEST_F(MediaStreamUIProxyTest, StopFromUI) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -340,7 +347,8 @@ TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
@ -388,7 +396,8 @@ TEST_F(MediaStreamUIProxyTest, ChangeSourceFromUI) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -443,8 +452,11 @@ TEST_F(MediaStreamUIProxyTest, ChangeSourceFromUI) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(source_callback.is_null());
EXPECT_CALL(source_handler, OnChangeSource(DesktopMediaID()));
source_callback.Run(DesktopMediaID());
EXPECT_CALL(source_handler,
OnChangeSource(DesktopMediaID(),
/*captured_surface_control_active=*/false));
source_callback.Run(DesktopMediaID(),
/*captured_surface_control_active=*/false);
base::RunLoop().RunUntilIdle();
}
@ -456,7 +468,8 @@ TEST_F(MediaStreamUIProxyTest, ChangeTabSourceFromUI) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -526,7 +539,8 @@ TEST_F(MediaStreamUIProxyTest, ChangeTabSourceFromUI) {
/*requested_video_device_ids=*/std::vector<std::string>{},
blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@ -611,7 +625,8 @@ class MediaStreamUIProxyPermissionsPolicyTest
/*requested_video_device_ids=*/std::vector<std::string>{}, mic_type,
cam_type,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
/*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
}
private:

@ -3122,7 +3122,8 @@ TEST_F(WebContentsImplTest, RequestMediaAccessPermissionNoDelegate) {
/*requested_video_device_ids=*/{},
blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE,
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false);
/*disable_local_echo=*/false, /*request_pan_tilt_zoom_permission=*/false,
/*captured_surface_control_active=*/false);
bool callback_run = false;
contents()->RequestMediaAccessPermission(
dummy_request,

@ -18,7 +18,8 @@ MediaStreamRequest::MediaStreamRequest(
blink::mojom::MediaStreamType audio_type,
blink::mojom::MediaStreamType video_type,
bool disable_local_echo,
bool request_pan_tilt_zoom_permission)
bool request_pan_tilt_zoom_permission,
bool captured_surface_control_active)
: render_process_id(render_process_id),
render_frame_id(render_frame_id),
page_request_id(page_request_id),
@ -31,7 +32,8 @@ MediaStreamRequest::MediaStreamRequest(
audio_type(audio_type),
video_type(video_type),
disable_local_echo(disable_local_echo),
request_pan_tilt_zoom_permission(request_pan_tilt_zoom_permission) {}
request_pan_tilt_zoom_permission(request_pan_tilt_zoom_permission),
captured_surface_control_active(captured_surface_control_active) {}
MediaStreamRequest::MediaStreamRequest(const MediaStreamRequest& other) =
default;

@ -36,7 +36,8 @@ struct CONTENT_EXPORT MediaStreamRequest {
blink::mojom::MediaStreamType audio_type,
blink::mojom::MediaStreamType video_type,
bool disable_local_echo,
bool request_pan_tilt_zoom_permission);
bool request_pan_tilt_zoom_permission,
bool captured_surface_control_active);
MediaStreamRequest(const MediaStreamRequest& other);
@ -112,6 +113,11 @@ struct CONTENT_EXPORT MediaStreamRequest {
// Flag to indicate whether the request is for PTZ use.
bool request_pan_tilt_zoom_permission;
// Indicates whether Captured Surface Control APIs (sendWheel, setZoomLevel)
// have previously been used on the capture-session associated with this
// request. This is only relevant for tab-sharing sessions.
bool captured_surface_control_active;
};
// Interface used by the content layer to notify chrome about changes in the
@ -120,7 +126,8 @@ struct CONTENT_EXPORT MediaStreamRequest {
class MediaStreamUI {
public:
using SourceCallback =
base::RepeatingCallback<void(const DesktopMediaID& media_id)>;
base::RepeatingCallback<void(const DesktopMediaID& media_id,
bool captured_surface_control_active)>;
using StateChangeCallback = base::RepeatingCallback<void(
const DesktopMediaID& media_id,
blink::mojom::MediaStreamStateChange new_state)>;
@ -151,7 +158,8 @@ class MediaStreamUI {
virtual void OnDeviceStoppedForSourceChange(
const std::string& label,
const DesktopMediaID& old_media_id,
const DesktopMediaID& new_media_id) = 0;
const DesktopMediaID& new_media_id,
bool captured_surface_control_active) = 0;
virtual void OnDeviceStopped(const std::string& label,
const DesktopMediaID& media_id) = 0;