blob: 43214709387b09fcd9321ea466f84cda2d3540e3 [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 "ui/display/chromeos/apply_content_protection_task.h"
#include "ui/display/chromeos/display_layout_manager.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_delegate.h"
namespace ui {
namespace {
bool GetHDCPCapableDisplays(
const DisplayLayoutManager& layout_manager,
std::vector<DisplaySnapshot*>* hdcp_capable_displays) {
for (DisplaySnapshot* display : layout_manager.GetDisplayStates()) {
switch (display->type()) {
case DISPLAY_CONNECTION_TYPE_UNKNOWN:
return false;
// DisplayPort, DVI, and HDMI all support HDCP.
case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
case DISPLAY_CONNECTION_TYPE_DVI:
case DISPLAY_CONNECTION_TYPE_HDMI:
hdcp_capable_displays->push_back(display);
break;
case DISPLAY_CONNECTION_TYPE_INTERNAL:
case DISPLAY_CONNECTION_TYPE_VGA:
case DISPLAY_CONNECTION_TYPE_NETWORK:
case DISPLAY_CONNECTION_TYPE_VIRTUAL:
// No protections for these types. Do nothing.
break;
case DISPLAY_CONNECTION_TYPE_NONE:
NOTREACHED();
break;
}
}
return true;
}
} // namespace
ApplyContentProtectionTask::ApplyContentProtectionTask(
DisplayLayoutManager* layout_manager,
NativeDisplayDelegate* native_display_delegate,
const DisplayConfigurator::ContentProtections& requests,
const ResponseCallback& callback)
: layout_manager_(layout_manager),
native_display_delegate_(native_display_delegate),
requests_(requests),
callback_(callback),
query_status_(true),
pending_requests_(0),
weak_ptr_factory_(this) {
}
ApplyContentProtectionTask::~ApplyContentProtectionTask() {
}
void ApplyContentProtectionTask::Run() {
std::vector<DisplaySnapshot*> hdcp_capable_displays;
if (!GetHDCPCapableDisplays(*layout_manager_, &hdcp_capable_displays)) {
callback_.Run(false);
return;
}
pending_requests_ = hdcp_capable_displays.size();
if (pending_requests_ == 0) {
callback_.Run(true);
return;
}
// Need to poll the driver for updates since other applications may have
// updated the state.
for (DisplaySnapshot* display : hdcp_capable_displays) {
native_display_delegate_->GetHDCPState(
*display,
base::Bind(&ApplyContentProtectionTask::OnHDCPStateUpdate,
weak_ptr_factory_.GetWeakPtr(), display->display_id()));
}
}
void ApplyContentProtectionTask::OnHDCPStateUpdate(int64_t display_id,
bool success,
HDCPState state) {
query_status_ &= success;
display_hdcp_state_map_[display_id] = state;
pending_requests_--;
// Wait for all the requests before continuing.
if (pending_requests_ != 0)
return;
if (!query_status_) {
callback_.Run(false);
return;
}
ApplyProtections();
}
void ApplyContentProtectionTask::ApplyProtections() {
std::vector<DisplaySnapshot*> hdcp_capable_displays;
if (!GetHDCPCapableDisplays(*layout_manager_, &hdcp_capable_displays)) {
callback_.Run(false);
return;
}
std::vector<std::pair<DisplaySnapshot*, HDCPState>> hdcp_requests;
// Figure out which displays need to have their HDCP state changed.
for (DisplaySnapshot* display : hdcp_capable_displays) {
uint32_t desired_mask = GetDesiredProtectionMask(display->display_id());
auto it = display_hdcp_state_map_.find(display->display_id());
// If the display can't be found, the display configuration changed.
if (it == display_hdcp_state_map_.end()) {
callback_.Run(false);
return;
}
bool hdcp_enabled = it->second != HDCP_STATE_UNDESIRED;
bool hdcp_requested = desired_mask & CONTENT_PROTECTION_METHOD_HDCP;
if (hdcp_enabled != hdcp_requested) {
hdcp_requests.push_back(std::make_pair(
display, hdcp_requested ? HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED));
}
}
pending_requests_ = hdcp_requests.size();
// All the requested changes are the same as the current HDCP state. Nothing
// to do anymore, just ack the content protection change.
if (pending_requests_ == 0) {
callback_.Run(true);
return;
}
for (const auto& pair : hdcp_requests) {
native_display_delegate_->SetHDCPState(
*pair.first, pair.second,
base::Bind(&ApplyContentProtectionTask::OnHDCPStateApplied,
weak_ptr_factory_.GetWeakPtr()));
}
}
void ApplyContentProtectionTask::OnHDCPStateApplied(bool success) {
query_status_ &= success;
pending_requests_--;
if (pending_requests_ == 0)
callback_.Run(query_status_);
}
uint32_t ApplyContentProtectionTask::GetDesiredProtectionMask(
int64_t display_id) const {
uint32_t desired_mask = 0;
// In mirror mode, protection request of all displays need to be fulfilled.
// In non-mirror mode, only request of client's display needs to be
// fulfilled.
if (layout_manager_->IsMirroring()) {
for (auto pair : requests_)
desired_mask |= pair.second;
} else {
auto it = requests_.find(display_id);
if (it != requests_.end())
desired_mask = it->second;
}
return desired_mask;
}
} // namespace ui