blob: 3aa5e5f85f2a1fe7e2afe964f09b18f163636383 [file] [log] [blame]
// Copyright 2015 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 "remoting/host/desktop_capturer_proxy.h"
#include <stddef.h>
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "remoting/host/client_session_control.h"
#include "remoting/proto/control.pb.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer_differ_wrapper.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
#if defined(OS_CHROMEOS)
#include "remoting/host/chromeos/aura_desktop_capturer.h"
#endif
namespace remoting {
class DesktopCapturerProxy::Core : public webrtc::DesktopCapturer::Callback {
public:
explicit Core(base::WeakPtr<DesktopCapturerProxy> proxy);
~Core() override;
void set_capturer(std::unique_ptr<webrtc::DesktopCapturer> capturer) {
DCHECK(!capturer_);
capturer_ = std::move(capturer);
}
void CreateCapturer(const webrtc::DesktopCaptureOptions& options);
void Start();
void SetSharedMemoryFactory(
std::unique_ptr<webrtc::SharedMemoryFactory> shared_memory_factory);
void SelectSource(SourceId id);
void CaptureFrame();
private:
// webrtc::DesktopCapturer::Callback implementation.
void OnCaptureResult(webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> frame) override;
base::ThreadChecker thread_checker_;
base::WeakPtr<DesktopCapturerProxy> proxy_;
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
std::unique_ptr<webrtc::DesktopCapturer> capturer_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
DesktopCapturerProxy::Core::Core(base::WeakPtr<DesktopCapturerProxy> proxy)
: proxy_(proxy), caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
thread_checker_.DetachFromThread();
}
DesktopCapturerProxy::Core::~Core() {
DCHECK(thread_checker_.CalledOnValidThread());
}
void DesktopCapturerProxy::Core::CreateCapturer(
const webrtc::DesktopCaptureOptions& options) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!capturer_);
#if defined(OS_CHROMEOS)
capturer_ = std::make_unique<webrtc::DesktopCapturerDifferWrapper>(
std::make_unique<AuraDesktopCapturer>());
#else // !defined(OS_CHROMEOS)
capturer_ = webrtc::DesktopCapturer::CreateScreenCapturer(options);
#endif // !defined(OS_CHROMEOS)
if (!capturer_)
LOG(ERROR) << "Failed to initialize screen capturer.";
}
void DesktopCapturerProxy::Core::Start() {
DCHECK(thread_checker_.CalledOnValidThread());
if (capturer_)
capturer_->Start(this);
}
void DesktopCapturerProxy::Core::SetSharedMemoryFactory(
std::unique_ptr<webrtc::SharedMemoryFactory> shared_memory_factory) {
DCHECK(thread_checker_.CalledOnValidThread());
if (capturer_) {
capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
}
}
void DesktopCapturerProxy::Core::SelectSource(SourceId id) {
DCHECK(thread_checker_.CalledOnValidThread());
if (capturer_) {
capturer_->SelectSource(id);
}
}
void DesktopCapturerProxy::Core::CaptureFrame() {
DCHECK(thread_checker_.CalledOnValidThread());
if (capturer_) {
capturer_->CaptureFrame();
} else {
OnCaptureResult(webrtc::DesktopCapturer::Result::ERROR_PERMANENT, nullptr);
}
}
void DesktopCapturerProxy::Core::OnCaptureResult(
webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> frame) {
DCHECK(thread_checker_.CalledOnValidThread());
caller_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DesktopCapturerProxy::OnFrameCaptured, proxy_,
result, std::move(frame)));
}
DesktopCapturerProxy::DesktopCapturerProxy(
scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner,
base::WeakPtr<ClientSessionControl> client_session_control)
: capture_task_runner_(capture_task_runner),
client_session_control_(client_session_control),
desktop_display_info_(new DesktopDisplayInfo()),
weak_factory_(this) {
core_.reset(new Core(weak_factory_.GetWeakPtr()));
}
DesktopCapturerProxy::~DesktopCapturerProxy() {
capture_task_runner_->DeleteSoon(FROM_HERE, core_.release());
}
void DesktopCapturerProxy::CreateCapturer(
const webrtc::DesktopCaptureOptions& options) {
DCHECK(thread_checker_.CalledOnValidThread());
capture_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&Core::CreateCapturer,
base::Unretained(core_.get()), options));
}
void DesktopCapturerProxy::set_capturer(
std::unique_ptr<webrtc::DesktopCapturer> capturer) {
core_->set_capturer(std::move(capturer));
}
void DesktopCapturerProxy::Start(Callback* callback) {
DCHECK(thread_checker_.CalledOnValidThread());
callback_ = callback;
capture_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&Core::Start, base::Unretained(core_.get())));
}
void DesktopCapturerProxy::SetSharedMemoryFactory(
std::unique_ptr<webrtc::SharedMemoryFactory> shared_memory_factory) {
DCHECK(thread_checker_.CalledOnValidThread());
capture_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&Core::SetSharedMemoryFactory, base::Unretained(core_.get()),
base::Passed(base::WrapUnique(shared_memory_factory.release()))));
}
void DesktopCapturerProxy::CaptureFrame() {
DCHECK(thread_checker_.CalledOnValidThread());
// Start() must be called before Capture().
DCHECK(callback_);
capture_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&Core::CaptureFrame, base::Unretained(core_.get())));
}
bool DesktopCapturerProxy::GetSourceList(SourceList* sources) {
NOTIMPLEMENTED();
return false;
}
bool DesktopCapturerProxy::SelectSource(SourceId id_index) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(desktop_display_info_);
SourceId id = -1;
if (id_index >= 0 && id_index < desktop_display_info_->NumDisplays()) {
DisplayGeometry display = desktop_display_info_->displays()[id_index];
id = display.id;
}
capture_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&Core::SelectSource, base::Unretained(core_.get()), id));
return false;
}
void DesktopCapturerProxy::OnFrameCaptured(
webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> frame) {
DCHECK(thread_checker_.CalledOnValidThread());
callback_->OnCaptureResult(result, std::move(frame));
if (client_session_control_) {
auto info = std::make_unique<DesktopDisplayInfo>();
info->LoadCurrentDisplayInfo();
if (*desktop_display_info_ != *info) {
desktop_display_info_ = std::move(info);
auto layout = std::make_unique<protocol::VideoLayout>();
for (auto display : desktop_display_info_->displays()) {
protocol::VideoTrackLayout* track = layout->add_video_track();
track->set_position_x(display.x);
track->set_position_y(display.y);
track->set_width(display.width);
track->set_height(display.height);
track->set_x_dpi(display.dpi);
track->set_y_dpi(display.dpi);
}
client_session_control_->OnDesktopDisplayChanged(std::move(layout));
}
}
}
} // namespace remoting