diff --git a/AUTHORS b/AUTHORS index df32313b3d..b11ca9a33d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -101,6 +101,7 @@ NVIDIA Corporation <*@nvidia.com> Opera Software ASA <*@opera.com> Optical Tone Ltd <*@opticaltone.com> Pengutronix e.K. <*@pengutronix.de> +RingCentral, Inc. <*@ringcentral.com> Sinch AB <*@sinch.com> struktur AG <*@struktur.de> Telenor Digital AS <*@telenor.com> diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 88a10a12af..789aac44e3 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -300,6 +300,10 @@ rtc_library("desktop_capture_generic") { "fake_desktop_capturer.h", "fallback_desktop_capturer_wrapper.cc", "fallback_desktop_capturer_wrapper.h", + "full_screen_application_handler.cc", + "full_screen_application_handler.h", + "full_screen_window_detector.cc", + "full_screen_window_detector.h", "mouse_cursor.cc", "mouse_cursor.h", "mouse_cursor_monitor.h", @@ -319,8 +323,8 @@ rtc_library("desktop_capture_generic") { "mac/desktop_configuration.h", "mac/desktop_configuration_monitor.cc", "mac/desktop_configuration_monitor.h", - "mac/full_screen_chrome_window_detector.cc", - "mac/full_screen_chrome_window_detector.h", + "mac/full_screen_mac_application_handler.cc", + "mac/full_screen_mac_application_handler.h", "mac/window_list_utils.cc", "mac/window_list_utils.h", ] @@ -431,6 +435,8 @@ rtc_library("desktop_capture_generic") { "win/dxgi_texture_mapping.h", "win/dxgi_texture_staging.cc", "win/dxgi_texture_staging.h", + "win/full_screen_win_application_handler.cc", + "win/full_screen_win_application_handler.h", "win/scoped_gdi_object.h", "win/scoped_thread_desktop.cc", "win/scoped_thread_desktop.h", @@ -470,6 +476,7 @@ rtc_library("desktop_capture_generic") { "../../system_wrappers:cpu_features_api", "../../system_wrappers:metrics", "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", ] if (build_with_mozilla) { diff --git a/modules/desktop_capture/cropping_window_capturer.h b/modules/desktop_capture/cropping_window_capturer.h index f9ad36cd4c..272a196972 100644 --- a/modules/desktop_capture/cropping_window_capturer.h +++ b/modules/desktop_capture/cropping_window_capturer.h @@ -68,6 +68,7 @@ class RTC_EXPORT CroppingWindowCapturer : public DesktopCapturer, WindowId selected_window() const { return selected_window_; } WindowId excluded_window() const { return excluded_window_; } + DesktopCapturer* window_capturer() const { return window_capturer_.get(); } private: DesktopCaptureOptions options_; diff --git a/modules/desktop_capture/cropping_window_capturer_win.cc b/modules/desktop_capture/cropping_window_capturer_win.cc index ce93ca3fbf..e67f4f4f2e 100644 --- a/modules/desktop_capture/cropping_window_capturer_win.cc +++ b/modules/desktop_capture/cropping_window_capturer_win.cc @@ -98,26 +98,53 @@ BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) { class CroppingWindowCapturerWin : public CroppingWindowCapturer { public: - CroppingWindowCapturerWin(const DesktopCaptureOptions& options) - : CroppingWindowCapturer(options) {} + explicit CroppingWindowCapturerWin(const DesktopCaptureOptions& options) + : CroppingWindowCapturer(options), + full_screen_window_detector_(options.full_screen_window_detector()) {} + + void CaptureFrame() override; private: bool ShouldUseScreenCapturer() override; DesktopRect GetWindowRectInVirtualScreen() override; + // Returns either selected by user sourceId or sourceId provided by + // FullScreenWindowDetector + WindowId GetWindowToCapture() const; + // The region from GetWindowRgn in the desktop coordinate if the region is // rectangular, or the rect from GetWindowRect if the region is not set. DesktopRect window_region_rect_; WindowCaptureHelperWin window_capture_helper_; + + rtc::scoped_refptr full_screen_window_detector_; }; +void CroppingWindowCapturerWin::CaptureFrame() { + DesktopCapturer* win_capturer = window_capturer(); + if (win_capturer) { + // Update the list of available sources and override source to capture if + // FullScreenWindowDetector returns not zero + if (full_screen_window_detector_) { + full_screen_window_detector_->UpdateWindowListIfNeeded( + selected_window(), + [win_capturer](DesktopCapturer::SourceList* sources) { + return win_capturer->GetSourceList(sources); + }); + } + win_capturer->SelectSource(GetWindowToCapture()); + } + + CroppingWindowCapturer::CaptureFrame(); +} + bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { if (!rtc::IsWindows8OrLater() && window_capture_helper_.IsAeroEnabled()) { return false; } - const HWND selected = reinterpret_cast(selected_window()); + const HWND selected = reinterpret_cast(GetWindowToCapture()); // Check if the window is visible on current desktop. if (!window_capture_helper_.IsWindowVisibleOnCurrentDesktop(selected)) { return false; @@ -207,7 +234,7 @@ DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() { TRACE_EVENT0("webrtc", "CroppingWindowCapturerWin::GetWindowRectInVirtualScreen"); DesktopRect window_rect; - HWND hwnd = reinterpret_cast(selected_window()); + HWND hwnd = reinterpret_cast(GetWindowToCapture()); if (!GetCroppedWindowRect(hwnd, /*avoid_cropping_border*/ false, &window_rect, /*original_rect*/ nullptr)) { RTC_LOG(LS_WARNING) << "Failed to get window info: " << GetLastError(); @@ -222,6 +249,15 @@ DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() { return window_rect; } +WindowId CroppingWindowCapturerWin::GetWindowToCapture() const { + const auto selected_source = selected_window(); + const auto full_screen_source = + full_screen_window_detector_ + ? full_screen_window_detector_->FindFullScreenWindow(selected_source) + : 0; + return full_screen_source ? full_screen_source : selected_source; +} + } // namespace // static diff --git a/modules/desktop_capture/desktop_capture_options.cc b/modules/desktop_capture/desktop_capture_options.cc index 8a33807bb3..ee1e4775cc 100644 --- a/modules/desktop_capture/desktop_capture_options.cc +++ b/modules/desktop_capture/desktop_capture_options.cc @@ -9,6 +9,11 @@ */ #include "modules/desktop_capture/desktop_capture_options.h" +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) +#include "modules/desktop_capture/mac/full_screen_mac_application_handler.h" +#elif defined(WEBRTC_WIN) +#include "modules/desktop_capture/win/full_screen_win_application_handler.h" +#endif namespace webrtc { @@ -32,8 +37,11 @@ DesktopCaptureOptions DesktopCaptureOptions::CreateDefault() { #endif #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) result.set_configuration_monitor(new DesktopConfigurationMonitor()); - result.set_full_screen_chrome_window_detector( - new FullScreenChromeWindowDetector()); + result.set_full_screen_window_detector( + new FullScreenWindowDetector(CreateFullScreenMacApplicationHandler)); +#elif defined(WEBRTC_WIN) + result.set_full_screen_window_detector( + new FullScreenWindowDetector(CreateFullScreenWinApplicationHandler)); #endif return result; } diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h index 11e5f4c789..d7dac1f0eb 100644 --- a/modules/desktop_capture/desktop_capture_options.h +++ b/modules/desktop_capture/desktop_capture_options.h @@ -19,9 +19,10 @@ #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) #include "modules/desktop_capture/mac/desktop_configuration_monitor.h" -#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h" #endif +#include "modules/desktop_capture/full_screen_window_detector.h" + namespace webrtc { // An object that stores initialization parameters for screen and window @@ -62,21 +63,18 @@ class RTC_EXPORT DesktopCaptureOptions { configuration_monitor_ = m; } - // TODO(zijiehe): Instead of FullScreenChromeWindowDetector, provide a - // FullScreenWindowDetector for external consumers to detect the target - // fullscreen window. - FullScreenChromeWindowDetector* full_screen_chrome_window_detector() const { - return full_screen_window_detector_; - } - void set_full_screen_chrome_window_detector( - rtc::scoped_refptr detector) { - full_screen_window_detector_ = detector; - } - bool allow_iosurface() const { return allow_iosurface_; } void set_allow_iosurface(bool allow) { allow_iosurface_ = allow; } #endif + FullScreenWindowDetector* full_screen_window_detector() const { + return full_screen_window_detector_; + } + void set_full_screen_window_detector( + rtc::scoped_refptr detector) { + full_screen_window_detector_ = detector; + } + // Flag indicating that the capturer should use screen change notifications. // Enables/disables use of XDAMAGE in the X11 capturer. bool use_update_notifications() const { return use_update_notifications_; } @@ -142,11 +140,11 @@ class RTC_EXPORT DesktopCaptureOptions { #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) rtc::scoped_refptr configuration_monitor_; - rtc::scoped_refptr - full_screen_window_detector_; bool allow_iosurface_ = false; #endif + rtc::scoped_refptr full_screen_window_detector_; + #if defined(WEBRTC_WIN) bool allow_use_magnification_api_ = false; bool allow_directx_capturer_ = false; diff --git a/modules/desktop_capture/full_screen_application_handler.cc b/modules/desktop_capture/full_screen_application_handler.cc new file mode 100644 index 0000000000..e0975570ba --- /dev/null +++ b/modules/desktop_capture/full_screen_application_handler.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/desktop_capture/full_screen_application_handler.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +FullScreenApplicationHandler::FullScreenApplicationHandler( + DesktopCapturer::SourceId sourceId) + : source_id_(sourceId) {} + +DesktopCapturer::SourceId FullScreenApplicationHandler::FindFullScreenWindow( + const DesktopCapturer::SourceList&, + int64_t) const { + return 0; +} + +DesktopCapturer::SourceId FullScreenApplicationHandler::GetSourceId() const { + return source_id_; +} + +} // namespace webrtc diff --git a/modules/desktop_capture/full_screen_application_handler.h b/modules/desktop_capture/full_screen_application_handler.h new file mode 100644 index 0000000000..849cb2c761 --- /dev/null +++ b/modules/desktop_capture/full_screen_application_handler.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_ +#define MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_ + +#include +#include "modules/desktop_capture/desktop_capturer.h" +#include "rtc_base/constructor_magic.h" + +namespace webrtc { + +// Base class for application specific handler to check criteria for switch to +// full-screen mode and find if possible the full-screen window to share. +// Supposed to be created and owned by platform specific +// FullScreenWindowDetector. +class FullScreenApplicationHandler { + public: + virtual ~FullScreenApplicationHandler() {} + + explicit FullScreenApplicationHandler(DesktopCapturer::SourceId sourceId); + + // Returns the full-screen window in place of the original window if all the + // criteria are met, or 0 if no such window found. + virtual DesktopCapturer::SourceId FindFullScreenWindow( + const DesktopCapturer::SourceList& window_list, + int64_t timestamp) const; + + // Returns source id of original window associated with + // FullScreenApplicationHandler + DesktopCapturer::SourceId GetSourceId() const; + + private: + const DesktopCapturer::SourceId source_id_; + + RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenApplicationHandler); +}; + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_ diff --git a/modules/desktop_capture/full_screen_window_detector.cc b/modules/desktop_capture/full_screen_window_detector.cc new file mode 100644 index 0000000000..d0bc9c7ca6 --- /dev/null +++ b/modules/desktop_capture/full_screen_window_detector.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/desktop_capture/full_screen_window_detector.h" +#include "modules/desktop_capture/full_screen_application_handler.h" +#include "rtc_base/time_utils.h" + +namespace webrtc { + +FullScreenWindowDetector::FullScreenWindowDetector( + ApplicationHandlerFactory application_handler_factory) + : application_handler_factory_(application_handler_factory), + last_update_time_ms_(0), + previous_source_id_(0), + no_handler_source_id_(0) {} + +DesktopCapturer::SourceId FullScreenWindowDetector::FindFullScreenWindow( + DesktopCapturer::SourceId original_source_id) { + if (app_handler_ == nullptr || + app_handler_->GetSourceId() != original_source_id) { + return 0; + } + return app_handler_->FindFullScreenWindow(window_list_, last_update_time_ms_); +} + +void FullScreenWindowDetector::UpdateWindowListIfNeeded( + DesktopCapturer::SourceId original_source_id, + rtc::FunctionView get_sources) { + const bool skip_update = previous_source_id_ != original_source_id; + previous_source_id_ = original_source_id; + + // Here is an attempt to avoid redundant creating application handler in case + // when an instance of WindowCapturer is used to generate a thumbnail to show + // in picker by calling SelectSource and CaptureFrame for every available + // source. + if (skip_update) { + return; + } + + CreateApplicationHandlerIfNeeded(original_source_id); + if (app_handler_ == nullptr) { + // There is no FullScreenApplicationHandler specific for + // current application + return; + } + + constexpr int64_t kUpdateIntervalMs = 500; + + if ((rtc::TimeMillis() - last_update_time_ms_) <= kUpdateIntervalMs) { + return; + } + + DesktopCapturer::SourceList window_list; + if (get_sources(&window_list)) { + last_update_time_ms_ = rtc::TimeMillis(); + window_list_.swap(window_list); + } +} + +void FullScreenWindowDetector::CreateApplicationHandlerIfNeeded( + DesktopCapturer::SourceId source_id) { + if (no_handler_source_id_ == source_id) { + return; + } + + if (app_handler_ == nullptr || app_handler_->GetSourceId() != source_id) { + app_handler_ = application_handler_factory_ + ? application_handler_factory_(source_id) + : nullptr; + } + + if (app_handler_ == nullptr) { + no_handler_source_id_ = source_id; + } +} + +} // namespace webrtc diff --git a/modules/desktop_capture/full_screen_window_detector.h b/modules/desktop_capture/full_screen_window_detector.h new file mode 100644 index 0000000000..46fb607b7d --- /dev/null +++ b/modules/desktop_capture/full_screen_window_detector.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_ +#define MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_ + +#include +#include "api/function_view.h" +#include "api/ref_counted_base.h" +#include "api/scoped_refptr.h" +#include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/full_screen_application_handler.h" +#include "rtc_base/constructor_magic.h" + +namespace webrtc { + +// This is a way to handle switch to full-screen mode for application in some +// specific cases: +// - Chrome on MacOS creates a new window in full-screen mode to +// show a tab full-screen and minimizes the old window. +// - PowerPoint creates new windows in full-screen mode when user goes to +// presentation mode (Slide Show Window, Presentation Window). +// +// To continue capturing in these cases, we try to find the new full-screen +// window using criteria provided by application specific +// FullScreenApplicationHandler. + +class FullScreenWindowDetector : public rtc::RefCountedBase { + public: + using ApplicationHandlerFactory = + std::function( + DesktopCapturer::SourceId sourceId)>; + + FullScreenWindowDetector( + ApplicationHandlerFactory application_handler_factory); + + // Returns the full-screen window in place of the original window if all the + // criteria provided by FullScreenApplicationHandler are met, or 0 if no such + // window found. + DesktopCapturer::SourceId FindFullScreenWindow( + DesktopCapturer::SourceId original_source_id); + + // The caller should call this function periodically, implementation will + // update internal state no often than twice per second + void UpdateWindowListIfNeeded( + DesktopCapturer::SourceId original_source_id, + rtc::FunctionView get_sources); + + static rtc::scoped_refptr + CreateFullScreenWindowDetector(); + + protected: + std::unique_ptr app_handler_; + + private: + void CreateApplicationHandlerIfNeeded(DesktopCapturer::SourceId source_id); + + ApplicationHandlerFactory application_handler_factory_; + + int64_t last_update_time_ms_; + DesktopCapturer::SourceId previous_source_id_; + + // Save the source id when we fail to create an instance of + // CreateApplicationHandlerIfNeeded to avoid redundant attempt to do it again. + DesktopCapturer::SourceId no_handler_source_id_; + + DesktopCapturer::SourceList window_list_; + RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenWindowDetector); +}; + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_ diff --git a/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc b/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc deleted file mode 100644 index f2c8fd47ab..0000000000 --- a/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h" - -#include - -#include - -#include "modules/desktop_capture/mac/window_list_utils.h" -#include "rtc_base/logging.h" -#include "rtc_base/time_utils.h" - -namespace webrtc { - -namespace { - -const int64_t kUpdateIntervalMs = 500; - -// Returns the window that is full-screen and has the same title and owner pid -// as the input window. -CGWindowID FindFullScreenWindowWithSamePidAndTitle(CGWindowID id) { - const int pid = GetWindowOwnerPid(id); - std::string title = GetWindowTitle(id); - if (title.empty()) - return kCGNullWindowID; - - // Only get on screen, non-desktop windows. - CFArrayRef window_array = CGWindowListCopyWindowInfo( - kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, - kCGNullWindowID); - if (!window_array) - return kCGNullWindowID; - - CGWindowID full_screen_window = kCGNullWindowID; - - MacDesktopConfiguration desktop_config = MacDesktopConfiguration::GetCurrent( - MacDesktopConfiguration::TopLeftOrigin); - - // Check windows to make sure they have an id, title, and use window layer - // other than 0. - CFIndex count = CFArrayGetCount(window_array); - for (CFIndex i = 0; i < count; ++i) { - CFDictionaryRef window = reinterpret_cast( - CFArrayGetValueAtIndex(window_array, i)); - - CGWindowID window_id = GetWindowId(window); - if (window_id == kNullWindowId) - continue; - - if (GetWindowOwnerPid(window) != pid) - continue; - - std::string window_title = GetWindowTitle(window); - if (window_title != title) - continue; - - if (IsWindowFullScreen(desktop_config, window)) { - full_screen_window = window_id; - break; - } - } - - CFRelease(window_array); - return full_screen_window; -} - -bool IsChromeWindow(CGWindowID id) { - int pid = GetWindowOwnerPid(id); - char buffer[PROC_PIDPATHINFO_MAXSIZE]; - int path_length = proc_pidpath(pid, buffer, sizeof(buffer)); - if (path_length <= 0) - return false; - - const char* last_slash = strrchr(buffer, '/'); - std::string name(last_slash ? last_slash + 1 : buffer); - return name.find("Google Chrome") == 0 || name == "Chromium"; -} - -} // namespace - -FullScreenChromeWindowDetector::FullScreenChromeWindowDetector() - : last_update_time_ns_(0) {} - -FullScreenChromeWindowDetector::~FullScreenChromeWindowDetector() {} - -CGWindowID FullScreenChromeWindowDetector::FindFullScreenWindow( - CGWindowID original_window) { - if (!IsChromeWindow(original_window) || IsWindowOnScreen(original_window)) - return kCGNullWindowID; - - CGWindowID full_screen_window_id = - FindFullScreenWindowWithSamePidAndTitle(original_window); - - if (full_screen_window_id == kCGNullWindowID) - return kCGNullWindowID; - - for (const auto& window : previous_window_list_) { - if (static_cast(window.id) != full_screen_window_id) - continue; - - RTC_LOG(LS_WARNING) << "The full-screen window exists in the list."; - return kCGNullWindowID; - } - - return full_screen_window_id; -} - -void FullScreenChromeWindowDetector::UpdateWindowListIfNeeded( - CGWindowID original_window) { - if (IsChromeWindow(original_window) && - (rtc::TimeNanos() - last_update_time_ns_) / rtc::kNumNanosecsPerMillisec > - kUpdateIntervalMs) { - previous_window_list_.clear(); - previous_window_list_.swap(current_window_list_); - - // No need to update the window list when the window is minimized. - if (!IsWindowOnScreen(original_window)) { - previous_window_list_.clear(); - return; - } - - GetWindowList(¤t_window_list_, false); - last_update_time_ns_ = rtc::TimeNanos(); - } -} - -} // namespace webrtc diff --git a/modules/desktop_capture/mac/full_screen_chrome_window_detector.h b/modules/desktop_capture/mac/full_screen_chrome_window_detector.h deleted file mode 100644 index 2ee99adedc..0000000000 --- a/modules/desktop_capture/mac/full_screen_chrome_window_detector.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_ -#define MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_ - -#include - -#include "api/ref_counted_base.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "rtc_base/constructor_magic.h" - -namespace webrtc { - -// This is a work around for the Chrome tab full-screen behavior: Chrome -// creates a new window in full-screen mode to show a tab full-screen and -// minimizes the old window. To continue capturing in this case, we try to -// find the new full-screen window using these criteria: -// 0. The original shared window is minimized. -// 1. The original shared window's owner application name is "Google Chrome". -// 2. The original window and the new window have the same title and owner -// pid. -// 3. The new window is full-screen. -// 4. The new window didn't exist at least 500 millisecond ago. - -class FullScreenChromeWindowDetector : public rtc::RefCountedBase { - public: - FullScreenChromeWindowDetector(); - - // Returns the full-screen window in place of the original window if all the - // criteria are met, or kCGNullWindowID if no such window found. - CGWindowID FindFullScreenWindow(CGWindowID original_window); - - // The caller should call this function periodically, no less than twice per - // second. - void UpdateWindowListIfNeeded(CGWindowID original_window); - - protected: - ~FullScreenChromeWindowDetector() override; - - private: - // We cache the last two results of the window list, so - // |previous_window_list_| is taken at least 500ms before the next Capture() - // call. If we only save the last result, we may get false positive (i.e. - // full-screen window exists in the list) if Capture() is called too soon. - DesktopCapturer::SourceList current_window_list_; - DesktopCapturer::SourceList previous_window_list_; - int64_t last_update_time_ns_; - - RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenChromeWindowDetector); -}; - -} // namespace webrtc - -#endif // MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_ diff --git a/modules/desktop_capture/mac/full_screen_mac_application_handler.cc b/modules/desktop_capture/mac/full_screen_mac_application_handler.cc new file mode 100644 index 0000000000..9e6eacce85 --- /dev/null +++ b/modules/desktop_capture/mac/full_screen_mac_application_handler.cc @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/desktop_capture/mac/full_screen_mac_application_handler.h" +#include +#include +#include +#include +#include "absl/strings/match.h" +#include "modules/desktop_capture/mac/window_list_utils.h" + +namespace webrtc { +namespace { + +static constexpr const char* kPowerPointSlideShowTitles[] = { + u8"PowerPoint-Bildschirmpräsentation", + u8"Προβολή παρουσίασης PowerPoint", + u8"PowerPoint スライド ショー", + u8"PowerPoint Slide Show", + u8"PowerPoint 幻灯片放映", + u8"Presentación de PowerPoint", + u8"PowerPoint-slideshow", + u8"Presentazione di PowerPoint", + u8"Prezentácia programu PowerPoint", + u8"Apresentação do PowerPoint", + u8"PowerPoint-bildspel", + u8"Prezentace v aplikaci PowerPoint", + u8"PowerPoint 슬라이드 쇼", + u8"PowerPoint-lysbildefremvisning", + u8"PowerPoint-vetítés", + u8"PowerPoint Slayt Gösterisi", + u8"Pokaz slajdów programu PowerPoint", + u8"PowerPoint 投影片放映", + u8"Демонстрация PowerPoint", + u8"Diaporama PowerPoint", + u8"PowerPoint-diaesitys", + u8"Peragaan Slide PowerPoint", + u8"PowerPoint-diavoorstelling", + u8"การนำเสนอสไลด์ PowerPoint", + u8"Apresentação de slides do PowerPoint", + u8"הצגת שקופיות של PowerPoint", + u8"عرض شرائح في PowerPoint"}; + +class FullScreenMacApplicationHandler : public FullScreenApplicationHandler { + public: + using TitlePredicate = + std::function; + + FullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId, + TitlePredicate title_predicate) + : FullScreenApplicationHandler(sourceId), + title_predicate_(title_predicate), + owner_pid_(GetWindowOwnerPid(sourceId)) {} + + void InvalidateCacheIfNeeded(const DesktopCapturer::SourceList& source_list, + int64_t timestamp) const { + // Copy only sources with the same pid + if (timestamp != cache_timestamp_) { + cache_sources_.clear(); + std::copy_if(source_list.begin(), source_list.end(), + std::back_inserter(cache_sources_), + [&](const DesktopCapturer::Source& src) { + return src.id != GetSourceId() && + GetWindowOwnerPid(src.id) == owner_pid_; + }); + cache_timestamp_ = timestamp; + } + } + + WindowId FindFullScreenWindowWithSamePid( + const DesktopCapturer::SourceList& source_list, + int64_t timestamp) const { + InvalidateCacheIfNeeded(source_list, timestamp); + if (cache_sources_.empty()) + return kCGNullWindowID; + + const auto original_window = GetSourceId(); + const std::string title = GetWindowTitle(original_window); + + // We can ignore any windows with empty titles cause regardless type of + // application it's impossible to verify that full screen window and + // original window are related to the same document. + if (title.empty()) + return kCGNullWindowID; + + MacDesktopConfiguration desktop_config = + MacDesktopConfiguration::GetCurrent( + MacDesktopConfiguration::TopLeftOrigin); + + const auto it = std::find_if( + cache_sources_.begin(), cache_sources_.end(), + [&](const DesktopCapturer::Source& src) { + const std::string window_title = GetWindowTitle(src.id); + + if (window_title.empty()) + return false; + + if (title_predicate_ && !title_predicate_(title, window_title)) + return false; + + return IsWindowFullScreen(desktop_config, src.id); + }); + + return it != cache_sources_.end() ? it->id : 0; + } + + DesktopCapturer::SourceId FindFullScreenWindow( + const DesktopCapturer::SourceList& source_list, + int64_t timestamp) const override { + return IsWindowOnScreen(GetSourceId()) + ? 0 + : FindFullScreenWindowWithSamePid(source_list, timestamp); + } + + private: + const TitlePredicate title_predicate_; + const int owner_pid_; + mutable int64_t cache_timestamp_ = 0; + mutable DesktopCapturer::SourceList cache_sources_; +}; + +bool equal_title_predicate(const std::string& original_title, + const std::string& title) { + return original_title == title; +} + +bool slide_show_title_predicate(const std::string& original_title, + const std::string& title) { + if (title.find(original_title) == std::string::npos) + return false; + + for (const char* pp_slide_title : kPowerPointSlideShowTitles) { + if (absl::StartsWith(title, pp_slide_title)) + return true; + } + return false; +} + +} // namespace + +std::unique_ptr +CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId) { + std::unique_ptr result; + int pid = GetWindowOwnerPid(sourceId); + char buffer[PROC_PIDPATHINFO_MAXSIZE]; + int path_length = proc_pidpath(pid, buffer, sizeof(buffer)); + if (path_length > 0) { + const char* last_slash = strrchr(buffer, '/'); + const std::string name{last_slash ? last_slash + 1 : buffer}; + FullScreenMacApplicationHandler::TitlePredicate predicate = nullptr; + if (name.find("Google Chrome") == 0 || name == "Chromium") { + predicate = equal_title_predicate; + } else if (name == "Microsoft PowerPoint") { + predicate = slide_show_title_predicate; + } else if (name == "Keynote") { + predicate = equal_title_predicate; + } + + if (predicate) { + result.reset(new FullScreenMacApplicationHandler(sourceId, predicate)); + } + } + + return result; +} + +} // namespace webrtc diff --git a/modules/desktop_capture/mac/full_screen_mac_application_handler.h b/modules/desktop_capture/mac/full_screen_mac_application_handler.h new file mode 100644 index 0000000000..f795a22030 --- /dev/null +++ b/modules/desktop_capture/mac/full_screen_mac_application_handler.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_ +#define MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_ + +#include +#include "modules/desktop_capture/full_screen_application_handler.h" + +namespace webrtc { + +std::unique_ptr +CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId); + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_ diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc index 3f0a9b0940..67cf81c5ce 100644 --- a/modules/desktop_capture/mac/window_list_utils.cc +++ b/modules/desktop_capture/mac/window_list_utils.cc @@ -15,8 +15,11 @@ #include #include #include +#include #include #include +#include +#include #include "rtc_base/checks.h" @@ -78,7 +81,8 @@ bool GetWindowRef(CGWindowID id, } // namespace bool GetWindowList(rtc::FunctionView on_window, - bool ignore_minimized) { + bool ignore_minimized, + bool only_zero_layer) { RTC_DCHECK(on_window); // Only get on screen, non-desktop windows. @@ -122,7 +126,7 @@ bool GetWindowList(rtc::FunctionView on_window, if (!CFNumberGetValue(window_layer, kCFNumberIntType, &layer)) { continue; } - if (layer != 0) { + if (only_zero_layer && layer != 0) { continue; } @@ -151,7 +155,8 @@ bool GetWindowList(rtc::FunctionView on_window, } bool GetWindowList(DesktopCapturer::SourceList* windows, - bool ignore_minimized) { + bool ignore_minimized, + bool only_zero_layer) { // Use a std::list so that iterators are preversed upon insertion and // deletion. std::list sources; @@ -201,7 +206,7 @@ bool GetWindowList(DesktopCapturer::SourceList* windows, } return true; }, - ignore_minimized); + ignore_minimized, only_zero_layer); if (!ret) return false; @@ -239,6 +244,15 @@ bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config, return fullscreen; } +bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config, + CGWindowID id) { + bool fullscreen = false; + GetWindowRef(id, [&](CFDictionaryRef window) { + fullscreen = IsWindowFullScreen(desktop_config, window); + }); + return fullscreen; +} + bool IsWindowOnScreen(CFDictionaryRef window) { CFBooleanRef on_screen = reinterpret_cast( CFDictionaryGetValue(window, kCGWindowIsOnscreen)); diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h index ff9ad14872..f1c06013cb 100644 --- a/modules/desktop_capture/mac/window_list_utils.h +++ b/modules/desktop_capture/mac/window_list_utils.h @@ -13,6 +13,7 @@ #include +#include #include "api/function_view.h" #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_capturer.h" @@ -24,18 +25,26 @@ namespace webrtc { // Iterates all on-screen windows in decreasing z-order and sends them // one-by-one to |on_window| function. If |on_window| returns false, this // function returns immediately. GetWindowList() returns false if native APIs -// failed. Menus, dock, minimized windows (if |ignore_minimized| is true) and -// any windows which do not have a valid window id or title will be ignored. +// failed. Menus, dock (if |only_zero_layer|), minimized windows (if +// |ignore_minimized| is true) and any windows which do not have a valid window +// id or title will be ignored. bool GetWindowList(rtc::FunctionView on_window, - bool ignore_minimized); + bool ignore_minimized, + bool only_zero_layer); // Another helper function to get the on-screen windows. -bool GetWindowList(DesktopCapturer::SourceList* windows, bool ignore_minimized); +bool GetWindowList(DesktopCapturer::SourceList* windows, + bool ignore_minimized, + bool only_zero_layer); // Returns true if the window is occupying a full screen. bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config, CFDictionaryRef window); +// Returns true if the window is occupying a full screen. +bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config, + CGWindowID id); + // Returns true if the |window| is on screen. This function returns false if // native APIs fail. bool IsWindowOnScreen(CFDictionaryRef window); diff --git a/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/modules/desktop_capture/mouse_cursor_monitor_mac.mm index afc4497cf7..31ad428e0a 100644 --- a/modules/desktop_capture/mouse_cursor_monitor_mac.mm +++ b/modules/desktop_capture/mouse_cursor_monitor_mac.mm @@ -24,7 +24,6 @@ #include "modules/desktop_capture/desktop_frame.h" #include "modules/desktop_capture/mac/desktop_configuration.h" #include "modules/desktop_capture/mac/desktop_configuration_monitor.h" -#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h" #include "modules/desktop_capture/mac/window_list_utils.h" #include "modules/desktop_capture/mouse_cursor.h" @@ -79,21 +78,16 @@ class MouseCursorMonitorMac : public MouseCursorMonitor { Callback* callback_; Mode mode_; __strong NSImage* last_cursor_; - rtc::scoped_refptr - full_screen_chrome_window_detector_; }; -MouseCursorMonitorMac::MouseCursorMonitorMac( - const DesktopCaptureOptions& options, - CGWindowID window_id, - ScreenId screen_id) +MouseCursorMonitorMac::MouseCursorMonitorMac(const DesktopCaptureOptions& options, + CGWindowID window_id, + ScreenId screen_id) : configuration_monitor_(options.configuration_monitor()), window_id_(window_id), screen_id_(screen_id), callback_(NULL), - mode_(SHAPE_AND_POSITION), - full_screen_chrome_window_detector_( - options.full_screen_chrome_window_detector()) { + mode_(SHAPE_AND_POSITION) { assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId); } diff --git a/modules/desktop_capture/win/full_screen_win_application_handler.cc b/modules/desktop_capture/win/full_screen_win_application_handler.cc new file mode 100644 index 0000000000..0b7e3fc437 --- /dev/null +++ b/modules/desktop_capture/win/full_screen_win_application_handler.cc @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/desktop_capture/win/full_screen_win_application_handler.h" +#include +#include +#include +#include +#include +#include "rtc_base/arraysize.h" +#include "rtc_base/logging.h" // For RTC_LOG_GLE +#include "rtc_base/string_utils.h" + +namespace webrtc { +namespace { + +std::string WindowText(HWND window) { + size_t len = ::GetWindowTextLength(window); + if (len == 0) + return std::string(); + + std::vector buffer(len + 1, 0); + size_t copied = ::GetWindowTextW(window, buffer.data(), buffer.size()); + if (copied == 0) + return std::string(); + return rtc::ToUtf8(buffer.data(), copied); +} + +DWORD WindowProcessId(HWND window) { + DWORD dwProcessId = 0; + ::GetWindowThreadProcessId(window, &dwProcessId); + return dwProcessId; +} + +std::wstring FileNameFromPath(const std::wstring& path) { + auto found = path.rfind(L"\\"); + if (found == std::string::npos) + return path; + return path.substr(found + 1); +} + +// Returns windows which belong to given process id +// |sources| is a full list of available windows +// |processId| is a process identifier (window owner) +// |window_to_exclude| is a window to be exluded from result +DesktopCapturer::SourceList GetProcessWindows( + const DesktopCapturer::SourceList& sources, + DWORD processId, + HWND window_to_exclude) { + DesktopCapturer::SourceList result; + std::copy_if(sources.begin(), sources.end(), std::back_inserter(result), + [&](DesktopCapturer::Source source) { + const HWND source_hwnd = reinterpret_cast(source.id); + return window_to_exclude != source_hwnd && + WindowProcessId(source_hwnd) == processId; + }); + return result; +} + +class FullScreenPowerPointHandler : public FullScreenApplicationHandler { + public: + explicit FullScreenPowerPointHandler(DesktopCapturer::SourceId sourceId) + : FullScreenApplicationHandler(sourceId) {} + + ~FullScreenPowerPointHandler() override {} + + DesktopCapturer::SourceId FindFullScreenWindow( + const DesktopCapturer::SourceList& window_list, + int64_t timestamp) const override { + if (window_list.empty()) + return 0; + + HWND original_window = reinterpret_cast(GetSourceId()); + DWORD process_id = WindowProcessId(original_window); + + DesktopCapturer::SourceList powerpoint_windows = + GetProcessWindows(window_list, process_id, original_window); + + if (powerpoint_windows.empty()) + return 0; + + if (GetWindowType(original_window) != WindowType::kEditor) + return 0; + + const auto original_document = GetDocumentFromEditorTitle(original_window); + + for (const auto& source : powerpoint_windows) { + HWND window = reinterpret_cast(source.id); + + // Looking for slide show window for the same document + if (GetWindowType(window) != WindowType::kSlideShow || + GetDocumentFromSlideShowTitle(window) != original_document) { + continue; + } + + return source.id; + } + + return 0; + } + + private: + enum class WindowType { kEditor, kSlideShow, kOther }; + + WindowType GetWindowType(HWND window) const { + if (IsEditorWindow(window)) + return WindowType::kEditor; + else if (IsSlideShowWindow(window)) + return WindowType::kSlideShow; + else + return WindowType::kOther; + } + + constexpr static char kDocumentTitleSeparator[] = " - "; + + std::string GetDocumentFromEditorTitle(HWND window) const { + std::string title = WindowText(window); + auto position = title.find(kDocumentTitleSeparator); + return rtc::string_trim(title.substr(0, position)); + } + + std::string GetDocumentFromSlideShowTitle(HWND window) const { + std::string title = WindowText(window); + auto left_pos = title.find(kDocumentTitleSeparator); + auto right_pos = title.rfind(kDocumentTitleSeparator); + constexpr size_t kSeparatorLength = arraysize(kDocumentTitleSeparator) - 1; + if (left_pos == std::string::npos || right_pos == std::string::npos) + return title; + + if (right_pos > left_pos + kSeparatorLength) { + auto result_len = right_pos - left_pos - kSeparatorLength; + auto document = title.substr(left_pos + kSeparatorLength, result_len); + return rtc::string_trim(document); + } else { + auto document = + title.substr(left_pos + kSeparatorLength, std::wstring::npos); + return rtc::string_trim(document); + } + } + + bool IsEditorWindow(HWND window) const { + constexpr WCHAR kScreenClassName[] = L"PPTFrameClass"; + constexpr size_t kScreenClassNameLength = arraysize(kScreenClassName) - 1; + + // We need to verify that window class is equal to |kScreenClassName|. + // To do that we need a buffer large enough to include a null terminated + // string one code point bigger than |kScreenClassName|. It will help us to + // check that size of class name string returned by GetClassNameW is equal + // to |kScreenClassNameLength| not being limited by size of buffer (case + // when |kScreenClassName| is a prefix for class name string). + WCHAR buffer[arraysize(kScreenClassName) + 3]; + const int length = ::GetClassNameW(window, buffer, arraysize(buffer)); + if (length != kScreenClassNameLength) + return false; + return wcsncmp(buffer, kScreenClassName, kScreenClassNameLength) == 0; + } + + bool IsSlideShowWindow(HWND window) const { + const LONG style = ::GetWindowLong(window, GWL_STYLE); + const bool min_box = WS_MINIMIZEBOX & style; + const bool max_box = WS_MAXIMIZEBOX & style; + return !min_box && !max_box; + } +}; + +std::wstring GetPathByWindowId(HWND window_id) { + DWORD process_id = WindowProcessId(window_id); + HANDLE process = + ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id); + if (process == NULL) + return L""; + DWORD path_len = MAX_PATH; + WCHAR path[MAX_PATH]; + std::wstring result; + if (::QueryFullProcessImageNameW(process, 0, path, &path_len)) + result = std::wstring(path, path_len); + else + RTC_LOG_GLE(LS_ERROR) << "QueryFullProcessImageName failed."; + + ::CloseHandle(process); + return result; +} + +} // namespace + +std::unique_ptr +CreateFullScreenWinApplicationHandler(DesktopCapturer::SourceId source_id) { + std::unique_ptr result; + std::wstring exe_path = GetPathByWindowId(reinterpret_cast(source_id)); + std::wstring file_name = FileNameFromPath(exe_path); + std::transform(file_name.begin(), file_name.end(), file_name.begin(), + std::towupper); + + if (file_name == L"POWERPNT.EXE") { + result = std::make_unique(source_id); + } + + return result; +} + +} // namespace webrtc diff --git a/modules/desktop_capture/win/full_screen_win_application_handler.h b/modules/desktop_capture/win/full_screen_win_application_handler.h new file mode 100644 index 0000000000..c97cbe252b --- /dev/null +++ b/modules/desktop_capture/win/full_screen_win_application_handler.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_ +#define MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_ + +#include +#include "modules/desktop_capture/full_screen_application_handler.h" + +namespace webrtc { + +std::unique_ptr +CreateFullScreenWinApplicationHandler(DesktopCapturer::SourceId sourceId); + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_ diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm index 828122b982..96f89eb14b 100644 --- a/modules/desktop_capture/window_capturer_mac.mm +++ b/modules/desktop_capture/window_capturer_mac.mm @@ -22,7 +22,6 @@ #include "modules/desktop_capture/mac/desktop_configuration.h" #include "modules/desktop_capture/mac/desktop_configuration_monitor.h" #include "modules/desktop_capture/mac/desktop_frame_cgimage.h" -#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h" #include "modules/desktop_capture/mac/window_list_utils.h" #include "modules/desktop_capture/window_finder_mac.h" #include "rtc_base/constructor_magic.h" @@ -48,10 +47,9 @@ bool IsWindowValid(CGWindowID id) { class WindowCapturerMac : public DesktopCapturer { public: - explicit WindowCapturerMac(rtc::scoped_refptr - full_screen_chrome_window_detector, - rtc::scoped_refptr - configuration_monitor); + explicit WindowCapturerMac( + rtc::scoped_refptr full_screen_window_detector, + rtc::scoped_refptr configuration_monitor); ~WindowCapturerMac() override; // DesktopCapturer interface. @@ -68,8 +66,7 @@ class WindowCapturerMac : public DesktopCapturer { // The window being captured. CGWindowID window_id_ = 0; - const rtc::scoped_refptr - full_screen_chrome_window_detector_; + rtc::scoped_refptr full_screen_window_detector_; const rtc::scoped_refptr configuration_monitor_; @@ -79,18 +76,16 @@ class WindowCapturerMac : public DesktopCapturer { }; WindowCapturerMac::WindowCapturerMac( - rtc::scoped_refptr - full_screen_chrome_window_detector, + rtc::scoped_refptr full_screen_window_detector, rtc::scoped_refptr configuration_monitor) - : full_screen_chrome_window_detector_( - std::move(full_screen_chrome_window_detector)), + : full_screen_window_detector_(std::move(full_screen_window_detector)), configuration_monitor_(std::move(configuration_monitor)), window_finder_(configuration_monitor_) {} WindowCapturerMac::~WindowCapturerMac() {} bool WindowCapturerMac::GetSourceList(SourceList* sources) { - return webrtc::GetWindowList(sources, true); + return webrtc::GetWindowList(sources, true, true); } bool WindowCapturerMac::SelectSource(SourceId id) { @@ -163,12 +158,15 @@ void WindowCapturerMac::CaptureFrame() { } CGWindowID on_screen_window = window_id_; - if (full_screen_chrome_window_detector_) { - CGWindowID full_screen_window = - full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_); + if (full_screen_window_detector_) { + full_screen_window_detector_->UpdateWindowListIfNeeded( + window_id_, [](DesktopCapturer::SourceList* sources) { + return webrtc::GetWindowList(sources, true, false); + }); - if (full_screen_window != kCGNullWindowID) - on_screen_window = full_screen_window; + CGWindowID full_screen_window = full_screen_window_detector_->FindFullScreenWindow(window_id_); + + if (full_screen_window != kCGNullWindowID) on_screen_window = full_screen_window; } std::unique_ptr frame = DesktopFrameCGImage::CreateForWindow(on_screen_window); @@ -186,9 +184,6 @@ void WindowCapturerMac::CaptureFrame() { frame->set_dpi(DesktopVector(kStandardDPI * scale_factor, kStandardDPI * scale_factor)); callback_->OnCaptureResult(Result::SUCCESS, std::move(frame)); - - if (full_screen_chrome_window_detector_) - full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_); } } // namespace @@ -196,9 +191,8 @@ void WindowCapturerMac::CaptureFrame() { // static std::unique_ptr DesktopCapturer::CreateRawWindowCapturer( const DesktopCaptureOptions& options) { - return std::unique_ptr( - new WindowCapturerMac(options.full_screen_chrome_window_detector(), - options.configuration_monitor())); + return std::unique_ptr(new WindowCapturerMac( + options.full_screen_window_detector(), options.configuration_monitor())); } } // namespace webrtc diff --git a/modules/desktop_capture/window_finder_mac.mm b/modules/desktop_capture/window_finder_mac.mm index 64979c62cd..e1d0316c79 100644 --- a/modules/desktop_capture/window_finder_mac.mm +++ b/modules/desktop_capture/window_finder_mac.mm @@ -38,6 +38,7 @@ WindowId WindowFinderMac::GetWindowUnderPoint(DesktopVector point) { } return true; }, + true, true); return id; }