mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00

Use SPA_CHUNK_FLAG_CORRUPTED and SPA_META_HEADER_FLAG_CORRUPTED flags to
determine corrupted buffers or corrupted buffer data. We used to only
rely on compositors setting chunk->size, but this doesn't make sense for
dmabufs where they have to make up arbitrary values. It also looks this
is not reliable and can cause glitches as we end up processing corrupted buffers.
(cherry picked from commit cfbd6b0884
)
Bug: chromium:341928670
Change-Id: Ida0c6a5e7a37e19598c6d5884726200f81b94962
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/349881
Commit-Queue: Mark Foltz <mfoltz@chromium.org>
Reviewed-by: Mark Foltz <mfoltz@chromium.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#42292}
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/351563
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/6478@{#1}
Cr-Branched-From: 16fb7903e546051483720548168cd40cded7a040-refs/heads/main@{#42290}
213 lines
7.7 KiB
C++
213 lines
7.7 KiB
C++
/*
|
|
* Copyright (c) 2022 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/linux/wayland/shared_screencast_stream.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "api/units/time_delta.h"
|
|
#include "modules/desktop_capture/desktop_capturer.h"
|
|
#include "modules/desktop_capture/desktop_frame.h"
|
|
#include "modules/desktop_capture/linux/wayland/test/test_screencast_stream_provider.h"
|
|
#include "modules/desktop_capture/rgba_color.h"
|
|
#include "rtc_base/event.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
using ::testing::_;
|
|
using ::testing::AtLeast;
|
|
using ::testing::Ge;
|
|
using ::testing::Invoke;
|
|
|
|
namespace webrtc {
|
|
|
|
constexpr TimeDelta kShortWait = TimeDelta::Seconds(5);
|
|
constexpr TimeDelta kLongWait = TimeDelta::Seconds(15);
|
|
|
|
constexpr int kBytesPerPixel = 4;
|
|
constexpr int32_t kWidth = 800;
|
|
constexpr int32_t kHeight = 640;
|
|
|
|
class PipeWireStreamTest : public ::testing::Test,
|
|
public TestScreenCastStreamProvider::Observer,
|
|
public SharedScreenCastStream::Observer {
|
|
public:
|
|
PipeWireStreamTest() = default;
|
|
~PipeWireStreamTest() = default;
|
|
|
|
// FakeScreenCastPortal::Observer
|
|
MOCK_METHOD(void, OnBufferAdded, (), (override));
|
|
MOCK_METHOD(void, OnFrameRecorded, (), (override));
|
|
MOCK_METHOD(void, OnStreamReady, (uint32_t stream_node_id), (override));
|
|
MOCK_METHOD(void, OnStartStreaming, (), (override));
|
|
MOCK_METHOD(void, OnStopStreaming, (), (override));
|
|
|
|
// SharedScreenCastStream::Observer
|
|
MOCK_METHOD(void, OnCursorPositionChanged, (), (override));
|
|
MOCK_METHOD(void, OnCursorShapeChanged, (), (override));
|
|
MOCK_METHOD(void, OnDesktopFrameChanged, (), (override));
|
|
MOCK_METHOD(void, OnFailedToProcessBuffer, (), (override));
|
|
MOCK_METHOD(void, OnBufferCorruptedMetadata, (), (override));
|
|
MOCK_METHOD(void, OnBufferCorruptedData, (), (override));
|
|
MOCK_METHOD(void, OnEmptyBuffer, (), (override));
|
|
MOCK_METHOD(void, OnStreamConfigured, (), (override));
|
|
MOCK_METHOD(void, OnFrameRateChanged, (uint32_t), (override));
|
|
|
|
void SetUp() override {
|
|
shared_screencast_stream_ = SharedScreenCastStream::CreateDefault();
|
|
shared_screencast_stream_->SetObserver(this);
|
|
test_screencast_stream_provider_ =
|
|
std::make_unique<TestScreenCastStreamProvider>(this, kWidth, kHeight);
|
|
}
|
|
|
|
void StartScreenCastStream(uint32_t stream_node_id) {
|
|
shared_screencast_stream_->StartScreenCastStream(stream_node_id);
|
|
}
|
|
|
|
protected:
|
|
uint recorded_frames_ = 0;
|
|
bool streaming_ = false;
|
|
std::unique_ptr<TestScreenCastStreamProvider>
|
|
test_screencast_stream_provider_;
|
|
rtc::scoped_refptr<SharedScreenCastStream> shared_screencast_stream_;
|
|
};
|
|
|
|
TEST_F(PipeWireStreamTest, TestPipeWire) {
|
|
// Set expectations for PipeWire to successfully connect both streams
|
|
rtc::Event waitConnectEvent;
|
|
rtc::Event waitStartStreamingEvent;
|
|
rtc::Event waitStreamParamChangedEvent1;
|
|
rtc::Event waitStreamParamChangedEvent2;
|
|
|
|
EXPECT_CALL(*this, OnStreamReady(_))
|
|
.WillOnce(Invoke(this, &PipeWireStreamTest::StartScreenCastStream));
|
|
EXPECT_CALL(*this, OnStreamConfigured).WillOnce([&waitConnectEvent] {
|
|
waitConnectEvent.Set();
|
|
});
|
|
EXPECT_CALL(*this, OnBufferAdded).Times(AtLeast(3));
|
|
EXPECT_CALL(*this, OnStartStreaming).WillOnce([&waitStartStreamingEvent] {
|
|
waitStartStreamingEvent.Set();
|
|
});
|
|
EXPECT_CALL(*this, OnFrameRateChanged(60)).Times(1); // Default frame rate.
|
|
|
|
// Give it some time to connect, the order between these shouldn't matter, but
|
|
// we need to be sure we are connected before we proceed to work with frames.
|
|
waitConnectEvent.Wait(kLongWait);
|
|
|
|
// Wait until we start streaming
|
|
waitStartStreamingEvent.Wait(kShortWait);
|
|
|
|
rtc::Event frameRetrievedEvent;
|
|
EXPECT_CALL(*this, OnFrameRecorded).Times(6);
|
|
EXPECT_CALL(*this, OnDesktopFrameChanged)
|
|
.Times(3)
|
|
.WillRepeatedly([&frameRetrievedEvent] { frameRetrievedEvent.Set(); });
|
|
|
|
// Record a frame in FakePipeWireStream
|
|
RgbaColor red_color(0, 0, 255);
|
|
test_screencast_stream_provider_->RecordFrame(red_color);
|
|
|
|
// Retrieve a frame from SharedScreenCastStream
|
|
frameRetrievedEvent.Wait(kShortWait);
|
|
std::unique_ptr<SharedDesktopFrame> frame =
|
|
shared_screencast_stream_->CaptureFrame();
|
|
|
|
// Check frame parameters
|
|
ASSERT_NE(frame, nullptr);
|
|
ASSERT_NE(frame->data(), nullptr);
|
|
EXPECT_EQ(frame->rect().width(), kWidth);
|
|
EXPECT_EQ(frame->rect().height(), kHeight);
|
|
EXPECT_EQ(frame->stride(), frame->rect().width() * kBytesPerPixel);
|
|
EXPECT_EQ(RgbaColor(frame->data()), red_color);
|
|
|
|
// Test DesktopFrameQueue
|
|
RgbaColor green_color(0, 255, 0);
|
|
test_screencast_stream_provider_->RecordFrame(green_color);
|
|
frameRetrievedEvent.Wait(kShortWait);
|
|
std::unique_ptr<SharedDesktopFrame> frame2 =
|
|
shared_screencast_stream_->CaptureFrame();
|
|
ASSERT_NE(frame2, nullptr);
|
|
ASSERT_NE(frame2->data(), nullptr);
|
|
EXPECT_EQ(frame2->rect().width(), kWidth);
|
|
EXPECT_EQ(frame2->rect().height(), kHeight);
|
|
EXPECT_EQ(frame2->stride(), frame->rect().width() * kBytesPerPixel);
|
|
EXPECT_EQ(RgbaColor(frame2->data()), green_color);
|
|
|
|
// Thanks to DesktopFrameQueue we should be able to have two frames shared
|
|
EXPECT_EQ(frame->IsShared(), true);
|
|
EXPECT_EQ(frame2->IsShared(), true);
|
|
EXPECT_NE(frame->data(), frame2->data());
|
|
|
|
// This should result into overwriting a frame in use
|
|
rtc::Event frameRecordedEvent;
|
|
RgbaColor blue_color(255, 0, 0);
|
|
EXPECT_CALL(*this, OnFailedToProcessBuffer).WillOnce([&frameRecordedEvent] {
|
|
frameRecordedEvent.Set();
|
|
});
|
|
|
|
test_screencast_stream_provider_->RecordFrame(blue_color);
|
|
frameRecordedEvent.Wait(kShortWait);
|
|
|
|
// First frame should be now overwritten with blue color
|
|
frameRetrievedEvent.Wait(kShortWait);
|
|
EXPECT_EQ(RgbaColor(frame->data()), blue_color);
|
|
|
|
// Check we don't process faulty buffers
|
|
rtc::Event corruptedMetadataFrameEvent;
|
|
EXPECT_CALL(*this, OnBufferCorruptedMetadata)
|
|
.WillOnce([&corruptedMetadataFrameEvent] {
|
|
corruptedMetadataFrameEvent.Set();
|
|
});
|
|
|
|
test_screencast_stream_provider_->RecordFrame(
|
|
blue_color, TestScreenCastStreamProvider::CorruptedMetadata);
|
|
corruptedMetadataFrameEvent.Wait(kShortWait);
|
|
|
|
rtc::Event corruptedDataFrameEvent;
|
|
EXPECT_CALL(*this, OnBufferCorruptedData)
|
|
.WillOnce([&corruptedDataFrameEvent] { corruptedDataFrameEvent.Set(); });
|
|
|
|
test_screencast_stream_provider_->RecordFrame(
|
|
blue_color, TestScreenCastStreamProvider::CorruptedData);
|
|
corruptedDataFrameEvent.Wait(kShortWait);
|
|
|
|
rtc::Event emptyFrameEvent;
|
|
EXPECT_CALL(*this, OnEmptyBuffer).WillOnce([&emptyFrameEvent] {
|
|
emptyFrameEvent.Set();
|
|
});
|
|
|
|
test_screencast_stream_provider_->RecordFrame(
|
|
blue_color, TestScreenCastStreamProvider::EmptyData);
|
|
emptyFrameEvent.Wait(kShortWait);
|
|
|
|
// Update stream parameters.
|
|
EXPECT_CALL(*this, OnFrameRateChanged(0))
|
|
.Times(1)
|
|
.WillOnce([&waitStreamParamChangedEvent1] {
|
|
waitStreamParamChangedEvent1.Set();
|
|
});
|
|
shared_screencast_stream_->UpdateScreenCastStreamFrameRate(0);
|
|
waitStreamParamChangedEvent1.Wait(kShortWait);
|
|
|
|
EXPECT_CALL(*this, OnFrameRateChanged(22))
|
|
.Times(1)
|
|
.WillOnce([&waitStreamParamChangedEvent2] {
|
|
waitStreamParamChangedEvent2.Set();
|
|
});
|
|
shared_screencast_stream_->UpdateScreenCastStreamFrameRate(22);
|
|
waitStreamParamChangedEvent2.Wait(kShortWait);
|
|
|
|
// Test disconnection from stream
|
|
EXPECT_CALL(*this, OnStopStreaming);
|
|
shared_screencast_stream_->StopScreenCastStream();
|
|
}
|
|
|
|
} // namespace webrtc
|