screen_capturer_mac_unittest.cc (5899B)
1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <ApplicationServices/ApplicationServices.h> 12 13 #include <chrono> 14 #include <memory> 15 #include <thread> 16 17 #include "modules/desktop_capture/desktop_capture_options.h" 18 #include "modules/desktop_capture/desktop_capturer.h" 19 #include "modules/desktop_capture/desktop_frame.h" 20 #include "modules/desktop_capture/desktop_geometry.h" 21 #include "modules/desktop_capture/desktop_region.h" 22 #include "modules/desktop_capture/mac/desktop_configuration.h" 23 #include "modules/desktop_capture/mock_desktop_capturer_callback.h" 24 #include "test/gtest.h" 25 26 using ::testing::_; 27 using ::testing::AnyNumber; 28 using ::testing::AnyOf; 29 using ::testing::InSequence; 30 31 namespace webrtc { 32 33 class ScreenCapturerMacTest : public ::testing::Test { 34 public: 35 // Verifies that the whole screen is initially dirty. 36 void CaptureDoneCallback1(DesktopCapturer::Result result, 37 std::unique_ptr<DesktopFrame>* frame); 38 39 // Verifies that a rectangle explicitly marked as dirty is propagated 40 // correctly. 41 void CaptureDoneCallback2(DesktopCapturer::Result result, 42 std::unique_ptr<DesktopFrame>* frame); 43 44 protected: 45 void SetUp() override { 46 capturer_ = DesktopCapturer::CreateScreenCapturer( 47 DesktopCaptureOptions::CreateDefault()); 48 } 49 50 std::unique_ptr<DesktopCapturer> capturer_; 51 MockDesktopCapturerCallback callback_; 52 }; 53 54 class ScreenCapturerSckTest : public ScreenCapturerMacTest { 55 protected: 56 void SetUp() override { 57 auto options = DesktopCaptureOptions::CreateDefault(); 58 options.set_allow_sck_capturer(true); 59 capturer_ = DesktopCapturer::CreateScreenCapturer(options); 60 } 61 62 std::unique_ptr<DesktopCapturer> capturer_; 63 MockDesktopCapturerCallback callback_; 64 }; 65 66 void ScreenCapturerMacTest::CaptureDoneCallback1( 67 DesktopCapturer::Result result, 68 std::unique_ptr<DesktopFrame>* frame) { 69 EXPECT_EQ(result, DesktopCapturer::Result::SUCCESS); 70 71 MacDesktopConfiguration config = MacDesktopConfiguration::GetCurrent( 72 MacDesktopConfiguration::BottomLeftOrigin); 73 74 // Verify that the region contains full frame. 75 DesktopRegion::Iterator it((*frame)->updated_region()); 76 EXPECT_TRUE(!it.IsAtEnd() && it.rect().equals(config.pixel_bounds)); 77 } 78 79 void ScreenCapturerMacTest::CaptureDoneCallback2( 80 DesktopCapturer::Result result, 81 std::unique_ptr<DesktopFrame>* frame) { 82 EXPECT_EQ(result, DesktopCapturer::Result::SUCCESS); 83 84 MacDesktopConfiguration config = MacDesktopConfiguration::GetCurrent( 85 MacDesktopConfiguration::BottomLeftOrigin); 86 int width = config.pixel_bounds.width(); 87 int height = config.pixel_bounds.height(); 88 89 EXPECT_EQ(width, (*frame)->size().width()); 90 EXPECT_EQ(height, (*frame)->size().height()); 91 EXPECT_TRUE((*frame)->data() != NULL); 92 // Depending on the capture method, the screen may be flipped or not, so 93 // the stride may be positive or negative. 94 // The stride may in theory be larger than the width due to alignment, but in 95 // other cases, like window capture, the stride normally matches the monitor 96 // resolution whereas the width matches the window region on said monitor. 97 // Make no assumptions. 98 EXPECT_LE(static_cast<int>(sizeof(uint32_t) * width), 99 abs((*frame)->stride())); 100 } 101 102 TEST_F(ScreenCapturerMacTest, Capture) { 103 EXPECT_CALL(callback_, 104 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) 105 .Times(2) 106 .WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback1)) 107 .WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback2)); 108 109 SCOPED_TRACE(""); 110 capturer_->Start(&callback_); 111 112 // Check that we get an initial full-screen updated. 113 capturer_->CaptureFrame(); 114 115 // Check that subsequent dirty rects are propagated correctly. 116 capturer_->CaptureFrame(); 117 } 118 119 TEST_F(ScreenCapturerSckTest, Capture) { 120 if (!CGPreflightScreenCaptureAccess()) { 121 GTEST_SKIP() 122 << "ScreenCapturerSckTest needs TCC ScreenCapture authorization"; 123 } 124 125 std::atomic<bool> done{false}; 126 std::atomic<DesktopCapturer::Result> result{ 127 DesktopCapturer::Result::ERROR_TEMPORARY}; 128 InSequence s; 129 EXPECT_CALL(callback_, 130 OnCaptureResultPtr(DesktopCapturer::Result::ERROR_TEMPORARY, _)) 131 .Times(AnyNumber()); 132 EXPECT_CALL(callback_, 133 OnCaptureResultPtr(AnyOf(DesktopCapturer::Result::ERROR_PERMANENT, 134 DesktopCapturer::Result::SUCCESS), 135 _)) 136 .WillOnce([this, &result](DesktopCapturer::Result res, 137 std::unique_ptr<DesktopFrame>* frame) { 138 result = res; 139 if (res == DesktopCapturer::Result::SUCCESS) { 140 CaptureDoneCallback1(res, frame); 141 } 142 }); 143 SCOPED_TRACE(""); 144 capturer_->Start(&callback_); 145 146 while (result == DesktopCapturer::Result::ERROR_TEMPORARY) { 147 // Check that we get an initial full-screen updated. 148 capturer_->CaptureFrame(); 149 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 150 } 151 ASSERT_NE(result, DesktopCapturer::Result::ERROR_PERMANENT); 152 153 EXPECT_CALL(callback_, 154 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) 155 .Times(1) 156 .WillOnce([this, &done](auto res, auto frame) { 157 CaptureDoneCallback2(res, frame); 158 done = true; 159 }); 160 161 while (!done) { 162 // Check that we get an initial full-screen updated. 163 capturer_->CaptureFrame(); 164 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 165 } 166 } 167 168 } // namespace webrtc