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