Initial import of Widevine Common Encryption DRM engine
Builds libwvmdrmengine.so, which is loaded by the new MediaDrm APIs to support playback of Widevine/CENC protected content. Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
This commit is contained in:
211
libwvdrmengine/cdm/core/src/policy_engine.cpp
Normal file
211
libwvdrmengine/cdm/core/src/policy_engine.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "policy_engine.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "log.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
PolicyEngine::PolicyEngine() :
|
||||
license_state_(kLicenseStateInitial),
|
||||
license_start_time_(0),
|
||||
next_renewal_time_(0),
|
||||
policy_max_duration_seconds_(0) {
|
||||
}
|
||||
|
||||
PolicyEngine::~PolicyEngine() {
|
||||
}
|
||||
|
||||
void PolicyEngine::OnTimerEvent(int64_t current_time, bool event_occured, CdmEventType& event) {
|
||||
event_occured = false;
|
||||
|
||||
// License expiration trumps all.
|
||||
if (IsLicenseDurationExpired(current_time) &&
|
||||
license_state_ != kLicenseStateExpired) {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
event = LICENSE_EXPIRED_EVENT;
|
||||
event_occured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Test to determine if renewal should be attempted.
|
||||
switch (license_state_) {
|
||||
case kLicenseStateCanPlay: {
|
||||
if (IsRenewalDelayExpired(current_time)) {
|
||||
license_state_ = kLicenseStateNeedRenewal;
|
||||
UpdateRenewalRequest(current_time);
|
||||
event = LICENSE_RENEWAL_NEEDED_EVENT;
|
||||
event_occured = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case kLicenseStateNeedRenewal: {
|
||||
UpdateRenewalRequest(current_time);
|
||||
event = LICENSE_RENEWAL_NEEDED_EVENT;
|
||||
event_occured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
case kLicenseStateWaitingLicenseUpdate: {
|
||||
if (IsRenewalRetryIntervalExpired(current_time)) {
|
||||
UpdateRenewalRequest(current_time);
|
||||
event = LICENSE_RENEWAL_NEEDED_EVENT;
|
||||
event_occured = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case kLicenseStateInitial:
|
||||
case kLicenseStateExpired: {
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
license_state_ = kLicenseStateCannotPlay;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fix up differences between Eureka and other platforms' use cases.
|
||||
// Eureka does not get calls to decrypt. license usage begins
|
||||
// when we receive the initial license. renew_with_usage will cause renewal to
|
||||
// occur on the first call to OnTimeEvent after PolicyEngine::SetLicense is
|
||||
// called.
|
||||
void PolicyEngine::SetLicense(
|
||||
const video_widevine_server::sdk::License& license) {
|
||||
license_id_.Clear();
|
||||
license_id_.CopyFrom(license.id());
|
||||
policy_.Clear();
|
||||
UpdateLicense(license);
|
||||
}
|
||||
|
||||
void PolicyEngine::UpdateLicense(
|
||||
const video_widevine_server::sdk::License& license) {
|
||||
if (!license.has_policy() || kLicenseStateExpired == license_state_)
|
||||
return;
|
||||
|
||||
policy_.MergeFrom(license.policy());
|
||||
policy_max_duration_seconds_ = 0;
|
||||
|
||||
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
|
||||
// will be set to the minimum of the following policies :
|
||||
// rental_duration_seconds, playback_duration_seconds, and
|
||||
// license_duration_seconds. The value is used to determine
|
||||
// when the license expires.
|
||||
if (policy_.has_rental_duration_seconds())
|
||||
policy_max_duration_seconds_ = policy_.rental_duration_seconds();
|
||||
|
||||
if ((policy_.has_playback_duration_seconds() &&
|
||||
(policy_.playback_duration_seconds() < policy_max_duration_seconds_)) ||
|
||||
!policy_max_duration_seconds_) {
|
||||
policy_max_duration_seconds_ = policy_.playback_duration_seconds();
|
||||
}
|
||||
|
||||
if ((policy_.has_license_duration_seconds() &&
|
||||
(policy_.license_duration_seconds() < policy_max_duration_seconds_)) ||
|
||||
!policy_max_duration_seconds_) {
|
||||
policy_max_duration_seconds_ = policy_.license_duration_seconds();
|
||||
}
|
||||
|
||||
switch (license_state_) {
|
||||
case kLicenseStateInitial: {
|
||||
// Process initial license.
|
||||
license_start_time_ = license.license_start_time();
|
||||
if (policy_.can_play()) {
|
||||
license_state_ =
|
||||
policy_.renew_with_usage() ?
|
||||
kLicenseStateNeedRenewal : kLicenseStateCanPlay;
|
||||
} else {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
}
|
||||
next_renewal_time_ = license_start_time_
|
||||
+ policy_.renewal_delay_seconds();
|
||||
}
|
||||
break;
|
||||
|
||||
case kLicenseStateExpired:
|
||||
// Ignore policy updates.
|
||||
return;
|
||||
|
||||
default: {
|
||||
// Process license renewal.
|
||||
if (license.id().version() > license_id_.version()) {
|
||||
// This is the normal case.
|
||||
policy_.MergeFrom(license.policy());
|
||||
license_id_.CopyFrom(license.id());
|
||||
} else {
|
||||
// This isn't supposed to happen.
|
||||
// TODO(jfore): Handle wrap? We can miss responses and that should be
|
||||
// considered normal until retries are exhausted.
|
||||
policy_.set_can_play(false);
|
||||
}
|
||||
|
||||
if (license.has_license_start_time()) {
|
||||
// license start has been updated. Transition back to the
|
||||
// normal kLicenseStateCanPlay state if playback is allowed by
|
||||
// the updated license.
|
||||
license_start_time_ = license.license_start_time();
|
||||
next_renewal_time_ = license_start_time_
|
||||
+ policy_.renewal_delay_seconds();
|
||||
license_state_ =
|
||||
policy_.can_play() ? kLicenseStateCanPlay : kLicenseStateExpired;
|
||||
} else {
|
||||
// license start was not updated. Continue sending renewel requests
|
||||
// at the specified retry rate. To perform this we transition directly
|
||||
// to kLicenseStateWaitingLicenseUpdate. While in this state
|
||||
// IsRenewalRetryIntervalExpired will always return false if retries are
|
||||
// not allowed. Note that next_renewal_time_ was updated when this
|
||||
// renewal was requested.
|
||||
license_state_ =
|
||||
policy_.can_play() ?
|
||||
kLicenseStateWaitingLicenseUpdate : kLicenseStateExpired;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyEngine::UpdateRenewalRequest(int64_t current_time) {
|
||||
license_state_ = kLicenseStateWaitingLicenseUpdate;
|
||||
next_renewal_time_ = current_time + policy_.renewal_retry_interval_seconds();
|
||||
}
|
||||
|
||||
// For the policy time fields checked in the following methods, a value of 0
|
||||
// indicates that there is no limit to the duration. These methods
|
||||
// will always return false if the value is 0.
|
||||
bool PolicyEngine::IsLicenseDurationExpired(int64_t current_time) {
|
||||
return policy_max_duration_seconds_ &&
|
||||
license_start_time_ + policy_max_duration_seconds_ <=
|
||||
current_time;
|
||||
}
|
||||
|
||||
bool PolicyEngine::IsRenewalDelayExpired(int64_t current_time) {
|
||||
return (policy_.renewal_delay_seconds() > 0) &&
|
||||
license_start_time_ + policy_.renewal_delay_seconds() <=
|
||||
current_time;
|
||||
}
|
||||
|
||||
// TODO(jfore): there is some gray around how this should be
|
||||
// implemented. It currently is not.
|
||||
bool PolicyEngine::IsRenewalRecoveryDurationExpired(
|
||||
int64_t current_time) {
|
||||
return (policy_.renewal_recovery_duration_seconds() > 0) &&
|
||||
license_start_time_ + policy_.renewal_recovery_duration_seconds() <=
|
||||
current_time;
|
||||
}
|
||||
|
||||
bool PolicyEngine::IsRenewalRetryIntervalExpired(
|
||||
int64_t current_time) {
|
||||
return (policy_.renewal_retry_interval_seconds() > 0) &&
|
||||
next_renewal_time_ <= current_time;
|
||||
}
|
||||
|
||||
} // wvcdm
|
||||
|
||||
Reference in New Issue
Block a user