зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1112392: Move webrtc Tab Sharing to work in e10s/fission r=dminor
Also we drop support for an independent-of-scroll/viewport capture, which the old Tab Sharing supported, for security reasons (and we don't need it). Differential Revision: https://phabricator.services.mozilla.com/D80974
This commit is contained in:
Родитель
95a2e8ea4c
Коммит
9756342857
|
@ -5,7 +5,6 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "VideoEngine.h"
|
||||
#include "video_engine/browser_capture_impl.h"
|
||||
#include "video_engine/desktop_capture_impl.h"
|
||||
#include "webrtc/system_wrappers/include/clock.h"
|
||||
#ifdef WEBRTC_ANDROID
|
||||
|
@ -183,13 +182,8 @@ VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
|
|||
LOG(("webrtc::CaptureDeviceType::Camera: Finished creating new device."));
|
||||
break;
|
||||
}
|
||||
case webrtc::CaptureDeviceType::Browser: {
|
||||
mDeviceInfo.reset(webrtc::BrowserDeviceInfoImpl::CreateDeviceInfo());
|
||||
LOG((
|
||||
"webrtc::CaptureDeviceType::Browser: Finished creating new device."));
|
||||
break;
|
||||
}
|
||||
// Window and Screen types are handled by DesktopCapture
|
||||
// Window and Screen and Browser (tab) types are handled by DesktopCapture
|
||||
case webrtc::CaptureDeviceType::Browser:
|
||||
case webrtc::CaptureDeviceType::Window:
|
||||
case webrtc::CaptureDeviceType::Screen: {
|
||||
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)
|
||||
|
|
|
@ -45,6 +45,7 @@ if CONFIG['MOZ_WEBRTC']:
|
|||
UNIFIED_SOURCES += [
|
||||
'video_engine/desktop_capture_impl.cc',
|
||||
'video_engine/platform_uithread.cc',
|
||||
'video_engine/tab_capturer.cc',
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -299,6 +299,86 @@ int32_t WindowDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::Init() {
|
||||
desktop_device_info_ =
|
||||
std::unique_ptr<DesktopDeviceInfo>(DesktopDeviceInfoImpl::Create());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::Refresh() {
|
||||
desktop_device_info_->Refresh();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t BrowserDeviceInfoImpl::NumberOfDevices() {
|
||||
return desktop_device_info_->getTabCount();
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::GetDeviceName(
|
||||
uint32_t deviceNumber, char* deviceNameUTF8, uint32_t deviceNameUTF8Size,
|
||||
char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Size,
|
||||
char* productUniqueIdUTF8, uint32_t productUniqueIdUTF8Size, pid_t* pid) {
|
||||
DesktopTab desktopTab;
|
||||
|
||||
// always initialize output
|
||||
if (deviceNameUTF8 && deviceNameUTF8Size > 0) {
|
||||
memset(deviceNameUTF8, 0, deviceNameUTF8Size);
|
||||
}
|
||||
if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Size > 0) {
|
||||
memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Size);
|
||||
}
|
||||
if (productUniqueIdUTF8 && productUniqueIdUTF8Size > 0) {
|
||||
memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Size);
|
||||
}
|
||||
|
||||
if (desktop_device_info_->getTabInfo(deviceNumber, desktopTab) == 0) {
|
||||
size_t len;
|
||||
|
||||
const char* deviceName = desktopTab.getTabName();
|
||||
len = deviceName ? strlen(deviceName) : 0;
|
||||
if (len && deviceNameUTF8 && len < deviceNameUTF8Size) {
|
||||
memcpy(deviceNameUTF8, deviceName, len);
|
||||
}
|
||||
|
||||
const char* deviceUniqueId = desktopTab.getUniqueIdName();
|
||||
len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
|
||||
if (len && deviceUniqueIdUTF8 && len < deviceUniqueIdUTF8Size) {
|
||||
memcpy(deviceUniqueIdUTF8, deviceUniqueId, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::DisplayCaptureSettingsDialogBox(
|
||||
const char* deviceUniqueIdUTF8, const char* dialogTitleUTF8,
|
||||
void* parentWindow, uint32_t positionX, uint32_t positionY) {
|
||||
// no device properties to change
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::NumberOfCapabilities(
|
||||
const char* deviceUniqueIdUTF8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::GetCapability(
|
||||
const char* deviceUniqueIdUTF8, const uint32_t deviceCapabilityNumber,
|
||||
VideoCaptureCapability& capability) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::GetBestMatchedCapability(
|
||||
const char* deviceUniqueIdUTF8, const VideoCaptureCapability& requested,
|
||||
VideoCaptureCapability& resulting) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t BrowserDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
|
||||
VideoRotation& orientation) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
VideoCaptureModule::DeviceInfo* DesktopCaptureImpl::CreateDeviceInfo(
|
||||
const int32_t id, const CaptureDeviceType type) {
|
||||
if (type == CaptureDeviceType::Screen) {
|
||||
|
@ -315,6 +395,14 @@ VideoCaptureModule::DeviceInfo* DesktopCaptureImpl::CreateDeviceInfo(
|
|||
pWindowDeviceInfoImpl = NULL;
|
||||
}
|
||||
return pWindowDeviceInfoImpl;
|
||||
} else if (type == CaptureDeviceType::Browser) {
|
||||
BrowserDeviceInfoImpl* pBrowserDeviceInfoImpl =
|
||||
new BrowserDeviceInfoImpl(id);
|
||||
if (!pBrowserDeviceInfoImpl || pBrowserDeviceInfoImpl->Init()) {
|
||||
delete pBrowserDeviceInfoImpl;
|
||||
pBrowserDeviceInfoImpl = NULL;
|
||||
}
|
||||
return pBrowserDeviceInfoImpl;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -364,8 +452,18 @@ int32_t DesktopCaptureImpl::Init() {
|
|||
desktop_capturer_cursor_composer_ =
|
||||
std::unique_ptr<DesktopAndCursorComposer>(new DesktopAndCursorComposer(
|
||||
pWindowCapturer.release(), pMouseCursorMonitor));
|
||||
}
|
||||
} else if (_deviceType == CaptureDeviceType::Browser) {
|
||||
// XXX We don't capture cursors, so avoid the extra indirection layer. We
|
||||
// could also pass null for the pMouseCursorMonitor.
|
||||
desktop_capturer_cursor_composer_ =
|
||||
DesktopCapturer::CreateTabCapturer(options);
|
||||
if (!desktop_capturer_cursor_composer_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DesktopCapturer::SourceId sourceId = atoi(_deviceUniqueId.c_str());
|
||||
desktop_capturer_cursor_composer_->SelectSource(sourceId);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -387,6 +485,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId,
|
|||
new rtc::PlatformUIThread(Run, this, "ScreenCaptureThread")),
|
||||
#else
|
||||
# if defined(WEBRTC_LINUX)
|
||||
// We start the thread lazily for Linux
|
||||
capturer_thread_(nullptr),
|
||||
# else
|
||||
capturer_thread_(
|
||||
|
@ -394,8 +493,10 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId,
|
|||
# endif
|
||||
#endif
|
||||
started_(false) {
|
||||
//-> TODO @@NG why is this crashing (seen on Linux)
|
||||
//-> capturer_thread_->SetPriority(rtc::kHighPriority);
|
||||
#if !defined(WEBRTC_LINUX)
|
||||
// XXX this crashes due to an immediate IsRunning() check on Linux
|
||||
capturer_thread_->SetPriority(rtc::kHighPriority);
|
||||
#endif
|
||||
_requestedCapability.width = kDefaultWidth;
|
||||
_requestedCapability.height = kDefaultHeight;
|
||||
_requestedCapability.maxFPS = 30;
|
||||
|
@ -582,6 +683,8 @@ int32_t DesktopCaptureImpl::StartCapture(
|
|||
if (!capturer_thread_) {
|
||||
capturer_thread_ = std::unique_ptr<rtc::PlatformThread>(
|
||||
new rtc::PlatformThread(Run, this, "ScreenCaptureThread"));
|
||||
// XXX this crashes due to an immediate IsRunning() check on Linux
|
||||
// capturer_thread_->SetPriority(rtc::kHighPriority);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -149,6 +149,41 @@ class WindowDeviceInfoImpl : public VideoCaptureModule::DeviceInfo {
|
|||
std::unique_ptr<DesktopDeviceInfo> desktop_device_info_;
|
||||
};
|
||||
|
||||
class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo {
|
||||
public:
|
||||
BrowserDeviceInfoImpl(const int32_t id) : _id(id){};
|
||||
virtual ~BrowserDeviceInfoImpl(void){};
|
||||
|
||||
int32_t Init();
|
||||
int32_t Refresh();
|
||||
|
||||
virtual uint32_t NumberOfDevices();
|
||||
virtual int32_t GetDeviceName(uint32_t deviceNumber, char* deviceNameUTF8,
|
||||
uint32_t deviceNameLength,
|
||||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length, pid_t* pid);
|
||||
|
||||
virtual int32_t DisplayCaptureSettingsDialogBox(
|
||||
const char* deviceUniqueIdUTF8, const char* dialogTitleUTF8,
|
||||
void* parentWindow, uint32_t positionX, uint32_t positionY);
|
||||
virtual int32_t NumberOfCapabilities(const char* deviceUniqueIdUTF8);
|
||||
virtual int32_t GetCapability(const char* deviceUniqueIdUTF8,
|
||||
const uint32_t deviceCapabilityNumber,
|
||||
VideoCaptureCapability& capability);
|
||||
|
||||
virtual int32_t GetBestMatchedCapability(
|
||||
const char* deviceUniqueIdUTF8, const VideoCaptureCapability& requested,
|
||||
VideoCaptureCapability& resulting);
|
||||
virtual int32_t GetOrientation(const char* deviceUniqueIdUTF8,
|
||||
VideoRotation& orientation);
|
||||
|
||||
protected:
|
||||
int32_t _id;
|
||||
std::unique_ptr<DesktopDeviceInfo> desktop_device_info_;
|
||||
};
|
||||
|
||||
// Reuses the video engine pipeline for screen sharing.
|
||||
// As with video, DesktopCaptureImpl is a proxy for screen sharing
|
||||
// and follows the video pipeline design
|
||||
|
@ -242,7 +277,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback,
|
|||
// This is created on the main thread and accessed on both the main thread
|
||||
// and the capturer thread. It is created prior to the capturer thread
|
||||
// starting and is destroyed after it is stopped.
|
||||
std::unique_ptr<DesktopAndCursorComposer> desktop_capturer_cursor_composer_;
|
||||
std::unique_ptr<DesktopCapturer> desktop_capturer_cursor_composer_;
|
||||
|
||||
std::unique_ptr<EventWrapper> time_event_;
|
||||
#if defined(_WIN32)
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (c) 2013 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/desktop_capture_options.h"
|
||||
#include "modules/desktop_capture/desktop_capturer.h"
|
||||
|
||||
#include "tab_capturer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "modules/desktop_capture/desktop_frame.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/scoped_ref_ptr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "mozilla/dom/BrowserHost.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
mozilla::LazyLogModule gTabShareLog("TabShare");
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
// XXX switch once we have UI
|
||||
#define NO_TABSHARE_UI 1
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
TabCapturer::TabCapturer(const webrtc::DesktopCaptureOptions& options)
|
||||
: mMonitor("TabCapture") {}
|
||||
|
||||
TabCapturer::~TabCapturer() {}
|
||||
|
||||
bool TabCapturer::GetSourceList(webrtc::DesktopCapturer::SourceList* sources) {
|
||||
MOZ_LOG(gTabShareLog, LogLevel::Debug,
|
||||
("TabShare: GetSourceList, result %lu", sources->size()));
|
||||
// XXX UI
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TabCapturer::SelectSource(webrtc::DesktopCapturer::SourceId id) {
|
||||
MOZ_LOG(gTabShareLog, LogLevel::Debug, ("TabShare: source %ld", id));
|
||||
mBrowserId = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TabCapturer::FocusOnSelectedSource() { return true; }
|
||||
|
||||
nsresult TabCapturer::StartRunnable::Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// We use BrowserId to identify a tab since it's the only stable id; we
|
||||
// need the top-level browserid for a tab.
|
||||
|
||||
#ifdef NO_TABSHARE_UI
|
||||
// XXX Since we have no UI to feed us a browserid, grab "a" browserid for a
|
||||
// tab. This is a temporary hack until we have UI (bug 1646597)
|
||||
nsCOMPtr<nsPIDOMWindowOuter> chromeWindow =
|
||||
nsContentUtils::GetMostRecentNonPBWindow();
|
||||
if (!chromeWindow) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIDocShell> docShell = chromeWindow->GetDocShell();
|
||||
if (!docShell) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIDocShellTreeOwner> owner;
|
||||
docShell->GetTreeOwner(getter_AddRefs(owner));
|
||||
if (!owner) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIRemoteTab> primaryRemoteTab;
|
||||
owner->GetPrimaryRemoteTab(getter_AddRefs(primaryRemoteTab));
|
||||
if (!primaryRemoteTab) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
RefPtr<BrowsingContext> context =
|
||||
BrowserHost::GetFrom(primaryRemoteTab)->GetBrowsingContext();
|
||||
if (!context) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mVideoSource->mBrowserId = context->BrowserId();
|
||||
#endif
|
||||
|
||||
MOZ_LOG(gTabShareLog, LogLevel::Debug,
|
||||
("TabShare: Start, id=%ld", mVideoSource->mBrowserId));
|
||||
|
||||
mVideoSource->CaptureFrameNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void TabCapturer::Start(webrtc::DesktopCapturer::Callback* callback) {
|
||||
RTC_DCHECK(!mCallback);
|
||||
RTC_DCHECK(callback);
|
||||
|
||||
mCallback = callback;
|
||||
NS_DispatchToMainThread(new StartRunnable(this));
|
||||
}
|
||||
|
||||
// NOTE: this method is synchronous
|
||||
void TabCapturer::CaptureFrame() {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction("TabCapturer: Capture a frame",
|
||||
[self = RefPtr{this}] {
|
||||
self->CaptureFrameNow();
|
||||
// New frame will be returned
|
||||
// via Promise callback on
|
||||
// mThread
|
||||
}));
|
||||
// mCallback may not be valid if we don't make this call synchronous;
|
||||
// especially since CaptureFrameNow isn't a synchronous event
|
||||
monitor.Wait();
|
||||
}
|
||||
|
||||
bool TabCapturer::IsOccluded(const webrtc::DesktopVector& pos) { return false; }
|
||||
|
||||
class TabCapturedHandler final : public dom::PromiseNativeHandler {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
static void Create(dom::Promise* aPromise, TabCapturer* aEngine) {
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<TabCapturedHandler> handler = new TabCapturedHandler(aEngine);
|
||||
aPromise->AppendNativeHandler(handler);
|
||||
}
|
||||
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MonitorAutoLock monitor(mEngine->mMonitor);
|
||||
if (NS_WARN_IF(!aValue.isObject())) {
|
||||
monitor.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<dom::ImageBitmap> bitmap;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
UNWRAP_OBJECT(ImageBitmap, &aValue.toObject(), bitmap)))) {
|
||||
monitor.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
mEngine->OnFrame(bitmap);
|
||||
mEngine->mCapturing = false;
|
||||
// We no longer will touch mCallback from MainThread for this frame
|
||||
monitor.Notify();
|
||||
}
|
||||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MonitorAutoLock monitor(mEngine->mMonitor);
|
||||
mEngine->mCapturing = false;
|
||||
monitor.Notify();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit TabCapturedHandler(TabCapturer* aEngine) : mEngine(aEngine) {
|
||||
MOZ_ASSERT(aEngine);
|
||||
}
|
||||
|
||||
~TabCapturedHandler() = default;
|
||||
|
||||
RefPtr<TabCapturer> mEngine;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(TabCapturedHandler)
|
||||
|
||||
void TabCapturer::CaptureFrameNow() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_LOG(gTabShareLog, LogLevel::Debug, ("TabShare: CaptureFrameNow"));
|
||||
|
||||
// Ensure we clean up on failures
|
||||
auto autoFailureCallback = MakeScopeExit([&] {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
mCallback->OnCaptureResult(webrtc::DesktopCapturer::Result::ERROR_TEMPORARY,
|
||||
nullptr);
|
||||
monitor.Notify();
|
||||
});
|
||||
WindowGlobalParent* wgp = nullptr;
|
||||
if (mBrowserId != 0) {
|
||||
RefPtr<BrowsingContext> context =
|
||||
BrowsingContext::GetCurrentTopByBrowserId(mBrowserId);
|
||||
if (context) {
|
||||
wgp = context->Canonical()->GetCurrentWindowGlobal();
|
||||
}
|
||||
// If we can't access the window, we just won't capture anything
|
||||
}
|
||||
if (!wgp) {
|
||||
return;
|
||||
}
|
||||
if (!mCapturing) {
|
||||
// XXX This would be more efficient if it returned a MozPromise, and
|
||||
// even more if we used CrossProcessPaint directly and returned a surface.
|
||||
RefPtr<dom::Promise> promise = wgp->DrawSnapshot(
|
||||
nullptr, 1.0, "white"_ns, IgnoreErrors());
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
mCapturing = true;
|
||||
TabCapturedHandler::Create(promise, this);
|
||||
}
|
||||
// else we haven't finished the previous capture
|
||||
|
||||
autoFailureCallback.release();
|
||||
}
|
||||
|
||||
void TabCapturer::OnFrame(dom::ImageBitmap* aBitmap) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
UniquePtr<dom::ImageBitmapCloneData> data = aBitmap->ToCloneData();
|
||||
webrtc::DesktopSize size(data->mPictureRect.Width(),
|
||||
data->mPictureRect.Height());
|
||||
webrtc::DesktopRect rect = webrtc::DesktopRect::MakeSize(size);
|
||||
std::unique_ptr<webrtc::DesktopFrame> frame(
|
||||
new webrtc::BasicDesktopFrame(size));
|
||||
|
||||
gfx::DataSourceSurface::ScopedMap map(data->mSurface,
|
||||
gfx::DataSourceSurface::READ);
|
||||
if (!map.IsMapped()) {
|
||||
mCallback->OnCaptureResult(webrtc::DesktopCapturer::Result::ERROR_TEMPORARY,
|
||||
nullptr);
|
||||
return;
|
||||
}
|
||||
frame->CopyPixelsFrom(map.GetData(), map.GetStride(), rect);
|
||||
|
||||
mCallback->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
|
||||
std::move(frame));
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
namespace webrtc {
|
||||
// static
|
||||
std::unique_ptr<webrtc::DesktopCapturer>
|
||||
webrtc::DesktopCapturer::CreateRawTabCapturer(
|
||||
const webrtc::DesktopCaptureOptions& options) {
|
||||
return std::unique_ptr<webrtc::DesktopCapturer>(
|
||||
new mozilla::TabCapturerWebrtc(options));
|
||||
}
|
||||
} // namespace webrtc
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_DESKTOP_CAPTURE_TAB_CAPTURER_H_
|
||||
#define MODULES_DESKTOP_CAPTURE_TAB_CAPTURER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "modules/desktop_capture/desktop_capture_options.h"
|
||||
#include "modules/desktop_capture/desktop_capturer.h"
|
||||
#include "rtc_base/constructormagic.h"
|
||||
#include "nsITabSource.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TabCapturedHandler;
|
||||
|
||||
class TabCapturer {
|
||||
private:
|
||||
~TabCapturer();
|
||||
|
||||
public:
|
||||
friend class TabCapturedHandler;
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TabCapturer)
|
||||
|
||||
explicit TabCapturer(const webrtc::DesktopCaptureOptions& options);
|
||||
|
||||
static std::unique_ptr<webrtc::DesktopCapturer> CreateRawWindowCapturer(
|
||||
const webrtc::DesktopCaptureOptions& options);
|
||||
|
||||
// support for DesktopCapturer interface.
|
||||
void Start(webrtc::DesktopCapturer::Callback* callback);
|
||||
void CaptureFrame();
|
||||
bool GetSourceList(webrtc::DesktopCapturer::SourceList* sources);
|
||||
bool SelectSource(webrtc::DesktopCapturer::SourceId id);
|
||||
bool FocusOnSelectedSource();
|
||||
bool IsOccluded(const webrtc::DesktopVector& pos);
|
||||
|
||||
// Capture code
|
||||
void CaptureFrameNow();
|
||||
void OnFrame(dom::ImageBitmap* aBitmap);
|
||||
|
||||
class StartRunnable : public Runnable {
|
||||
public:
|
||||
explicit StartRunnable(TabCapturer* videoSource)
|
||||
: Runnable("TabCapturer::StartRunnable"), mVideoSource(videoSource) {}
|
||||
NS_IMETHOD Run() override;
|
||||
const RefPtr<TabCapturer> mVideoSource;
|
||||
};
|
||||
|
||||
private:
|
||||
// Used to protect mCallback, since TabCapturer's lifetime might be
|
||||
// longer than mCallback's on stop/shutdown, and we may be waiting on a
|
||||
// tab to finish capturing on MainThread.
|
||||
Monitor mMonitor;
|
||||
webrtc::DesktopCapturer::Callback* mCallback = nullptr;
|
||||
|
||||
uint64_t mBrowserId = 0;
|
||||
bool mCapturing = false;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(TabCapturer);
|
||||
};
|
||||
|
||||
// Warning: webrtc capture wants this in a uniqueptr, but it greatly eases
|
||||
// things for us if it's a refcounted object (so we can pass it around to
|
||||
// Dispatch/etc). Solve this by having a DesktopCapturer that just holds the
|
||||
// refcounted TabCapturer.
|
||||
|
||||
// XXX This is a little ugly; we could decompose into front-end (webrtc)
|
||||
// and backend (refcounted), but that doesn't actually make things a lot better.
|
||||
class TabCapturerWebrtc : public webrtc::DesktopCapturer {
|
||||
public:
|
||||
explicit TabCapturerWebrtc(const webrtc::DesktopCaptureOptions& options) {
|
||||
mInternal = new TabCapturer(options);
|
||||
}
|
||||
|
||||
~TabCapturerWebrtc() override {}
|
||||
|
||||
// DesktopCapturer interface.
|
||||
void Start(Callback* callback) override { mInternal->Start(callback); }
|
||||
void CaptureFrame() override { mInternal->CaptureFrame(); }
|
||||
bool GetSourceList(SourceList* sources) override {
|
||||
return mInternal->GetSourceList(sources);
|
||||
}
|
||||
bool SelectSource(SourceId id) override {
|
||||
return mInternal->SelectSource(id);
|
||||
}
|
||||
bool FocusOnSelectedSource() override {
|
||||
return mInternal->FocusOnSelectedSource();
|
||||
}
|
||||
bool IsOccluded(const webrtc::DesktopVector& pos) override {
|
||||
return mInternal->IsOccluded(pos);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<TabCapturer> mInternal;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MODULES_DESKTOP_CAPTURE_TAB_CAPTURER_H_
|
|
@ -1,403 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaEngineTabVideoSource.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/layers/SharedRGBImage.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "Layers.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "MediaTrackConstraints.h"
|
||||
#include "Tracing.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
MediaEngineTabVideoSource::MediaEngineTabVideoSource()
|
||||
: mSettings(MakeAndAddRef<media::Refcountable<MediaTrackSettings>>()) {}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::StartRunnable::Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mVideoSource->mWindowId != -1) {
|
||||
nsGlobalWindowOuter* globalWindow =
|
||||
nsGlobalWindowOuter::GetOuterWindowWithId(mVideoSource->mWindowId);
|
||||
if (!globalWindow) {
|
||||
// We can't access the window, just send a blacked out screen.
|
||||
mVideoSource->mWindow = nullptr;
|
||||
mVideoSource->mBlackedoutWindow = true;
|
||||
} else {
|
||||
mVideoSource->mWindow = globalWindow;
|
||||
mVideoSource->mBlackedoutWindow = false;
|
||||
}
|
||||
}
|
||||
if (!mVideoSource->mWindow && !mVideoSource->mBlackedoutWindow) {
|
||||
nsresult rv;
|
||||
mVideoSource->mTabSource =
|
||||
do_GetService(NS_TABSOURCESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> win;
|
||||
rv = mVideoSource->mTabSource->GetTabToStream(getter_AddRefs(win));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!win) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mVideoSource->mWindow = nsPIDOMWindowOuter::From(win);
|
||||
MOZ_ASSERT(mVideoSource->mWindow);
|
||||
}
|
||||
mVideoSource->mTimer = NS_NewTimer();
|
||||
mVideoSource->mTrackMain = mTrack;
|
||||
mVideoSource->mPrincipalHandleMain = mPrincipal;
|
||||
mVideoSource->Draw();
|
||||
mVideoSource->mTimer->InitWithNamedFuncCallback(
|
||||
[](nsITimer* aTimer, void* aClosure) mutable {
|
||||
auto source = static_cast<MediaEngineTabVideoSource*>(aClosure);
|
||||
source->Draw();
|
||||
},
|
||||
mVideoSource, mVideoSource->mTimePerFrame, nsITimer::TYPE_REPEATING_SLACK,
|
||||
"MediaEngineTabVideoSource DrawTimer");
|
||||
if (mVideoSource->mTabSource) {
|
||||
mVideoSource->mTabSource->NotifyStreamStart(mVideoSource->mWindow);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::StopRunnable::Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mVideoSource->mTimer) {
|
||||
mVideoSource->mTimer->Cancel();
|
||||
mVideoSource->mTimer = nullptr;
|
||||
}
|
||||
if (mVideoSource->mTabSource) {
|
||||
mVideoSource->mTabSource->NotifyStreamStop(mVideoSource->mWindow);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::DestroyRunnable::Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mVideoSource->mWindow = nullptr;
|
||||
mVideoSource->mTabSource = nullptr;
|
||||
|
||||
if (mVideoSource->mTrackMain) {
|
||||
mVideoSource->mTrackMain->End();
|
||||
}
|
||||
mVideoSource->mPrincipalHandle = PRINCIPAL_HANDLE_NONE;
|
||||
mVideoSource->mTrackMain = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsString MediaEngineTabVideoSource::GetName() const {
|
||||
return u"&getUserMedia.videoSource.tabShare;"_ns;
|
||||
}
|
||||
|
||||
nsCString MediaEngineTabVideoSource::GetUUID() const { return "tab"_ns; }
|
||||
|
||||
nsString MediaEngineTabVideoSource::GetGroupId() const {
|
||||
return u"&getUserMedia.videoSource.tabShareGroup;"_ns;
|
||||
}
|
||||
|
||||
#define DEFAULT_TABSHARE_VIDEO_MAX_WIDTH 4096
|
||||
#define DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT 4096
|
||||
#define DEFAULT_TABSHARE_VIDEO_FRAMERATE 30
|
||||
|
||||
nsresult MediaEngineTabVideoSource::Allocate(
|
||||
const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const char** aOutBadConstraint) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// windowId is not a proper constraint, so just read it.
|
||||
// It has no well-defined behavior in advanced, so ignore it there.
|
||||
|
||||
int64_t windowId = aConstraints.mBrowserWindow.WasPassed()
|
||||
? aConstraints.mBrowserWindow.Value()
|
||||
: -1;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"MediaEngineTabVideoSource::Allocate window id main thread setter",
|
||||
[self = RefPtr<MediaEngineTabVideoSource>(this), this, windowId] {
|
||||
mWindowId = windowId;
|
||||
}));
|
||||
mState = kAllocated;
|
||||
|
||||
return Reconfigure(aConstraints, aPrefs, aOutBadConstraint);
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::Reconfigure(
|
||||
const dom::MediaTrackConstraints& aConstraints,
|
||||
const mozilla::MediaEnginePrefs& aPrefs, const char** aOutBadConstraint) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState != kReleased);
|
||||
|
||||
// scrollWithPage is not proper a constraint, so just read it.
|
||||
// It has no well-defined behavior in advanced, so ignore it there.
|
||||
|
||||
const bool scrollWithPage = aConstraints.mScrollWithPage.WasPassed()
|
||||
? aConstraints.mScrollWithPage.Value()
|
||||
: false;
|
||||
|
||||
FlattenedConstraints c(aConstraints);
|
||||
|
||||
const int32_t bufWidthMax = c.mWidth.Get(DEFAULT_TABSHARE_VIDEO_MAX_WIDTH);
|
||||
const int32_t bufHeightMax = c.mHeight.Get(DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT);
|
||||
const double frameRate = c.mFrameRate.Get(DEFAULT_TABSHARE_VIDEO_FRAMERATE);
|
||||
const int32_t timePerFrame =
|
||||
std::max(10, int(1000.0 / (frameRate > 0 ? frameRate : 1)));
|
||||
|
||||
Maybe<int32_t> viewportOffsetX;
|
||||
Maybe<int32_t> viewportOffsetY;
|
||||
Maybe<int32_t> viewportWidth;
|
||||
Maybe<int32_t> viewportHeight;
|
||||
if (!scrollWithPage) {
|
||||
viewportOffsetX = Some(c.mViewportOffsetX.Get(0));
|
||||
viewportOffsetY = Some(c.mViewportOffsetY.Get(0));
|
||||
viewportWidth = Some(c.mViewportWidth.Get(INT32_MAX));
|
||||
viewportHeight = Some(c.mViewportHeight.Get(INT32_MAX));
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"MediaEngineTabVideoSource::Reconfigure main thread setter",
|
||||
[self = RefPtr<MediaEngineTabVideoSource>(this), this, scrollWithPage,
|
||||
bufWidthMax, bufHeightMax, frameRate, timePerFrame, viewportOffsetX,
|
||||
viewportOffsetY, viewportWidth, viewportHeight]() {
|
||||
mScrollWithPage = scrollWithPage;
|
||||
mBufWidthMax = bufWidthMax;
|
||||
mBufHeightMax = bufHeightMax;
|
||||
mTimePerFrame = timePerFrame;
|
||||
*mSettings = MediaTrackSettings();
|
||||
mSettings->mScrollWithPage.Construct(scrollWithPage);
|
||||
mSettings->mWidth.Construct(bufWidthMax);
|
||||
mSettings->mHeight.Construct(bufHeightMax);
|
||||
mSettings->mFrameRate.Construct(frameRate);
|
||||
if (viewportOffsetX.isSome()) {
|
||||
mSettings->mViewportOffsetX.Construct(*viewportOffsetX);
|
||||
mViewportOffsetX = *viewportOffsetX;
|
||||
}
|
||||
if (viewportOffsetY.isSome()) {
|
||||
mSettings->mViewportOffsetY.Construct(*viewportOffsetY);
|
||||
mViewportOffsetY = *viewportOffsetY;
|
||||
}
|
||||
if (viewportWidth.isSome()) {
|
||||
mSettings->mViewportWidth.Construct(*viewportWidth);
|
||||
mViewportWidth = *viewportWidth;
|
||||
}
|
||||
if (viewportHeight.isSome()) {
|
||||
mSettings->mViewportHeight.Construct(*viewportHeight);
|
||||
mViewportHeight = *viewportHeight;
|
||||
}
|
||||
if (mWindowId != -1) {
|
||||
mSettings->mBrowserWindow.Construct(mWindowId);
|
||||
}
|
||||
}));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::Deallocate() {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState == kAllocated || mState == kStopped);
|
||||
|
||||
NS_DispatchToMainThread(do_AddRef(new DestroyRunnable(this)));
|
||||
mState = kReleased;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaEngineTabVideoSource::SetTrack(
|
||||
const RefPtr<SourceMediaTrack>& aTrack,
|
||||
const mozilla::PrincipalHandle& aPrincipal) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState == kAllocated);
|
||||
|
||||
MOZ_ASSERT(!mTrack);
|
||||
MOZ_ASSERT(aTrack);
|
||||
mTrack = aTrack;
|
||||
mPrincipalHandle = aPrincipal;
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::Start() {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState == kAllocated);
|
||||
|
||||
NS_DispatchToMainThread(new StartRunnable(this, mTrack, mPrincipalHandle));
|
||||
mState = kStarted;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaEngineTabVideoSource::Draw() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mWindow && !mBlackedoutWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mTrackMain || mTrackMain->IsDestroyed()) {
|
||||
// The track is already gone or destroyed by MediaManager. This can happen
|
||||
// because stopping the draw timer is async.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWindow) {
|
||||
if (mScrollWithPage || mViewportWidth == INT32_MAX) {
|
||||
mWindow->GetInnerWidth(&mViewportWidth);
|
||||
}
|
||||
if (mScrollWithPage || mViewportHeight == INT32_MAX) {
|
||||
mWindow->GetInnerHeight(&mViewportHeight);
|
||||
}
|
||||
if (!mViewportWidth || !mViewportHeight) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mViewportWidth = 640;
|
||||
mViewportHeight = 480;
|
||||
}
|
||||
|
||||
IntSize size;
|
||||
{
|
||||
float pixelRatio;
|
||||
if (mWindow) {
|
||||
pixelRatio = mWindow->GetDevicePixelRatio(dom::CallerType::System);
|
||||
} else {
|
||||
pixelRatio = 1.0f;
|
||||
}
|
||||
const int32_t deviceWidth = (int32_t)(pixelRatio * mViewportWidth);
|
||||
const int32_t deviceHeight = (int32_t)(pixelRatio * mViewportHeight);
|
||||
|
||||
if ((deviceWidth <= mBufWidthMax) && (deviceHeight <= mBufHeightMax)) {
|
||||
size = IntSize(deviceWidth, deviceHeight);
|
||||
} else {
|
||||
const float scaleWidth = (float)mBufWidthMax / (float)deviceWidth;
|
||||
const float scaleHeight = (float)mBufHeightMax / (float)deviceHeight;
|
||||
const float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
|
||||
|
||||
size = IntSize((int)(scale * deviceWidth), (int)(scale * deviceHeight));
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<PresShell> presShell;
|
||||
if (mWindow) {
|
||||
nsIDocShell* docshell = mWindow->GetDocShell();
|
||||
if (docshell) {
|
||||
presShell = docshell->GetPresShell();
|
||||
}
|
||||
if (!presShell) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mImageContainer) {
|
||||
mImageContainer = layers::LayerManager::CreateImageContainer(
|
||||
layers::ImageContainer::ASYNCHRONOUS);
|
||||
}
|
||||
|
||||
RefPtr<layers::SharedRGBImage> rgbImage =
|
||||
mImageContainer->CreateSharedRGBImage();
|
||||
if (!rgbImage) {
|
||||
NS_WARNING("Failed to create SharedRGBImage");
|
||||
return;
|
||||
}
|
||||
if (!rgbImage->Allocate(size, SurfaceFormat::B8G8R8X8)) {
|
||||
NS_WARNING("Failed to allocate a shared image");
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<layers::TextureClient> texture =
|
||||
rgbImage->GetTextureClient(/* aKnowsCompositor */ nullptr);
|
||||
if (!texture) {
|
||||
NS_WARNING("Failed to allocate TextureClient");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
layers::TextureClientAutoLock autoLock(texture,
|
||||
layers::OpenMode::OPEN_WRITE_ONLY);
|
||||
if (!autoLock.Succeeded()) {
|
||||
NS_WARNING("Failed to lock TextureClient");
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DrawTarget> dt = texture->BorrowDrawTarget();
|
||||
if (!dt || !dt->IsValid()) {
|
||||
NS_WARNING("Failed to borrow DrawTarget");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWindow) {
|
||||
RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
|
||||
MOZ_ASSERT(context); // already checked the draw target above
|
||||
context->SetMatrix(context->CurrentMatrix().PreScale(
|
||||
(((float)size.width) / mViewportWidth),
|
||||
(((float)size.height) / mViewportHeight)));
|
||||
|
||||
nscolor bgColor = NS_RGB(255, 255, 255);
|
||||
RenderDocumentFlags renderDocFlags =
|
||||
mScrollWithPage ? RenderDocumentFlags::None
|
||||
: (RenderDocumentFlags::IgnoreViewportScrolling |
|
||||
RenderDocumentFlags::DocumentRelative);
|
||||
nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight));
|
||||
NS_ENSURE_SUCCESS_VOID(
|
||||
presShell->RenderDocument(r, renderDocFlags, bgColor, context));
|
||||
} else {
|
||||
dt->ClearRect(Rect(0, 0, size.width, size.height));
|
||||
}
|
||||
}
|
||||
|
||||
VideoSegment segment;
|
||||
segment.AppendFrame(do_AddRef(rgbImage), size, mPrincipalHandle);
|
||||
mTrackMain->AppendData(&segment);
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::FocusOnSelectedSource() {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult MediaEngineTabVideoSource::Stop() {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mState == kStopped || mState == kAllocated) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == kStarted);
|
||||
|
||||
// If mBlackedoutWindow is true, we may be running
|
||||
// despite mWindow == nullptr.
|
||||
if (!mWindow && !mBlackedoutWindow) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new StopRunnable(this));
|
||||
mState = kStopped;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaEngineTabVideoSource::GetSettings(
|
||||
MediaTrackSettings& aOutSettings) const {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aOutSettings = *mSettings;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,117 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaEngine.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "nsITimer.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsITabSource.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class ImageContainer;
|
||||
}
|
||||
|
||||
class MediaEngineTabVideoSource : public MediaEngineSource {
|
||||
public:
|
||||
MediaEngineTabVideoSource();
|
||||
|
||||
nsString GetName() const override;
|
||||
nsCString GetUUID() const override;
|
||||
nsString GetGroupId() const override;
|
||||
|
||||
bool GetScary() const override { return true; }
|
||||
|
||||
dom::MediaSourceEnum GetMediaSource() const override {
|
||||
return dom::MediaSourceEnum::Browser;
|
||||
}
|
||||
|
||||
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs, uint64_t aWindowID,
|
||||
const char** aOutBadConstraint) override;
|
||||
nsresult Deallocate() override;
|
||||
void SetTrack(const RefPtr<SourceMediaTrack>& aTrack,
|
||||
const PrincipalHandle& aPrincipal) override;
|
||||
nsresult Start() override;
|
||||
nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const char** aOutBadConstraint) override;
|
||||
nsresult FocusOnSelectedSource() override;
|
||||
nsresult Stop() override;
|
||||
|
||||
void GetSettings(dom::MediaTrackSettings& aOutSettings) const override;
|
||||
|
||||
void Draw();
|
||||
|
||||
class StartRunnable : public Runnable {
|
||||
public:
|
||||
StartRunnable(MediaEngineTabVideoSource* videoSource,
|
||||
SourceMediaTrack* aTrack, const PrincipalHandle& aPrincipal)
|
||||
: Runnable("MediaEngineTabVideoSource::StartRunnable"),
|
||||
mVideoSource(videoSource),
|
||||
mTrack(aTrack),
|
||||
mPrincipal(aPrincipal) {}
|
||||
NS_IMETHOD Run() override;
|
||||
const RefPtr<MediaEngineTabVideoSource> mVideoSource;
|
||||
const RefPtr<SourceMediaTrack> mTrack;
|
||||
const PrincipalHandle mPrincipal;
|
||||
};
|
||||
|
||||
class StopRunnable : public Runnable {
|
||||
public:
|
||||
explicit StopRunnable(MediaEngineTabVideoSource* videoSource)
|
||||
: Runnable("MediaEngineTabVideoSource::StopRunnable"),
|
||||
mVideoSource(videoSource) {}
|
||||
NS_IMETHOD Run() override;
|
||||
const RefPtr<MediaEngineTabVideoSource> mVideoSource;
|
||||
};
|
||||
|
||||
class DestroyRunnable : public Runnable {
|
||||
public:
|
||||
explicit DestroyRunnable(MediaEngineTabVideoSource* videoSource)
|
||||
: Runnable("MediaEngineTabVideoSource::DestroyRunnable"),
|
||||
mVideoSource(videoSource) {}
|
||||
NS_IMETHOD Run() override;
|
||||
const RefPtr<MediaEngineTabVideoSource> mVideoSource;
|
||||
};
|
||||
|
||||
protected:
|
||||
~MediaEngineTabVideoSource() = default;
|
||||
|
||||
private:
|
||||
// These are accessed only on main thread.
|
||||
int32_t mBufWidthMax = 0;
|
||||
int32_t mBufHeightMax = 0;
|
||||
int64_t mWindowId = 0;
|
||||
bool mScrollWithPage = false;
|
||||
int32_t mViewportOffsetX = 0;
|
||||
int32_t mViewportOffsetY = 0;
|
||||
int32_t mViewportWidth = 0;
|
||||
int32_t mViewportHeight = 0;
|
||||
int32_t mTimePerFrame = 0;
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
// The current settings of this source.
|
||||
// Members are main thread only.
|
||||
const RefPtr<media::Refcountable<dom::MediaTrackSettings>> mSettings;
|
||||
|
||||
// Main thread only.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> mWindow;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsITabSource> mTabSource;
|
||||
RefPtr<SourceMediaTrack> mTrackMain;
|
||||
PrincipalHandle mPrincipalHandleMain = PRINCIPAL_HANDLE_NONE;
|
||||
// If this is set, we will run despite mWindow == nullptr.
|
||||
bool mBlackedoutWindow = false;
|
||||
|
||||
// Current state of this source. Accessed on owning thread only.
|
||||
MediaEngineSourceState mState = kReleased;
|
||||
// mTrack is set in SetTrack() to keep track of what to end in Deallocate().
|
||||
// Owning thread only.
|
||||
RefPtr<SourceMediaTrack> mTrack;
|
||||
PrincipalHandle mPrincipalHandle = PRINCIPAL_HANDLE_NONE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "CamerasChild.h"
|
||||
#include "CSFLog.h"
|
||||
#include "MediaEngineTabVideoSource.h"
|
||||
#include "MediaEngineRemoteVideoSource.h"
|
||||
#include "MediaEngineWebRTCAudio.h"
|
||||
#include "MediaManager.h"
|
||||
|
@ -35,17 +34,9 @@ CubebDeviceEnumerator* GetEnumerator() {
|
|||
|
||||
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs& aPrefs)
|
||||
: mDelayAgnostic(aPrefs.mDelayAgnostic),
|
||||
mExtendedFilter(aPrefs.mExtendedFilter),
|
||||
mHasTabVideoSource(false) {
|
||||
mExtendedFilter(aPrefs.mExtendedFilter) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
nsCOMPtr<nsIComponentRegistrar> compMgr;
|
||||
NS_GetComponentRegistrar(getter_AddRefs(compMgr));
|
||||
if (compMgr) {
|
||||
compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID,
|
||||
&mHasTabVideoSource);
|
||||
}
|
||||
|
||||
GetChildAndCall(
|
||||
&CamerasChild::ConnectDeviceListChangeListener<MediaEngineWebRTC>,
|
||||
&mCameraListChangeListener, AbstractThread::MainThread(), this,
|
||||
|
@ -169,14 +160,6 @@ void MediaEngineWebRTC::EnumerateVideoDevices(
|
|||
vSource, vSource->GetName(), NS_ConvertUTF8toUTF16(vSource->GetUUID()),
|
||||
vSource->GetGroupId(), u""_ns));
|
||||
}
|
||||
|
||||
if (mHasTabVideoSource || aCapEngine == camera::BrowserEngine) {
|
||||
RefPtr<MediaEngineSource> tabVideoSource = new MediaEngineTabVideoSource();
|
||||
aDevices->AppendElement(MakeRefPtr<MediaDevice>(
|
||||
tabVideoSource, tabVideoSource->GetName(),
|
||||
NS_ConvertUTF8toUTF16(tabVideoSource->GetUUID()),
|
||||
tabVideoSource->GetGroupId(), u""_ns));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaEngineWebRTC::EnumerateMicrophoneDevices(
|
||||
|
@ -279,6 +262,7 @@ void MediaEngineWebRTC::EnumerateDevices(
|
|||
// are still useful for testing.
|
||||
EnumerateVideoDevices(aWindowId, camera::WinEngine, aDevices);
|
||||
EnumerateVideoDevices(aWindowId, camera::ScreenEngine, aDevices);
|
||||
EnumerateVideoDevices(aWindowId, camera::BrowserEngine, aDevices);
|
||||
break;
|
||||
case dom::MediaSourceEnum::Screen:
|
||||
EnumerateVideoDevices(aWindowId, camera::ScreenEngine, aDevices);
|
||||
|
|
|
@ -227,7 +227,6 @@ class NormalizedConstraintSet {
|
|||
StringRange mFacingMode;
|
||||
StringRange mMediaSource;
|
||||
LongLongRange mBrowserWindow;
|
||||
BooleanRange mScrollWithPage;
|
||||
StringRange mDeviceId;
|
||||
StringRange mGroupId;
|
||||
LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
|
||||
|
@ -254,11 +253,6 @@ class NormalizedConstraintSet {
|
|||
? aOther.mBrowserWindow.Value()
|
||||
: 0,
|
||||
aList),
|
||||
mScrollWithPage(&T::mScrollWithPage, "scrollWithPage",
|
||||
aOther.mScrollWithPage.WasPassed()
|
||||
? aOther.mScrollWithPage.Value()
|
||||
: false,
|
||||
aList),
|
||||
mDeviceId(&T::mDeviceId, "deviceId", aOther.mDeviceId, advanced, aList),
|
||||
mGroupId(&T::mGroupId, "groupId", aOther.mGroupId, advanced, aList),
|
||||
mViewportOffsetX(&T::mViewportOffsetX, "viewportOffsetX",
|
||||
|
|
|
@ -35,7 +35,6 @@ if CONFIG['MOZ_WEBRTC']:
|
|||
EXPORTS.mozilla.dom += [ 'RTCIdentityProviderRegistrar.h' ]
|
||||
UNIFIED_SOURCES += [
|
||||
'MediaEngineRemoteVideoSource.cpp',
|
||||
'MediaEngineTabVideoSource.cpp',
|
||||
'MediaEngineWebRTCAudio.cpp',
|
||||
'RTCCertificate.cpp',
|
||||
'RTCIdentityProviderRegistrar.cpp',
|
||||
|
|
|
@ -60,6 +60,17 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
|
|||
return capturer;
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateTabCapturer(
|
||||
const DesktopCaptureOptions& options) {
|
||||
std::unique_ptr<DesktopCapturer> capturer = CreateRawTabCapturer(options);
|
||||
if (capturer && options.detect_updated_region()) {
|
||||
capturer.reset(new DesktopCapturerDifferWrapper(std::move(capturer)));
|
||||
}
|
||||
|
||||
return capturer;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
||||
bool DesktopCapturer::IsRunningUnderWayland() {
|
||||
const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
|
||||
|
|
|
@ -139,6 +139,10 @@ class DesktopCapturer {
|
|||
static std::unique_ptr<DesktopCapturer> CreateAppCapturer(
|
||||
const DesktopCaptureOptions& options);
|
||||
|
||||
// Creates a DesktopCapturer instance which targets to capture tab.
|
||||
static std::unique_ptr<DesktopCapturer> CreateTabCapturer(
|
||||
const DesktopCaptureOptions& options);
|
||||
|
||||
#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
||||
static bool IsRunningUnderWayland();
|
||||
#endif // defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
||||
|
@ -161,6 +165,10 @@ class DesktopCapturer {
|
|||
// capture apps.
|
||||
static std::unique_ptr<DesktopCapturer> CreateRawAppCapturer(
|
||||
const DesktopCaptureOptions& options);
|
||||
|
||||
// Creates a DesktopCapturer instance which targets to capture tabs
|
||||
static std::unique_ptr<DesktopCapturer> CreateRawTabCapturer(
|
||||
const DesktopCaptureOptions& options);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -170,6 +170,66 @@ DesktopApplication& DesktopApplication::operator= (DesktopApplication& other) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
DesktopTab::DesktopTab() {
|
||||
tabBrowserId_ = 0;
|
||||
tabNameUTF8_= NULL;
|
||||
tabUniqueIdUTF8_= NULL;
|
||||
tabCount_ = 0;
|
||||
}
|
||||
|
||||
DesktopTab::~DesktopTab() {
|
||||
if (tabNameUTF8_) {
|
||||
delete [] tabNameUTF8_;
|
||||
}
|
||||
|
||||
if (tabUniqueIdUTF8_) {
|
||||
delete [] tabUniqueIdUTF8_;
|
||||
}
|
||||
|
||||
tabNameUTF8_= NULL;
|
||||
tabUniqueIdUTF8_= NULL;
|
||||
}
|
||||
|
||||
void DesktopTab::setTabBrowserId(uint64_t tabBrowserId) {
|
||||
tabBrowserId_ = tabBrowserId;
|
||||
}
|
||||
|
||||
void DesktopTab::setUniqueIdName(const char *tabUniqueIdUTF8) {
|
||||
SetStringMember(&tabUniqueIdUTF8_, tabUniqueIdUTF8);
|
||||
}
|
||||
|
||||
void DesktopTab::setTabName(const char *tabNameUTF8) {
|
||||
SetStringMember(&tabNameUTF8_, tabNameUTF8);
|
||||
}
|
||||
|
||||
void DesktopTab::setTabCount(const uint32_t count) {
|
||||
tabCount_ = count;
|
||||
}
|
||||
|
||||
uint64_t DesktopTab::getTabBrowserId() {
|
||||
return tabBrowserId_;
|
||||
}
|
||||
|
||||
const char *DesktopTab::getUniqueIdName() {
|
||||
return tabUniqueIdUTF8_;
|
||||
}
|
||||
|
||||
const char *DesktopTab::getTabName() {
|
||||
return tabNameUTF8_;
|
||||
}
|
||||
|
||||
uint32_t DesktopTab::getTabCount() {
|
||||
return tabCount_;
|
||||
}
|
||||
|
||||
DesktopTab& DesktopTab::operator= (DesktopTab& other) {
|
||||
tabBrowserId_ = other.getTabBrowserId();
|
||||
setUniqueIdName(other.getUniqueIdName());
|
||||
setTabName(other.getTabName());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
DesktopDeviceInfoImpl::DesktopDeviceInfoImpl() {
|
||||
}
|
||||
|
||||
|
@ -183,7 +243,7 @@ int32_t DesktopDeviceInfoImpl::getDisplayDeviceCount() {
|
|||
|
||||
int32_t DesktopDeviceInfoImpl::getDesktopDisplayDeviceInfo(int32_t nIndex,
|
||||
DesktopDisplayDevice & desktopDisplayDevice) {
|
||||
if(nIndex < 0 || nIndex >= desktop_display_list_.size()) {
|
||||
if(nIndex < 0 || (size_t) nIndex >= desktop_display_list_.size()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -202,7 +262,7 @@ int32_t DesktopDeviceInfoImpl::getWindowCount() {
|
|||
}
|
||||
int32_t DesktopDeviceInfoImpl::getWindowInfo(int32_t nIndex,
|
||||
DesktopDisplayDevice &windowDevice) {
|
||||
if (nIndex < 0 || nIndex >= desktop_window_list_.size()) {
|
||||
if (nIndex < 0 || (size_t) nIndex >= desktop_window_list_.size()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -223,7 +283,7 @@ int32_t DesktopDeviceInfoImpl::getApplicationCount() {
|
|||
|
||||
int32_t DesktopDeviceInfoImpl::getApplicationInfo(int32_t nIndex,
|
||||
DesktopApplication & desktopApplication) {
|
||||
if(nIndex < 0 || nIndex >= desktop_application_list_.size()) {
|
||||
if(nIndex < 0 || (size_t) nIndex >= desktop_application_list_.size()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -237,15 +297,37 @@ int32_t DesktopDeviceInfoImpl::getApplicationInfo(int32_t nIndex,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t DesktopDeviceInfoImpl::getTabCount() {
|
||||
return desktop_tab_list_.size();
|
||||
}
|
||||
|
||||
int32_t DesktopDeviceInfoImpl::getTabInfo(int32_t nIndex,
|
||||
DesktopTab & desktopTab) {
|
||||
if (nIndex < 0 || (size_t) nIndex >= desktop_tab_list_.size()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::map<intptr_t,DesktopTab*>::iterator iter = desktop_tab_list_.begin();
|
||||
std::advance(iter, nIndex);
|
||||
DesktopTab * pDesktopTab = iter->second;
|
||||
if (pDesktopTab) {
|
||||
desktopTab = (*pDesktopTab);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DesktopDeviceInfoImpl::CleanUp() {
|
||||
CleanUpScreenList();
|
||||
CleanUpWindowList();
|
||||
CleanUpApplicationList();
|
||||
CleanUpTabList();
|
||||
}
|
||||
int32_t DesktopDeviceInfoImpl::Init() {
|
||||
InitializeScreenList();
|
||||
InitializeWindowList();
|
||||
InitializeApplicationList();
|
||||
InitializeTabList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -253,6 +335,7 @@ int32_t DesktopDeviceInfoImpl::Refresh() {
|
|||
RefreshScreenList();
|
||||
RefreshWindowList();
|
||||
RefreshApplicationList();
|
||||
RefreshTabList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -311,6 +394,31 @@ void DesktopDeviceInfoImpl::RefreshApplicationList() {
|
|||
InitializeApplicationList();
|
||||
}
|
||||
|
||||
void DesktopDeviceInfoImpl::CleanUpTabList() {
|
||||
for (auto &iterTab : desktop_tab_list_) {
|
||||
DesktopTab *pDesktopTab = iterTab.second;
|
||||
delete pDesktopTab;
|
||||
iterTab.second = NULL;
|
||||
}
|
||||
desktop_tab_list_.clear();
|
||||
}
|
||||
|
||||
void DesktopDeviceInfoImpl::DummyTabList(DesktopTabList &list) {
|
||||
DesktopTab* desktop_tab = new DesktopTab;
|
||||
if (desktop_tab) {
|
||||
desktop_tab->setTabBrowserId(0);
|
||||
desktop_tab->setTabName("dummy tab");
|
||||
desktop_tab->setUniqueIdName("dummy tab 0");
|
||||
desktop_tab->setTabCount(1);
|
||||
list[desktop_tab->getTabBrowserId()] = desktop_tab;
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopDeviceInfoImpl::RefreshTabList() {
|
||||
CleanUpTabList();
|
||||
InitializeTabList();
|
||||
}
|
||||
|
||||
void DesktopDeviceInfoImpl::CleanUpScreenList() {
|
||||
std::map<intptr_t,DesktopDisplayDevice*>::iterator iterDevice;
|
||||
for (iterDevice=desktop_display_list_.begin(); iterDevice != desktop_display_list_.end(); iterDevice++){
|
||||
|
@ -319,9 +427,11 @@ void DesktopDeviceInfoImpl::CleanUpScreenList() {
|
|||
iterDevice->second = NULL;
|
||||
}
|
||||
desktop_display_list_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopDeviceInfoImpl::RefreshScreenList() {
|
||||
CleanUpScreenList();
|
||||
InitializeScreenList();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,32 @@ protected:
|
|||
|
||||
typedef std::map<intptr_t, DesktopApplication*> DesktopApplicationList;
|
||||
|
||||
class DesktopTab {
|
||||
public:
|
||||
DesktopTab();
|
||||
~DesktopTab();
|
||||
|
||||
void setTabBrowserId(uint64_t tabBrowserId);
|
||||
void setUniqueIdName(const char *tabUniqueIdUTF8);
|
||||
void setTabName(const char *tabNameUTF8);
|
||||
void setTabCount(const uint32_t count);
|
||||
|
||||
uint64_t getTabBrowserId();
|
||||
const char *getUniqueIdName();
|
||||
const char *getTabName();
|
||||
uint32_t getTabCount();
|
||||
|
||||
DesktopTab& operator= (DesktopTab& other);
|
||||
|
||||
protected:
|
||||
uint64_t tabBrowserId_;
|
||||
char* tabNameUTF8_;
|
||||
char* tabUniqueIdUTF8_;
|
||||
uint32_t tabCount_;
|
||||
};
|
||||
|
||||
typedef std::map<intptr_t, DesktopTab*> DesktopTabList;
|
||||
|
||||
class DesktopDeviceInfo {
|
||||
public:
|
||||
virtual ~DesktopDeviceInfo() {};
|
||||
|
@ -80,6 +106,9 @@ public:
|
|||
virtual int32_t getApplicationCount() = 0;
|
||||
virtual int32_t getApplicationInfo(int32_t nIndex,
|
||||
DesktopApplication & desktopApplication) = 0;
|
||||
virtual int32_t getTabCount() = 0;
|
||||
virtual int32_t getTabInfo(int32_t nIndex,
|
||||
DesktopTab & desktopTab) = 0;
|
||||
};
|
||||
|
||||
class DesktopDeviceInfoImpl : public DesktopDeviceInfo {
|
||||
|
@ -87,37 +116,46 @@ public:
|
|||
DesktopDeviceInfoImpl();
|
||||
~DesktopDeviceInfoImpl();
|
||||
|
||||
virtual int32_t Init();
|
||||
virtual int32_t Refresh();
|
||||
virtual int32_t getDisplayDeviceCount();
|
||||
virtual int32_t getDesktopDisplayDeviceInfo(int32_t nIndex,
|
||||
DesktopDisplayDevice & desktopDisplayDevice);
|
||||
virtual int32_t getWindowCount();
|
||||
virtual int32_t getWindowInfo(int32_t nindex,
|
||||
DesktopDisplayDevice &windowDevice);
|
||||
virtual int32_t getApplicationCount();
|
||||
virtual int32_t getApplicationInfo(int32_t nIndex,
|
||||
DesktopApplication & desktopApplication);
|
||||
|
||||
int32_t Init() override;
|
||||
int32_t Refresh() override;
|
||||
int32_t getDisplayDeviceCount() override;
|
||||
int32_t getDesktopDisplayDeviceInfo(int32_t nIndex,
|
||||
DesktopDisplayDevice & desktopDisplayDevice) override;
|
||||
int32_t getWindowCount() override;
|
||||
int32_t getWindowInfo(int32_t nindex,
|
||||
DesktopDisplayDevice &windowDevice) override;
|
||||
int32_t getApplicationCount() override;
|
||||
int32_t getApplicationInfo(int32_t nIndex,
|
||||
DesktopApplication & desktopApplication) override;
|
||||
int32_t getTabCount() override;
|
||||
int32_t getTabInfo(int32_t nIndex,
|
||||
DesktopTab & desktopTab) override;
|
||||
static DesktopDeviceInfo * Create();
|
||||
protected:
|
||||
DesktopDisplayDeviceList desktop_display_list_;
|
||||
DesktopDisplayDeviceList desktop_window_list_;
|
||||
DesktopApplicationList desktop_application_list_;
|
||||
DesktopTabList desktop_tab_list_;
|
||||
|
||||
void CleanUp();
|
||||
void CleanUpWindowList();
|
||||
void CleanUpApplicationList();
|
||||
void CleanUpTabList();
|
||||
void CleanUpScreenList();
|
||||
|
||||
void InitializeWindowList();
|
||||
virtual void InitializeApplicationList() = 0;
|
||||
virtual void InitializeTabList() {
|
||||
DummyTabList(desktop_tab_list_);
|
||||
}
|
||||
virtual void InitializeScreenList() = 0;
|
||||
|
||||
void RefreshWindowList();
|
||||
void RefreshApplicationList();
|
||||
void RefreshTabList();
|
||||
void RefreshScreenList();
|
||||
|
||||
void DummyTabList(DesktopTabList &list);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
protected:
|
||||
virtual void InitializeScreenList();
|
||||
virtual void InitializeApplicationList();
|
||||
virtual void InitializeTabList();
|
||||
};
|
||||
|
||||
DesktopDeviceInfo * DesktopDeviceInfoImpl::Create() {
|
||||
|
|
|
@ -133,5 +133,4 @@ void DesktopDeviceInfoX11::InitializeApplicationList() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace webrtc
|
||||
|
|
Загрузка…
Ссылка в новой задаче