diff --git a/dom/media/systemservices/VideoEngine.cpp b/dom/media/systemservices/VideoEngine.cpp index 08fd6c441132..20243ae9504b 100644 --- a/dom/media/systemservices/VideoEngine.cpp +++ b/dom/media/systemservices/VideoEngine.cpp @@ -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) diff --git a/dom/media/systemservices/moz.build b/dom/media/systemservices/moz.build index b0b9256cad0a..d9db028092c3 100644 --- a/dom/media/systemservices/moz.build +++ b/dom/media/systemservices/moz.build @@ -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', ] diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc index 6fdb72a8ec50..d3183d3db64c 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc @@ -299,6 +299,86 @@ int32_t WindowDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, return 0; } +int32_t BrowserDeviceInfoImpl::Init() { + desktop_device_info_ = + std::unique_ptr(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(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( new rtc::PlatformThread(Run, this, "ScreenCaptureThread")); + // XXX this crashes due to an immediate IsRunning() check on Linux + // capturer_thread_->SetPriority(rtc::kHighPriority); } #endif diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h index 4270926fbb83..d11ae63a636b 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.h +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h @@ -149,6 +149,41 @@ class WindowDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { std::unique_ptr 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 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 desktop_capturer_cursor_composer_; + std::unique_ptr desktop_capturer_cursor_composer_; std::unique_ptr time_event_; #if defined(_WIN32) diff --git a/dom/media/systemservices/video_engine/tab_capturer.cc b/dom/media/systemservices/video_engine/tab_capturer.cc new file mode 100644 index 000000000000..4676b66b0b59 --- /dev/null +++ b/dom/media/systemservices/video_engine/tab_capturer.cc @@ -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 +#include +#include + +#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 chromeWindow = + nsContentUtils::GetMostRecentNonPBWindow(); + if (!chromeWindow) { + return NS_ERROR_FAILURE; + } + nsCOMPtr docShell = chromeWindow->GetDocShell(); + if (!docShell) { + return NS_ERROR_FAILURE; + } + nsCOMPtr owner; + docShell->GetTreeOwner(getter_AddRefs(owner)); + if (!owner) { + return NS_ERROR_FAILURE; + } + nsCOMPtr primaryRemoteTab; + owner->GetPrimaryRemoteTab(getter_AddRefs(primaryRemoteTab)); + if (!primaryRemoteTab) { + return NS_ERROR_FAILURE; + } + RefPtr 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 handler = new TabCapturedHandler(aEngine); + aPromise->AppendNativeHandler(handler); + } + + void ResolvedCallback(JSContext* aCx, JS::Handle aValue) override { + MOZ_ASSERT(NS_IsMainThread()); + MonitorAutoLock monitor(mEngine->mMonitor); + if (NS_WARN_IF(!aValue.isObject())) { + monitor.Notify(); + return; + } + + RefPtr 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 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 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 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 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 data = aBitmap->ToCloneData(); + webrtc::DesktopSize size(data->mPictureRect.Width(), + data->mPictureRect.Height()); + webrtc::DesktopRect rect = webrtc::DesktopRect::MakeSize(size); + std::unique_ptr 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::CreateRawTabCapturer( + const webrtc::DesktopCaptureOptions& options) { + return std::unique_ptr( + new mozilla::TabCapturerWebrtc(options)); +} +} // namespace webrtc diff --git a/dom/media/systemservices/video_engine/tab_capturer.h b/dom/media/systemservices/video_engine/tab_capturer.h new file mode 100644 index 000000000000..571383986e77 --- /dev/null +++ b/dom/media/systemservices/video_engine/tab_capturer.h @@ -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 +#include + +#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 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 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 mInternal; +}; + +} // namespace mozilla + +#endif // MODULES_DESKTOP_CAPTURE_TAB_CAPTURER_H_ diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.cpp b/dom/media/webrtc/MediaEngineTabVideoSource.cpp deleted file mode 100644 index 9e8cf069a0fe..000000000000 --- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp +++ /dev/null @@ -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>()) {} - -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 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(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(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 viewportOffsetX; - Maybe viewportOffsetY; - Maybe viewportWidth; - Maybe 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(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& 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; - if (mWindow) { - nsIDocShell* docshell = mWindow->GetDocShell(); - if (docshell) { - presShell = docshell->GetPresShell(); - } - if (!presShell) { - return; - } - } - - if (!mImageContainer) { - mImageContainer = layers::LayerManager::CreateImageContainer( - layers::ImageContainer::ASYNCHRONOUS); - } - - RefPtr 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 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 dt = texture->BorrowDrawTarget(); - if (!dt || !dt->IsValid()) { - NS_WARNING("Failed to borrow DrawTarget"); - return; - } - - if (mWindow) { - RefPtr 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 diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.h b/dom/media/webrtc/MediaEngineTabVideoSource.h deleted file mode 100644 index ea948859558e..000000000000 --- a/dom/media/webrtc/MediaEngineTabVideoSource.h +++ /dev/null @@ -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& 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 mVideoSource; - const RefPtr mTrack; - const PrincipalHandle mPrincipal; - }; - - class StopRunnable : public Runnable { - public: - explicit StopRunnable(MediaEngineTabVideoSource* videoSource) - : Runnable("MediaEngineTabVideoSource::StopRunnable"), - mVideoSource(videoSource) {} - NS_IMETHOD Run() override; - const RefPtr mVideoSource; - }; - - class DestroyRunnable : public Runnable { - public: - explicit DestroyRunnable(MediaEngineTabVideoSource* videoSource) - : Runnable("MediaEngineTabVideoSource::DestroyRunnable"), - mVideoSource(videoSource) {} - NS_IMETHOD Run() override; - const RefPtr 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 mImageContainer; - // The current settings of this source. - // Members are main thread only. - const RefPtr> mSettings; - - // Main thread only. - nsCOMPtr mWindow; - nsCOMPtr mTimer; - nsCOMPtr mTabSource; - RefPtr 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 mTrack; - PrincipalHandle mPrincipalHandle = PRINCIPAL_HANDLE_NONE; -}; - -} // namespace mozilla diff --git a/dom/media/webrtc/MediaEngineWebRTC.cpp b/dom/media/webrtc/MediaEngineWebRTC.cpp index acea12efe3f0..54d23f6473c5 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.cpp +++ b/dom/media/webrtc/MediaEngineWebRTC.cpp @@ -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 compMgr; - NS_GetComponentRegistrar(getter_AddRefs(compMgr)); - if (compMgr) { - compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, - &mHasTabVideoSource); - } - GetChildAndCall( &CamerasChild::ConnectDeviceListChangeListener, &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 tabVideoSource = new MediaEngineTabVideoSource(); - aDevices->AppendElement(MakeRefPtr( - 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); diff --git a/dom/media/webrtc/MediaTrackConstraints.h b/dom/media/webrtc/MediaTrackConstraints.h index a9cad508bac9..9a8e313be1c9 100644 --- a/dom/media/webrtc/MediaTrackConstraints.h +++ b/dom/media/webrtc/MediaTrackConstraints.h @@ -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", diff --git a/dom/media/webrtc/moz.build b/dom/media/webrtc/moz.build index de96d41a0614..a58a558728f9 100644 --- a/dom/media/webrtc/moz.build +++ b/dom/media/webrtc/moz.build @@ -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', diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc index d43d571a86fb..ebfced94d778 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc @@ -60,6 +60,17 @@ std::unique_ptr DesktopCapturer::CreateScreenCapturer( return capturer; } +// static +std::unique_ptr DesktopCapturer::CreateTabCapturer( + const DesktopCaptureOptions& options) { + std::unique_ptr 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"); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h index 76d399eca8ad..461e8fd53d5e 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h @@ -139,6 +139,10 @@ class DesktopCapturer { static std::unique_ptr CreateAppCapturer( const DesktopCaptureOptions& options); + // Creates a DesktopCapturer instance which targets to capture tab. + static std::unique_ptr 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 CreateRawAppCapturer( const DesktopCaptureOptions& options); + + // Creates a DesktopCapturer instance which targets to capture tabs + static std::unique_ptr CreateRawTabCapturer( + const DesktopCaptureOptions& options); }; } // namespace webrtc diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc index 0a7222c7b91a..1df38f28f022 100755 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc @@ -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::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::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(); } } + diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.h b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.h index 6a16c15a1981..65fc23eecf9c 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.h +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.h @@ -65,6 +65,32 @@ protected: typedef std::map 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 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); }; }; diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info_null.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info_null.cc index 3b0dc03a6c64..20a35689281b 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info_null.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info_null.cc @@ -14,6 +14,7 @@ public: protected: virtual void InitializeScreenList(); virtual void InitializeApplicationList(); + virtual void InitializeTabList(); }; DesktopDeviceInfo * DesktopDeviceInfoImpl::Create() { diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/linux/desktop_device_info_x11.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/linux/desktop_device_info_x11.cc index b95a8b8b89b6..0c967193d296 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/linux/desktop_device_info_x11.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/linux/desktop_device_info_x11.cc @@ -133,5 +133,4 @@ void DesktopDeviceInfoX11::InitializeApplicationList() { } } } - } //namespace webrtc