| // 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 |