Skip to content

Commit

Permalink
Add AshDesktopMediaList and enable Desktop Capture API on Chrome OS.
Browse files Browse the repository at this point in the history
The new AshDesktopMediaList gets list of windows/screens for the window
picker dialog which allows to enable Desktop Capture API on Chrome OS.

BUG=295102
R=ben@chromium.org, hshi@chromium.org

Review URL: https://codereview.chromium.org/100833002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242361 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
sergeyu@chromium.org committed Dec 23, 2013
1 parent ad780b7 commit ce2807a
Show file tree
Hide file tree
Showing 17 changed files with 615 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
#include "base/compiler_specific.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/media/desktop_media_list_ash.h"
#include "chrome/browser/media/desktop_streams_registry.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/native_desktop_media_list.h"
#include "chrome/browser/ui/ash/ash_util.h"
#include "chrome/common/extensions/api/tabs.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
Expand Down Expand Up @@ -163,19 +165,29 @@ bool DesktopCaptureChooseDesktopMediaFunction::RunImpl() {
show_screens, show_windows);
picker_ = g_picker_factory->CreatePicker();
} else {
#if defined(USE_ASH)
if (chrome::IsNativeWindowInAsh(parent_window)) {
media_list.reset(new DesktopMediaListAsh(
(show_screens ? DesktopMediaListAsh::SCREENS : 0) |
(show_windows ? DesktopMediaListAsh::WINDOWS : 0)));
} else
#endif
{
webrtc::DesktopCaptureOptions options =
webrtc::DesktopCaptureOptions::CreateDefault();
options.set_disable_effects(false);
scoped_ptr<webrtc::ScreenCapturer> screen_capturer(
show_screens ? webrtc::ScreenCapturer::Create(options) : NULL);
scoped_ptr<webrtc::WindowCapturer> window_capturer(
show_windows ? webrtc::WindowCapturer::Create(options) : NULL);

media_list.reset(new NativeDesktopMediaList(
screen_capturer.Pass(), window_capturer.Pass()));
}

// DesktopMediaPicker is implemented only for Windows, OSX and
// Aura Linux builds.
#if (defined(TOOLKIT_VIEWS) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
webrtc::DesktopCaptureOptions options =
webrtc::DesktopCaptureOptions::CreateDefault();
options.set_disable_effects(false);
scoped_ptr<webrtc::ScreenCapturer> screen_capturer(
show_screens ? webrtc::ScreenCapturer::Create(options) : NULL);
scoped_ptr<webrtc::WindowCapturer> window_capturer(
show_windows ? webrtc::WindowCapturer::Create(options) : NULL);

media_list.reset(new NativeDesktopMediaList(
screen_capturer.Pass(), window_capturer.Pass()));
#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
picker_ = DesktopMediaPicker::Create();
#else
error_ = "Desktop Capture API is not yet implemented for this platform.";
Expand Down
215 changes: 215 additions & 0 deletions chrome/browser/media/desktop_media_list_ash.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// Copyright 2013 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/media/desktop_media_list_ash.h"

#include <map>

#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "base/hash.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/media/desktop_media_list_observer.h"
#include "content/public/browser/browser_thread.h"
#include "grit/generated_resources.h"
#include "media/base/video_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/dip_util.h"
#include "ui/gfx/image/image.h"
#include "ui/snapshot/snapshot.h"

using content::BrowserThread;
using content::DesktopMediaID;

namespace {

// Update the list twice per second.
const int kDefaultUpdatePeriod = 500;

} // namespace

DesktopMediaListAsh::SourceDescription::SourceDescription(
DesktopMediaID id,
const base::string16& name)
: id(id),
name(name) {
}

DesktopMediaListAsh::DesktopMediaListAsh(int source_types)
: source_types_(source_types),
update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
thumbnail_size_(100, 100),
view_dialog_id_(-1),
observer_(NULL),
pending_window_capture_requests_(0),
weak_factory_(this) {
}

DesktopMediaListAsh::~DesktopMediaListAsh() {}

void DesktopMediaListAsh::SetUpdatePeriod(base::TimeDelta period) {
DCHECK(!observer_);
update_period_ = period;
}

void DesktopMediaListAsh::SetThumbnailSize(
const gfx::Size& thumbnail_size) {
thumbnail_size_ = thumbnail_size;
}

void DesktopMediaListAsh::SetViewDialogWindowId(
content::DesktopMediaID::Id dialog_id) {
view_dialog_id_ = dialog_id;
}

void DesktopMediaListAsh::StartUpdating(DesktopMediaListObserver* observer) {
DCHECK(!observer_);

observer_ = observer;
Refresh();
}

int DesktopMediaListAsh::GetSourceCount() const {
return sources_.size();
}

const DesktopMediaList::Source& DesktopMediaListAsh::GetSource(
int index) const {
return sources_[index];
}

// static
bool DesktopMediaListAsh::CompareSources(const SourceDescription& a,
const SourceDescription& b) {
return a.id < b.id;
}

void DesktopMediaListAsh::Refresh() {
std::vector<SourceDescription> new_sources;
EnumerateSources(&new_sources);

// Sort the list of sources so that they appear in a predictable order.
std::sort(new_sources.begin(), new_sources.end(), CompareSources);

// Step through |new_sources| adding and removing entries from |sources_|, and
// notifying the |observer_|, until two match. Requires that |sources| and
// |sources_| have the same ordering.
size_t pos = 0;
while (pos < sources_.size() || pos < new_sources.size()) {
// If |sources_[pos]| is not in |new_sources| then remove it.
if (pos < sources_.size() &&
(pos == new_sources.size() || sources_[pos].id < new_sources[pos].id)) {
sources_.erase(sources_.begin() + pos);
observer_->OnSourceRemoved(pos);
continue;
}

if (pos == sources_.size() || !(sources_[pos].id == new_sources[pos].id)) {
sources_.insert(sources_.begin() + pos, Source());
sources_[pos].id = new_sources[pos].id;
sources_[pos].name = new_sources[pos].name;
observer_->OnSourceAdded(pos);
} else if (sources_[pos].name != new_sources[pos].name) {
sources_[pos].name = new_sources[pos].name;
observer_->OnSourceNameChanged(pos);
}

++pos;
}

DCHECK_EQ(new_sources.size(), sources_.size());
}

void DesktopMediaListAsh::EnumerateWindowsForRoot(
std::vector<DesktopMediaListAsh::SourceDescription>* sources,
aura::Window* root_window,
int container_id) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

aura::Window* container = ash::Shell::GetContainer(root_window, container_id);
if (!container)
return;
for (aura::Window::Windows::const_iterator it = container->children().begin();
it != container->children().end(); ++it) {
if (!(*it)->IsVisible() || !(*it)->CanFocus())
continue;
content::DesktopMediaID id =
content::DesktopMediaID::RegisterAuraWindow(*it);
if (id.id == view_dialog_id_)
continue;
SourceDescription window_source(id, (*it)->title());
sources->push_back(window_source);

CaptureThumbnail(window_source.id, *it);
}
}

void DesktopMediaListAsh::EnumerateSources(
std::vector<DesktopMediaListAsh::SourceDescription>* sources) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();

for (aura::Window::Windows::const_iterator iter = root_windows.begin();
iter != root_windows.end(); ++iter) {
if (source_types_ & SCREENS) {
SourceDescription screen_source(
content::DesktopMediaID::RegisterAuraWindow(*iter), (*iter)->title());
sources->push_back(screen_source);

CaptureThumbnail(screen_source.id, *iter);
}

if (source_types_ & WINDOWS) {
EnumerateWindowsForRoot(
sources, *iter, ash::internal::kShellWindowId_DefaultContainer);
EnumerateWindowsForRoot(
sources, *iter, ash::internal::kShellWindowId_AlwaysOnTopContainer);
EnumerateWindowsForRoot(
sources, *iter, ash::internal::kShellWindowId_DockedContainer);
}
}
}

void DesktopMediaListAsh::CaptureThumbnail(content::DesktopMediaID id,
aura::Window* window) {
gfx::Rect window_rect(window->bounds().width(), window->bounds().height());
gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
gfx::Rect(thumbnail_size_), window_rect.size());

++pending_window_capture_requests_;
ui::GrapWindowSnapshotAsync(
window, window_rect,
scaled_rect.size(),
BrowserThread::GetBlockingPool(),
base::Bind(&DesktopMediaListAsh::OnThumbnailCaptured,
weak_factory_.GetWeakPtr(),
id));
}

void DesktopMediaListAsh::OnThumbnailCaptured(content::DesktopMediaID id,
const gfx::Image& image) {
for (size_t i = 0; i < sources_.size(); ++i) {
if (sources_[i].id == id) {
sources_[i].thumbnail = image.AsImageSkia();
observer_->OnSourceThumbnailChanged(i);
break;
}
}

--pending_window_capture_requests_;
DCHECK_GE(pending_window_capture_requests_, 0);

if (!pending_window_capture_requests_) {
// Once we've finished capturing all windows post a task for the next list
// update.
BrowserThread::PostDelayedTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&DesktopMediaListAsh::Refresh,
weak_factory_.GetWeakPtr()),
update_period_);
}
}
99 changes: 99 additions & 0 deletions chrome/browser/media/desktop_media_list_ash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2013 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_MEDIA_DESKTOP_MEDIA_LIST_ASH_H_
#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_ASH_H_

#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "chrome/browser/media/desktop_media_list.h"
#include "content/public/browser/desktop_media_id.h"

class SkBitmap;

namespace aura {
class Window;
}

namespace cc {
class CopyOutputResult;
class SingleReleaseCallback;
}

namespace gfx {
class Image;
}

// Implementation of DesktopMediaList that shows native screens and
// native windows.
class DesktopMediaListAsh : public DesktopMediaList {
public:
enum SourceTypes {
SCREENS = 1,
WINDOWS = 2,
};

explicit DesktopMediaListAsh(int source_types);
virtual ~DesktopMediaListAsh();

// DesktopMediaList interface.
virtual void SetUpdatePeriod(base::TimeDelta period) OVERRIDE;
virtual void SetThumbnailSize(const gfx::Size& thumbnail_size) OVERRIDE;
virtual void StartUpdating(DesktopMediaListObserver* observer) OVERRIDE;
virtual int GetSourceCount() const OVERRIDE;
virtual const Source& GetSource(int index) const OVERRIDE;
virtual void SetViewDialogWindowId(
content::DesktopMediaID::Id dialog_id) OVERRIDE;

private:
// Struct used to represent sources list the model gets from the Worker.
struct SourceDescription {
SourceDescription(content::DesktopMediaID id, const base::string16& name);

content::DesktopMediaID id;
base::string16 name;
};

// Order comparator for sources. Used to sort list of sources.
static bool CompareSources(const SourceDescription& a,
const SourceDescription& b);

void Refresh();
void EnumerateWindowsForRoot(
std::vector<DesktopMediaListAsh::SourceDescription>* windows,
aura::Window* root_window,
int container_id);
void EnumerateSources(
std::vector<DesktopMediaListAsh::SourceDescription>* windows);
void CaptureThumbnail(content::DesktopMediaID id, aura::Window* window);
void OnThumbnailCaptured(content::DesktopMediaID id,
const gfx::Image& image);

int source_types_;

// Time interval between mode updates.
base::TimeDelta update_period_;

// Size of thumbnails generated by the model.
gfx::Size thumbnail_size_;

// ID of the hosting dialog.
content::DesktopMediaID::Id view_dialog_id_;

// The observer passed to StartUpdating().
DesktopMediaListObserver* observer_;

// Current list of sources.
std::vector<Source> sources_;

int pending_window_capture_requests_;

base::WeakPtrFactory<DesktopMediaListAsh> weak_factory_;

DISALLOW_COPY_AND_ASSIGN(DesktopMediaListAsh);
};

#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_ASH_H_
Loading

0 comments on commit ce2807a

Please sign in to comment.