Merge "Use session with longest remaining duration when session sharing is used." into nyc-dev
This commit is contained in:
@@ -91,6 +91,7 @@ class CdmSession {
|
|||||||
virtual CdmResponseType ReleaseKey(const CdmKeyResponse& key_response);
|
virtual CdmResponseType ReleaseKey(const CdmKeyResponse& key_response);
|
||||||
|
|
||||||
virtual bool IsKeyLoaded(const KeyId& key_id);
|
virtual bool IsKeyLoaded(const KeyId& key_id);
|
||||||
|
virtual int64_t GetDurationRemaining();
|
||||||
|
|
||||||
// Used for notifying the Policy Engine of resolution changes
|
// Used for notifying the Policy Engine of resolution changes
|
||||||
virtual void NotifyResolution(uint32_t width, uint32_t height);
|
virtual void NotifyResolution(uint32_t width, uint32_t height);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ class PolicyEngine {
|
|||||||
bool IsPlaybackStarted() { return playback_start_time_ > 0; }
|
bool IsPlaybackStarted() { return playback_start_time_ > 0; }
|
||||||
|
|
||||||
bool IsLicenseOrPlaybackDurationExpired(int64_t current_time);
|
bool IsLicenseOrPlaybackDurationExpired(int64_t current_time);
|
||||||
|
int64_t GetLicenseOrPlaybackDurationRemaining();
|
||||||
|
|
||||||
bool CanRenew() { return policy_.can_renew(); }
|
bool CanRenew() { return policy_.can_renew(); }
|
||||||
|
|
||||||
|
|||||||
@@ -1034,24 +1034,31 @@ CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
|
|||||||
// else we must be level 1 direct and we don't need to return a buffer.
|
// else we must be level 1 direct and we don't need to return a buffer.
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmSessionMap::iterator iter;
|
CdmSessionMap::iterator session_iter = sessions_.end();
|
||||||
if (session_id.empty()) {
|
if (session_id.empty()) {
|
||||||
// Loop through the sessions to find the session containing the key_id.
|
// Loop through the sessions to find the session containing the key_id
|
||||||
for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
// with the longest remaining license validity.
|
||||||
|
int64_t seconds_remaining = 0;
|
||||||
|
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||||
|
iter != sessions_.end(); ++iter) {
|
||||||
if (iter->second->IsKeyLoaded(*parameters.key_id)) {
|
if (iter->second->IsKeyLoaded(*parameters.key_id)) {
|
||||||
break;
|
int64_t duration = iter->second->GetDurationRemaining();
|
||||||
|
if (duration > seconds_remaining) {
|
||||||
|
session_iter = iter;
|
||||||
|
seconds_remaining = duration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iter = sessions_.find(session_id);
|
session_iter = sessions_.find(session_id);
|
||||||
}
|
}
|
||||||
if (iter == sessions_.end()) {
|
if (session_iter == sessions_.end()) {
|
||||||
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
|
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
|
||||||
session_id.c_str(), session_id.size());
|
session_id.c_str(), session_id.size());
|
||||||
return SESSION_NOT_FOUND_FOR_DECRYPT;
|
return SESSION_NOT_FOUND_FOR_DECRYPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return iter->second->Decrypt(parameters);
|
return session_iter->second->Decrypt(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmEngine::IsKeyLoaded(const KeyId& key_id) {
|
bool CdmEngine::IsKeyLoaded(const KeyId& key_id) {
|
||||||
@@ -1071,25 +1078,29 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmSessionMap::iterator iter = sessions_.find(*session_id);
|
|
||||||
if (iter != sessions_.end()) {
|
|
||||||
if (iter->second->IsKeyLoaded(key_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
|
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
|
||||||
|
|
||||||
for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
CdmSessionMap::iterator session_iter = sessions_.end();
|
||||||
|
int64_t seconds_remaining = 0;
|
||||||
|
for (CdmSessionMap::iterator iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
||||||
CdmSessionId local_session_id = iter->second->session_id();
|
CdmSessionId local_session_id = iter->second->session_id();
|
||||||
if (Properties::GetSessionSharingId(local_session_id) ==
|
if (Properties::GetSessionSharingId(local_session_id) ==
|
||||||
session_sharing_id) {
|
session_sharing_id) {
|
||||||
if (iter->second->IsKeyLoaded(key_id)) {
|
if (iter->second->IsKeyLoaded(key_id)) {
|
||||||
*session_id = local_session_id;
|
int64_t duration = iter->second->GetDurationRemaining();
|
||||||
|
if (duration > seconds_remaining) {
|
||||||
|
session_iter = iter;
|
||||||
|
seconds_remaining = duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_iter != sessions_.end()) {
|
||||||
|
*session_id = session_iter->second->session_id();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -461,6 +461,11 @@ bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
|
|||||||
return license_parser_->IsKeyLoaded(key_id);
|
return license_parser_->IsKeyLoaded(key_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t CdmSession::GetDurationRemaining() {
|
||||||
|
if (policy_engine_->IsLicenseForFuture()) return 0;
|
||||||
|
return policy_engine_->GetLicenseOrPlaybackDurationRemaining();
|
||||||
|
}
|
||||||
|
|
||||||
CdmSessionId CdmSession::GenerateSessionId() {
|
CdmSessionId CdmSession::GenerateSessionId() {
|
||||||
static int session_num = 1;
|
static int session_num = 1;
|
||||||
return SESSION_ID_PREFIX + IntToString(++session_num);
|
return SESSION_ID_PREFIX + IntToString(++session_num);
|
||||||
|
|||||||
@@ -272,6 +272,12 @@ bool PolicyEngine::GetSecondsSinceLastPlayed(
|
|||||||
return (*seconds_since_last_played >= 0) ? true : false;
|
return (*seconds_since_last_played >= 0) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t PolicyEngine::GetLicenseOrPlaybackDurationRemaining() {
|
||||||
|
int64_t current_time = clock_->GetCurrentTime();
|
||||||
|
return std::min(GetLicenseDurationRemaining(current_time),
|
||||||
|
GetPlaybackDurationRemaining(current_time));
|
||||||
|
}
|
||||||
|
|
||||||
void PolicyEngine::RestorePlaybackTimes(int64_t playback_start_time,
|
void PolicyEngine::RestorePlaybackTimes(int64_t playback_start_time,
|
||||||
int64_t last_playback_time) {
|
int64_t last_playback_time) {
|
||||||
playback_start_time_ = (playback_start_time > 0) ? playback_start_time : 0;
|
playback_start_time_ = (playback_start_time > 0) ? playback_start_time : 0;
|
||||||
|
|||||||
@@ -363,8 +363,9 @@ SubSampleInfo usage_info_sub_samples_icp[] = {
|
|||||||
"614f080d83f3b15cbc6600ddda43adff5d2941da13ebe49d80fd0cea5025412b"),
|
"614f080d83f3b15cbc6600ddda43adff5d2941da13ebe49d80fd0cea5025412b"),
|
||||||
wvcdm::a2b_hex("964c2dfda920357c668308d52d33c652"), 0, 3}};
|
wvcdm::a2b_hex("964c2dfda920357c668308d52d33c652"), 0, 3}};
|
||||||
|
|
||||||
// License duration + fudge factor
|
// License duration and uncertainty window
|
||||||
const uint32_t kSingleEncryptedSubSampleIcpLicenseDurationExpiration = 5 + 2;
|
const uint32_t kSingleEncryptedSubSampleIcpLicenseDurationExpiration = 5;
|
||||||
|
const uint32_t kSingleEncryptedSubSampleIcpLicenseExpirationWindow = 2;
|
||||||
|
|
||||||
struct SessionSharingSubSampleInfo {
|
struct SessionSharingSubSampleInfo {
|
||||||
SubSampleInfo* sub_sample;
|
SubSampleInfo* sub_sample;
|
||||||
@@ -2663,6 +2664,74 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
|||||||
decryptor_.CloseSession(gp_session_id_2);
|
decryptor_.CloseSession(gp_session_id_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingTest,
|
||||||
|
::testing::Range(&session_sharing_sub_samples[0],
|
||||||
|
&session_sharing_sub_samples[6]));
|
||||||
|
|
||||||
|
TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) {
|
||||||
|
TestWvCdmClientPropertySet property_set;
|
||||||
|
property_set.set_session_sharing_mode(true);
|
||||||
|
|
||||||
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
||||||
|
const std::string init_data1 = a2bs_hex(
|
||||||
|
"000000347073736800000000" // blob size and pssh
|
||||||
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id
|
||||||
|
"0801121030313233343536373839616263646566"); // pssh data
|
||||||
|
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
|
||||||
|
&session_id_);
|
||||||
|
CdmSessionId session_id1 = session_id_;
|
||||||
|
GenerateKeyRequest(init_data1, kLicenseTypeStreaming);
|
||||||
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
||||||
|
|
||||||
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
||||||
|
std::string gp_client_auth2 =
|
||||||
|
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
||||||
|
std::string init_data2 = a2bs_hex(
|
||||||
|
"000000347073736800000000" // blob size and pssh
|
||||||
|
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
||||||
|
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
||||||
|
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
|
||||||
|
&session_id_);
|
||||||
|
CdmSessionId session_id2 = session_id_;
|
||||||
|
GenerateKeyRequest(init_data2, kLicenseTypeStreaming);
|
||||||
|
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, false);
|
||||||
|
|
||||||
|
SubSampleInfo* data = &single_encrypted_sub_sample_short_expiry;
|
||||||
|
|
||||||
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
||||||
|
CdmDecryptionParameters decryption_parameters(
|
||||||
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
||||||
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
||||||
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
||||||
|
decryption_parameters.is_secure = data->is_secure;
|
||||||
|
|
||||||
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
|
||||||
|
decryption_parameters));
|
||||||
|
|
||||||
|
sleep(kSingleEncryptedSubSampleIcpLicenseDurationExpiration -
|
||||||
|
kSingleEncryptedSubSampleIcpLicenseExpirationWindow);
|
||||||
|
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set, EMPTY_ORIGIN, NULL,
|
||||||
|
&session_id_);
|
||||||
|
CdmSessionId session_id3 = session_id_;
|
||||||
|
GenerateKeyRequest(init_data1, kLicenseTypeStreaming);
|
||||||
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
||||||
|
|
||||||
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
|
||||||
|
decryption_parameters));
|
||||||
|
|
||||||
|
sleep(2*kSingleEncryptedSubSampleIcpLicenseExpirationWindow);
|
||||||
|
// session 1 will be expired, shared session 3 will be used to decrypt
|
||||||
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
|
||||||
|
decryption_parameters));
|
||||||
|
|
||||||
|
decryptor_.CloseSession(session_id1);
|
||||||
|
decryptor_.CloseSession(session_id2);
|
||||||
|
decryptor_.CloseSession(session_id3);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) {
|
TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) {
|
||||||
const std::string kCpKeyId = a2bs_hex(
|
const std::string kCpKeyId = a2bs_hex(
|
||||||
"000000347073736800000000" // blob size and pssh
|
"000000347073736800000000" // blob size and pssh
|
||||||
@@ -2683,16 +2752,13 @@ TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) {
|
|||||||
decryption_parameters.is_secure = data->is_secure;
|
decryption_parameters.is_secure = data->is_secure;
|
||||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
||||||
decryption_parameters));
|
decryption_parameters));
|
||||||
sleep(kSingleEncryptedSubSampleIcpLicenseDurationExpiration);
|
sleep(kSingleEncryptedSubSampleIcpLicenseDurationExpiration +
|
||||||
|
kSingleEncryptedSubSampleIcpLicenseExpirationWindow);
|
||||||
EXPECT_EQ(NEED_KEY, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
EXPECT_EQ(NEED_KEY, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
||||||
decryption_parameters));
|
decryption_parameters));
|
||||||
decryptor_.CloseSession(session_id_);
|
decryptor_.CloseSession(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingTest,
|
|
||||||
::testing::Range(&session_sharing_sub_samples[0],
|
|
||||||
&session_sharing_sub_samples[6]));
|
|
||||||
|
|
||||||
class WvCdmDecryptionTest
|
class WvCdmDecryptionTest
|
||||||
: public WvCdmRequestLicenseTest,
|
: public WvCdmRequestLicenseTest,
|
||||||
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
||||||
|
|||||||
Reference in New Issue
Block a user