fix: getUserMedia needs macOS system permissions check (#42899)

fix: getUserMedia needs macOS system permissions check

Closes https://github.com/electron/electron/issues/42714
Closes https://github.com/electron/electron/issues/29861
This commit is contained in:
Shelley Vohr 2024-07-17 11:30:05 +02:00 committed by GitHub
parent c7709747d0
commit fd907bc0a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -7,23 +7,29 @@
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include "components/content_settings/core/common/content_settings.h"
#include "components/webrtc/media_stream_devices_controller.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
#include "shell/browser/electron_permission_manager.h" #include "shell/browser/electron_permission_manager.h"
// #include "shell/browser/media/media_stream_devices_controller.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/webrtc/media_stream_devices_controller.h"
#include "shell/browser/media/media_capture_devices_dispatcher.h" #include "shell/browser/media/media_capture_devices_dispatcher.h"
#if BUILDFLAG(IS_MAC)
#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
#endif
using blink::mojom::MediaStreamRequestResult;
using blink::mojom::MediaStreamType;
namespace { namespace {
constexpr std::string_view MediaStreamTypeToString( constexpr std::string_view MediaStreamTypeToString(
blink::mojom::MediaStreamType type) { blink::mojom::MediaStreamType type) {
switch (type) { switch (type) {
case blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE: case MediaStreamType::DEVICE_AUDIO_CAPTURE:
return "audio"; return "audio";
case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE: case MediaStreamType::DEVICE_VIDEO_CAPTURE:
return "video"; return "video";
default: default:
return "unknown"; return "unknown";
@ -48,53 +54,74 @@ namespace {
-1 /* kFullDesktopScreenId */); -1 /* kFullDesktopScreenId */);
} }
#if BUILDFLAG(IS_MAC)
bool SystemMediaPermissionDenied(const content::MediaStreamRequest& request) {
if (request.audio_type != MediaStreamType::NO_SERVICE) {
const auto system_audio_permission =
system_media_permissions::CheckSystemAudioCapturePermission();
return system_audio_permission ==
system_media_permissions::SystemPermission::kRestricted ||
system_audio_permission ==
system_media_permissions::SystemPermission::kDenied;
}
if (request.video_type != MediaStreamType::NO_SERVICE) {
const auto system_video_permission =
system_media_permissions::CheckSystemVideoCapturePermission();
return system_video_permission ==
system_media_permissions::SystemPermission::kRestricted ||
system_video_permission ==
system_media_permissions::SystemPermission::kDenied;
}
return false;
}
#endif
// Handles requests for legacy-style `navigator.getUserMedia(...)` calls. // Handles requests for legacy-style `navigator.getUserMedia(...)` calls.
// This includes desktop capture through the chromeMediaSource / // This includes desktop capture through the chromeMediaSource /
// chromeMediaSourceId constraints. // chromeMediaSourceId constraints.
void HandleUserMediaRequest(const content::MediaStreamRequest& request, void HandleUserMediaRequest(const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) { content::MediaResponseCallback callback) {
blink::mojom::StreamDevicesSetPtr stream_devices_set = auto stream_devices_set = blink::mojom::StreamDevicesSet::New();
blink::mojom::StreamDevicesSet::New(); auto devices = blink::mojom::StreamDevices::New();
stream_devices_set->stream_devices.emplace_back( stream_devices_set->stream_devices.emplace_back(std::move(devices));
blink::mojom::StreamDevices::New()); auto& devices_ref = *stream_devices_set->stream_devices[0];
blink::mojom::StreamDevices& devices = *stream_devices_set->stream_devices[0];
if (request.audio_type == if (request.audio_type == MediaStreamType::GUM_TAB_AUDIO_CAPTURE ||
blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE) { request.audio_type == MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE) {
devices.audio_device = blink::MediaStreamDevice( devices_ref.audio_device = blink::MediaStreamDevice(
blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE, "", ""); request.audio_type,
} request.audio_type == MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE
if (request.video_type == ? "loopback"
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE) { : "",
devices.video_device = blink::MediaStreamDevice( request.audio_type == MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE, "", ""); ? "System Audio"
} : "");
if (request.audio_type ==
blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE) {
devices.audio_device = blink::MediaStreamDevice(
blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE, "loopback",
"System Audio");
}
if (request.video_type ==
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) {
devices.video_device = blink::MediaStreamDevice(
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
GetScreenId(request.requested_video_device_ids).ToString(), "Screen");
} }
bool empty = if (request.video_type == MediaStreamType::GUM_TAB_VIDEO_CAPTURE ||
!devices.audio_device.has_value() && !devices.video_device.has_value(); request.video_type == MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) {
std::move(callback).Run( devices_ref.video_device = blink::MediaStreamDevice(
*stream_devices_set, request.video_type,
empty ? blink::mojom::MediaStreamRequestResult::NO_HARDWARE request.video_type == MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE
: blink::mojom::MediaStreamRequestResult::OK, ? GetScreenId(request.requested_video_device_ids).ToString()
: "",
request.video_type == MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE
? "Screen"
: "");
}
bool empty = !devices_ref.audio_device.has_value() &&
!devices_ref.video_device.has_value();
std::move(callback).Run(*stream_devices_set,
empty ? MediaStreamRequestResult::NO_HARDWARE
: MediaStreamRequestResult::OK,
nullptr); nullptr);
} }
void OnMediaStreamRequestResponse( void OnMediaStreamRequestResponse(
content::MediaResponseCallback callback, content::MediaResponseCallback callback,
const blink::mojom::StreamDevicesSet& stream_devices_set, const blink::mojom::StreamDevicesSet& stream_devices_set,
blink::mojom::MediaStreamRequestResult result, MediaStreamRequestResult result,
bool blocked_by_permissions_policy, bool blocked_by_permissions_policy,
ContentSetting audio_setting, ContentSetting audio_setting,
ContentSetting video_setting) { ContentSetting video_setting) {
@ -105,31 +132,34 @@ void MediaAccessAllowed(const content::MediaStreamRequest& request,
content::MediaResponseCallback callback, content::MediaResponseCallback callback,
bool allowed) { bool allowed) {
if (allowed) { if (allowed) {
if (request.video_type == #if BUILDFLAG(IS_MAC)
blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE || // If the request was approved, ask for system permissions if needed.
request.audio_type == // See
blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE || // chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc.
request.video_type == if (SystemMediaPermissionDenied(request)) {
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE || std::move(callback).Run(blink::mojom::StreamDevicesSet(),
request.audio_type == MediaStreamRequestResult::PERMISSION_DENIED,
blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE) { nullptr);
return;
}
#endif
if (request.video_type == MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE ||
request.audio_type == MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE ||
request.video_type == MediaStreamType::GUM_TAB_VIDEO_CAPTURE ||
request.audio_type == MediaStreamType::GUM_TAB_AUDIO_CAPTURE) {
HandleUserMediaRequest(request, std::move(callback)); HandleUserMediaRequest(request, std::move(callback));
} else if (request.video_type == } else if (request.video_type == MediaStreamType::DEVICE_VIDEO_CAPTURE ||
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE || request.audio_type == MediaStreamType::DEVICE_AUDIO_CAPTURE) {
request.audio_type ==
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) {
webrtc::MediaStreamDevicesController::RequestPermissions( webrtc::MediaStreamDevicesController::RequestPermissions(
request, MediaCaptureDevicesDispatcher::GetInstance(), request, MediaCaptureDevicesDispatcher::GetInstance(),
base::BindOnce(&OnMediaStreamRequestResponse, std::move(callback)), base::BindOnce(&OnMediaStreamRequestResponse, std::move(callback)),
allowed); allowed);
} else if (request.video_type == } else if (request.video_type == MediaStreamType::DISPLAY_VIDEO_CAPTURE ||
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE ||
request.video_type == blink::mojom::MediaStreamType::
DISPLAY_VIDEO_CAPTURE_THIS_TAB ||
request.video_type == request.video_type ==
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_SET || MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB ||
request.audio_type == request.video_type ==
blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE) { MediaStreamType::DISPLAY_VIDEO_CAPTURE_SET ||
request.audio_type == MediaStreamType::DISPLAY_AUDIO_CAPTURE) {
content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
request.render_process_id, request.render_frame_id); request.render_process_id, request.render_frame_id);
if (!rfh) if (!rfh)
@ -144,16 +174,15 @@ void MediaAccessAllowed(const content::MediaStreamRequest& request,
return; return;
std::move(split_callback.first) std::move(split_callback.first)
.Run(blink::mojom::StreamDevicesSet(), .Run(blink::mojom::StreamDevicesSet(),
blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr); MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
} else { } else {
std::move(callback).Run( std::move(callback).Run(blink::mojom::StreamDevicesSet(),
blink::mojom::StreamDevicesSet(), MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
} }
} else { } else {
std::move(callback).Run( std::move(callback).Run(blink::mojom::StreamDevicesSet(),
blink::mojom::StreamDevicesSet(), MediaStreamRequestResult::PERMISSION_DENIED,
blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr); nullptr);
} }
} }