Widevine SDK Release Branch: beta-19.10.1
This commit is contained in:
316
ubuntu/sdk/examples/license_server_sdk/cpp/wvpl_license_sdk_example.cc
Executable file
316
ubuntu/sdk/examples/license_server_sdk/cpp/wvpl_license_sdk_example.cc
Executable file
@@ -0,0 +1,316 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2018 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_sdk_environment.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_types.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_environment.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_session.h"
|
||||
|
||||
using ::video_widevine_server::wv_pl_sdk::HDCP_V1;
|
||||
using ::video_widevine_server::wv_pl_sdk::HDCP_V2;
|
||||
using ::video_widevine_server::wv_pl_sdk::kDeviceCertificateExpiration;
|
||||
using ::video_widevine_server::wv_pl_sdk::kDrmCertificateType;
|
||||
using ::video_widevine_server::wv_pl_sdk::VIDEO_HD;
|
||||
using ::video_widevine_server::wv_pl_sdk::VIDEO_SD;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLCapabilityStatus;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLDeviceStatusOptions;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLEnvironment;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLKey;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLPlaybackPolicy;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLSession;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLSessionInit;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
|
||||
constexpr uint32_t kSystemId = 0x112;
|
||||
constexpr char kKeyBytes1[] =
|
||||
"\x69\xea\xa8\x02\xa6\x76\x3a\xf9\x79\xe8\xd1\x94\x0f\xb8\x83\x92";
|
||||
constexpr char kKeyId1[] =
|
||||
"\xab\xba\x27\x1e\x8b\xcf\x55\x2b\xbd\x2e\x86\xa4\x34\xa9\xa5\xd9";
|
||||
constexpr char kKeyBytes2[] =
|
||||
"\xa4\x63\x1a\x15\x3a\x44\x3d\xf9\xee\xd0\x59\x30\x43\xdb\x75\x19";
|
||||
constexpr char kKeyId2[] =
|
||||
"\xf3\xc5\xe0\x36\x1e\x66\x54\xb2\x8f\x80\x49\xc7\x78\xb2\x39\x46";
|
||||
constexpr char kKeyId3[] =
|
||||
"\x10\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";
|
||||
constexpr char kKeyBytes3[] =
|
||||
"\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0\x10";
|
||||
|
||||
constexpr char kPreProvisioningKey[] = "f7538b38acc78ec68c732ac665c55c65";
|
||||
constexpr char kValidCertList[] =
|
||||
"{"
|
||||
"\"kind\": \"certificateprovisioning#certificateStatusListResponse\","
|
||||
"\"signedList\": \""
|
||||
"CisIhdC/"
|
||||
"9gUSIwoNc2VyaWFsLW51bWJlciIQCJICGgRtYWtlIgVtb2RlbDAeEoADMI21pWCKSrmyeUAiCT"
|
||||
"gkYwrZsXXHKsDQ7J9pkNbZTYj5kqpa/WaXQDWV3KNsEAf0a9FERSFr1V/"
|
||||
"Vr3oEwOVZ8pA2uHY7KA/ghY7FByzDYA8GQyofi8XV/m27QL/o2iu1YQXkO87l37/"
|
||||
"RdWY1gHzqiwbiCXJsPqD4+S2g9o5/hwlDOzHToqylUS2rj5iBO/"
|
||||
"0fkuxKnWbxU0+PCcV2cuUhBv+jqOg8wDAw3/9HJEiUAzH7la/"
|
||||
"f8nZQMUj1AOBZuKbgdobIPNs9tj3cCRKDIY8DomfceZgJO+"
|
||||
"DHtxdggeZoBfq8jiFS5NynMx7OcINT3LRPmJ6opTwMhF5uurXRmRDXxJ/E+Z5bTCEbxCZ/"
|
||||
"6rhr+faGam9tDZHxHuetDPx5l2mfQnF7lY7Te+FChv+"
|
||||
"xIc93FvqNYF3TCZui3LYoqqPylijzLNZ7dPaVZ7hN/cFPJVudA/"
|
||||
"eHq6ElmJquoKd5022d6Rin6oFymJUKF7FKRKfIkepkgncT5C/kI3/tX6nilNb6"
|
||||
"\" }";
|
||||
|
||||
/** Example of how to use WvPL API. */
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// -- Set up WvPLEnvironment.
|
||||
|
||||
std::map<std::string, std::string> config;
|
||||
// Set device certificate expiration time to 10 years (10 * 365 * 24 * 3600).
|
||||
// Note that in practice, the expiration should not be 10 years long.
|
||||
// Certificate status list should be updated periodically.
|
||||
config[kDeviceCertificateExpiration] = "315360000";
|
||||
|
||||
// The DCSL and service certificate used in this example are for "development"
|
||||
// and will not work with Widevine's production servers. Replace "dev" with
|
||||
// "prod" when using production certificates.
|
||||
config[kDrmCertificateType] = "dev";
|
||||
|
||||
// Set parameters on the environment.
|
||||
WvPLEnvironment wvpl_env(config);
|
||||
WvPLStatus status = wvpl_env.Initialize();
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to Initialize environment: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// The preProvKeys map takes a device systemID as the key and an associated
|
||||
// preprovisioning key as the value.
|
||||
std::map<uint32_t, std::string> prev_prov_keys;
|
||||
prev_prov_keys[kSystemId] = kPreProvisioningKey;
|
||||
status = wvpl_env.SetPreProvisioningKeys(prev_prov_keys);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set pre-prov keys: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
std::string b64DrmServiceCertificate =
|
||||
"CsMCCAMSENU2hMYAMrDf+"
|
||||
"Z9TlWepj1UY7eXE9gUijgIwggEKAoIBAQCqBNtJ830093pLL7h0daCvCUY7WQ8nrNfyYa5NI"
|
||||
"TMR8V6JxHUtykxzMP2FR6cgJb0NPXQXg3U6kTqHClUYu2OOHjoSi68LtbTL4S+7d/"
|
||||
"b1NqOhLLLQqiRXUOfZE4BrSJx0W+bUrzLOFgl+xmMv5jlNpdFLhn1+/"
|
||||
"QOs0u2dxen+yCDoXIOVbFtQtA3RB+sRxvjaOwW4u5dqMj2Xzd/"
|
||||
"JjWiAwgDAMe3g256M2s+5ZzZ1CnZv6KWPwKzQKXzO/O/"
|
||||
"bSGrMz9K9T1kRVPPnq8FAiXh2IY+"
|
||||
"JZ5EcPwrbcdEmiMWxf7bWv3Pk9vSSC8ZDUUI4oBdocf6TCEFKFq1uZBXP0VGbAgMBAAE6Emh"
|
||||
"hbWlkLXd2cGwtc2RrLXVhdEABSAESgAO0xjYXyZAJ7UNU0N5duOxRkSjlZW7DcqYE5DH8T9n"
|
||||
"QzCZ/PHPraiWcOaHxyG1sR6Vn6zW7EFV4izXWPI0BTI6Kys/3fQmbstX71om2h8lm3+zOh/"
|
||||
"baLl605RaIpTCHdQj5hfoxs/nn6CI+VxxxD8L1JiGXbcg0/"
|
||||
"noSHMJorOq+sDJDK6aYqZDEtrJaY6DfZa+IAK7Nn/"
|
||||
"WDWVpefrVJwP2h2chjKpYSbOVxRnpqWqWVxT30ROyJwF1BA9F/"
|
||||
"dMeqTyeyzk1fMfVRQuHaaFqYz6HazSg7dqoXGEKTonN9kHWXTzdPY5jhdXO3vOu4U1k9LzSM"
|
||||
"4Gnb/"
|
||||
"8K2F2vQQECskoGkGTF85NB2vyXA95FJa5ExwCXrTnCuBZOLOsR6wwazn5H0gDAmqbTxm2I0r"
|
||||
"7Ar7IrU8z9v83k1171RDk9xHO+yJD6eFQSyk9stqQH/dNU1DPjCaMylk8ysQ/"
|
||||
"8XYRj9O0LBEsT2oC4Y7lFd17/NqJeOGvOwVgUmQ/lIVNMmZajEqz0=";
|
||||
|
||||
std::string b64EncryptedProviderKeyConfig =
|
||||
"ChJoYW1pZC13dnBsLXNkay11YXQSENU2hMYAMrDf+Z9TlWepj1Ua0AHd4Ov+L/"
|
||||
"2wwOhiCSmULAExqAav8E8Ori0F2/"
|
||||
"fIjdP4dCU+1M5EGJgMQhoyrYz9VFpUpFm9nFZdMhcafHjcKkN4NUVeH24xbJDPIN2+"
|
||||
"B9TyRmqVYR+2iIqrHnIRwd8jJMOy8X6tS3hi1fJk7JFYRnPHPhkiUANkV/"
|
||||
"4pAZINquNkFnoswt7oo40dFv+ztgrIbkofXdW/"
|
||||
"COJYZKWdVM27RFWk0VxSTglYMVPkXTNSwhR+i6DpB11ZwAFXw2ndiFYd3Skx47knYGobNW/"
|
||||
"kUV7azqnUIhDdntgweqt2QSyUFYa4c99MKoACBTGaIdLXmRh6sVRhQ4f6pYWEK+b+Kf/"
|
||||
"9cGItNmH4Y+3Pzpr61wmV8b8NIju2ztRuOR+gzQwyWWoqZh3otqnpd6Fds4Bs+4+"
|
||||
"FQRLOTSBoV9d6JFKvokLtCqFDPWTHVZnKX9PKcjng6MNwGjwMlYELam7qWwXElXKjvBZGNEx"
|
||||
"INA5v97xF+"
|
||||
"CCCXysVAxC8MQmRQA9rDBhroN2akkrk1qau4L7Nb3T8oKIGEfiwHcENP2TlgDzmRK9W//"
|
||||
"+tFnZLJ1e12L1Vd390pV4G9cLOrTkF368LZ4lykOHeIQ1jgvUjuGk0uEwzi+"
|
||||
"hHDyA7WtbtpUXbteq8ytD9MUvIOGVyHwRnzw==";
|
||||
|
||||
std::string b64PrivateKey =
|
||||
"MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI4UNtEZV1vrkCAggAMBQGCCqG"
|
||||
"SIb3DQMHBAhSpl2tcdfcVwSCBMi7K5Ne/XsAB49mm0gIQ1BCTiIfdzuS/OO0Z3xoUry9/"
|
||||
"Z50vE6aAkqLbvP7XbWltDU+jzjkjoAnkEUJ56Njifd7EhTSN7M6W6x2mC7c+"
|
||||
"qgdVW7XqR8iKIpULYaU9txNadwl1p1iP0MoKN0cORXKHzhgUPaTkUKiseCMVdCsImPrDlBrm"
|
||||
"s+jeyft8YwPpUlCxFLTQo+F9HmxKBKxYcEs1g9EByrXCrIx1oHAJBgCihFOi+"
|
||||
"qFC2HQJex54tx1QEf/"
|
||||
"bb5G7xW3vD4T3fZU9by9GNKq9MOVsARmy7ozvDeark6f+"
|
||||
"MxCuUhVvRqRK4EC3YiaVj9GB6kqWA1UjldF+"
|
||||
"HFHsqs6qV2J6HNs42JL7N9PQTJJx6Xdxp7f7PjgsJUslZeiyW+uZ8wIpMsBg4NtOkcbgb+"
|
||||
"ijGiPGYCPMv7mVFWqyMeSM+BQN3NF48P/"
|
||||
"VHfHQ9CmX41uE8+"
|
||||
"IhXdi1b4fjenUIKcJ95yoB1yauZGBRBdvjjrZtduczYnoJd9BYCbEYErRC5cvNU+"
|
||||
"FzYEUYKqUBLc25RWd8hg/"
|
||||
"NGiaC7YwCJjI59o7SGgY1BFuPuEaehJ60OvbgJiyBofAGOMulrF+"
|
||||
"Quf6QFgltUFnOIpcXhll9/"
|
||||
"C+"
|
||||
"RWW6uLXfxZICt3F6Z4dq9xZi5ZSUzZVsdLtbYAP4QLXTqGTgPA7FdFvHrhf3GJTIppE2a58x"
|
||||
"uEkVkXl2cqYSuat4QGRxNrleJ55gWvZKIzIN2j85Jk2E9UljNURso/9FIsEF/"
|
||||
"S2Js77nvn5t40VNdzhUvSjDkD8S75hlyHMTFbc/"
|
||||
"9yOlrUWT2AP+veMnzgR5wltQ32qgkujBj7ogHz+0/"
|
||||
"RvpBKyvmHI+mvmqm6aS22yEjQ6jhyEN8mKZNPpgz94TFzYwP9s/qV+/"
|
||||
"AllJNQ0ruMue9gUKYu381u/"
|
||||
"F0eLG4ZORinxnxMtWQhpB7cR71nBmt2SYicg2moqKc9hQ7JRJ7g0V07AjWByRRHaOwgJ/"
|
||||
"YBsCaVeyMl8ynKpWB9r8AW9qKaf79JC+brcWrel8S+YKHX8akmTrs0gSzI+M0hBGqp3f/"
|
||||
"xnRiAuBXLGZ8Vm2YqsJpFYGyFKBoPUinCuoDLWJnbWt3GBAvHp8OWry67Ldz6vcQmh0eEWmi"
|
||||
"qIzHGGw2eti2BNpJwATXZ7CfETB9jlHfk4vPZlTWzuzBaQtExLNGXJbgXDJeaTxVdZ7JU2ul"
|
||||
"S4VgmBAUZnXXJYBgNc1qCCnijFX/R06hN3LrG/"
|
||||
"d5odxQCfhIMuSieaTrWuoqBYxxi5dLzarRRp9DySURt9JepyOps9sPBfvLh5iDy2LQ2dWbmS"
|
||||
"A/"
|
||||
"rqsaV+"
|
||||
"8z4v4Y1gDJCmKFMa2GPNSlJDqjASw8tDDMXL4dwYb2RcWLCHM5CXJAnxSE4ZpHvf0dwAyDqg"
|
||||
"hikih9D7CvOwGdv7oVW6/"
|
||||
"tTdoOo+WkrQtgmRfboxX9Spin+vL1ia2jW2VugSMQbEhTkKH+"
|
||||
"NE0TC6VGsvPJt0wLLhzRMzTEeT05Zl4QpeCKUmHFM4LIXWcACQ8L1Q0YjOXg733q/"
|
||||
"fs2kmXsHV9TG5kqHemGIf7t0baF7ibzwnl7F+GGWmg/"
|
||||
"dQ1RdM7T0p5wRtqHK0wAKxG8hxZkejHPBnV9GYK8QUOlxnE7tVM2Sv6QmTOKGXGKDRBsoacm"
|
||||
"BaGLiE=";
|
||||
|
||||
std::string b64DecodedDrmServiceCertificate;
|
||||
std::string b64DecodedEncryptedProviderKeyConfig;
|
||||
std::string b64DecodedPrivateKey;
|
||||
if (!absl::Base64Unescape(b64DrmServiceCertificate,
|
||||
&b64DecodedDrmServiceCertificate)) {
|
||||
std::cerr << "Failed to decode ServiceCertificate." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!absl::Base64Unescape(b64EncryptedProviderKeyConfig,
|
||||
&b64DecodedEncryptedProviderKeyConfig)) {
|
||||
std::cerr << "Failed to decode EncryptedProviderKeyConfig." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!absl::Base64Unescape(b64PrivateKey, &b64DecodedPrivateKey)) {
|
||||
std::cerr << "Failed to decode PrivateKey." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Must set a valid drm service certificate, otherwise it will failed to
|
||||
// create session.
|
||||
std::string passphrase = "encryptallthekitties";
|
||||
status = wvpl_env.SetDrmServiceCertificate(b64DecodedDrmServiceCertificate,
|
||||
b64DecodedPrivateKey, passphrase);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set DrmServiceCertificate: "
|
||||
<< status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// If using provider keys: set an encrypted provider key config. Note that the
|
||||
// service certificate has to be set first.
|
||||
status = wvpl_env.SetEncryptedProviderKeyConfig(
|
||||
b64DecodedEncryptedProviderKeyConfig);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set an encrypted provider key config: "
|
||||
<< status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Set a valid device certificate status list.
|
||||
status = wvpl_env.SetDeviceCertificateStatusList(kValidCertList);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to update the certificate status list: "
|
||||
<< status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// -- Create the DRM session.
|
||||
WvPLSession* session = nullptr;
|
||||
|
||||
// Set the license request.
|
||||
const char kLicenseRequestExample[] =
|
||||
"\x12\x90\x01\x0a\x58\x08\x00\x12\x48\x00\x00\x00\x02\x00\x00\x01\x12\x8e"
|
||||
"\x1e\xbf\xe0\x37\x82\x80\x96\xca\x65\x38\xb4\xf6\xf4\xbc\xb5\x1c\x2b\x71"
|
||||
"\x91\xcf\x03\x7e\x98\xbe\xaa\x24\x92\x49\x07\xe1\x28\xf9\xff\x49\xb5\x4a"
|
||||
"\x16\x5c\xd9\xc3\x3e\x65\x47\x53\x7e\xb4\xd2\x9f\xb7\xe8\xdf\x3c\x2c\x1c"
|
||||
"\xd9\x25\x17\xa1\x2f\x49\x22\x95\x3e\x1a\x0a\x0a\x03\x66\x6f\x6f\x12\x03"
|
||||
"\x62\x61\x72\x12\x2c\x12\x2a\x0a\x10\x30\x31\x32\x33\x34\x35\x36\x37\x38"
|
||||
"\x39\x41\x42\x43\x44\x45\x46\x10\x01\x1a\x14\x6d\x79\x43\x6f\x6f\x6c\x52"
|
||||
"\x65\x71\x75\x65\x73\x74\x2c\x20\x44\x75\x64\x65\x21\x18\x01\x20\x9d\x88"
|
||||
"\xf7\x8a\x05\x1a\x20\xac\xc0\x12\xac\xcd\x1a\xac\x9f\x11\xaa\x84\xbf\xd1"
|
||||
"\x6f\x01\x44\x8a\xd5\x00\xb8\x60\x2e\x26\x9d\xd2\x71\x7e\x0b\x26\x55\x31"
|
||||
"\x83";
|
||||
|
||||
status =
|
||||
wvpl_env.CreateSession(std::string(std::begin(kLicenseRequestExample),
|
||||
std::end(kLicenseRequestExample) - 1),
|
||||
&session);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to create session: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
// -- Inspect the request.
|
||||
// Set parameters on the created session.
|
||||
|
||||
// Set policy parameters
|
||||
WvPLPlaybackPolicy policy;
|
||||
policy.set_license_duration_seconds(604800);
|
||||
policy.set_playback_duration_seconds(86400);
|
||||
session->set_policy(policy);
|
||||
|
||||
// Set key parameters
|
||||
WvPLKey wvpl_key1;
|
||||
// Key bytes and key id must be in bytes.
|
||||
wvpl_key1.set_key_id(kKeyId1);
|
||||
wvpl_key1.set_key_bytes(kKeyBytes1);
|
||||
wvpl_key1.set_track_type(VIDEO_HD);
|
||||
wvpl_key1.mutable_output_protection()->set_hdcp(HDCP_V1);
|
||||
wvpl_key1.mutable_output_protection()->set_secure_data_path(true);
|
||||
status = session->AddKey(wvpl_key1);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key: " << status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
WvPLKey wvpl_key2;
|
||||
wvpl_key2.set_key_id(kKeyId2);
|
||||
wvpl_key2.set_key_bytes(kKeyBytes2);
|
||||
wvpl_key2.set_track_type(VIDEO_SD);
|
||||
wvpl_key2.mutable_requested_output_protection()->set_hdcp(HDCP_V2);
|
||||
wvpl_key2.mutable_requested_output_protection()->set_secure_data_path(false);
|
||||
status = session->AddKey(wvpl_key2);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key: " << status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// We also could use filterKey to filter out the key.
|
||||
WvPLKey filtered_key1;
|
||||
filtered_key1.set_key_id(kKeyId3);
|
||||
filtered_key1.set_key_bytes(kKeyBytes3);
|
||||
filtered_key1.set_track_type(VIDEO_HD);
|
||||
WvPLCapabilityStatus capability_status = session->FilterKey(filtered_key1);
|
||||
if (!capability_status.ok()) {
|
||||
std::cerr << "Failed to add filtered key: " << capability_status.status()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Set SessionInit
|
||||
WvPLDeviceStatusOptions wvpl_device_status_options;
|
||||
wvpl_device_status_options.set_allow_test_only_system_id(true);
|
||||
WvPLSessionInit wvpl_session_init;
|
||||
wvpl_session_init.set_device_status_options(wvpl_device_status_options);
|
||||
session->set_session_init(wvpl_session_init);
|
||||
|
||||
// -- Generate the license
|
||||
|
||||
std::string license_response;
|
||||
status = session->GenerateLicense(&license_response);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate license: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
std::cout << "Generated license: " << absl::BytesToHexString(license_response)
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
441
ubuntu/sdk/examples/license_server_sdk/cpp/wvpl_license_sdk_using_dsp_example.cc
Executable file
441
ubuntu/sdk/examples/license_server_sdk/cpp/wvpl_license_sdk_using_dsp_example.cc
Executable file
@@ -0,0 +1,441 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2021 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "common/status.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_sdk_environment.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_types.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_environment.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_session.h"
|
||||
|
||||
using ::video_widevine_server::wv_pl_sdk::HDCP_NONE;
|
||||
using ::video_widevine_server::wv_pl_sdk::HDCP_V1;
|
||||
using ::video_widevine_server::wv_pl_sdk::kDeviceCertificateExpiration;
|
||||
using ::video_widevine_server::wv_pl_sdk::kDrmCertificateType;
|
||||
using ::video_widevine_server::wv_pl_sdk::VIDEO_HD;
|
||||
using ::video_widevine_server::wv_pl_sdk::VIDEO_SD;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLCapabilityStatus;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLDeviceStatusOptions;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLEnvironment;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLKey;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLPlaybackPolicy;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLSession;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLSessionInit;
|
||||
using ::video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
|
||||
constexpr uint32_t kSystemId = 0x112;
|
||||
constexpr char kKeyBytes1[] =
|
||||
"\x69\xea\xa8\x02\xa6\x76\x3a\xf9\x79\xe8\xd1\x94\x0f\xb8\x83\x92";
|
||||
constexpr char kKeyId1[] =
|
||||
"\xab\xba\x27\x1e\x8b\xcf\x55\x2b\xbd\x2e\x86\xa4\x34\xa9\xa5\xd9";
|
||||
constexpr char kKeyBytes2[] =
|
||||
"\xa4\x63\x1a\x15\x3a\x44\x3d\xf9\xee\xd0\x59\x30\x43\xdb\x75\x19";
|
||||
constexpr char kKeyId2[] =
|
||||
"\xf3\xc5\xe0\x36\x1e\x66\x54\xb2\x8f\x80\x49\xc7\x78\xb2\x39\x46";
|
||||
constexpr char kKeyId3[] =
|
||||
"\x10\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";
|
||||
constexpr char kKeyBytes3[] =
|
||||
"\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0\x10";
|
||||
constexpr char kPreProvisioningKey[] = "f7538b38acc78ec68c732ac665c55c65";
|
||||
constexpr char kValidCertList[] =
|
||||
"{"
|
||||
"\"kind\": \"certificateprovisioning#certificateStatusListResponse\","
|
||||
"\"signedList\": \""
|
||||
"CisIhdC/"
|
||||
"9gUSIwoNc2VyaWFsLW51bWJlciIQCJICGgRtYWtlIgVtb2RlbDAeEoADMI21pWCKSrmyeUAiCT"
|
||||
"gkYwrZsXXHKsDQ7J9pkNbZTYj5kqpa/WaXQDWV3KNsEAf0a9FERSFr1V/"
|
||||
"Vr3oEwOVZ8pA2uHY7KA/ghY7FByzDYA8GQyofi8XV/m27QL/o2iu1YQXkO87l37/"
|
||||
"RdWY1gHzqiwbiCXJsPqD4+S2g9o5/hwlDOzHToqylUS2rj5iBO/"
|
||||
"0fkuxKnWbxU0+PCcV2cuUhBv+jqOg8wDAw3/9HJEiUAzH7la/"
|
||||
"f8nZQMUj1AOBZuKbgdobIPNs9tj3cCRKDIY8DomfceZgJO+"
|
||||
"DHtxdggeZoBfq8jiFS5NynMx7OcINT3LRPmJ6opTwMhF5uurXRmRDXxJ/E+Z5bTCEbxCZ/"
|
||||
"6rhr+faGam9tDZHxHuetDPx5l2mfQnF7lY7Te+FChv+"
|
||||
"xIc93FvqNYF3TCZui3LYoqqPylijzLNZ7dPaVZ7hN/cFPJVudA/"
|
||||
"eHq6ElmJquoKd5022d6Rin6oFymJUKF7FKRKfIkepkgncT5C/kI3/tX6nilNb6"
|
||||
"\" }";
|
||||
constexpr char b64DrmServiceCertificate[] =
|
||||
"CsMCCAMSENU2hMYAMrDf+"
|
||||
"Z9TlWepj1UY7eXE9gUijgIwggEKAoIBAQCqBNtJ830093pLL7h0daCvCUY7WQ8nrNfyYa5NI"
|
||||
"TMR8V6JxHUtykxzMP2FR6cgJb0NPXQXg3U6kTqHClUYu2OOHjoSi68LtbTL4S+7d/"
|
||||
"b1NqOhLLLQqiRXUOfZE4BrSJx0W+bUrzLOFgl+xmMv5jlNpdFLhn1+/"
|
||||
"QOs0u2dxen+yCDoXIOVbFtQtA3RB+sRxvjaOwW4u5dqMj2Xzd/"
|
||||
"JjWiAwgDAMe3g256M2s+5ZzZ1CnZv6KWPwKzQKXzO/O/"
|
||||
"bSGrMz9K9T1kRVPPnq8FAiXh2IY+"
|
||||
"JZ5EcPwrbcdEmiMWxf7bWv3Pk9vSSC8ZDUUI4oBdocf6TCEFKFq1uZBXP0VGbAgMBAAE6Emh"
|
||||
"hbWlkLXd2cGwtc2RrLXVhdEABSAESgAO0xjYXyZAJ7UNU0N5duOxRkSjlZW7DcqYE5DH8T9n"
|
||||
"QzCZ/PHPraiWcOaHxyG1sR6Vn6zW7EFV4izXWPI0BTI6Kys/3fQmbstX71om2h8lm3+zOh/"
|
||||
"baLl605RaIpTCHdQj5hfoxs/nn6CI+VxxxD8L1JiGXbcg0/"
|
||||
"noSHMJorOq+sDJDK6aYqZDEtrJaY6DfZa+IAK7Nn/"
|
||||
"WDWVpefrVJwP2h2chjKpYSbOVxRnpqWqWVxT30ROyJwF1BA9F/"
|
||||
"dMeqTyeyzk1fMfVRQuHaaFqYz6HazSg7dqoXGEKTonN9kHWXTzdPY5jhdXO3vOu4U1k9LzSM"
|
||||
"4Gnb/"
|
||||
"8K2F2vQQECskoGkGTF85NB2vyXA95FJa5ExwCXrTnCuBZOLOsR6wwazn5H0gDAmqbTxm2I0r"
|
||||
"7Ar7IrU8z9v83k1171RDk9xHO+yJD6eFQSyk9stqQH/dNU1DPjCaMylk8ysQ/"
|
||||
"8XYRj9O0LBEsT2oC4Y7lFd17/NqJeOGvOwVgUmQ/lIVNMmZajEqz0=";
|
||||
|
||||
constexpr char b64PrivateKey[] =
|
||||
"MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI4UNtEZV1vrkCAggAMBQGCCqG"
|
||||
"SIb3DQMHBAhSpl2tcdfcVwSCBMi7K5Ne/XsAB49mm0gIQ1BCTiIfdzuS/OO0Z3xoUry9/"
|
||||
"Z50vE6aAkqLbvP7XbWltDU+jzjkjoAnkEUJ56Njifd7EhTSN7M6W6x2mC7c+"
|
||||
"qgdVW7XqR8iKIpULYaU9txNadwl1p1iP0MoKN0cORXKHzhgUPaTkUKiseCMVdCsImPrDlBrm"
|
||||
"s+jeyft8YwPpUlCxFLTQo+F9HmxKBKxYcEs1g9EByrXCrIx1oHAJBgCihFOi+"
|
||||
"qFC2HQJex54tx1QEf/"
|
||||
"bb5G7xW3vD4T3fZU9by9GNKq9MOVsARmy7ozvDeark6f+"
|
||||
"MxCuUhVvRqRK4EC3YiaVj9GB6kqWA1UjldF+"
|
||||
"HFHsqs6qV2J6HNs42JL7N9PQTJJx6Xdxp7f7PjgsJUslZeiyW+uZ8wIpMsBg4NtOkcbgb+"
|
||||
"ijGiPGYCPMv7mVFWqyMeSM+BQN3NF48P/"
|
||||
"VHfHQ9CmX41uE8+"
|
||||
"IhXdi1b4fjenUIKcJ95yoB1yauZGBRBdvjjrZtduczYnoJd9BYCbEYErRC5cvNU+"
|
||||
"FzYEUYKqUBLc25RWd8hg/"
|
||||
"NGiaC7YwCJjI59o7SGgY1BFuPuEaehJ60OvbgJiyBofAGOMulrF+"
|
||||
"Quf6QFgltUFnOIpcXhll9/"
|
||||
"C+"
|
||||
"RWW6uLXfxZICt3F6Z4dq9xZi5ZSUzZVsdLtbYAP4QLXTqGTgPA7FdFvHrhf3GJTIppE2a58x"
|
||||
"uEkVkXl2cqYSuat4QGRxNrleJ55gWvZKIzIN2j85Jk2E9UljNURso/9FIsEF/"
|
||||
"S2Js77nvn5t40VNdzhUvSjDkD8S75hlyHMTFbc/"
|
||||
"9yOlrUWT2AP+veMnzgR5wltQ32qgkujBj7ogHz+0/"
|
||||
"RvpBKyvmHI+mvmqm6aS22yEjQ6jhyEN8mKZNPpgz94TFzYwP9s/qV+/"
|
||||
"AllJNQ0ruMue9gUKYu381u/"
|
||||
"F0eLG4ZORinxnxMtWQhpB7cR71nBmt2SYicg2moqKc9hQ7JRJ7g0V07AjWByRRHaOwgJ/"
|
||||
"YBsCaVeyMl8ynKpWB9r8AW9qKaf79JC+brcWrel8S+YKHX8akmTrs0gSzI+M0hBGqp3f/"
|
||||
"xnRiAuBXLGZ8Vm2YqsJpFYGyFKBoPUinCuoDLWJnbWt3GBAvHp8OWry67Ldz6vcQmh0eEWmi"
|
||||
"qIzHGGw2eti2BNpJwATXZ7CfETB9jlHfk4vPZlTWzuzBaQtExLNGXJbgXDJeaTxVdZ7JU2ul"
|
||||
"S4VgmBAUZnXXJYBgNc1qCCnijFX/R06hN3LrG/"
|
||||
"d5odxQCfhIMuSieaTrWuoqBYxxi5dLzarRRp9DySURt9JepyOps9sPBfvLh5iDy2LQ2dWbmS"
|
||||
"A/"
|
||||
"rqsaV+"
|
||||
"8z4v4Y1gDJCmKFMa2GPNSlJDqjASw8tDDMXL4dwYb2RcWLCHM5CXJAnxSE4ZpHvf0dwAyDqg"
|
||||
"hikih9D7CvOwGdv7oVW6/"
|
||||
"tTdoOo+WkrQtgmRfboxX9Spin+vL1ia2jW2VugSMQbEhTkKH+"
|
||||
"NE0TC6VGsvPJt0wLLhzRMzTEeT05Zl4QpeCKUmHFM4LIXWcACQ8L1Q0YjOXg733q/"
|
||||
"fs2kmXsHV9TG5kqHemGIf7t0baF7ibzwnl7F+GGWmg/"
|
||||
"dQ1RdM7T0p5wRtqHK0wAKxG8hxZkejHPBnV9GYK8QUOlxnE7tVM2Sv6QmTOKGXGKDRBsoacm"
|
||||
"BaGLiE=";
|
||||
constexpr char kLicenseRequestExample[] =
|
||||
"\x12\x90\x01\x0a\x58\x08\x00\x12\x48\x00\x00\x00\x02\x00\x00\x01\x12\x8e"
|
||||
"\x1e\xbf\xe0\x37\x82\x80\x96\xca\x65\x38\xb4\xf6\xf4\xbc\xb5\x1c\x2b\x71"
|
||||
"\x91\xcf\x03\x7e\x98\xbe\xaa\x24\x92\x49\x07\xe1\x28\xf9\xff\x49\xb5\x4a"
|
||||
"\x16\x5c\xd9\xc3\x3e\x65\x47\x53\x7e\xb4\xd2\x9f\xb7\xe8\xdf\x3c\x2c\x1c"
|
||||
"\xd9\x25\x17\xa1\x2f\x49\x22\x95\x3e\x1a\x0a\x0a\x03\x66\x6f\x6f\x12\x03"
|
||||
"\x62\x61\x72\x12\x2c\x12\x2a\x0a\x10\x30\x31\x32\x33\x34\x35\x36\x37\x38"
|
||||
"\x39\x41\x42\x43\x44\x45\x46\x10\x01\x1a\x14\x6d\x79\x43\x6f\x6f\x6c\x52"
|
||||
"\x65\x71\x75\x65\x73\x74\x2c\x20\x44\x75\x64\x65\x21\x18\x01\x20\x9d\x88"
|
||||
"\xf7\x8a\x05\x1a\x20\xac\xc0\x12\xac\xcd\x1a\xac\x9f\x11\xaa\x84\xbf\xd1"
|
||||
"\x6f\x01\x44\x8a\xd5\x00\xb8\x60\x2e\x26\x9d\xd2\x71\x7e\x0b\x26\x55\x31"
|
||||
"\x83";
|
||||
constexpr char b64SerializedSignedDeviceSecurityProfiles[] =
|
||||
"Cm0I45_P_"
|
||||
"AUSLwoIZHNwX3Rlc3QQAhoECAAQACIGCAAQAyACKg13aWRldmluZV90ZXN0OgQIABAAEjQKC"
|
||||
"GxpdmVkZW1vEAIaAggEIgIQASoNd2lkZXZpbmVfdGVzdDIFCNcIEAI6CAiDwrX6BRAAEoADb"
|
||||
"oYJI5ouzml8W63DmiTBA7thzSl5OaKbyc1dAKGpHrMw-lTuUyrzULPm5nb_"
|
||||
"st4YJk2w3F0k4Ly0lsRY_QweMSIechtcII5jO_9N2scy0y5V-lBRH_"
|
||||
"7AtZFdfwD2wrseVCCarSyWDZN84-"
|
||||
"6Wu3ekKbNO8vehiP8Tx2VWmkcIypJ09nPuTDxPT5CutLkgzlIS2q9HjwE5IK4nfC-"
|
||||
"rx7seGgMxouyEb-QsTBtJ-Lx9O8D1GFMvOtHmfG-KfoD1L-"
|
||||
"9lUT6j8W3TfyrUesnIDQy2bCCQzsbsNg60M9B-YZNvl6DX_-"
|
||||
"PqE1CT2Lal7rp5TsZluOtwEj8TMBzyNl5kC5MAXZ3ETEFDag_9qEZrMJMIEsw194_lo_"
|
||||
"o2ivjkiPNwCC00rJ91RI9gc2ctDlXUqtbqfz5-lx_v04VsI8AEYfuXmO8OBhFZwz4__"
|
||||
"ZVwpI8fOtedm1KI46uCWZUwIi3yigYNJvgxoynzxVF8uMLTJi3iqiG5BAtrRImEt1iRVD8Ow"
|
||||
"h4-GAI=";
|
||||
|
||||
int GenerateLicenseUsingProfiles(
|
||||
WvPLSession& session, absl::string_view content_owner,
|
||||
const std::vector<std::string>& qualified_profile_names,
|
||||
std::string* license_response) {
|
||||
// Set parameters on the created session.
|
||||
// Set policy parameters.
|
||||
WvPLPlaybackPolicy policy;
|
||||
policy.set_license_duration_seconds(604800);
|
||||
policy.set_playback_duration_seconds(86400);
|
||||
session.set_policy(policy);
|
||||
|
||||
// Set key parameters.
|
||||
// Content keys are generated based on the info from qualifying profiles.
|
||||
// The qualified profiles can be used to determine the content keys allowed
|
||||
// in the license.
|
||||
// In this example case, qualified custom profiles for owner_name
|
||||
// "widevine_test" is non-empty, so the following keys are generated based on
|
||||
// qualified custom profiles. Those keys would support SD content.
|
||||
WvPLKey wvpl_key1;
|
||||
// Key bytes and key id must be in bytes.
|
||||
wvpl_key1.set_key_id(kKeyId1);
|
||||
wvpl_key1.set_key_bytes(kKeyBytes1);
|
||||
wvpl_key1.set_track_type(VIDEO_SD);
|
||||
wvpl_key1.mutable_output_protection()->set_hdcp(HDCP_NONE);
|
||||
wvpl_key1.mutable_output_protection()->set_secure_data_path(true);
|
||||
WvPLStatus status = session.AddKey(wvpl_key1);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key: " << status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
WvPLKey wvpl_key2;
|
||||
wvpl_key2.set_key_id(kKeyId2);
|
||||
wvpl_key2.set_key_bytes(kKeyBytes2);
|
||||
wvpl_key2.set_track_type(VIDEO_SD);
|
||||
wvpl_key2.mutable_requested_output_protection()->set_hdcp(HDCP_V1);
|
||||
wvpl_key2.mutable_requested_output_protection()->set_secure_data_path(false);
|
||||
status = session.AddKey(wvpl_key2);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key: " << status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Generate the license
|
||||
status = session.GenerateLicense(license_response);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate license: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
std::cout << "Generated license. "
|
||||
<< absl::BytesToHexString(*license_response) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GenerateLicense(WvPLSession& session, const std::string& content_owner,
|
||||
const std::vector<std::string>& profile_owners,
|
||||
std::string* license_response) {
|
||||
std::vector<std::string> qualified_profile_names;
|
||||
WvPLStatus status;
|
||||
std::string content_id;
|
||||
status = session.GetContentId(&content_id);
|
||||
|
||||
// Set parameters on the created session.
|
||||
// Set policy parameters.
|
||||
WvPLPlaybackPolicy policy;
|
||||
policy.set_license_duration_seconds(604800);
|
||||
policy.set_playback_duration_seconds(86400);
|
||||
session.set_policy(policy);
|
||||
|
||||
// Optional. Check the qualified custom profiles for the content owner.
|
||||
if (std::find(profile_owners.begin(), profile_owners.end(), content_owner) !=
|
||||
profile_owners.end()) {
|
||||
status = session.GetQualifiedCustomDeviceSecurityProfiles(
|
||||
content_owner, &qualified_profile_names);
|
||||
if (status.ok() && !qualified_profile_names.empty()) {
|
||||
std::cout << "DRM qualifying custom profiles for owner <" << content_owner
|
||||
<< ">: ";
|
||||
for (const auto& profile_name : qualified_profile_names) {
|
||||
std::cout << "<" << profile_name << "> ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
// Set key parameters.
|
||||
// Content keys could be generated based on the info from qualifying profiles.
|
||||
// The qualified profiles can be used to determine the content keys allowed
|
||||
// in the license.
|
||||
// In this example case, qualified custom profiles for owner_name
|
||||
// "widevine_test" is non-empty, so the following `wvpl_key1` could be
|
||||
// generated based on qualified custom profiles.
|
||||
WvPLKey wvpl_key1;
|
||||
// Key bytes and key id must be in bytes.
|
||||
wvpl_key1.set_key_id(kKeyId1);
|
||||
wvpl_key1.set_key_bytes(kKeyBytes1);
|
||||
wvpl_key1.set_track_type(VIDEO_SD);
|
||||
wvpl_key1.mutable_output_protection()->set_hdcp(HDCP_NONE);
|
||||
wvpl_key1.mutable_output_protection()->set_secure_data_path(true);
|
||||
status = session.AddKey(wvpl_key1);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key: " << status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Or we could call FilterKey() to filter out the keys. Keys could be inserted
|
||||
// with one security profile as required profile, as well as content owner. In
|
||||
// Filterkey() API it already contains the logic of checking the qualified
|
||||
// security profiles for the content owner.
|
||||
WvPLKey wvpl_key2;
|
||||
wvpl_key2.set_key_id(kKeyId2);
|
||||
wvpl_key2.set_key_bytes(kKeyBytes2);
|
||||
wvpl_key2.set_track_type(VIDEO_SD);
|
||||
wvpl_key2.mutable_requested_output_protection()->set_hdcp(HDCP_V1);
|
||||
wvpl_key2.mutable_requested_output_protection()->set_secure_data_path(false);
|
||||
wvpl_key2.set_required_profile("dsp_test");
|
||||
wvpl_key2.set_content_owner(content_owner);
|
||||
WvPLCapabilityStatus wvpl_capability_status2 = session.FilterKey(wvpl_key2);
|
||||
if (!wvpl_capability_status2.ok()) {
|
||||
std::cerr << "Failed to add key: " << wvpl_key2.key_id()
|
||||
<< " with status:" << wvpl_capability_status2.status()
|
||||
<< std::endl;
|
||||
}
|
||||
// The following example `wvpl_key3` will be filtered out because the profile
|
||||
// name the key associated with is not qualified.
|
||||
WvPLKey wvpl_key3;
|
||||
wvpl_key3.set_key_id(kKeyId3);
|
||||
wvpl_key3.set_key_bytes(kKeyBytes3);
|
||||
wvpl_key3.set_track_type(VIDEO_HD);
|
||||
wvpl_key3.mutable_output_protection()->set_hdcp(HDCP_NONE);
|
||||
wvpl_key3.mutable_output_protection()->set_secure_data_path(true);
|
||||
wvpl_key3.set_required_profile("L3");
|
||||
wvpl_key3.set_content_owner(content_owner);
|
||||
WvPLCapabilityStatus wvpl_capability_status1 = session.FilterKey(wvpl_key3);
|
||||
if (!wvpl_capability_status1.ok()) {
|
||||
std::cerr << "Failed to add key: " << wvpl_capability_status1.status()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Generate the license
|
||||
status = session.GenerateLicense(license_response);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate license: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
std::cout << "Generated license. "
|
||||
<< absl::BytesToHexString(*license_response) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** This example is used when content providers want to use DSP API for license
|
||||
* generation. The qualified profiles can be used to determine the content keys
|
||||
* allowed in the license.
|
||||
*
|
||||
* If content provider doesn't want to use DSP for license generation, they
|
||||
* could follow the example shown in "wvpl_license_sdk_example.cc".
|
||||
*/
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// Set up WvPLEnvironment.
|
||||
std::map<std::string, std::string> config;
|
||||
// Set device certificate expiration time to 10 years (10 * 365 * 24 * 3600).
|
||||
// Note that in practice, the expiration should not be 10 years long.
|
||||
// Certificate status list should be updated periodically.
|
||||
config[kDeviceCertificateExpiration] = "315360000";
|
||||
|
||||
// The DCSL and service certificate used in this example are for "development"
|
||||
// and will not work with Widevine's production servers. Replace "dev" with
|
||||
// "prod" when using production certificates.
|
||||
config[kDrmCertificateType] = "dev";
|
||||
|
||||
// Set parameters on the environment.
|
||||
WvPLEnvironment wvpl_env(config);
|
||||
WvPLStatus status = wvpl_env.Initialize();
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to Initialize environment: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// The preProvKeys map takes a device systemID as the key and an associated
|
||||
// preprovisioning key as value.
|
||||
std::map<uint32_t, std::string> prev_prov_keys;
|
||||
prev_prov_keys[kSystemId] = kPreProvisioningKey;
|
||||
video_widevine::Status wv_status =
|
||||
wvpl_env.SetPreProvisioningKeys(prev_prov_keys);
|
||||
if (!wv_status.ok()) {
|
||||
std::cerr << "Failed to set pre prov keys with stats: " << wv_status
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string b64DecodedDrmServiceCertificate;
|
||||
std::string b64DecodedPrivateKey;
|
||||
if (!absl::Base64Unescape(b64DrmServiceCertificate,
|
||||
&b64DecodedDrmServiceCertificate)) {
|
||||
std::cerr << "Failed to decode ServiceCertificate." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!absl::Base64Unescape(b64PrivateKey, &b64DecodedPrivateKey)) {
|
||||
std::cerr << "Failed to decode PrivateKey." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Must set a valid drm service certificate, otherwise it will failed to
|
||||
// create session.
|
||||
std::string passphrase = "encryptallthekitties";
|
||||
status = wvpl_env.SetDrmServiceCertificate(b64DecodedDrmServiceCertificate,
|
||||
b64DecodedPrivateKey, passphrase);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set DrmServiceCertificate: "
|
||||
<< status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Set a valid device certificate status list.
|
||||
status = wvpl_env.SetDeviceCertificateStatusList(kValidCertList);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to update the certificate status list: "
|
||||
<< status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Set custom device security profile list.
|
||||
// One time setup each time new DSPs are loaded.
|
||||
std::string serialized_signed_dsps;
|
||||
if (!absl::WebSafeBase64Unescape(b64SerializedSignedDeviceSecurityProfiles,
|
||||
&serialized_signed_dsps)) {
|
||||
std::cerr << "Failed to decode serialized_signed_dsps." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
status = wvpl_env.SetCustomDeviceSecurityProfiles(serialized_signed_dsps);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set custom device security profiles: "
|
||||
<< status.error_message()
|
||||
<< ". wvpl_env will continue to use the previously loaded DSPs "
|
||||
"if there is any."
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Optional sannity check.
|
||||
// Verify the custom profile owners match with list of expected content
|
||||
// owners.
|
||||
std::vector<std::string> custom_profile_owners;
|
||||
status =
|
||||
wvpl_env.GetCustomDeviceSecurityProfileOwners(&custom_profile_owners);
|
||||
if (!status.ok() || custom_profile_owners.empty()) {
|
||||
std::cerr
|
||||
<< "Failed to get owner list for custom device security profiles: "
|
||||
<< status.error_message() << std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
std::cout << "DRM custom profile owner list: ";
|
||||
for (const auto& owner_name : custom_profile_owners) {
|
||||
std::cout << "<" << owner_name << "> ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Create the DRM session.
|
||||
WvPLSession* session = nullptr;
|
||||
|
||||
// Set the license request.
|
||||
status =
|
||||
wvpl_env.CreateSession(std::string(std::begin(kLicenseRequestExample),
|
||||
std::end(kLicenseRequestExample) - 1),
|
||||
&session);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to create session: " << status.error_message()
|
||||
<< std::endl;
|
||||
return status.error_code();
|
||||
}
|
||||
|
||||
// Set SessionInit
|
||||
WvPLDeviceStatusOptions wvpl_device_status_options;
|
||||
wvpl_device_status_options.set_allow_test_only_system_id(true);
|
||||
WvPLSessionInit wvpl_session_init;
|
||||
wvpl_session_init.set_device_status_options(wvpl_device_status_options);
|
||||
session->set_session_init(wvpl_session_init);
|
||||
|
||||
// Generate the license for |content_owner| after successfully creating a
|
||||
// WvPL session. Assume license is generated for content_owner =
|
||||
// "widevine_test".
|
||||
std::string content_owner = "widevine_test";
|
||||
std::string license_response;
|
||||
return GenerateLicense(*session, content_owner, custom_profile_owners,
|
||||
&license_response);
|
||||
}
|
||||
Reference in New Issue
Block a user