blob: cce6a7d8609dab21f2dd1b8c9afd392495e89415 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/media/capture/aura_window_video_capture_device.h"
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
#include "media/base/bind_to_current_loop.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#if defined(OS_CHROMEOS)
#include "content/browser/media/capture/lame_window_capturer_chromeos.h"
#endif
namespace content {
// Threading note: This is constructed on the device thread, while the
// destructor and the rest of the class will run exclusively on the UI thread.
class AuraWindowVideoCaptureDevice::WindowTracker
: public aura::WindowObserver,
public base::SupportsWeakPtr<
AuraWindowVideoCaptureDevice::WindowTracker> {
public:
WindowTracker(base::WeakPtr<AuraWindowVideoCaptureDevice> device,
MouseCursorOverlayController* cursor_controller,
const DesktopMediaID& source_id)
: device_(std::move(device)),
device_task_runner_(base::ThreadTaskRunnerHandle::Get()),
cursor_controller_(cursor_controller),
target_type_(source_id.type) {
DCHECK(device_task_runner_);
DCHECK(cursor_controller_);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&WindowTracker::ResolveTarget, AsWeakPtr(), source_id));
}
~WindowTracker() final {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (target_window_) {
target_window_->RemoveObserver(this);
}
}
DesktopMediaID::Type target_type() const { return target_type_; }
aura::Window* target_window() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return target_window_;
}
private:
// Determines which frame sink and aura::Window should be targeted for capture
// and notifies the device.
void ResolveTarget(const DesktopMediaID& source_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Since ResolveTarget() should only ever be called once, expect
// |target_window_| to be null at this point.
DCHECK(!target_window_);
target_window_ = DesktopMediaID::GetAuraWindowById(source_id);
if (target_window_ &&
#if defined(OS_CHROMEOS)
// See class comments for LameWindowCapturerChromeOS.
(source_id.type == DesktopMediaID::TYPE_WINDOW ||
target_window_->GetFrameSinkId().is_valid()) &&
#else
target_window_->GetFrameSinkId().is_valid() &&
#endif
true) {
target_window_->AddObserver(this);
device_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&FrameSinkVideoCaptureDevice::OnTargetChanged, device_,
target_window_->GetFrameSinkId()));
// Note: The MouseCursorOverlayController runs on the UI thread. It's also
// important that SetTargetView() be called in the current stack while
// |target_window_| is known to be a valid pointer.
// http://crbug.com/818679
cursor_controller_->SetTargetView(target_window_);
} else {
device_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&FrameSinkVideoCaptureDevice::OnTargetPermanentlyLost,
device_));
}
}
// aura::WindowObserver override.
void OnWindowDestroying(aura::Window* window) final {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(window, target_window_);
target_window_->RemoveObserver(this);
target_window_ = nullptr;
device_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&FrameSinkVideoCaptureDevice::OnTargetPermanentlyLost,
device_));
cursor_controller_->SetTargetView(gfx::NativeView());
}
private:
// |device_| may be dereferenced only by tasks run by |device_task_runner_|.
const base::WeakPtr<FrameSinkVideoCaptureDevice> device_;
const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
// Owned by FrameSinkVideoCaptureDevice. This will be valid for the life of
// WindowTracker because the WindowTracker deleter task will be posted to the
// UI thread before the MouseCursorOverlayController deleter task.
MouseCursorOverlayController* const cursor_controller_;
const DesktopMediaID::Type target_type_;
aura::Window* target_window_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(WindowTracker);
};
AuraWindowVideoCaptureDevice::AuraWindowVideoCaptureDevice(
const DesktopMediaID& source_id)
: tracker_(new WindowTracker(AsWeakPtr(), cursor_controller(), source_id)) {
}
AuraWindowVideoCaptureDevice::~AuraWindowVideoCaptureDevice() = default;
#if defined(OS_CHROMEOS)
void AuraWindowVideoCaptureDevice::CreateCapturer(
viz::mojom::FrameSinkVideoCapturerRequest request) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(
[](base::WeakPtr<WindowTracker> tracker_ptr,
viz::mojom::FrameSinkVideoCapturerRequest request) {
WindowTracker* const tracker = tracker_ptr.get();
if (!tracker) {
// WindowTracker was destroyed in the meantime, due to early
// shutdown.
return;
}
if (tracker->target_type() == DesktopMediaID::TYPE_WINDOW) {
VLOG(1) << "AuraWindowVideoCaptureDevice is using the LAME "
"capturer. :(";
mojo::StrongBinding<viz::mojom::FrameSinkVideoCapturer>::Create(
std::make_unique<LameWindowCapturerChromeOS>(
tracker->target_window()),
std::move(request));
} else {
VLOG(1) << "AuraWindowVideoCaptureDevice is using the frame "
"sink capturer. :)";
CreateCapturerViaGlobalManager(std::move(request));
}
},
tracker_->AsWeakPtr(), std::move(request)));
}
#endif
} // namespace content