1 /*
2 * Copyright (c) 2022 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 "modules/desktop_capture/linux/wayland/shared_screencast_stream.h"
12
13 #include <memory>
14 #include <utility>
15
16 #include "api/units/time_delta.h"
17 #include "modules/desktop_capture/desktop_capturer.h"
18 #include "modules/desktop_capture/desktop_frame.h"
19 #include "modules/desktop_capture/linux/wayland/test/test_screencast_stream_provider.h"
20 #include "modules/desktop_capture/rgba_color.h"
21 #include "rtc_base/event.h"
22 #include "test/gmock.h"
23 #include "test/gtest.h"
24
25 using ::testing::_;
26 using ::testing::AtLeast;
27 using ::testing::Ge;
28 using ::testing::Invoke;
29
30 namespace webrtc {
31
32 constexpr TimeDelta kShortWait = TimeDelta::Seconds(5);
33 constexpr TimeDelta kLongWait = TimeDelta::Seconds(15);
34
35 constexpr int kBytesPerPixel = 4;
36 constexpr int32_t kWidth = 800;
37 constexpr int32_t kHeight = 640;
38
39 class PipeWireStreamTest : public ::testing::Test,
40 public TestScreenCastStreamProvider::Observer,
41 public SharedScreenCastStream::Observer {
42 public:
43 PipeWireStreamTest() = default;
44 ~PipeWireStreamTest() = default;
45
46 // FakeScreenCastPortal::Observer
47 MOCK_METHOD(void, OnBufferAdded, (), (override));
48 MOCK_METHOD(void, OnFrameRecorded, (), (override));
49 MOCK_METHOD(void, OnStreamReady, (uint32_t stream_node_id), (override));
50 MOCK_METHOD(void, OnStartStreaming, (), (override));
51 MOCK_METHOD(void, OnStopStreaming, (), (override));
52
53 // SharedScreenCastStream::Observer
54 MOCK_METHOD(void, OnCursorPositionChanged, (), (override));
55 MOCK_METHOD(void, OnCursorShapeChanged, (), (override));
56 MOCK_METHOD(void, OnDesktopFrameChanged, (), (override));
57 MOCK_METHOD(void, OnFailedToProcessBuffer, (), (override));
58 MOCK_METHOD(void, OnStreamConfigured, (), (override));
59
SetUp()60 void SetUp() override {
61 shared_screencast_stream_ = SharedScreenCastStream::CreateDefault();
62 shared_screencast_stream_->SetObserver(this);
63 test_screencast_stream_provider_ =
64 std::make_unique<TestScreenCastStreamProvider>(this, kWidth, kHeight);
65 }
66
StartScreenCastStream(uint32_t stream_node_id)67 void StartScreenCastStream(uint32_t stream_node_id) {
68 shared_screencast_stream_->StartScreenCastStream(stream_node_id);
69 }
70
71 protected:
72 uint recorded_frames_ = 0;
73 bool streaming_ = false;
74 std::unique_ptr<TestScreenCastStreamProvider>
75 test_screencast_stream_provider_;
76 rtc::scoped_refptr<SharedScreenCastStream> shared_screencast_stream_;
77 };
78
TEST_F(PipeWireStreamTest,TestPipeWire)79 TEST_F(PipeWireStreamTest, TestPipeWire) {
80 // Set expectations for PipeWire to successfully connect both streams
81 rtc::Event waitConnectEvent;
82 rtc::Event waitStartStreamingEvent;
83
84 EXPECT_CALL(*this, OnStreamReady(_))
85 .WillOnce(Invoke(this, &PipeWireStreamTest::StartScreenCastStream));
86 EXPECT_CALL(*this, OnStreamConfigured).WillOnce([&waitConnectEvent] {
87 waitConnectEvent.Set();
88 });
89 EXPECT_CALL(*this, OnBufferAdded).Times(AtLeast(3));
90 EXPECT_CALL(*this, OnStartStreaming).WillOnce([&waitStartStreamingEvent] {
91 waitStartStreamingEvent.Set();
92 });
93
94 // Give it some time to connect, the order between these shouldn't matter, but
95 // we need to be sure we are connected before we proceed to work with frames.
96 waitConnectEvent.Wait(kLongWait);
97
98 // Wait until we start streaming
99 waitStartStreamingEvent.Wait(kShortWait);
100
101 rtc::Event frameRetrievedEvent;
102 EXPECT_CALL(*this, OnFrameRecorded).Times(3);
103 EXPECT_CALL(*this, OnDesktopFrameChanged)
104 .WillRepeatedly([&frameRetrievedEvent] { frameRetrievedEvent.Set(); });
105
106 // Record a frame in FakePipeWireStream
107 RgbaColor red_color(0, 0, 255);
108 test_screencast_stream_provider_->RecordFrame(red_color);
109
110 // Retrieve a frame from SharedScreenCastStream
111 frameRetrievedEvent.Wait(kShortWait);
112 std::unique_ptr<SharedDesktopFrame> frame =
113 shared_screencast_stream_->CaptureFrame();
114
115 // Check frame parameters
116 ASSERT_NE(frame, nullptr);
117 ASSERT_NE(frame->data(), nullptr);
118 EXPECT_EQ(frame->rect().width(), kWidth);
119 EXPECT_EQ(frame->rect().height(), kHeight);
120 EXPECT_EQ(frame->stride(), frame->rect().width() * kBytesPerPixel);
121 EXPECT_EQ(RgbaColor(frame->data()), red_color);
122
123 // Test DesktopFrameQueue
124 RgbaColor green_color(0, 255, 0);
125 test_screencast_stream_provider_->RecordFrame(green_color);
126 frameRetrievedEvent.Wait(kShortWait);
127 std::unique_ptr<SharedDesktopFrame> frame2 =
128 shared_screencast_stream_->CaptureFrame();
129 ASSERT_NE(frame2, nullptr);
130 ASSERT_NE(frame2->data(), nullptr);
131 EXPECT_EQ(frame2->rect().width(), kWidth);
132 EXPECT_EQ(frame2->rect().height(), kHeight);
133 EXPECT_EQ(frame2->stride(), frame->rect().width() * kBytesPerPixel);
134 EXPECT_EQ(RgbaColor(frame2->data()), green_color);
135
136 // Thanks to DesktopFrameQueue we should be able to have two frames shared
137 EXPECT_EQ(frame->IsShared(), true);
138 EXPECT_EQ(frame2->IsShared(), true);
139 EXPECT_NE(frame->data(), frame2->data());
140
141 // This should result into overwriting a frame in use
142 rtc::Event frameRecordedEvent;
143 RgbaColor blue_color(255, 0, 0);
144 EXPECT_CALL(*this, OnFailedToProcessBuffer).WillOnce([&frameRecordedEvent] {
145 frameRecordedEvent.Set();
146 });
147
148 test_screencast_stream_provider_->RecordFrame(blue_color);
149 frameRecordedEvent.Wait(kShortWait);
150
151 // First frame should be now overwritten with blue color
152 frameRetrievedEvent.Wait(kShortWait);
153 EXPECT_EQ(RgbaColor(frame->data()), blue_color);
154
155 // Test disconnection from stream
156 EXPECT_CALL(*this, OnStopStreaming);
157 shared_screencast_stream_->StopScreenCastStream();
158 }
159
160 } // namespace webrtc
161