зеркало из 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "VideoEngine.h"
|
#include "VideoEngine.h"
|
||||||
#include "video_engine/browser_capture_impl.h"
|
|
||||||
#include "video_engine/desktop_capture_impl.h"
|
#include "video_engine/desktop_capture_impl.h"
|
||||||
#include "webrtc/system_wrappers/include/clock.h"
|
#include "webrtc/system_wrappers/include/clock.h"
|
||||||
#ifdef WEBRTC_ANDROID
|
#ifdef WEBRTC_ANDROID
|
||||||
|
@ -183,13 +182,8 @@ VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
|
||||||
LOG(("webrtc::CaptureDeviceType::Camera: Finished creating new device."));
|
LOG(("webrtc::CaptureDeviceType::Camera: Finished creating new device."));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case webrtc::CaptureDeviceType::Browser: {
|
// Window and Screen and Browser (tab) types are handled by DesktopCapture
|
||||||
mDeviceInfo.reset(webrtc::BrowserDeviceInfoImpl::CreateDeviceInfo());
|
case webrtc::CaptureDeviceType::Browser:
|
||||||
LOG((
|
|
||||||
"webrtc::CaptureDeviceType::Browser: Finished creating new device."));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Window and Screen types are handled by DesktopCapture
|
|
||||||
case webrtc::CaptureDeviceType::Window:
|
case webrtc::CaptureDeviceType::Window:
|
||||||
case webrtc::CaptureDeviceType::Screen: {
|
case webrtc::CaptureDeviceType::Screen: {
|
||||||
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)
|
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)
|
||||||
|
|
|
@ -45,6 +45,7 @@ if CONFIG['MOZ_WEBRTC']:
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'video_engine/desktop_capture_impl.cc',
|
'video_engine/desktop_capture_impl.cc',
|
||||||
'video_engine/platform_uithread.cc',
|
'video_engine/platform_uithread.cc',
|
||||||
|
'video_engine/tab_capturer.cc',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -299,6 +299,86 @@ int32_t WindowDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
|
||||||
return 0;
|
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(
|
VideoCaptureModule::DeviceInfo* DesktopCaptureImpl::CreateDeviceInfo(
|
||||||
const int32_t id, const CaptureDeviceType type) {
|
const int32_t id, const CaptureDeviceType type) {
|
||||||
if (type == CaptureDeviceType::Screen) {
|
if (type == CaptureDeviceType::Screen) {
|
||||||
|
@ -315,6 +395,14 @@ VideoCaptureModule::DeviceInfo* DesktopCaptureImpl::CreateDeviceInfo(
|
||||||
pWindowDeviceInfoImpl = NULL;
|
pWindowDeviceInfoImpl = NULL;
|
||||||
}
|
}
|
||||||
return pWindowDeviceInfoImpl;
|
return pWindowDeviceInfoImpl;
|
||||||
|
} else if (type == CaptureDeviceType::Browser) {
|
||||||
|
BrowserDeviceInfoImpl* pBrowserDeviceInfoImpl =
|
||||||
|
new BrowserDeviceInfoImpl(id);
|
||||||
|
if (!pBrowserDeviceInfoImpl || pBrowserDeviceInfoImpl->Init()) {
|
||||||
|
delete pBrowserDeviceInfoImpl;
|
||||||
|
pBrowserDeviceInfoImpl = NULL;
|
||||||
|
}
|
||||||
|
return pBrowserDeviceInfoImpl;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -364,8 +452,18 @@ int32_t DesktopCaptureImpl::Init() {
|
||||||
desktop_capturer_cursor_composer_ =
|
desktop_capturer_cursor_composer_ =
|
||||||
std::unique_ptr<DesktopAndCursorComposer>(new DesktopAndCursorComposer(
|
std::unique_ptr<DesktopAndCursorComposer>(new DesktopAndCursorComposer(
|
||||||
pWindowCapturer.release(), pMouseCursorMonitor));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +485,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId,
|
||||||
new rtc::PlatformUIThread(Run, this, "ScreenCaptureThread")),
|
new rtc::PlatformUIThread(Run, this, "ScreenCaptureThread")),
|
||||||
#else
|
#else
|
||||||
# if defined(WEBRTC_LINUX)
|
# if defined(WEBRTC_LINUX)
|
||||||
|
// We start the thread lazily for Linux
|
||||||
capturer_thread_(nullptr),
|
capturer_thread_(nullptr),
|
||||||
# else
|
# else
|
||||||
capturer_thread_(
|
capturer_thread_(
|
||||||
|
@ -394,8 +493,10 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId,
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
started_(false) {
|
started_(false) {
|
||||||
//-> TODO @@NG why is this crashing (seen on Linux)
|
#if !defined(WEBRTC_LINUX)
|
||||||
//-> capturer_thread_->SetPriority(rtc::kHighPriority);
|
// XXX this crashes due to an immediate IsRunning() check on Linux
|
||||||
|
capturer_thread_->SetPriority(rtc::kHighPriority);
|
||||||
|
#endif
|
||||||
_requestedCapability.width = kDefaultWidth;
|
_requestedCapability.width = kDefaultWidth;
|
||||||
_requestedCapability.height = kDefaultHeight;
|
_requestedCapability.height = kDefaultHeight;
|
||||||
_requestedCapability.maxFPS = 30;
|
_requestedCapability.maxFPS = 30;
|
||||||
|
@ -582,6 +683,8 @@ int32_t DesktopCaptureImpl::StartCapture(
|
||||||
if (!capturer_thread_) {
|
if (!capturer_thread_) {
|
||||||
capturer_thread_ = std::unique_ptr<rtc::PlatformThread>(
|
capturer_thread_ = std::unique_ptr<rtc::PlatformThread>(
|
||||||
new rtc::PlatformThread(Run, this, "ScreenCaptureThread"));
|
new rtc::PlatformThread(Run, this, "ScreenCaptureThread"));
|
||||||
|
// XXX this crashes due to an immediate IsRunning() check on Linux
|
||||||
|
// capturer_thread_->SetPriority(rtc::kHighPriority);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,41 @@ class WindowDeviceInfoImpl : public VideoCaptureModule::DeviceInfo {
|
||||||
std::unique_ptr<DesktopDeviceInfo> desktop_device_info_;
|
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.
|
// Reuses the video engine pipeline for screen sharing.
|
||||||
// As with video, DesktopCaptureImpl is a proxy for screen sharing
|
// As with video, DesktopCaptureImpl is a proxy for screen sharing
|
||||||
// and follows the video pipeline design
|
// 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
|
// 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
|
// and the capturer thread. It is created prior to the capturer thread
|
||||||
// starting and is destroyed after it is stopped.
|
// 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_;
|
std::unique_ptr<EventWrapper> time_event_;
|
||||||
#if defined(_WIN32)
|
#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 "CamerasChild.h"
|
||||||
#include "CSFLog.h"
|
#include "CSFLog.h"
|
||||||
#include "MediaEngineTabVideoSource.h"
|
|
||||||
#include "MediaEngineRemoteVideoSource.h"
|
#include "MediaEngineRemoteVideoSource.h"
|
||||||
#include "MediaEngineWebRTCAudio.h"
|
#include "MediaEngineWebRTCAudio.h"
|
||||||
#include "MediaManager.h"
|
#include "MediaManager.h"
|
||||||
|
@ -35,17 +34,9 @@ CubebDeviceEnumerator* GetEnumerator() {
|
||||||
|
|
||||||
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs& aPrefs)
|
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs& aPrefs)
|
||||||
: mDelayAgnostic(aPrefs.mDelayAgnostic),
|
: mDelayAgnostic(aPrefs.mDelayAgnostic),
|
||||||
mExtendedFilter(aPrefs.mExtendedFilter),
|
mExtendedFilter(aPrefs.mExtendedFilter) {
|
||||||
mHasTabVideoSource(false) {
|
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
nsCOMPtr<nsIComponentRegistrar> compMgr;
|
|
||||||
NS_GetComponentRegistrar(getter_AddRefs(compMgr));
|
|
||||||
if (compMgr) {
|
|
||||||
compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID,
|
|
||||||
&mHasTabVideoSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
GetChildAndCall(
|
GetChildAndCall(
|
||||||
&CamerasChild::ConnectDeviceListChangeListener<MediaEngineWebRTC>,
|
&CamerasChild::ConnectDeviceListChangeListener<MediaEngineWebRTC>,
|
||||||
&mCameraListChangeListener, AbstractThread::MainThread(), this,
|
&mCameraListChangeListener, AbstractThread::MainThread(), this,
|
||||||
|
@ -169,14 +160,6 @@ void MediaEngineWebRTC::EnumerateVideoDevices(
|
||||||
vSource, vSource->GetName(), NS_ConvertUTF8toUTF16(vSource->GetUUID()),
|
vSource, vSource->GetName(), NS_ConvertUTF8toUTF16(vSource->GetUUID()),
|
||||||
vSource->GetGroupId(), u""_ns));
|
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(
|
void MediaEngineWebRTC::EnumerateMicrophoneDevices(
|
||||||
|
@ -279,6 +262,7 @@ void MediaEngineWebRTC::EnumerateDevices(
|
||||||
// are still useful for testing.
|
// are still useful for testing.
|
||||||
EnumerateVideoDevices(aWindowId, camera::WinEngine, aDevices);
|
EnumerateVideoDevices(aWindowId, camera::WinEngine, aDevices);
|
||||||
EnumerateVideoDevices(aWindowId, camera::ScreenEngine, aDevices);
|
EnumerateVideoDevices(aWindowId, camera::ScreenEngine, aDevices);
|
||||||
|
EnumerateVideoDevices(aWindowId, camera::BrowserEngine, aDevices);
|
||||||
break;
|
break;
|
||||||
case dom::MediaSourceEnum::Screen:
|
case dom::MediaSourceEnum::Screen:
|
||||||
EnumerateVideoDevices(aWindowId, camera::ScreenEngine, aDevices);
|
EnumerateVideoDevices(aWindowId, camera::ScreenEngine, aDevices);
|
||||||
|
|
|
@ -227,7 +227,6 @@ class NormalizedConstraintSet {
|
||||||
StringRange mFacingMode;
|
StringRange mFacingMode;
|
||||||
StringRange mMediaSource;
|
StringRange mMediaSource;
|
||||||
LongLongRange mBrowserWindow;
|
LongLongRange mBrowserWindow;
|
||||||
BooleanRange mScrollWithPage;
|
|
||||||
StringRange mDeviceId;
|
StringRange mDeviceId;
|
||||||
StringRange mGroupId;
|
StringRange mGroupId;
|
||||||
LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
|
LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
|
||||||
|
@ -254,11 +253,6 @@ class NormalizedConstraintSet {
|
||||||
? aOther.mBrowserWindow.Value()
|
? aOther.mBrowserWindow.Value()
|
||||||
: 0,
|
: 0,
|
||||||
aList),
|
aList),
|
||||||
mScrollWithPage(&T::mScrollWithPage, "scrollWithPage",
|
|
||||||
aOther.mScrollWithPage.WasPassed()
|
|
||||||
? aOther.mScrollWithPage.Value()
|
|
||||||
: false,
|
|
||||||
aList),
|
|
||||||
mDeviceId(&T::mDeviceId, "deviceId", aOther.mDeviceId, advanced, aList),
|
mDeviceId(&T::mDeviceId, "deviceId", aOther.mDeviceId, advanced, aList),
|
||||||
mGroupId(&T::mGroupId, "groupId", aOther.mGroupId, advanced, aList),
|
mGroupId(&T::mGroupId, "groupId", aOther.mGroupId, advanced, aList),
|
||||||
mViewportOffsetX(&T::mViewportOffsetX, "viewportOffsetX",
|
mViewportOffsetX(&T::mViewportOffsetX, "viewportOffsetX",
|
||||||
|
|
|
@ -35,7 +35,6 @@ if CONFIG['MOZ_WEBRTC']:
|
||||||
EXPORTS.mozilla.dom += [ 'RTCIdentityProviderRegistrar.h' ]
|
EXPORTS.mozilla.dom += [ 'RTCIdentityProviderRegistrar.h' ]
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'MediaEngineRemoteVideoSource.cpp',
|
'MediaEngineRemoteVideoSource.cpp',
|
||||||
'MediaEngineTabVideoSource.cpp',
|
|
||||||
'MediaEngineWebRTCAudio.cpp',
|
'MediaEngineWebRTCAudio.cpp',
|
||||||
'RTCCertificate.cpp',
|
'RTCCertificate.cpp',
|
||||||
'RTCIdentityProviderRegistrar.cpp',
|
'RTCIdentityProviderRegistrar.cpp',
|
||||||
|
|
|
@ -60,6 +60,17 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
|
||||||
return capturer;
|
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)
|
#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
||||||
bool DesktopCapturer::IsRunningUnderWayland() {
|
bool DesktopCapturer::IsRunningUnderWayland() {
|
||||||
const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
|
const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
|
||||||
|
|
|
@ -139,6 +139,10 @@ class DesktopCapturer {
|
||||||
static std::unique_ptr<DesktopCapturer> CreateAppCapturer(
|
static std::unique_ptr<DesktopCapturer> CreateAppCapturer(
|
||||||
const DesktopCaptureOptions& options);
|
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)
|
#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
||||||
static bool IsRunningUnderWayland();
|
static bool IsRunningUnderWayland();
|
||||||
#endif // defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
#endif // defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
|
||||||
|
@ -161,6 +165,10 @@ class DesktopCapturer {
|
||||||
// capture apps.
|
// capture apps.
|
||||||
static std::unique_ptr<DesktopCapturer> CreateRawAppCapturer(
|
static std::unique_ptr<DesktopCapturer> CreateRawAppCapturer(
|
||||||
const DesktopCaptureOptions& options);
|
const DesktopCaptureOptions& options);
|
||||||
|
|
||||||
|
// Creates a DesktopCapturer instance which targets to capture tabs
|
||||||
|
static std::unique_ptr<DesktopCapturer> CreateRawTabCapturer(
|
||||||
|
const DesktopCaptureOptions& options);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
|
@ -170,6 +170,66 @@ DesktopApplication& DesktopApplication::operator= (DesktopApplication& other) {
|
||||||
return *this;
|
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() {
|
DesktopDeviceInfoImpl::DesktopDeviceInfoImpl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +243,7 @@ int32_t DesktopDeviceInfoImpl::getDisplayDeviceCount() {
|
||||||
|
|
||||||
int32_t DesktopDeviceInfoImpl::getDesktopDisplayDeviceInfo(int32_t nIndex,
|
int32_t DesktopDeviceInfoImpl::getDesktopDisplayDeviceInfo(int32_t nIndex,
|
||||||
DesktopDisplayDevice & desktopDisplayDevice) {
|
DesktopDisplayDevice & desktopDisplayDevice) {
|
||||||
if(nIndex < 0 || nIndex >= desktop_display_list_.size()) {
|
if(nIndex < 0 || (size_t) nIndex >= desktop_display_list_.size()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +262,7 @@ int32_t DesktopDeviceInfoImpl::getWindowCount() {
|
||||||
}
|
}
|
||||||
int32_t DesktopDeviceInfoImpl::getWindowInfo(int32_t nIndex,
|
int32_t DesktopDeviceInfoImpl::getWindowInfo(int32_t nIndex,
|
||||||
DesktopDisplayDevice &windowDevice) {
|
DesktopDisplayDevice &windowDevice) {
|
||||||
if (nIndex < 0 || nIndex >= desktop_window_list_.size()) {
|
if (nIndex < 0 || (size_t) nIndex >= desktop_window_list_.size()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +283,7 @@ int32_t DesktopDeviceInfoImpl::getApplicationCount() {
|
||||||
|
|
||||||
int32_t DesktopDeviceInfoImpl::getApplicationInfo(int32_t nIndex,
|
int32_t DesktopDeviceInfoImpl::getApplicationInfo(int32_t nIndex,
|
||||||
DesktopApplication & desktopApplication) {
|
DesktopApplication & desktopApplication) {
|
||||||
if(nIndex < 0 || nIndex >= desktop_application_list_.size()) {
|
if(nIndex < 0 || (size_t) nIndex >= desktop_application_list_.size()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,15 +297,37 @@ int32_t DesktopDeviceInfoImpl::getApplicationInfo(int32_t nIndex,
|
||||||
return 0;
|
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() {
|
void DesktopDeviceInfoImpl::CleanUp() {
|
||||||
CleanUpScreenList();
|
CleanUpScreenList();
|
||||||
CleanUpWindowList();
|
CleanUpWindowList();
|
||||||
CleanUpApplicationList();
|
CleanUpApplicationList();
|
||||||
|
CleanUpTabList();
|
||||||
}
|
}
|
||||||
int32_t DesktopDeviceInfoImpl::Init() {
|
int32_t DesktopDeviceInfoImpl::Init() {
|
||||||
InitializeScreenList();
|
InitializeScreenList();
|
||||||
InitializeWindowList();
|
InitializeWindowList();
|
||||||
InitializeApplicationList();
|
InitializeApplicationList();
|
||||||
|
InitializeTabList();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -253,6 +335,7 @@ int32_t DesktopDeviceInfoImpl::Refresh() {
|
||||||
RefreshScreenList();
|
RefreshScreenList();
|
||||||
RefreshWindowList();
|
RefreshWindowList();
|
||||||
RefreshApplicationList();
|
RefreshApplicationList();
|
||||||
|
RefreshTabList();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -311,6 +394,31 @@ void DesktopDeviceInfoImpl::RefreshApplicationList() {
|
||||||
InitializeApplicationList();
|
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() {
|
void DesktopDeviceInfoImpl::CleanUpScreenList() {
|
||||||
std::map<intptr_t,DesktopDisplayDevice*>::iterator iterDevice;
|
std::map<intptr_t,DesktopDisplayDevice*>::iterator iterDevice;
|
||||||
for (iterDevice=desktop_display_list_.begin(); iterDevice != desktop_display_list_.end(); iterDevice++){
|
for (iterDevice=desktop_display_list_.begin(); iterDevice != desktop_display_list_.end(); iterDevice++){
|
||||||
|
@ -319,9 +427,11 @@ void DesktopDeviceInfoImpl::CleanUpScreenList() {
|
||||||
iterDevice->second = NULL;
|
iterDevice->second = NULL;
|
||||||
}
|
}
|
||||||
desktop_display_list_.clear();
|
desktop_display_list_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopDeviceInfoImpl::RefreshScreenList() {
|
void DesktopDeviceInfoImpl::RefreshScreenList() {
|
||||||
CleanUpScreenList();
|
CleanUpScreenList();
|
||||||
InitializeScreenList();
|
InitializeScreenList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,32 @@ protected:
|
||||||
|
|
||||||
typedef std::map<intptr_t, DesktopApplication*> DesktopApplicationList;
|
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 {
|
class DesktopDeviceInfo {
|
||||||
public:
|
public:
|
||||||
virtual ~DesktopDeviceInfo() {};
|
virtual ~DesktopDeviceInfo() {};
|
||||||
|
@ -80,6 +106,9 @@ public:
|
||||||
virtual int32_t getApplicationCount() = 0;
|
virtual int32_t getApplicationCount() = 0;
|
||||||
virtual int32_t getApplicationInfo(int32_t nIndex,
|
virtual int32_t getApplicationInfo(int32_t nIndex,
|
||||||
DesktopApplication & desktopApplication) = 0;
|
DesktopApplication & desktopApplication) = 0;
|
||||||
|
virtual int32_t getTabCount() = 0;
|
||||||
|
virtual int32_t getTabInfo(int32_t nIndex,
|
||||||
|
DesktopTab & desktopTab) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DesktopDeviceInfoImpl : public DesktopDeviceInfo {
|
class DesktopDeviceInfoImpl : public DesktopDeviceInfo {
|
||||||
|
@ -87,37 +116,46 @@ public:
|
||||||
DesktopDeviceInfoImpl();
|
DesktopDeviceInfoImpl();
|
||||||
~DesktopDeviceInfoImpl();
|
~DesktopDeviceInfoImpl();
|
||||||
|
|
||||||
virtual int32_t Init();
|
int32_t Init() override;
|
||||||
virtual int32_t Refresh();
|
int32_t Refresh() override;
|
||||||
virtual int32_t getDisplayDeviceCount();
|
int32_t getDisplayDeviceCount() override;
|
||||||
virtual int32_t getDesktopDisplayDeviceInfo(int32_t nIndex,
|
int32_t getDesktopDisplayDeviceInfo(int32_t nIndex,
|
||||||
DesktopDisplayDevice & desktopDisplayDevice);
|
DesktopDisplayDevice & desktopDisplayDevice) override;
|
||||||
virtual int32_t getWindowCount();
|
int32_t getWindowCount() override;
|
||||||
virtual int32_t getWindowInfo(int32_t nindex,
|
int32_t getWindowInfo(int32_t nindex,
|
||||||
DesktopDisplayDevice &windowDevice);
|
DesktopDisplayDevice &windowDevice) override;
|
||||||
virtual int32_t getApplicationCount();
|
int32_t getApplicationCount() override;
|
||||||
virtual int32_t getApplicationInfo(int32_t nIndex,
|
int32_t getApplicationInfo(int32_t nIndex,
|
||||||
DesktopApplication & desktopApplication);
|
DesktopApplication & desktopApplication) override;
|
||||||
|
int32_t getTabCount() override;
|
||||||
|
int32_t getTabInfo(int32_t nIndex,
|
||||||
|
DesktopTab & desktopTab) override;
|
||||||
static DesktopDeviceInfo * Create();
|
static DesktopDeviceInfo * Create();
|
||||||
protected:
|
protected:
|
||||||
DesktopDisplayDeviceList desktop_display_list_;
|
DesktopDisplayDeviceList desktop_display_list_;
|
||||||
DesktopDisplayDeviceList desktop_window_list_;
|
DesktopDisplayDeviceList desktop_window_list_;
|
||||||
DesktopApplicationList desktop_application_list_;
|
DesktopApplicationList desktop_application_list_;
|
||||||
|
DesktopTabList desktop_tab_list_;
|
||||||
|
|
||||||
void CleanUp();
|
void CleanUp();
|
||||||
void CleanUpWindowList();
|
void CleanUpWindowList();
|
||||||
void CleanUpApplicationList();
|
void CleanUpApplicationList();
|
||||||
|
void CleanUpTabList();
|
||||||
void CleanUpScreenList();
|
void CleanUpScreenList();
|
||||||
|
|
||||||
void InitializeWindowList();
|
void InitializeWindowList();
|
||||||
virtual void InitializeApplicationList() = 0;
|
virtual void InitializeApplicationList() = 0;
|
||||||
|
virtual void InitializeTabList() {
|
||||||
|
DummyTabList(desktop_tab_list_);
|
||||||
|
}
|
||||||
virtual void InitializeScreenList() = 0;
|
virtual void InitializeScreenList() = 0;
|
||||||
|
|
||||||
void RefreshWindowList();
|
void RefreshWindowList();
|
||||||
void RefreshApplicationList();
|
void RefreshApplicationList();
|
||||||
|
void RefreshTabList();
|
||||||
void RefreshScreenList();
|
void RefreshScreenList();
|
||||||
|
|
||||||
|
void DummyTabList(DesktopTabList &list);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void InitializeScreenList();
|
virtual void InitializeScreenList();
|
||||||
virtual void InitializeApplicationList();
|
virtual void InitializeApplicationList();
|
||||||
|
virtual void InitializeTabList();
|
||||||
};
|
};
|
||||||
|
|
||||||
DesktopDeviceInfo * DesktopDeviceInfoImpl::Create() {
|
DesktopDeviceInfo * DesktopDeviceInfoImpl::Create() {
|
||||||
|
|
|
@ -133,5 +133,4 @@ void DesktopDeviceInfoX11::InitializeApplicationList() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} //namespace webrtc
|
} //namespace webrtc
|
||||||
|
|
Загрузка…
Ссылка в новой задаче