Skip to content

Commit

Permalink
Implement basic screen-sharing for lacros.
Browse files Browse the repository at this point in the history
This CL creates a new mojo interface: ScreenManager. This interface has
a single method TakeScreenSnapshot which returns a bitmap of the
screen's contents. Lacros-chrome uses this interface to implement a
rudimentary version of screen-sharing. This in turn allows
meet.google.com screen sharing to function properly.

This interface will eventually be supplemented with methods to allow
window-sharing as well. The whole interface will likely be overhauled in
the future to create a more performant and fully-featured version of
screen/window sharing.

Change-Id: I821c59464ea4d2ff57665381038837f29645750d
Bug: 1094460
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2261430
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Ken Rockot <rockot@google.com>
Reviewed-by: James Cook <jamescook@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Auto-Submit: Erik Chen <erikchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#786507}
  • Loading branch information
erikchen authored and Commit Bot committed Jul 8, 2020
1 parent 630c7ae commit 438f054
Show file tree
Hide file tree
Showing 25 changed files with 563 additions and 2 deletions.
3 changes: 3 additions & 0 deletions chrome/browser/chromeos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ source_set("chromeos") {
"//chromeos/dbus/upstart",
"//chromeos/disks",
"//chromeos/geolocation",
"//chromeos/lacros/cpp",
"//chromeos/lacros/mojom",
"//chromeos/login/auth",
"//chromeos/login/login_state",
Expand Down Expand Up @@ -1365,6 +1366,8 @@ source_set("chromeos") {
"lacros/lacros_manager.h",
"lacros/lacros_util.cc",
"lacros/lacros_util.h",
"lacros/screen_manager_crosapi.cc",
"lacros/screen_manager_crosapi.h",
"lacros/select_file_impl.cc",
"lacros/select_file_impl.h",
"language_preferences.cc",
Expand Down
4 changes: 4 additions & 0 deletions chrome/browser/chromeos/lacros/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ specific_include_rules = {
# For window parenting.
"+ash/shell.h",
],
"screen_manager_crosapi\.cc": [
# For window parenting.
"+ash/shell.h",
],
}
10 changes: 9 additions & 1 deletion chrome/browser/chromeos/lacros/ash_chrome_service_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
#include <utility>

#include "base/logging.h"
#include "chrome/browser/chromeos/lacros/screen_manager_crosapi.h"
#include "chrome/browser/chromeos/lacros/select_file_impl.h"
#include "chromeos/lacros/mojom/screen_manager.mojom.h"
#include "chromeos/lacros/mojom/select_file.mojom.h"

AshChromeServiceImpl::AshChromeServiceImpl(
mojo::PendingReceiver<lacros::mojom::AshChromeService> pending_receiver)
: receiver_(this, std::move(pending_receiver)) {
: receiver_(this, std::move(pending_receiver)),
screen_manager_crosapi_(std::make_unique<ScreenManagerCrosapi>()) {
// TODO(hidehiko): Remove non-critical log from here.
// Currently this is the signal that the connection is established.
LOG(WARNING) << "AshChromeService connected.";
Expand All @@ -24,3 +27,8 @@ void AshChromeServiceImpl::BindSelectFile(
mojo::PendingReceiver<lacros::mojom::SelectFile> receiver) {
select_file_impl_ = std::make_unique<SelectFileImpl>(std::move(receiver));
}

void AshChromeServiceImpl::BindScreenManager(
mojo::PendingReceiver<lacros::mojom::ScreenManager> receiver) {
screen_manager_crosapi_->BindReceiver(std::move(receiver));
}
5 changes: 5 additions & 0 deletions chrome/browser/chromeos/lacros/ash_chrome_service_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"

class ScreenManagerCrosapi;

class SelectFileImpl;

// Implementation of AshChromeService. It provides a set of APIs that
Expand All @@ -22,12 +24,15 @@ class AshChromeServiceImpl : public lacros::mojom::AshChromeService {
~AshChromeServiceImpl() override;

// lacros::mojom::AshChromeService:
void BindScreenManager(
mojo::PendingReceiver<lacros::mojom::ScreenManager> receiver) override;
void BindSelectFile(
mojo::PendingReceiver<lacros::mojom::SelectFile> receiver) override;

private:
mojo::Receiver<lacros::mojom::AshChromeService> receiver_;

std::unique_ptr<ScreenManagerCrosapi> screen_manager_crosapi_;
std::unique_ptr<SelectFileImpl> select_file_impl_;
};

Expand Down
58 changes: 58 additions & 0 deletions chrome/browser/chromeos/lacros/screen_manager_crosapi.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2020 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 "chrome/browser/chromeos/lacros/screen_manager_crosapi.h"

#include <utility>
#include <vector>

#include "ash/shell.h"
#include "base/files/file_path.h"
#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "chromeos/lacros/cpp/window_snapshot.h"
#include "ui/snapshot/snapshot.h"

ScreenManagerCrosapi::ScreenManagerCrosapi() = default;

ScreenManagerCrosapi::~ScreenManagerCrosapi() = default;

void ScreenManagerCrosapi::BindReceiver(
mojo::PendingReceiver<lacros::mojom::ScreenManager> receiver) {
receivers_.Add(this, std::move(receiver));
}

void ScreenManagerCrosapi::TakeScreenSnapshot(
TakeScreenSnapshotCallback callback) {
// TODO(https://crbug.com/1094460): Handle display selection and multiple
// displays.
aura::Window* primary_window = ash::Shell::GetPrimaryRootWindow();

ui::GrabWindowSnapshotAsync(
primary_window, primary_window->bounds(),
base::BindOnce(&ScreenManagerCrosapi::DidTakeScreenSnapshot,
weak_factory_.GetWeakPtr(), std::move(callback)));
}

void ScreenManagerCrosapi::DidTakeScreenSnapshot(
TakeScreenSnapshotCallback callback,
gfx::Image image) {
SkBitmap bitmap = image.AsBitmap();

// This code currently relies on the assumption that the bitmap is unpadded,
// and uses 4 bytes per pixel.
int size;
size = base::CheckMul(bitmap.width(), bitmap.height()).ValueOrDie();
size = base::CheckMul(size, 4).ValueOrDie();
CHECK_EQ(bitmap.computeByteSize(), base::checked_cast<size_t>(size));

uint8_t* base = static_cast<uint8_t*>(bitmap.getPixels());
std::vector<uint8_t> bytes(base, base + bitmap.computeByteSize());

lacros::WindowSnapshot snapshot;
snapshot.width = bitmap.width();
snapshot.height = bitmap.height();
snapshot.bitmap.swap(bytes);
std::move(callback).Run(std::move(snapshot));
}
41 changes: 41 additions & 0 deletions chrome/browser/chromeos/lacros/screen_manager_crosapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2020 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.

#ifndef CHROME_BROWSER_CHROMEOS_LACROS_SCREEN_MANAGER_CROSAPI_H_
#define CHROME_BROWSER_CHROMEOS_LACROS_SCREEN_MANAGER_CROSAPI_H_

#include "base/memory/weak_ptr.h"
#include "chromeos/lacros/mojom/screen_manager.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/gfx/image/image.h"

// This class is the ash-chrome implementation of the ScreenManager interface.
// This class must only be used from the main thread.
class ScreenManagerCrosapi : public lacros::mojom::ScreenManager {
public:
ScreenManagerCrosapi();
ScreenManagerCrosapi(const ScreenManagerCrosapi&) = delete;
ScreenManagerCrosapi& operator=(const ScreenManagerCrosapi&) = delete;
~ScreenManagerCrosapi() override;

void BindReceiver(
mojo::PendingReceiver<lacros::mojom::ScreenManager> receiver);

// lacros::mojom::ScreenManager:
void TakeScreenSnapshot(TakeScreenSnapshotCallback callback) override;

private:
void DidTakeScreenSnapshot(TakeScreenSnapshotCallback callback,
gfx::Image image);

// This class supports any number of connections. This allows the client to
// have multiple, potentially thread-affine, remotes. This is needed by
// WebRTC.
mojo::ReceiverSet<lacros::mojom::ScreenManager> receivers_;

base::WeakPtrFactory<ScreenManagerCrosapi> weak_factory_{this};
};

#endif // CHROME_BROWSER_CHROMEOS_LACROS_SCREEN_MANAGER_CROSAPI_H_
1 change: 1 addition & 0 deletions chrome/browser/media/webrtc/window_icon_util_ozone.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "ui/aura/client/aura_constants.h"

gfx::ImageSkia GetWindowIcon(content::DesktopMediaID id) {
// TODO(https://crbug.com/1094460): Hook up Window Icons for lacros.
DCHECK_EQ(content::DesktopMediaID::TYPE_WINDOW, id.type);
// TODO(tonikitoo): can we make the implementation of
// chrome/browser/media/webrtc/window_icon_util_chromeos.cc generic
Expand Down
5 changes: 5 additions & 0 deletions chromeos/lacros/browser/lacros_chrome_service_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ void LacrosChromeServiceImpl::BindReceiver(
receiver_.Bind(std::move(receiver));
}

void LacrosChromeServiceImpl::BindScreenManagerReceiver(
mojo::PendingReceiver<lacros::mojom::ScreenManager> pending_receiver) {
ash_chrome_service_->BindScreenManager(std::move(pending_receiver));
}

void LacrosChromeServiceImpl::RequestAshChromeServiceReceiver(
RequestAshChromeServiceReceiverCallback callback) {
// TODO(hidehiko): Remove non-error logging from here.
Expand Down
5 changes: 5 additions & 0 deletions chromeos/lacros/browser/lacros_chrome_service_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "base/component_export.h"
#include "chromeos/lacros/mojom/lacros.mojom.h"
#include "chromeos/lacros/mojom/screen_manager.mojom.h"
#include "chromeos/lacros/mojom/select_file.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
Expand All @@ -16,6 +17,7 @@ namespace chromeos {

// Implements LacrosChromeService, which owns the mojo remote connection to
// ash-chrome.
// This class is not thread safe. It can only be used on the main thread.
class COMPONENT_EXPORT(CHROMEOS_LACROS) LacrosChromeServiceImpl
: public lacros::mojom::LacrosChromeService {
public:
Expand All @@ -31,6 +33,9 @@ class COMPONENT_EXPORT(CHROMEOS_LACROS) LacrosChromeServiceImpl
return select_file_remote_;
}

void BindScreenManagerReceiver(
mojo::PendingReceiver<lacros::mojom::ScreenManager> pending_receiver);

// lacros::mojom::LacrosChromeService:
void RequestAshChromeServiceReceiver(
RequestAshChromeServiceReceiverCallback callback) override;
Expand Down
18 changes: 18 additions & 0 deletions chromeos/lacros/cpp/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2020 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.

# C++ components used by both lacros-chrome and ash-chrome.
config("lacros_implementation") {
defines = [ "IS_LACROS_IMPL" ]
}

component("cpp") {
output_name = "lacros_public_cpp"
sources = [
"window_snapshot.cc",
"window_snapshot.h",
]
configs += [ ":lacros_implementation" ]
deps = [ "//base" ]
}
12 changes: 12 additions & 0 deletions chromeos/lacros/cpp/window_snapshot.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2020 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 "chromeos/lacros/cpp/window_snapshot.h"

namespace lacros {

WindowSnapshot::WindowSnapshot() = default;
WindowSnapshot::~WindowSnapshot() = default;

} // namespace lacros
28 changes: 28 additions & 0 deletions chromeos/lacros/cpp/window_snapshot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2020 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.

#ifndef CHROMEOS_LACROS_CPP_WINDOW_SNAPSHOT_H_
#define CHROMEOS_LACROS_CPP_WINDOW_SNAPSHOT_H_

#include <stdint.h>

#include <vector>

#include "base/component_export.h"

namespace lacros {

// bitmap is a 4-byte RGBA bitmap representation of the window. Its size must
// be exactly equal to width * height * 4.
struct COMPONENT_EXPORT(LACROS) WindowSnapshot {
WindowSnapshot();
~WindowSnapshot();
uint32_t width = 0;
uint32_t height = 0;
std::vector<uint8_t> bitmap;
};

} // namespace lacros

#endif // CHROMEOS_LACROS_CPP_WINDOW_SNAPSHOT_H_
35 changes: 35 additions & 0 deletions chromeos/lacros/mojom/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,43 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
sources = [
"lacros.mojom",
"screen_manager.mojom",
"select_file.mojom",
]

cpp_typemaps = [
{
types = [
{
mojom = "lacros.mojom.WindowSnapshot"
cpp = "lacros::WindowSnapshot"
},
]
traits_headers =
[ "//chromeos/lacros/mojom/window_snapshot_mojom_traits.h" ]
traits_public_deps = [
":mojom_traits",
"//chromeos/lacros/cpp",
]
},
]

public_deps = [ "//mojo/public/mojom/base" ]
}

component("mojom_traits") {
output_name = "lacros_mojom_traits"

sources = [
"window_snapshot_mojom_traits.cc",
"window_snapshot_mojom_traits.h",
]

defines = [ "IS_LACROS_MOJOM_TRAITS_IMPL" ]

public_deps = [
":mojom_shared",
"//chromeos/lacros/cpp",
"//mojo/public/cpp/base:shared_typemap_traits",
]
}
5 changes: 4 additions & 1 deletion chromeos/lacros/mojom/OWNERS
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS

# Prefer Chrome OS owners for large changes to the Lacros API.
per-file *.mojom=file://chromeos/SECURITY_OWNERS

per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.mojom_traits*.*=file://chromeos/SECURITY_OWNERS
5 changes: 5 additions & 0 deletions chromeos/lacros/mojom/lacros.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@

module lacros.mojom;

import "chromeos/lacros/mojom/screen_manager.mojom";
import "chromeos/lacros/mojom/select_file.mojom";

// AshChromeService defines the APIs that live in ash-chrome and are
// accessed from lacros-chrome.
interface AshChromeService {
// Binds the ScreenManager interface for interacting with windows, screens and
// displays.
BindScreenManager@1(pending_receiver<ScreenManager> receiver);

// Binds the SelectFile interface for open/save dialogs.
BindSelectFile@0(pending_receiver<SelectFile> receiver);
};
Expand Down
41 changes: 41 additions & 0 deletions chromeos/lacros/mojom/screen_manager.mojom
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2020 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.

module lacros.mojom;

// A bitmap representation of the current contents of a window or screen. Each
// pixel is represented by 4 bytes [RGBA].
struct WindowSnapshot {
uint32 width;
uint32 height;
array<uint8> bitmap;
};

// This interface is implemented by ash-chrome. It allows lacros-chrome to query
// information about existing windows, screens, and displays.
//
// This interface cannot be used to make changes to screens, windows or
// displays. That's because Wayland is the protocol for that, and attempting to
// introduce another protocol would require careful synchronization between the
// two, which we'd like to avoid.
//
// TODO(https://crbug.com/1094460): This is a very simple interface. We will
// likely want to replace it with a more feature-complete and performant
// interface in the future.
interface ScreenManager {
// TODO(https://crbug.com/1094460): We will need to add more methods for
// querying screens, windows, etc. Details still TBD.

// TODO(https://crbug.com/1094460): Use a more performant transport
// mechanism.
// This method assumes that there's exactly one screen. The implementation
// of this method takes a screenshot and converts it into a bitmap. Each
// pixel is represented by 4 bytes [RGBA].
//
// The media screen capture implementation assumes that every platform
// provides a synchronous method to take a snapshot of the screen.
[Sync]
TakeScreenSnapshot@0() => (WindowSnapshot snapshot);
};

Loading

0 comments on commit 438f054

Please sign in to comment.