Reland "Add plumbing to control PipeWire picker visibility"
This reverts commit 0098a441e3990f80bcbe05dfce8c6e2359f7ef25. Reason for revert: Fix chromium build break Original change's description: > Revert "Add plumbing to control PipeWire picker visibility" > > This reverts commit fbea8c519684577a38cb35b9287ba4645a905094. > > Reason for revert: Breaks WebRTC import into Chromium, e.g: > https://chromium-review.googlesource.com/c/chromium/src/+/3863998/ > > Original change's description: > > Add plumbing to control PipeWire picker visibility > > > > Introduces the notion of a "delegated source list" and corresponding > > controller. This is used by desktop capturers (currently just the > > PipeWire capturer), who control selecting the source through their own > > (often system-level) UI, rather than returning a source list with all > > available options that can then be selected by the embedder. > > > > Adds a method to get the controller which serves to also tell embedders > > if the capturer makes use of a delegated source list. The controller > > currently allows the embedder to request that the delegated source list > > be shown or hidden, and will in the future be used to expose events > > from the source list (e.g. selection, dismissal, error). > > > > Bug: chromium:1351572 > > Change-Id: Ie1d36ed654013f59b8d9095deef01a4705fd5bde > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/272621 > > Reviewed-by: Mark Foltz <mfoltz@chromium.org> > > Commit-Queue: Alexander Cooper <alcooper@chromium.org> > > Cr-Commit-Position: refs/heads/main@{#37956} > > Bug: chromium:1351572 > Change-Id: I06f76ab9c8bc1aa303dae177d48698951fdc5ecd > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/273703 > Auto-Submit: Henrik Boström <hbos@webrtc.org> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org> > Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com> > Reviewed-by: Henrik Boström <hbos@webrtc.org> > Commit-Queue: Henrik Andreassson <henrika@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#37964} Bug: chromium:1351572 Change-Id: I9e5e691746b81517bf0e211d0ad5a23371ab29ba Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/273685 Reviewed-by: Mark Foltz <mfoltz@chromium.org> Auto-Submit: Alexander Cooper <alcooper@chromium.org> Commit-Queue: Mark Foltz <mfoltz@chromium.org> Cr-Commit-Position: refs/heads/main@{#37972}
This commit is contained in:
parent
813177d98f
commit
86015a6610
@ -29,6 +29,11 @@ namespace webrtc {
|
||||
|
||||
DesktopCapturer::~DesktopCapturer() = default;
|
||||
|
||||
DelegatedSourceListController*
|
||||
DesktopCapturer::GetDelegatedSourceListController() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DesktopCapturer::SetSharedMemoryFactory(
|
||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {}
|
||||
|
||||
|
||||
@ -32,6 +32,31 @@ namespace webrtc {
|
||||
class DesktopCaptureOptions;
|
||||
class DesktopFrame;
|
||||
|
||||
// A controller to be implemented and returned by
|
||||
// GetDelegatedSourceListController in capturers that require showing their own
|
||||
// source list and managing user selection there. Apart from ensuring the
|
||||
// visibility of the source list, these capturers should largely be interacted
|
||||
// with the same as a normal capturer, though there may be some caveats for
|
||||
// some DesktopCapturer methods. See GetDelegatedSourceListController for more
|
||||
// information.
|
||||
class RTC_EXPORT DelegatedSourceListController {
|
||||
public:
|
||||
// Used to prompt the capturer to show the delegated source list. If the
|
||||
// source list is already visible, this will be a no-op. Must be called after
|
||||
// starting the DesktopCapturer.
|
||||
//
|
||||
// Note that any selection from a previous invocation of the source list may
|
||||
// be cleared when this method is called.
|
||||
virtual void EnsureVisible() = 0;
|
||||
|
||||
// Used to prompt the capturer to hide the delegated source list. If the
|
||||
// source list is already hidden, this will be a no-op.
|
||||
virtual void EnsureHidden() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DelegatedSourceListController() {}
|
||||
};
|
||||
|
||||
// Abstract interface for screen and window capturers.
|
||||
class RTC_EXPORT DesktopCapturer {
|
||||
public:
|
||||
@ -88,6 +113,18 @@ class RTC_EXPORT DesktopCapturer {
|
||||
// valid until capturer is destroyed.
|
||||
virtual void Start(Callback* callback) = 0;
|
||||
|
||||
// Returns a valid pointer if the capturer requires the user to make a
|
||||
// selection from a source list provided by the capturer.
|
||||
// Returns nullptr if the capturer does not provide a UI for the user to make
|
||||
// a selection.
|
||||
//
|
||||
// Callers should not take ownership of the returned pointer, but it is
|
||||
// guaranteed to be valid as long as the desktop_capturer is valid.
|
||||
// Note that consumers should still use GetSourceList and SelectSource, but
|
||||
// their behavior may be modified if this returns a value. See those methods
|
||||
// for a more in-depth discussion of those potential modifications.
|
||||
virtual DelegatedSourceListController* GetDelegatedSourceListController();
|
||||
|
||||
// Sets SharedMemoryFactory that will be used to create buffers for the
|
||||
// captured frames. The factory can be invoked on a thread other than the one
|
||||
// where CaptureFrame() is called. It will be destroyed on the same thread.
|
||||
@ -116,10 +153,19 @@ class RTC_EXPORT DesktopCapturer {
|
||||
// should return monitors.
|
||||
// For DesktopCapturer implementations to capture windows, this function
|
||||
// should only return root windows owned by applications.
|
||||
//
|
||||
// Note that capturers who use a delegated source list will return a
|
||||
// SourceList with exactly one value, but it may not be viable for capture
|
||||
// (e.g. CaptureFrame will return ERROR_TEMPORARY) until a selection has been
|
||||
// made.
|
||||
virtual bool GetSourceList(SourceList* sources);
|
||||
|
||||
// Selects a source to be captured. Returns false in case of a failure (e.g.
|
||||
// if there is no source with the specified type and id.)
|
||||
//
|
||||
// Note that some capturers with delegated source lists may also support
|
||||
// selecting a SourceID that is not in the returned source list as a form of
|
||||
// restore token.
|
||||
virtual bool SelectSource(SourceId id);
|
||||
|
||||
// Brings the selected source to the front and sets the input focus on it.
|
||||
|
||||
@ -16,8 +16,6 @@
|
||||
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/random.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -44,8 +42,7 @@ BaseCapturerPipeWire::BaseCapturerPipeWire(
|
||||
: options_(options),
|
||||
is_screencast_portal_(false),
|
||||
portal_(std::move(portal)) {
|
||||
Random random(rtc::TimeMicros());
|
||||
source_id_ = static_cast<SourceId>(random.Rand(1, INT_MAX));
|
||||
source_id_ = RestoreTokenManager::GetInstance().GetUnusedId();
|
||||
}
|
||||
|
||||
BaseCapturerPipeWire::~BaseCapturerPipeWire() {}
|
||||
@ -53,6 +50,11 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() {}
|
||||
void BaseCapturerPipeWire::OnScreenCastRequestResult(RequestResponse result,
|
||||
uint32_t stream_node_id,
|
||||
int fd) {
|
||||
is_portal_open_ = false;
|
||||
|
||||
// Reset the value of capturer_failed_ in case we succeed below. If we fail,
|
||||
// then it'll set it to the right value again soon enough.
|
||||
capturer_failed_ = false;
|
||||
if (result != RequestResponse::kSuccess ||
|
||||
!options_.screencast_stream()->StartScreenCastStream(
|
||||
stream_node_id, fd, options_.get_width(), options_.get_height())) {
|
||||
@ -95,11 +97,15 @@ void BaseCapturerPipeWire::Start(Callback* callback) {
|
||||
}
|
||||
}
|
||||
|
||||
is_portal_open_ = true;
|
||||
portal_->Start();
|
||||
}
|
||||
|
||||
void BaseCapturerPipeWire::CaptureFrame() {
|
||||
if (capturer_failed_) {
|
||||
// This could be recoverable if the source list is re-summoned; but for our
|
||||
// purposes this is fine, since it requires intervention to resolve and
|
||||
// essentially starts a new capture.
|
||||
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||
return;
|
||||
}
|
||||
@ -137,6 +143,35 @@ bool BaseCapturerPipeWire::SelectSource(SourceId id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DelegatedSourceListController*
|
||||
BaseCapturerPipeWire::GetDelegatedSourceListController() {
|
||||
return this;
|
||||
}
|
||||
|
||||
void BaseCapturerPipeWire::EnsureVisible() {
|
||||
RTC_DCHECK(callback_);
|
||||
if (is_portal_open_)
|
||||
return;
|
||||
|
||||
// Clear any previously selected state/capture
|
||||
portal_->Stop();
|
||||
options_.screencast_stream()->StopScreenCastStream();
|
||||
|
||||
// Get a new source id to reflect that the source has changed.
|
||||
source_id_ = RestoreTokenManager::GetInstance().GetUnusedId();
|
||||
|
||||
is_portal_open_ = true;
|
||||
portal_->Start();
|
||||
}
|
||||
|
||||
void BaseCapturerPipeWire::EnsureHidden() {
|
||||
if (!is_portal_open_)
|
||||
return;
|
||||
|
||||
is_portal_open_ = false;
|
||||
portal_->Stop();
|
||||
}
|
||||
|
||||
SessionDetails BaseCapturerPipeWire::GetSessionDetails() {
|
||||
return portal_->GetSessionDetails();
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
namespace webrtc {
|
||||
|
||||
class BaseCapturerPipeWire : public DesktopCapturer,
|
||||
public DelegatedSourceListController,
|
||||
public ScreenCastPortal::PortalNotifier {
|
||||
public:
|
||||
explicit BaseCapturerPipeWire(const DesktopCaptureOptions& options);
|
||||
@ -39,6 +40,11 @@ class BaseCapturerPipeWire : public DesktopCapturer,
|
||||
void CaptureFrame() override;
|
||||
bool GetSourceList(SourceList* sources) override;
|
||||
bool SelectSource(SourceId id) override;
|
||||
DelegatedSourceListController* GetDelegatedSourceListController() override;
|
||||
|
||||
// DelegatedSourceListController
|
||||
void EnsureVisible() override;
|
||||
void EnsureHidden() override;
|
||||
|
||||
// ScreenCastPortal::PortalNotifier interface.
|
||||
void OnScreenCastRequestResult(xdg_portal::RequestResponse result,
|
||||
@ -56,6 +62,7 @@ class BaseCapturerPipeWire : public DesktopCapturer,
|
||||
Callback* callback_ = nullptr;
|
||||
bool capturer_failed_ = false;
|
||||
bool is_screencast_portal_ = false;
|
||||
bool is_portal_open_ = false;
|
||||
|
||||
// SourceId that is selected using SelectSource() and that we previously
|
||||
// returned in GetSourceList(). This should be a SourceId that has a restore
|
||||
|
||||
@ -30,4 +30,8 @@ std::string RestoreTokenManager::TakeToken(DesktopCapturer::SourceId id) {
|
||||
return token;
|
||||
}
|
||||
|
||||
DesktopCapturer::SourceId RestoreTokenManager::GetUnusedId() {
|
||||
return ++last_source_id_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -29,10 +29,15 @@ class RestoreTokenManager {
|
||||
void AddToken(DesktopCapturer::SourceId id, const std::string& token);
|
||||
std::string TakeToken(DesktopCapturer::SourceId id);
|
||||
|
||||
// Returns a source ID which does not have any token associated with it yet.
|
||||
DesktopCapturer::SourceId GetUnusedId();
|
||||
|
||||
private:
|
||||
RestoreTokenManager() = default;
|
||||
~RestoreTokenManager() = default;
|
||||
|
||||
DesktopCapturer::SourceId last_source_id_ = 0;
|
||||
|
||||
std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_;
|
||||
};
|
||||
|
||||
|
||||
@ -42,6 +42,10 @@ class ScreenCapturePortalInterface {
|
||||
virtual xdg_portal::SessionDetails GetSessionDetails() { return {}; }
|
||||
// Starts the portal setup.
|
||||
virtual void Start() {}
|
||||
|
||||
// Stops and cleans up the portal.
|
||||
virtual void Stop() {}
|
||||
|
||||
// Notifies observers about the success/fail state of the portal
|
||||
// request/response.
|
||||
virtual void OnPortalDone(xdg_portal::RequestResponse result) {}
|
||||
|
||||
@ -56,19 +56,21 @@ ScreenCastPortal::ScreenCastPortal(
|
||||
user_data_(user_data) {}
|
||||
|
||||
ScreenCastPortal::~ScreenCastPortal() {
|
||||
Cleanup();
|
||||
Stop();
|
||||
}
|
||||
|
||||
void ScreenCastPortal::Cleanup() {
|
||||
void ScreenCastPortal::Stop() {
|
||||
UnsubscribeSignalHandlers();
|
||||
TearDownSession(std::move(session_handle_), proxy_, cancellable_,
|
||||
connection_);
|
||||
session_handle_ = "";
|
||||
cancellable_ = nullptr;
|
||||
proxy_ = nullptr;
|
||||
restore_token_ = "";
|
||||
|
||||
if (pw_fd_ != -1) {
|
||||
close(pw_fd_);
|
||||
pw_fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +123,7 @@ xdg_portal::SessionDetails ScreenCastPortal::GetSessionDetails() {
|
||||
void ScreenCastPortal::OnPortalDone(RequestResponse result) {
|
||||
notifier_->OnScreenCastRequestResult(result, pw_stream_node_id_, pw_fd_);
|
||||
if (result != RequestResponse::kSuccess) {
|
||||
Cleanup();
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -105,6 +105,7 @@ class ScreenCastPortal : public xdg_portal::ScreenCapturePortalInterface {
|
||||
// was successful and only then you will be able to get all the required
|
||||
// information in order to continue working with PipeWire.
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
xdg_portal::SessionDetails GetSessionDetails() override;
|
||||
|
||||
// Method to notify the reason for failure of a portal request.
|
||||
@ -112,7 +113,6 @@ class ScreenCastPortal : public xdg_portal::ScreenCapturePortalInterface {
|
||||
|
||||
// Sends a create session request to the portal.
|
||||
void RequestSession(GDBusProxy* proxy) override;
|
||||
void Cleanup();
|
||||
|
||||
// Set of methods leveraged by remote desktop portal to setup a common session
|
||||
// with screen cast portal.
|
||||
|
||||
@ -98,6 +98,9 @@ class SharedScreenCastStreamPrivate {
|
||||
DesktopVector CaptureCursorPosition();
|
||||
|
||||
private:
|
||||
// Stops the streams and cleans up any in-use elements.
|
||||
void StopAndCleanupStream();
|
||||
|
||||
uint32_t pw_stream_node_id_ = 0;
|
||||
|
||||
DesktopSize stream_size_ = {};
|
||||
@ -363,25 +366,7 @@ void SharedScreenCastStreamPrivate::OnRenegotiateFormat(void* data, uint64_t) {
|
||||
SharedScreenCastStreamPrivate::SharedScreenCastStreamPrivate() {}
|
||||
|
||||
SharedScreenCastStreamPrivate::~SharedScreenCastStreamPrivate() {
|
||||
if (pw_main_loop_) {
|
||||
pw_thread_loop_stop(pw_main_loop_);
|
||||
}
|
||||
|
||||
if (pw_stream_) {
|
||||
pw_stream_destroy(pw_stream_);
|
||||
}
|
||||
|
||||
if (pw_core_) {
|
||||
pw_core_disconnect(pw_core_);
|
||||
}
|
||||
|
||||
if (pw_context_) {
|
||||
pw_context_destroy(pw_context_);
|
||||
}
|
||||
|
||||
if (pw_main_loop_) {
|
||||
pw_thread_loop_destroy(pw_main_loop_);
|
||||
}
|
||||
StopAndCleanupStream();
|
||||
}
|
||||
|
||||
RTC_NO_SANITIZE("cfi-icall")
|
||||
@ -550,15 +535,54 @@ void SharedScreenCastStreamPrivate::UpdateScreenCastStreamResolution(
|
||||
}
|
||||
|
||||
void SharedScreenCastStreamPrivate::StopScreenCastStream() {
|
||||
StopAndCleanupStream();
|
||||
}
|
||||
|
||||
void SharedScreenCastStreamPrivate::StopAndCleanupStream() {
|
||||
// We get buffers on the PipeWire thread, but this is called from the capturer
|
||||
// thread, so we need to wait on and stop the pipewire thread before we
|
||||
// disconnect the stream so that we can guarantee we aren't in the middle of
|
||||
// processing a new frame.
|
||||
|
||||
// Even if we *do* somehow have the other objects without a pipewire thread,
|
||||
// destroying them without a thread causes a crash.
|
||||
if (!pw_main_loop_)
|
||||
return;
|
||||
|
||||
// While we can stop the thread now, we cannot destroy it until we've cleaned
|
||||
// up the other members.
|
||||
pw_thread_loop_wait(pw_main_loop_);
|
||||
pw_thread_loop_stop(pw_main_loop_);
|
||||
|
||||
if (pw_stream_) {
|
||||
pw_stream_disconnect(pw_stream_);
|
||||
pw_stream_destroy(pw_stream_);
|
||||
pw_stream_ = nullptr;
|
||||
|
||||
{
|
||||
webrtc::MutexLock lock(&queue_lock_);
|
||||
queue_.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (pw_core_) {
|
||||
pw_core_disconnect(pw_core_);
|
||||
pw_core_ = nullptr;
|
||||
}
|
||||
|
||||
if (pw_context_) {
|
||||
pw_context_destroy(pw_context_);
|
||||
pw_context_ = nullptr;
|
||||
}
|
||||
|
||||
pw_thread_loop_destroy(pw_main_loop_);
|
||||
pw_main_loop_ = nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DesktopFrame> SharedScreenCastStreamPrivate::CaptureFrame() {
|
||||
webrtc::MutexLock lock(&queue_lock_);
|
||||
|
||||
if (!queue_.current_frame()) {
|
||||
if (!pw_stream_ || !queue_.current_frame()) {
|
||||
return std::unique_ptr<DesktopFrame>{};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user