Fix for b/3501089 Require an API in the DRM client to specify the license type (offline/streaming) and b/4084670 Define events in DRM API to support license expiration, revocation, license failure. Implements events and license changes as documented in the Widevine_Java_API_for_Android_DRM_Framework spec

Change-Id: I3d0440e4f64d2279ab3b272a5287db5144e41eb1
This commit is contained in:
Jeffrey Tinker
2011-03-15 23:32:02 -07:00
parent f2c4035d15
commit 778b5ce26f
9 changed files with 177 additions and 50 deletions

View File

@@ -1,17 +1,7 @@
/*
* Copyright (C) 2011 The Android Open Source Project
* Copyright 2011 Widevine Technologies, Inc., All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Declarations for Widevine DRM Plugin API
*/
#ifndef __WVMDRMPLUGIN_API_H__
@@ -38,6 +28,12 @@ class WVDRMPluginAPI {
PLAYBACK_INVALID
};
static const int PlaybackMode_Default = 0;
static const int PlaybackMode_Streaming = 1;
static const int PlaybackMode_Offline = 2;
static const int PlaybackMode_Any = PlaybackMode_Streaming |
PlaybackMode_Offline;
static WVDRMPluginAPI *create();
static void destroy(WVDRMPluginAPI *plugin);
@@ -48,19 +44,35 @@ class WVDRMPluginAPI {
virtual bool RegisterDrmInfo(std::string &portal, std::string &dsPath) = 0;
virtual bool UnregisterDrmInfo(std::string &portal, std::string &dsPath) = 0;
virtual bool AcquireDrmInfo(std::string &assetPath, WVCredentials &credentials,
std::string &dsPath,
const std::string &assetIdStr, const std::string &systemIdStr,
std::string &dsPath, const std::string &assetIdStr,
const std::string &systemIdStr,
const std::string &keyIdStr,
uint32_t *assetId, uint32_t *systemId, uint32_t *keyId) = 0;
virtual bool ProcessDrmInfo(std::string &assetPath) = 0;
uint32_t *assetId, uint32_t *systemId,
uint32_t *keyId) = 0;
virtual bool ProcessDrmInfo(std::string &assetPath, int playbackMode) = 0;
virtual int CheckRightsStatus(std::string &path) = 0;
virtual bool GetConstraints(std::string &path, uint32_t *timeSincePlayback, uint32_t *timeRemaining, uint32_t *licenseDuration) = 0;
virtual bool GetConstraints(std::string &path, uint32_t *timeSincePlayback,
uint32_t *timeRemaining,
uint32_t *licenseDuration, std::string &lastError,
bool &allowOffline, bool &allowStreaming,
bool &denyHD) = 0;
virtual bool SetPlaybackStatus(int playbackStatus, off64_t position) = 0;
virtual bool RemoveRights(std::string &path) = 0;
virtual bool RemoveAllRights() = 0;
virtual bool Prepare(char *data, int len) = 0;
virtual bool Operate(char *in, char *out, int len, char *iv) = 0;
enum EventType {
EventType_AcquireDrmInfoFailed,
EventType_ProcessDrmInfoFailed,
EventType_RightsInstalled,
EventType_RightsRemoved
};
typedef void (*EventHandler)(EventType type, const std::string &path);
virtual void SetEventHandler(EventHandler handler) = 0;
protected:
// use create factory method, don't construct directly
WVDRMPluginAPI() {}

View File

@@ -101,7 +101,10 @@ protected:
void* buffer, ssize_t numBytes, off64_t offset);
private:
const IDrmEngine::OnInfoListener *mOnInfoListener;
static void SendEvent(WVDRMPluginAPI::EventType code, const std::string &path);
static IDrmEngine::OnInfoListener *sOnInfoListener;
static int sUniqueId;
WVDRMPluginAPI *mDrmPluginImpl;
};

View File

@@ -21,6 +21,7 @@
#include <drm/DrmRights.h>
#include <drm/DrmConstraints.h>
#include <drm/DrmInfo.h>
#include <drm/DrmInfoEvent.h>
#include <drm/DrmInfoStatus.h>
#include <drm/DrmConvertedStatus.h>
#include <drm/DrmInfoRequest.h>
@@ -45,11 +46,15 @@ extern "C" void destroy(IDrmEngine* pPlugIn) {
delete pPlugIn;
}
// Needed for event callout from implementation object
IDrmEngine::OnInfoListener *WVMDrmPlugin::sOnInfoListener = NULL;
int WVMDrmPlugin::sUniqueId;
WVMDrmPlugin::WVMDrmPlugin()
: DrmEngineBase(),
mOnInfoListener(NULL),
mDrmPluginImpl(WVDRMPluginAPI::create())
{
mDrmPluginImpl->SetEventHandler(&SendEvent);
}
WVMDrmPlugin::~WVMDrmPlugin() {
@@ -96,10 +101,38 @@ status_t WVMDrmPlugin::onTerminate(int uniqueId) {
status_t WVMDrmPlugin::onSetOnInfoListener(
int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
//LOGD("WVMDrmPlugin::onSetOnInfoListener : %d", uniqueId);
mOnInfoListener = infoListener;
sOnInfoListener = const_cast<IDrmEngine::OnInfoListener *>(infoListener);
sUniqueId = uniqueId;
return DRM_NO_ERROR;
}
void WVMDrmPlugin::SendEvent(WVDRMPluginAPI::EventType type, const std::string &path)
{
int code = -1;
switch(type) {
EventType_AcquireFailed:
code = DrmInfoEvent::TYPE_ACQUIRE_DRM_INFO_FAILED;
break;
EventType_ProcessDrmInfoFailed:
code = DrmInfoEvent::TYPE_PROCESS_DRM_INFO_FAILED;
break;
EventType_RightsInstalled:
code = DrmInfoEvent::TYPE_RIGHTS_INSTALLED;
break;
EventType_RightsRemoved:
code = DrmInfoEvent::TYPE_RIGHTS_REMOVED;
break;
default:
break;
}
if (sOnInfoListener) {
DrmInfoEvent event(sUniqueId, code, String8(path.c_str()));
sOnInfoListener->onInfo(event);
}
}
/**
* Retrieves necessary information for registration, unregistration or rights
* acquisition information.
@@ -141,6 +174,7 @@ DrmInfo* WVMDrmPlugin::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmI
string systemIdStr = drmInfoRequest->get(String8("WVSystemIDKey")).string();
string assetIdStr = drmInfoRequest->get(String8("WVAssetIDKey")).string();
string keyIdStr = drmInfoRequest->get(String8("WVKeyIDKey")).string();
string licenseTypeStr = drmInfoRequest->get(String8("WVLicenseTypeKey")).string();
uint32_t systemId, assetId, keyId;
@@ -166,6 +200,7 @@ DrmInfo* WVMDrmPlugin::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmI
drmInfo->put(String8("WVCAUserDataKey"), String8(credentials.userData.c_str()));
drmInfo->put(String8("WVDeviceIDKey"), String8(credentials.deviceID.c_str()));
drmInfo->put(String8("WVStreamIDKey"), String8(credentials.streamID.c_str()));
drmInfo->put(String8("WVLicenseTypeKey"), String8(licenseTypeStr.c_str()));
char buffer[16];
sprintf(buffer, "%lu", (unsigned long)systemId);
@@ -239,8 +274,9 @@ DrmInfoStatus* WVMDrmPlugin::onProcessDrmInfo(int uniqueId, const DrmInfo* drmIn
if (NULL != drmInfo) {
if (drmInfo->getInfoType() == DrmInfoRequest::TYPE_RIGHTS_ACQUISITION_INFO) {
std::string assetPath = drmInfo->get(String8("WVAssetURIKey")).string();
int playbackMode = atol(drmInfo->get(String8("WVLicenseTypeKey")).string());
if (mDrmPluginImpl->ProcessDrmInfo(assetPath))
if (mDrmPluginImpl->ProcessDrmInfo(assetPath, playbackMode))
status = DrmInfoStatus::STATUS_OK;
} else if ((drmInfo->getInfoType() == DrmInfoRequest::TYPE_REGISTRATION_INFO) ||
(drmInfo->getInfoType() == DrmInfoRequest::TYPE_UNREGISTRATION_INFO)) {
@@ -288,9 +324,15 @@ DrmConstraints* WVMDrmPlugin::onGetConstraints(int uniqueId, const String8* path
uint32_t licenseDuration = 0;
uint32_t timeSincePlayback = 0;
uint32_t timeRemaining = 0;
std::string lastError;
bool allowOffline;
bool allowStreaming;
bool denyHD;
std::string assetPath(path->string());
if (!mDrmPluginImpl->GetConstraints(assetPath, &timeSincePlayback, &timeRemaining, &licenseDuration))
if (!mDrmPluginImpl->GetConstraints(assetPath, &timeSincePlayback, &timeRemaining,
&licenseDuration, lastError, allowOffline,
allowStreaming, denyHD))
return NULL;
DrmConstraints* drmConstraints = new DrmConstraints();
@@ -308,6 +350,16 @@ DrmConstraints* WVMDrmPlugin::onGetConstraints(int uniqueId, const String8* path
sprintf(charValue, "%lu", (unsigned long)licenseDuration);
drmConstraints->put(&(DrmConstraints::LICENSE_AVAILABLE_TIME), charValue);
String8 key = String8("WVLicenseTypeKey");
sprintf(charValue, "%u", (allowStreaming ? 1 : 0) | (allowOffline ? 2 : 0));
drmConstraints->put(&key, charValue);
key = String8("WVLicensedResolutionKey");
sprintf(charValue, "%u", (denyHD ? 1 : 2));
drmConstraints->put(&key, charValue);
key = String8("WVLastErrorKey");
drmConstraints->put(&key, lastError.c_str());
return drmConstraints;
}
@@ -755,4 +807,3 @@ DrmConvertedStatus* WVMDrmPlugin::onCloseConvertSession(int uniqueId, int conver
return NULL;
}

View File

@@ -35,15 +35,22 @@ public:
void TestAsset(IDrmEngine *plugin, String8 &url);
void TestRemoveAllRights(IDrmEngine *plugin);
void TestAcquireRights(IDrmEngine *plugin, String8 &url);
void TestRegister(IDrmEngine *plugin);
void TestAcquireRights(IDrmEngine *plugin, String8 &url, int playbackMode);
void TestCheckRightsNotAcquired(IDrmEngine *plugin, String8 &url);
void TestCheckValidRights(IDrmEngine *plugin, String8 &url);
void TestGetConstraints(IDrmEngine *plugin, String8 &url);
void TestGetConstraints(IDrmEngine *plugin, String8 &url, int playbackMode);
void TestRemoveRights(IDrmEngine *plugin, String8 &url);
void TestRemoveAllRights(IDrmEngine *plugin);
// Tests
void Run();
private:
static const int PlaybackMode_Default = 0;
static const int PlaybackMode_Streaming = 1;
static const int PlaybackMode_Offline = 2;
static const int PlaybackMode_Any = PlaybackMode_Streaming | PlaybackMode_Offline;
};
void WVMDrmPluginTest::Run()
@@ -101,9 +108,25 @@ void WVMDrmPluginTest::Run()
exit(0);
}
void WVMDrmPluginTest::TestAcquireRights(IDrmEngine *plugin, String8 &url)
void WVMDrmPluginTest::TestRegister(IDrmEngine *plugin)
{
cout << "WVDrmPluginTest::TestAcquireRights url=" << url << endl;
cout << "WVDrmPluginTest::TestRegister" << endl;
String8 mimeType("video/wvm");
DrmInfoRequest registrationInfo(DrmInfoRequest::TYPE_REGISTRATION_INFO, mimeType);
registrationInfo.put(String8("WVPortalKey"), String8("YouTube"));
DrmInfo *info = plugin->acquireDrmInfo(0, &registrationInfo);
if (info == NULL) {
fprintf(stderr, "acquireDrmInfo failed!\n");
exit(-1);
}
delete info;
}
void WVMDrmPluginTest::TestAcquireRights(IDrmEngine *plugin, String8 &url, int playbackMode)
{
cout << "WVDrmPluginTest::TestAcquireRights url=" << url << " mode=" << playbackMode << endl;
String8 mimeType("video/wvm");
DrmInfoRequest rightsAcquisitionInfo(DrmInfoRequest::TYPE_RIGHTS_ACQUISITION_INFO, mimeType);
@@ -111,6 +134,12 @@ void WVMDrmPluginTest::TestAcquireRights(IDrmEngine *plugin, String8 &url)
rightsAcquisitionInfo.put(String8("WVAssetURIKey"), url);
rightsAcquisitionInfo.put(String8("WVDeviceIDKey"), String8("device1234"));
rightsAcquisitionInfo.put(String8("WVPortalKey"), String8("YouTube"));
if (playbackMode) {
char num[4];
sprintf(num, "%d", playbackMode);
rightsAcquisitionInfo.put(String8("WVLicenseTypeKey"), String8(num));
cout << "WVLicenseTypeKey = " << num << endl;
}
DrmInfo *info = plugin->acquireDrmInfo(0, &rightsAcquisitionInfo);
if (info == NULL) {
@@ -158,7 +187,7 @@ void WVMDrmPluginTest::TestCheckValidRights(IDrmEngine *plugin, String8 &url)
}
}
void WVMDrmPluginTest::TestGetConstraints(IDrmEngine *plugin, String8 &url)
void WVMDrmPluginTest::TestGetConstraints(IDrmEngine *plugin, String8 &url, int playbackMode)
{
cout << "WVDrmPluginTest::TestGetConstraints url=" << url << endl;
@@ -169,23 +198,45 @@ void WVMDrmPluginTest::TestGetConstraints(IDrmEngine *plugin, String8 &url)
exit(-1);
}
if (constraints->getCount() != 3) {
if (constraints->getCount() != 6) {
fprintf(stderr, "getConstraints returned unexpected count!\n");
exit(-1);
}
if (constraints->get(DrmConstraints::LICENSE_START_TIME) == "") {
fprintf(stderr, "getConstraints returned unexpected count!\n");
fprintf(stderr, "getConstraints missing start time!\n");
exit(-1);
}
if (constraints->get(DrmConstraints::LICENSE_AVAILABLE_TIME) == "") {
fprintf(stderr, "getConstraints returned unexpected count!\n");
fprintf(stderr, "getConstraints missing available time!\n");
exit(-1);
}
if (constraints->get(DrmConstraints::LICENSE_EXPIRY_TIME) == "") {
fprintf(stderr, "getConstraints returned unexpected count!\n");
fprintf(stderr, "getConstraints missing expiry time!\n");
exit(-1);
}
if (constraints->get(String8("WVLicenseTypeKey")) == "") {
fprintf(stderr, "getConstraints missing license type key!\n");
exit(-1);
}
if (constraints->get(String8("WVLicensedResolutionKey")) == "") {
fprintf(stderr, "getConstraints missing resolution key!\n");
exit(-1);
}
if (constraints->get(String8("WVLastErrorKey")) == "") {
fprintf(stderr, "getConstraints missing last error key!\n");
exit(-1);
}
String8 licenseTypeStr = constraints->get(String8("WVLicenseTypeKey"));
int licenseType = atol(licenseTypeStr.string());
if (licenseType != playbackMode) {
fprintf(stderr, "license type mismatch, expected %d, found %d\n", playbackMode, licenseType);
exit(-1);
}
@@ -218,13 +269,32 @@ void WVMDrmPluginTest::TestAsset(IDrmEngine *plugin, String8 &url)
{
cout << "WVDrmPluginTest::TestAsset url=" << url << endl;
TestAcquireRights(plugin, url);
TestRegister(plugin);
TestRemoveAllRights(plugin);
TestCheckRightsNotAcquired(plugin, url);
TestAcquireRights(plugin, url, PlaybackMode_Default);
TestCheckValidRights(plugin, url);
TestGetConstraints(plugin, url);
TestGetConstraints(plugin, url, PlaybackMode_Any);
TestRemoveRights(plugin, url);
TestCheckRightsNotAcquired(plugin, url);
TestAcquireRights(plugin, url);
TestRemoveAllRights(plugin);
TestAcquireRights(plugin, url, PlaybackMode_Offline);
TestCheckValidRights(plugin, url);
TestGetConstraints(plugin, url, PlaybackMode_Offline);
TestRemoveRights(plugin, url);
TestCheckRightsNotAcquired(plugin, url);
TestAcquireRights(plugin, url, PlaybackMode_Streaming);
TestCheckValidRights(plugin, url);
TestGetConstraints(plugin, url, PlaybackMode_Streaming);
TestRemoveRights(plugin, url);
TestCheckRightsNotAcquired(plugin, url);
TestAcquireRights(plugin, url, PlaybackMode_Any);
TestCheckValidRights(plugin, url);
TestGetConstraints(plugin, url, PlaybackMode_Any);
TestRemoveRights(plugin, url);
TestCheckRightsNotAcquired(plugin, url);
}
@@ -232,6 +302,7 @@ int main(int argc, char **argv)
{
// turn off some noisy printing in WVStreamControl
setenv("WV_SILENT", "true", 1);
WVMDrmPluginTest test;
test.Run();
}

View File

@@ -1,17 +1,7 @@
/*
* Copyright (C) 2011 The Android Open Source Project
* Copyright 2011 Widevine Technologies, Inc., All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Declarations for Widevine Adaptive Streaming API
*/
#ifndef __WV_STREAM_CONTROL_API_H__

View File

@@ -315,7 +315,7 @@ int main( int argc, char *argv[] )
Terminate();
}
if (!sDrmPlugin->ProcessDrmInfo(url)) {
if (!sDrmPlugin->ProcessDrmInfo(url, WVDRMPluginAPI::PlaybackMode_Any)) {
fprintf(stderr, "ERROR: ProcessDrmInfo failed\n");
Terminate();
}