blob: 202e849c408bcf851dc218d7f0ab5bbd52385c36 [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 "chrome/browser/extensions/api/tab_capture/offscreen_tabs_owner.h"
#include <algorithm>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/stl_util.h"
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/process_manager.h"
using content::WebContents;
namespace {
// Upper limit on the number of simultaneous off-screen tabs per extension
// instance.
const int kMaxOffscreenTabsPerExtension = 4;
} // namespace
namespace extensions {
OffscreenTabsOwner::OffscreenTabsOwner(WebContents* extension_web_contents)
: extension_web_contents_(extension_web_contents) {
DCHECK(extension_web_contents_);
}
OffscreenTabsOwner::~OffscreenTabsOwner() {}
// static
OffscreenTabsOwner* OffscreenTabsOwner::Get(
content::WebContents* extension_web_contents) {
// CreateForWebContents() really means "create if not exists."
CreateForWebContents(extension_web_contents);
return FromWebContents(extension_web_contents);
}
OffscreenTab* OffscreenTabsOwner::OpenNewTab(
const GURL& start_url,
const gfx::Size& initial_size,
const std::string& optional_presentation_id) {
if (tabs_.size() >= kMaxOffscreenTabsPerExtension)
return nullptr; // Maximum number of offscreen tabs reached.
tabs_.emplace_back(std::make_unique<OffscreenTab>(
this, extension_web_contents_->GetBrowserContext()));
tabs_.back()->Start(start_url, initial_size, optional_presentation_id);
return tabs_.back().get();
}
void OffscreenTabsOwner::RequestMediaAccessPermission(
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) {
// This method is being called to check whether an extension is permitted to
// capture the page. Verify that the request is being made by the extension
// that spawned this OffscreenTab.
// Find the extension ID associated with the extension background page's
// WebContents.
content::BrowserContext* const extension_browser_context =
extension_web_contents_->GetBrowserContext();
const extensions::Extension* const extension =
ProcessManager::Get(extension_browser_context)
->GetExtensionForWebContents(extension_web_contents_);
const std::string extension_id = extension ? extension->id() : "";
LOG_IF(DFATAL, extension_id.empty())
<< "Extension that started this OffscreenTab was not found.";
// If verified, allow any tab capture audio/video devices that were requested.
extensions::TabCaptureRegistry* const tab_capture_registry =
extensions::TabCaptureRegistry::Get(extension_browser_context);
content::MediaStreamDevices devices;
if (tab_capture_registry &&
tab_capture_registry->VerifyRequest(
request.render_process_id, request.render_frame_id, extension_id)) {
if (request.audio_type == content::MEDIA_GUM_TAB_AUDIO_CAPTURE) {
devices.push_back(content::MediaStreamDevice(
content::MEDIA_GUM_TAB_AUDIO_CAPTURE, std::string(), std::string()));
}
if (request.video_type == content::MEDIA_GUM_TAB_VIDEO_CAPTURE) {
devices.push_back(content::MediaStreamDevice(
content::MEDIA_GUM_TAB_VIDEO_CAPTURE, std::string(), std::string()));
}
}
DVLOG(2) << "Allowing " << devices.size()
<< " capture devices for OffscreenTab content.";
std::move(callback).Run(devices,
devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE
: content::MEDIA_DEVICE_OK,
nullptr);
}
void OffscreenTabsOwner::DestroyTab(OffscreenTab* tab) {
for (std::vector<std::unique_ptr<OffscreenTab>>::iterator iter =
tabs_.begin();
iter != tabs_.end(); ++iter) {
if (iter->get() == tab) {
tabs_.erase(iter);
break;
}
}
}
} // namespace extensions