Media CAS Proxy SDK release: 16.5.0
This commit is contained in:
346
ubuntu/example/WvPLCASProxyExample.java
Normal file
346
ubuntu/example/WvPLCASProxyExample.java
Normal file
@@ -0,0 +1,346 @@
|
||||
// Copyright 2019 Google LLC. All rights reserved.
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCASProxyEnvironment;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCASProxySession;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCasKey;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLClientCapabilities;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLClientInfo;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLDeviceInfo;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLHdcp;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLKeyType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLMessageType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLOutputProtection;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLPlaybackPolicy;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLRequestType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLSessionInit;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatus;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatusException;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLTrackType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLWidevinePsshData;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WvPLCASProxyExample {
|
||||
/* Creates WvTestRunner to run wvpl proxy test */
|
||||
public static String loadCertificateStatusListFromFile(String certificateStatusListFile)
|
||||
throws IOException {
|
||||
BufferedReader br = Files.newBufferedReader(Paths.get(certificateStatusListFile), UTF_8);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
sb.append(line);
|
||||
sb.append(System.lineSeparator());
|
||||
line = br.readLine();
|
||||
}
|
||||
br.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
String b64DrmServiceCertificateWithCASProxyType =
|
||||
"CrwCCAMSELBFY1_OQaWD87swUMHQjTMY0Ont7AUijgIwggEKAoIBAQCUNggP3JYvTaepEoHfiG32zOEbimIPtzmjTsu-"
|
||||
+ "3mOyXn3iA_d-aL6PnCqB0ORWvHld-xkRGHUUCSMAX0stvi-vTAd7e5fdMTXVtDbmj4o2fYDfp0klk3qj3OS7-X"
|
||||
+ "H-z2musgRkbzZTzpH8MzUnLRHz97TMx46bwYyL8SskrvnaWwyPBhkDfmAoNQKSVuLZNc6snfOAE4hNCdB4Qq-H"
|
||||
+ "TgC3FIl-1Kt4svUUPL4LYAzpKG5xH2r6ol0PQGSIKQ2qhJ-dyXLgDZcFLYdKd7hnKD1yUpvv8tGdHwcXawq7B-"
|
||||
+ "eLitKy0gRJx1nyMmLQ-RG31FBEfR6Gtatzcs2OTyoZuktzAgMBAAE6DXdpZGV2aW5lX3Rlc3RABBKAAwtMdfh-"
|
||||
+ "yBur-Ivq7rz_00RR8vA4MPJOPR3sZXDVFRQsATRvqUVPCTP88hh6Y7Y3IdHTEfXgcjiz2GZqEOvXzl3iuWkSjN"
|
||||
+ "QjNl5ghk955VIryOdzkIYBZJIv4_eEon2RRflExbv4y2GuWxTxHxMmIrFKXF-w2fLSvpiy1qT5daHPIcdvRBDH"
|
||||
+ "wIAVbmNmfv2EXoAqbvBWLhOdA8IRd5Lylqa8SWsUgkuyt9mglUdno6h_WCXZBm99eTfuN66ls-rJrlDgUNO3OU"
|
||||
+ "OXpMYMI8jE4Neo4GF8AKXoyt0lcckHwynzdlSYa04V6vbPMNycO-u1wpnUAPqkXYbnoYnbjm5gJ7Vav5wJtUM4"
|
||||
+ "wFAREefRmS_Dz_kqspC1CxQXo10KZQm3b4QXc_S0cqNXM_R9NGct0qjUdKec_k1RfC1j7MckdZMg4oU-mnqmwO"
|
||||
+ "ZS7jTNIaHS4ASTuicsDUsfX1Ac4eqGv1L3qEY4pipCOps-5mRJ3sCjz87cX8QnPsArgtFYSYPgAg==";
|
||||
String b64PrivateKeyWithCASProxyType =
|
||||
"MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI5Qd3AH24lskCAggAMB0GCWCGSAFlAwQBKgQQ9X4D3HPW"
|
||||
+ "x35HsgzSgMWCzASCBNBDZGDdRs_hyeRTrca0H4UERbrKRYFsoce9n6-cghmLtIzAn8pYdGH_jfj5Hc3HTo9aXx"
|
||||
+ "fJJz9Juckh9teStzVmA-8y2Qj7W8W243DjbyNyKKDzk9esQme5sVvNugEb8wiqraZ0q4KxfjcK60HsZrOK1Ise"
|
||||
+ "0TglQMvudrDzV3vTxtgP5LTer6wEnUjfGixzhL120X48me-1stTPeG2ji9zlsgmMCjYCEbe4ovMCZmVOaHnbQ3"
|
||||
+ "WNVVnMnVQCqCAmBg_0AKgYB9wvvy7vdRaFHv0EtmyCOegLToNE0I7L5LMcL4-HQ--bwQMHjVkDmIqB3s3XWyhN"
|
||||
+ "U_nneES3qpgAbKpObfPGs814BqjbKwGj6z8jrNJ9Lmlaj_7msphYCuOAEjc26CEmxMYG1dTe-XiluHGIVunau6"
|
||||
+ "iL7OguAdgbhkc2MQ7XJISjQ8j2sYuryUW33Pn2JSoKa4vVCWxTwg2t86Mc3FJ_daLM_z_kqTh5zel6o05tGXgH"
|
||||
+ "hn2UGRTjAs3PgxzExUX6M2_-6uSmdnS4oWxAqVd9ZREMjZaSBY6qPdXyM-Wd2RmUfLNSO3aazLxWu8uH2nbud_"
|
||||
+ "3vLyMSj_7lLjtAATqDKrcr1PyNlrn0MTQWIUZ4S5rsHHtprPB_v-7Ufh4OVPdyWfapBGJLx8Eg0Xscoxc_DpwA"
|
||||
+ "D9KoA62GGg2CPu4NvvHiFIvEkpsxNFGTEAbZfoXXw78GP370doSguKvbTI3INcguKM35pbpe7-gbU8BjSednsl"
|
||||
+ "bQMk4QKFg0YIQmTPDVXAC7FVnyP_dlNf2RXQRObGBGvA_oWv62iz8d3UhpIJOFHeyNic-qoQTj6wRFcxdFR61J"
|
||||
+ "hvqZ8rM_KHJl_pvazrhMJ4JAQJXWhQzOvp4rqAJ7Jfx1u_pF_ZRZ6AX2Rjec-xep4EaqRZPdfEUydKKlr10IIc"
|
||||
+ "_kNQwU15m0UEE_40wDJ3XqrhKuUnPfHpm4cziFYsQPrfuI36MCKklPvjdWS6VdSA-evN6KBZwD3RQh4jdzTxWf"
|
||||
+ "zN-0p9612jIwzUzZj8Zax-TRRaOaN-0-nuPsmR88Ps4Y8AE2-CocYykAD8jh5WbuZKJDEtrNsIfz6keNZVk5ji"
|
||||
+ "1JWcpwzbPk9L_A8MdZh5XBA7X-BLe2F6EIVgI3mwTUPSC8wpoGsc4Hu2VeePzOuuZ59IGSmDkyi68usMQzsVeq"
|
||||
+ "2VJyz4UpDgy5dC5EOcBHLf3_oiAoxuYu6MIXLk-srrO8-mikdRcey9EzmK9uqMV1e4b7Ts7hdIglBij1QwIKbD"
|
||||
+ "mMDMnmnPGX9X5KJojYuxkboe4WWwUgloyRkwxqKWIuEhLirO7E9eS-OOeqtz0idkcMNWziJRiUkVh768T4yfOf"
|
||||
+ "Z8ZvOCx59YN8bL390OZIIdaxSvj5mGeQX2-DTDspxDLpiluDJzTQmH7UZsSQ9DlQiXBtJwuaiFoRsyr0b1hh6n"
|
||||
+ "yE1TibcD_mWuwMOanUnvGF7OzRyneki4aB-v_PwpvplIDQuRqmkjn9i5P7tl6msEMUhp0yBE2tQIYPbQlIw57n"
|
||||
+ "3wRcGOz9ymOrREzEW1UhZQBibr8ZFNoWzRt-k0EVLYzNt96NDtHfHc7AlxJv8ERIDOZ4ai_nNeLgtV76-ybXnT"
|
||||
+ "RqRO9TXwqZhHQ_7gEs4Y01IJxvEQ==";
|
||||
String passphrase = "encryptallthekitties";
|
||||
String providerIv = "d58ce954203b7c9a9a9d467f59839249";
|
||||
String providerKey = "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
|
||||
String b64LicenseRequest =
|
||||
"CAcSuQsKhAsIARLtCQquAggCEhCLiDL7eSGz5lQZxhEvltHOGOTt1OEFIo4CMIIBCgKCAQEApynnDkNRVwiBn-bGL5_C"
|
||||
+ "bqnyMAvVzKeRMbRpl8woIqhHmljqKHt9zq2mt3KQzQ3z96mL1OkZB2Mb_EBlr-k7CPlaV5n3ORJS3mo9Cg5QLc"
|
||||
+ "EWwOCFPIdeXr_4Q4WMMi8sBgF9QjmBp6QQcP-OrgwqwTVJEYfrInkHsRhey3bNPybrAlmj5sF3w1reLAeqJD0p"
|
||||
+ "WZ4lGmq027m-oAESe9OXZb1AobsjuIOxCrgprd4XMRuQKVBZVwk28O5exr2roL4Hrb_zBQVTfGfxAE2vRp5tdg"
|
||||
+ "Ak9vBwlWh_3jWmJlG1BL7qynkoLOgwAakU_dnvrOfm0VlZq-5TazxMtT5XOzkSjQIDAQABKJkgEoACMjGvs7ZD"
|
||||
+ "6n2zCV_co_6N9J4pnSsZ_p2nq18obvIXoIImvQ1TDpaD-7eO3syn2Lw_H5rAOlOo1IApwPSQpq8wG9onMW5ZIE"
|
||||
+ "CaWoiay6SVOdHZLAt4SxgdoRTzu0XtvHu6fN36blmVAOkvjA3RHs6-u4D-xzJz1cYgvzCzDAvhqQ8bhuqRNJc5"
|
||||
+ "2WG1ic4bG4PTHhNeSJt1KjJDGtG9botphtvQyYBzhytTSRH8jr-lKMYvaWm21LUHmmQLAvpZiczKxwjUEw5Ghg"
|
||||
+ "IPi1D56jj4JCQpNVX4L8kgrTP0E5i1Mv4B4otQ9201NJg1MocUlpurZ_aOs8wwqsXScf_z4bHJYhq2BQqwAggB"
|
||||
+ "EhAITWC8ZZN9tqx_mStB7PXyGKLTiowFIo4CMIIBCgKCAQEAmRs1e7cU3srB5w6qNtHQg03ySj0QNp-Qoic0o6"
|
||||
+ "1K68z8JDK91tzR_9dWmbpWCMRFeXLSfEerz_jIjNmQCTgmC4yFeVMnsq7zodsn6LliA5KE1gLGp0xqFDpnvmSh"
|
||||
+ "ahyPRPr62sJCzrbYrenE1FQuvT7p0qCnHrekzPkW4C8meTsME6SSHD7tScXJbNRVWY7eBAzkcrAVqa882oLEl5"
|
||||
+ "Kqf2u_v0ZnKTtE7HQpw5oDiRHOH-Riw16VwmTTYzQ8OtuUT6KqvboPthxAJ5dYXz37eW9s4dzzt5yYh76YFHDs"
|
||||
+ "vLBI5Z5WT8OtLEuGD3CqRo-2bEooR-7HVa3om9YiV0DJpQIDAQABKJkgMAESgAMhLeFBwTBXwZhyGN1_vC3J-E"
|
||||
+ "yC-R9bFj0DcMcGk4fHDJDDBg8FBFc8bgvTrLmE_Dq3siGnfTczMk1nCppe6mRpHVZmqbZ902eAPNV1O9depyOb"
|
||||
+ "7AwAgpdpV3HOIDxgiY1PJkrVXT0ByW9m1vtsU9GSimCtBA19SOnIPWhJwkjkXA-Vu7jNCx_u5EWMXGCrDVLh-w"
|
||||
+ "-O6Ydmr5z5MwdXhlfoAPGk7T9qAOiVGyFY9Fz8wvfl5cw9fwTqK-NKqN1J69eMYYwUBOMIJX5QKqyN8A1SqJhT"
|
||||
+ "Ab_l5ueE13sLxSyTWosYP7Wv7SWlhVp3_PJxXJB2EWJKWLA32BmFe6uSa-5NVgJ3CJ77Bw-z9ThdHd4eSG2PMt"
|
||||
+ "JT3oaS4wmONbMZJkfnlUTPD7KLNiEz6UKXeBzz9olgUxZn7nTnAmvXITfrHd0FeDTPHavo1wafiKy0t6QCRw8o"
|
||||
+ "ASZLtJw7_uJPxkCkY3TWwQvH0rlgeS0R2lCGq4zP9GGAwkPDldIvGp5PawIaEwoMY29tcGFueV9uYW1lEgN3d3"
|
||||
+ "caEQoKbW9kZWxfbmFtZRIDd3d3GiAKDHByb2R1Y3RfbmFtZRIQV2lkZXZpbmVDYXNUZXN0cxomChFhcmNoaXRl"
|
||||
+ "Y3R1cmVfbmFtZRIRYXJjaGl0ZWN0dXJlX25hbWUaGgoLZGV2aWNlX25hbWUSC2RldmljZV9uYW1lMgIoDhIgCh"
|
||||
+ "4KHBoNd2lkZXZpbmVfdGVzdCIJQ2FzVHNGYWtlWAIYASDk7dThBTAVONOi-_4CGoACBXDXgJopfGQLxWI0z-o2"
|
||||
+ "h-dH3L-ObMMm3moRAv7MQ-xnTALlyNMRCaGsfyy1L0SmsrQQptJjK7hB6tZDe-UQ76fIpQLeHnNOBXuaxl7sY2"
|
||||
+ "Gvrztx8HT_N0KFgAZ9hW1L--zvFw0R1ctjG88xGTpmFWsGoWEZ0NGTgc1XyssK62tuWz5CfIEXvhN7ZiMyoagP"
|
||||
+ "SOWZZ1Mltbiv1AEPeFC6My-njq8N3u9whokMzhlGMePSBctFmn4f8RtUeR7zlLdPuKcp0BBLAOF7ngXF1C-skj"
|
||||
+ "-Y1DrtxwqwczA56yLzXGlh5FhwhaFMSprOHbAFCIQ-ee66aDIbVZ-9_fBMiIE83Q==";
|
||||
String testSessionId = "TestSessionId";
|
||||
String testPurchaseId = "TestPurchaseId";
|
||||
String testProviderClientToken = "TestProviderClientToken";
|
||||
byte[] testMasterSigningKeys = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
boolean testOverrideProviderClientToken = true;
|
||||
|
||||
byte[] passphraseBytes = passphrase.getBytes(UTF_8);
|
||||
byte[] decodedDrmServiceCertificate =
|
||||
Base64.getUrlDecoder().decode(b64DrmServiceCertificateWithCASProxyType);
|
||||
byte[] decodedPrivateKey = Base64.getUrlDecoder().decode(b64PrivateKeyWithCASProxyType);
|
||||
byte[] decodedLicenseRequest = Base64.getUrlDecoder().decode(b64LicenseRequest);
|
||||
java.util.Map<String, String> configValues = new java.util.HashMap<>();
|
||||
|
||||
// Define the configuration that is to be used for WvPLCASEnvironment.
|
||||
configValues.put("drm_certificate_type", "dev");
|
||||
configValues.put("provider", "widevine_test");
|
||||
configValues.put("provider_iv", providerIv);
|
||||
configValues.put("provider_key", providerKey);
|
||||
// Set the device certificate expiration 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.
|
||||
configValues.put("device_certificate_expiration", "315360000");
|
||||
|
||||
// Construct WvPLCASProxyEnvironment.
|
||||
WvPLCASProxyEnvironment environment = new WvPLCASProxyEnvironment(configValues);
|
||||
WvPLStatus status = environment.setServiceCertificate(
|
||||
decodedDrmServiceCertificate, decodedPrivateKey, passphraseBytes);
|
||||
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
||||
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
} else {
|
||||
System.out.println("Successfully loaded service certificate");
|
||||
}
|
||||
|
||||
// Get Device Certificate Status List Request.
|
||||
try {
|
||||
byte[] deviceCertificateStatusListRequest = environment.generateDeviceStatusListRequest();
|
||||
System.out.println(
|
||||
"generateDeviceStatusListRequest = "
|
||||
+ Arrays.toString(deviceCertificateStatusListRequest));
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GenerateDeviceStatusListRequest exception: code = "
|
||||
+ status.getStatusCode() + ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Get service certificate response.
|
||||
byte[] serviceCertificateResponse = environment.generateDrmServiceCertificateResponse();
|
||||
System.out.println(
|
||||
"Service certificate response = " + Arrays.toString(serviceCertificateResponse));
|
||||
|
||||
// Set device certificate statusList.
|
||||
String certificateStatusListFile =
|
||||
"sdk/testing/sampleTestCertificateStatusList.json";
|
||||
String certList = "";
|
||||
try {
|
||||
certList = loadCertificateStatusListFromFile(certificateStatusListFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("FileNotFoundException in reading input cert list.");
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException in reading input cert list.");
|
||||
}
|
||||
status = environment.setDeviceCertificateStatusList(certList.getBytes(UTF_8));
|
||||
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
||||
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
} else {
|
||||
System.out
|
||||
.println("Successfully set DeviceCertificateStatusList in WvPLCASProxyEnvironment.");
|
||||
}
|
||||
|
||||
// Construct a WVPLCASProxySession for a license request.
|
||||
WvPLCASProxySession session = null;
|
||||
try {
|
||||
session = environment.createSession(decodedLicenseRequest);
|
||||
} catch (WvPLStatusException e) {
|
||||
System.out.println("Message: " + e.getMessage());
|
||||
System.out.println("Status message: " + e.getStatus().getMessage());
|
||||
}
|
||||
System.out.println("Successful create WvPLCASProxySession in WvPLCASProxyEnvironment.");
|
||||
|
||||
System.out.println("Version of Cas Proxy SDK library: "
|
||||
+ WvPLCASProxySession.getVersionString());
|
||||
WvPLRequestType requestType = session.getRequestType();
|
||||
System.out.println("Message type : " + requestType.getMessageType());
|
||||
System.out.println("License type : " + requestType.getLicenseType());
|
||||
System.out.println("LicenseRequest type : " + requestType.getLicenseRequestType());
|
||||
|
||||
// Examine the license request by retrieving WvPLClientInfo.
|
||||
try {
|
||||
WvPLClientInfo clientInfo = session.getClientInfo();
|
||||
WvPLHdcp.HDCP maxHdcpVersion = clientInfo.getMaxHdcpVersion();
|
||||
System.out.println("WvPLClientInfo, max hdcp version = " + maxHdcpVersion.getHDCP()
|
||||
+ ", oem crypto api version = " + clientInfo.getOemCryptoApiVersion()
|
||||
+ ", provider client token = " + clientInfo.getProviderClientToken());
|
||||
Map<String, String> namesValues = clientInfo.getNamesValues();
|
||||
for (Map.Entry<String, String> nameValue : namesValues.entrySet()) {
|
||||
System.out.println("Key = " + nameValue.getKey() + ", Value = " + nameValue.getValue());
|
||||
}
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetClientInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Retrieve the content ID
|
||||
byte[] contentId = session.getContentId();
|
||||
System.out.println("Content ID: " + Arrays.toString(contentId));
|
||||
|
||||
// Examine the license request by retrieving WvPLDeviceInfo.
|
||||
try {
|
||||
WvPLDeviceInfo deviceInfo = session.getDeviceInfo();
|
||||
System.out.println("soc = " + deviceInfo.getSoc() + ", manufacturer = "
|
||||
+ deviceInfo.getManufacturer() + ", model = " + deviceInfo.getModel()
|
||||
+ ", device_type = " + deviceInfo.getDeviceType()
|
||||
+ ", system_id = " + deviceInfo.getSystemId());
|
||||
// Retrieve DRM Device Certificate serial number.
|
||||
byte[] drmDeviceCertificateSerialNumber =
|
||||
deviceInfo.getDrmCertificateSerialNumber();
|
||||
System.out.println("DrmDeviceCertificateSerialNumber = "
|
||||
+ Arrays.toString(drmDeviceCertificateSerialNumber));
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetDeviceInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Validate setting/getting WvPLPlaybackPolicy for a session.
|
||||
WvPLPlaybackPolicy policy = new WvPLPlaybackPolicy();
|
||||
policy.setLicenseDurationSeconds(604800);
|
||||
policy.setPlaybackDurationSeconds(86400);
|
||||
session.setPolicy(policy);
|
||||
System.out.println(
|
||||
"License Duration Seconds = " + session.getPolicy().getLicenseDurationSeconds());
|
||||
System.out.println(
|
||||
"Playback duration Seconds = " + session.getPolicy().getPlaybackDurationSeconds());
|
||||
|
||||
// Construct WvPLCasKey. Multiple keys can be added per session.
|
||||
WvPLCasKey key1 = new WvPLCasKey();
|
||||
|
||||
// Set key fields by using the WvPLCasKey API.
|
||||
// CAS entitlement key id size should be 16 bytes, entitlement key size should be 32 bytes.
|
||||
byte[] oddKeyId = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
|
||||
key1.setOddKeyId(oddKeyId);
|
||||
byte[] oddKeyBytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key1.setOddKeyBytes(oddKeyBytes);
|
||||
byte[] evenKeyId = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
|
||||
key1.setEvenKeyId(evenKeyId);
|
||||
byte[] evenKeyBytes = {16, 15, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key1.setEvenKeyBytes(evenKeyBytes);
|
||||
key1.setTrackType(WvPLTrackType.TrackType.VIDEO_HD);
|
||||
key1.setKeyType(WvPLKeyType.KeyType.ENTITLEMENT);
|
||||
WvPLOutputProtection requiredOutputProtection = new WvPLOutputProtection();
|
||||
|
||||
// Set required output protection fields.
|
||||
requiredOutputProtection.setSecuredataPath(true);
|
||||
requiredOutputProtection.setDisableAnalogOutput(true);
|
||||
|
||||
// Set output protection on the Cas key.
|
||||
key1.setOutputProtection(requiredOutputProtection);
|
||||
|
||||
// Add WvPLCasKey to WvPLSession.
|
||||
status = session.addKey(key1);
|
||||
|
||||
// Adding a TrackType.VIDEO_SD with even key and even keyId.
|
||||
WvPLCasKey key2 = new WvPLCasKey();
|
||||
evenKeyId = new byte[] {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
evenKeyBytes = new byte[] {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key2.setEvenKeyId(evenKeyId);
|
||||
key2.setEvenKeyBytes(evenKeyBytes);
|
||||
key2.setTrackType(WvPLTrackType.TrackType.VIDEO_SD);
|
||||
status = session.addKey(key2);
|
||||
|
||||
List<WvPLCasKey> wvplCasKeys = session.getKeys();
|
||||
|
||||
// Validate setting/getting sessionInit values.
|
||||
WvPLSessionInit sessionInit = new WvPLSessionInit();
|
||||
sessionInit.setSessionId(testSessionId);
|
||||
sessionInit.setPurchaseId(testPurchaseId);
|
||||
sessionInit.setMasterSigningKey(testMasterSigningKeys);
|
||||
sessionInit.setProviderClientToken(testProviderClientToken);
|
||||
sessionInit.setOverrideProviderClientToken(testOverrideProviderClientToken);
|
||||
|
||||
session.setSessionInit(sessionInit);
|
||||
WvPLSessionInit retrievedSessionInit = session.getSessionInit();
|
||||
System.out.println(
|
||||
"retrieved session init fields: sessionId = " + retrievedSessionInit.getSessionId()
|
||||
+ ", purchaseId = " + retrievedSessionInit.getPurchaseId()
|
||||
+ ", masterSigningKey = " + Arrays.toString(retrievedSessionInit.getMasterSigningKey())
|
||||
+ ", providerClientToken = " + retrievedSessionInit.getProviderClientToken()
|
||||
+ ", overrideProviderClientToken = "
|
||||
+ retrievedSessionInit.getOverrideProviderClientToken());
|
||||
// Retrieve session pssh data.
|
||||
try {
|
||||
WvPLWidevinePsshData widevinePsshData = session.getPsshData();
|
||||
System.out.println("ContentId from Widevine Pssh = "
|
||||
+ Arrays.toString(widevinePsshData.getContentId()));
|
||||
if (!widevinePsshData.getKeyIds().isEmpty()) {
|
||||
for (byte[] keyId : widevinePsshData.getKeyIds()) {
|
||||
System.out.println("keyId from Widevine Pssh = " + Arrays.toString(keyId));
|
||||
}
|
||||
} else {
|
||||
System.out.println("KeyIds from Widevine Pssh is empty");
|
||||
}
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("Get WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Retrieve a CAS License request that is to be sent to Widevine License Service using HTTP(s)
|
||||
// POST.
|
||||
String licenseRequest = session.generateLicenseRequestAsJSON();
|
||||
System.out.println("License request is: " + licenseRequest);
|
||||
|
||||
try {
|
||||
WvPLClientCapabilities wvplClientCapabilities = session.getClientCapabilities();
|
||||
System.out.println("WvPLClientCapabilities = " + wvplClientCapabilities);
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetClientInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Destroy the created session.
|
||||
environment.destroySession(session);
|
||||
// Tear down the environment object.
|
||||
environment.close();
|
||||
}
|
||||
}
|
||||
383
ubuntu/example/WvPLCASProxyUsingGroupLicenseExample.java
Normal file
383
ubuntu/example/WvPLCASProxyUsingGroupLicenseExample.java
Normal file
@@ -0,0 +1,383 @@
|
||||
// Copyright 2021 Google LLC. All rights reserved.
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCASProxyEnvironment;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCASProxySession;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCasKey;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLClientCapabilities;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLClientInfo;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLDeviceInfo;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLHdcp;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLKeyType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLLicenseCategory;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLLicenseCategorySpec;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLMessageType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLOutputProtection;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLPlaybackPolicy;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLRequestType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLSessionInit;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatus;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatusException;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLTrackType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLWidevinePsshData;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WvPLCASProxyUsingGroupLicenseExample {
|
||||
static final String B64_DRM_SERVICE_CERTIFICATE_WITH_CAS_PROXY_TYPE =
|
||||
"CrwCCAMSELBFY1_OQaWD87swUMHQjTMY0Ont7AUijgIwggEKAoIBAQCUNggP3JYvTaepEoHfiG32zOEbimIPtzmjTsu-"
|
||||
+ "3mOyXn3iA_d-aL6PnCqB0ORWvHld-xkRGHUUCSMAX0stvi-vTAd7e5fdMTXVtDbmj4o2fYDfp0klk3qj3OS7-X"
|
||||
+ "H-z2musgRkbzZTzpH8MzUnLRHz97TMx46bwYyL8SskrvnaWwyPBhkDfmAoNQKSVuLZNc6snfOAE4hNCdB4Qq-H"
|
||||
+ "TgC3FIl-1Kt4svUUPL4LYAzpKG5xH2r6ol0PQGSIKQ2qhJ-dyXLgDZcFLYdKd7hnKD1yUpvv8tGdHwcXawq7B-"
|
||||
+ "eLitKy0gRJx1nyMmLQ-RG31FBEfR6Gtatzcs2OTyoZuktzAgMBAAE6DXdpZGV2aW5lX3Rlc3RABBKAAwtMdfh-"
|
||||
+ "yBur-Ivq7rz_00RR8vA4MPJOPR3sZXDVFRQsATRvqUVPCTP88hh6Y7Y3IdHTEfXgcjiz2GZqEOvXzl3iuWkSjN"
|
||||
+ "QjNl5ghk955VIryOdzkIYBZJIv4_eEon2RRflExbv4y2GuWxTxHxMmIrFKXF-w2fLSvpiy1qT5daHPIcdvRBDH"
|
||||
+ "wIAVbmNmfv2EXoAqbvBWLhOdA8IRd5Lylqa8SWsUgkuyt9mglUdno6h_WCXZBm99eTfuN66ls-rJrlDgUNO3OU"
|
||||
+ "OXpMYMI8jE4Neo4GF8AKXoyt0lcckHwynzdlSYa04V6vbPMNycO-u1wpnUAPqkXYbnoYnbjm5gJ7Vav5wJtUM4"
|
||||
+ "wFAREefRmS_Dz_kqspC1CxQXo10KZQm3b4QXc_S0cqNXM_R9NGct0qjUdKec_k1RfC1j7MckdZMg4oU-mnqmwO"
|
||||
+ "ZS7jTNIaHS4ASTuicsDUsfX1Ac4eqGv1L3qEY4pipCOps-5mRJ3sCjz87cX8QnPsArgtFYSYPgAg==";
|
||||
static final String B64_PRIVATE_KEY_WITH_CAS_PROXY_TYPE =
|
||||
"MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI5Qd3AH24lskCAggAMB0GCWCGSAFlAwQBKgQQ9X4D3HPW"
|
||||
+ "x35HsgzSgMWCzASCBNBDZGDdRs_hyeRTrca0H4UERbrKRYFsoce9n6-cghmLtIzAn8pYdGH_jfj5Hc3HTo9aXx"
|
||||
+ "fJJz9Juckh9teStzVmA-8y2Qj7W8W243DjbyNyKKDzk9esQme5sVvNugEb8wiqraZ0q4KxfjcK60HsZrOK1Ise"
|
||||
+ "0TglQMvudrDzV3vTxtgP5LTer6wEnUjfGixzhL120X48me-1stTPeG2ji9zlsgmMCjYCEbe4ovMCZmVOaHnbQ3"
|
||||
+ "WNVVnMnVQCqCAmBg_0AKgYB9wvvy7vdRaFHv0EtmyCOegLToNE0I7L5LMcL4-HQ--bwQMHjVkDmIqB3s3XWyhN"
|
||||
+ "U_nneES3qpgAbKpObfPGs814BqjbKwGj6z8jrNJ9Lmlaj_7msphYCuOAEjc26CEmxMYG1dTe-XiluHGIVunau6"
|
||||
+ "iL7OguAdgbhkc2MQ7XJISjQ8j2sYuryUW33Pn2JSoKa4vVCWxTwg2t86Mc3FJ_daLM_z_kqTh5zel6o05tGXgH"
|
||||
+ "hn2UGRTjAs3PgxzExUX6M2_-6uSmdnS4oWxAqVd9ZREMjZaSBY6qPdXyM-Wd2RmUfLNSO3aazLxWu8uH2nbud_"
|
||||
+ "3vLyMSj_7lLjtAATqDKrcr1PyNlrn0MTQWIUZ4S5rsHHtprPB_v-7Ufh4OVPdyWfapBGJLx8Eg0Xscoxc_DpwA"
|
||||
+ "D9KoA62GGg2CPu4NvvHiFIvEkpsxNFGTEAbZfoXXw78GP370doSguKvbTI3INcguKM35pbpe7-gbU8BjSednsl"
|
||||
+ "bQMk4QKFg0YIQmTPDVXAC7FVnyP_dlNf2RXQRObGBGvA_oWv62iz8d3UhpIJOFHeyNic-qoQTj6wRFcxdFR61J"
|
||||
+ "hvqZ8rM_KHJl_pvazrhMJ4JAQJXWhQzOvp4rqAJ7Jfx1u_pF_ZRZ6AX2Rjec-xep4EaqRZPdfEUydKKlr10IIc"
|
||||
+ "_kNQwU15m0UEE_40wDJ3XqrhKuUnPfHpm4cziFYsQPrfuI36MCKklPvjdWS6VdSA-evN6KBZwD3RQh4jdzTxWf"
|
||||
+ "zN-0p9612jIwzUzZj8Zax-TRRaOaN-0-nuPsmR88Ps4Y8AE2-CocYykAD8jh5WbuZKJDEtrNsIfz6keNZVk5ji"
|
||||
+ "1JWcpwzbPk9L_A8MdZh5XBA7X-BLe2F6EIVgI3mwTUPSC8wpoGsc4Hu2VeePzOuuZ59IGSmDkyi68usMQzsVeq"
|
||||
+ "2VJyz4UpDgy5dC5EOcBHLf3_oiAoxuYu6MIXLk-srrO8-mikdRcey9EzmK9uqMV1e4b7Ts7hdIglBij1QwIKbD"
|
||||
+ "mMDMnmnPGX9X5KJojYuxkboe4WWwUgloyRkwxqKWIuEhLirO7E9eS-OOeqtz0idkcMNWziJRiUkVh768T4yfOf"
|
||||
+ "Z8ZvOCx59YN8bL390OZIIdaxSvj5mGeQX2-DTDspxDLpiluDJzTQmH7UZsSQ9DlQiXBtJwuaiFoRsyr0b1hh6n"
|
||||
+ "yE1TibcD_mWuwMOanUnvGF7OzRyneki4aB-v_PwpvplIDQuRqmkjn9i5P7tl6msEMUhp0yBE2tQIYPbQlIw57n"
|
||||
+ "3wRcGOz9ymOrREzEW1UhZQBibr8ZFNoWzRt-k0EVLYzNt96NDtHfHc7AlxJv8ERIDOZ4ai_nNeLgtV76-ybXnT"
|
||||
+ "RqRO9TXwqZhHQ_7gEs4Y01IJxvEQ==";
|
||||
static final String PASSPHRASE = "encryptallthekitties";
|
||||
static final String PROVIDER_IV = "d58ce954203b7c9a9a9d467f59839249";
|
||||
static final String PROVIDER_KEY = "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f9"
|
||||
+ "47ab9";
|
||||
static final String B64_LICENSE_REQUEST_WITH_GROUP_ID =
|
||||
"CAcS8QsKowsIARLrCQquAggCEhCmtANA4NnoLls7_9gZFKkZGJeNyOYFIo4CMIIBCgKCAQEAnI1PFI4ighGr3ZFRh8Gk"
|
||||
+ "8WAIhphh-iVb48L7QYMwdszHvPTCxBwXPmw_KSsfBHrJviVOp_VO53zns0kKvcHUjqQpcRrSBlpd3b-2RK-twI"
|
||||
+ "f6H3JtxCeT4GQFQ-Ey4GvQvLiGb4eg_WjsYoDU2f9nlIUBPcE5Yi4qhorl75JOiI3TI9hiCN9wlNjl7cnylcbE"
|
||||
+ "lSc2TYCcC3KUSCppPdBEsUkq60MG2RjZYYtdO-wrdekRTFYTZq6hZrcoIe9s6uDDpaCNW5FmJ5V88T-hs1y3dz"
|
||||
+ "lXouNIdru2CK1tEoQYZQmBeSYKtOTuNeOHYj6yjYPyxBXE1WZqp-6yULEPdZ3igwIDAQABKOg9EoACKrZ9-iTj"
|
||||
+ "Lu1SSv4PcF1oGcp6jbyY-ntNFnjw-u6veF7O6YiqUEYcxvYiZ8CoJFzknsFnmyvp9z0PzTBgSt-eHhxoKXFzs2"
|
||||
+ "Ix26pu3uIWjiMlNx7LcceS2b6ny35C0AfdNAgq9k5L-bXVuRxfXzUeyD9AonGXodNVWUDobD5oqXL7N8-cHx9K"
|
||||
+ "yC76T2BTUkIQmOa_R9_kBznpHMsh67PCcO75Kt14xMnm53nCTDBGrANJb-jLlvkmNomg96phP38UgXyg-oUwdg"
|
||||
+ "ioU6WMNm9HWzrvHv_o1-aogodilB5LAhPk7rb8HLlvjX8MWRgfV0Wyhgmw-CI7GxOlmpVyX97B5hq0BQquAggB"
|
||||
+ "EhBlgCybYl5aMZwz3By3w8bUGOOlvdAFIo4CMIIBCgKCAQEAuAUCBDwqig_Y0lxhPh4-O140nzMvBFFqdRDTgC"
|
||||
+ "GlYpuaoCeurTx1m3r-cL7WXz32hg_162C5g6P_oz_eBvO3MBTfyEWrNxxmAFYunZBPhCuLpKXZIA_6PtRdcFUg"
|
||||
+ "pcNyqIn54xQ4YjTGiXrmVYUfzZrbTvkSbHg4bqk7yyW6PsR1xVxgjnccdjqwJQb5sHJS1qv36mSx6957lcZAdp"
|
||||
+ "BTO9aJC5J0wWBm90_EAeo1XwoCEGgU1JvwyJ5uH42ypHhBzQ2teTKWoQfDYiNATyvx_KFv0KS5gmNNtiQH-PFK"
|
||||
+ "yuOwWgOL0-S7uuQ5G7-npH-50B3oV-qI5eNu424kWFn8DwIDAQABKOg9EoADfgZYGgGRhKtXKv3K3dA_Fhzmgg"
|
||||
+ "D45vitFhlHNgvI1JwNaACbHEZE-bPz-23f2S75LeYtQdRZ0p2Bv67zlwo6OdJbJmLssDstp7aDAvqm3ZjZWhQ8"
|
||||
+ "yMHLat2nbS7pw3I_r5WinNw-lotoIakcBRyigKhmaXEKGtekS_khgCdGDfaU4uknA5bfIhlj8h7mqiIKXuSk0P"
|
||||
+ "6z1T61cy-PkempazuL4oTFEznqKE1NDt1Vtq1W90FkIOBeBZ-XNKlr4lqkRWDbqMOHVaQqgr1_iO3RnfNGpmez"
|
||||
+ "O4EUx2qIOMQj2CSlCyMlGgiBNtbo9HUpnSr9Rs6lG1y994mlchJc0k-7gTs4ehDNKjDjRHY0qzQI-Wuc89mIlt"
|
||||
+ "QF8_VA2cV5YnYPzRd83RAeuKQUi5wpztXq1kWpW2mPHNxuHbZni4UHQYYIDWjRPNN-B7Ft43DNmvubJVZKc6MO"
|
||||
+ "KvgIXqN9MQxHTw5nrADKmSpSlvrtrXqgbs15Dx49QmVY-pg4PjzS7UgwGhMKDGNvbXBhbnlfbmFtZRIDd3d3Gh"
|
||||
+ "EKCm1vZGVsX25hbWUSA3d3dxogCgxwcm9kdWN0X25hbWUSEFdpZGV2aW5lQ2FzVGVzdHMaJgoRYXJjaGl0ZWN0"
|
||||
+ "dXJlX25hbWUSEWFyY2hpdGVjdHVyZV9uYW1lGhoKC2RldmljZV9uYW1lEgtkZXZpY2VfbmFtZRofChR3aWRldm"
|
||||
+ "luZV9jZG1fdmVyc2lvbhIHZ28tdGVzdDICKBASOQo3CjMaDXdpZGV2aW5lX3Rlc3QiCkNhc1RzR3JvdXBYAWoJ"
|
||||
+ "Q2FzR3JvdXAxaglDYXNHcm91cDIQAxgBIMK_1YUGMBU4pNrohw8agAJKmxx2xhQgthsAcZtpmES323mFQBlvWc"
|
||||
+ "4mdt5W45hVPlbKb4PMKSkGl-_TjQKRlyu_gd6ZC0fbJSdeWVI148ZbJhZBJm3_KgqwH3mPGQzpglgY8kU-3DqK"
|
||||
+ "UC-8CmhN41ipgok1qwCJyrODL1BG_YYC_RixRYYxsMQcc8Fkrd962NSuwAr1Jr64UyQWWj9ZGluk0mvB6hwMTK"
|
||||
+ "VQiCPwmQE0EQ3ZXZXMdi5JOwT6_RCAfXjhA7ExQ8MGLAxJ6E6FyjC6PdkBpm3jzSptq7CsOADzgTmrnqZKXT6O"
|
||||
+ "ft-ajciJDybO4WnjyrTmK6f6PPwIOp2Ud4ok5qLnYFqo0fu86a9DShQAAAABAAAAFAAEABDw-i0kAAAAIA==";
|
||||
|
||||
/* Creates WvTestRunner to run wvpl proxy test */
|
||||
public static String loadCertificateStatusListFromFile(String certificateStatusListFile)
|
||||
throws IOException {
|
||||
BufferedReader br = Files.newBufferedReader(Paths.get(certificateStatusListFile), UTF_8);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
sb.append(line);
|
||||
sb.append(System.lineSeparator());
|
||||
line = br.readLine();
|
||||
}
|
||||
br.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void groupLicenseRequestGeneration(WvPLCASProxySession session) {
|
||||
WvPLPlaybackPolicy policy = new WvPLPlaybackPolicy();
|
||||
policy.setLicenseDurationSeconds(604800);
|
||||
policy.setPlaybackDurationSeconds(86400);
|
||||
session.setPolicy(policy);
|
||||
System.out.println(
|
||||
"License Duration Seconds = " + session.getPolicy().getLicenseDurationSeconds());
|
||||
System.out.println(
|
||||
"Playback duration Seconds = " + session.getPolicy().getPlaybackDurationSeconds());
|
||||
|
||||
// Add keys for one group.
|
||||
// Assume keys in this example are entitlement keys created for group.
|
||||
WvPLCasKey key1 = new WvPLCasKey();
|
||||
|
||||
byte[] oddGroupKeyId = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
|
||||
key1.setOddKeyId(oddGroupKeyId);
|
||||
byte[] oddGroupKeyBytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key1.setOddKeyBytes(oddGroupKeyBytes);
|
||||
byte[] evenGroupKeyId = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
|
||||
key1.setEvenKeyId(evenGroupKeyId);
|
||||
byte[] evenGroupKeyBytes = {16, 15, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key1.setEvenKeyBytes(evenGroupKeyBytes);
|
||||
key1.setTrackType(WvPLTrackType.TrackType.VIDEO_HD);
|
||||
key1.setKeyType(WvPLKeyType.KeyType.ENTITLEMENT);
|
||||
WvPLOutputProtection requiredOutputProtection = new WvPLOutputProtection();
|
||||
|
||||
// Set required output protection fields.
|
||||
requiredOutputProtection.setSecuredataPath(true);
|
||||
requiredOutputProtection.setDisableAnalogOutput(true);
|
||||
// Set output protection on the Cas key.
|
||||
key1.setOutputProtection(requiredOutputProtection);
|
||||
|
||||
// Add WvPLCasKey to WvPLSession.
|
||||
WvPLStatus status = session.addKey(key1);
|
||||
|
||||
WvPLCasKey key2 = new WvPLCasKey();
|
||||
evenGroupKeyId = new byte[] {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
evenGroupKeyBytes = new byte[] {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key2.setEvenKeyId(evenGroupKeyId);
|
||||
key2.setEvenKeyBytes(evenGroupKeyBytes);
|
||||
key2.setTrackType(WvPLTrackType.TrackType.VIDEO_SD);
|
||||
|
||||
status = session.addKey(key2);
|
||||
|
||||
List<WvPLCasKey> wvplCasKeys = session.getKeys();
|
||||
|
||||
// Validate setting/getting sessionInit values.
|
||||
WvPLSessionInit sessionInit = new WvPLSessionInit();
|
||||
String testSessionId = "TestSessionId";
|
||||
String testPurchaseId = "TestPurchaseId";
|
||||
String testProviderClientToken = "TestProviderClientToken";
|
||||
byte[] testMasterSigningKeys = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
boolean testOverrideProviderClientToken = true;
|
||||
|
||||
sessionInit.setSessionId(testSessionId);
|
||||
sessionInit.setPurchaseId(testPurchaseId);
|
||||
sessionInit.setMasterSigningKey(testMasterSigningKeys);
|
||||
sessionInit.setProviderClientToken(testProviderClientToken);
|
||||
sessionInit.setOverrideProviderClientToken(testOverrideProviderClientToken);
|
||||
|
||||
// List group ids shown in pssh_data.
|
||||
List<byte[]> groupIds = new ArrayList<>();
|
||||
try {
|
||||
WvPLWidevinePsshData widevinePsshData = session.getPsshData();
|
||||
groupIds = widevinePsshData.getGroupIds();
|
||||
System.out.println("Group Ids from Widevine Pssh = ");
|
||||
for (int i = 0; i < groupIds.size(); i++) {
|
||||
System.out.printf ("%s ", Arrays.toString(widevinePsshData.getGroupIds().get(i)));
|
||||
}
|
||||
System.out.println();
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("Get WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Select one group id shown in group ids list in psshData.
|
||||
// Here assume group keys inserted are generated based on the first group
|
||||
// shown in the list.
|
||||
// Any group id which are not shown in the psshData will throw an error.
|
||||
WvPLLicenseCategorySpec licenseCategorySpec = new WvPLLicenseCategorySpec();
|
||||
licenseCategorySpec.setLicenseCategory(WvPLLicenseCategory.LicenseCategory.GROUP_LICENSE);
|
||||
licenseCategorySpec.setContentOrGroupId(groupIds.get(0));
|
||||
sessionInit.setLicenseCategorySpec(licenseCategorySpec);
|
||||
session.setSessionInit(sessionInit);
|
||||
|
||||
WvPLSessionInit retrievedSessionInit = session.getSessionInit();
|
||||
System.out.println(
|
||||
"retrieved session init fields: sessionId = " + retrievedSessionInit.getSessionId()
|
||||
+ ", purchaseId = " + retrievedSessionInit.getPurchaseId()
|
||||
+ ", masterSigningKey = " + Arrays.toString(retrievedSessionInit.getMasterSigningKey())
|
||||
+ ", providerClientToken = " + retrievedSessionInit.getProviderClientToken()
|
||||
+ ", overrideProviderClientToken = "
|
||||
+ retrievedSessionInit.getOverrideProviderClientToken()
|
||||
+ ", licenseCategorySpec= " + retrievedSessionInit.getLicenseCategorySpec().toString());
|
||||
}
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
byte[] passphraseBytes = PASSPHRASE.getBytes(UTF_8);
|
||||
byte[] decodedDrmServiceCertificate =
|
||||
Base64.getUrlDecoder().decode(B64_DRM_SERVICE_CERTIFICATE_WITH_CAS_PROXY_TYPE);
|
||||
byte[] decodedPrivateKey = Base64.getUrlDecoder().decode(B64_PRIVATE_KEY_WITH_CAS_PROXY_TYPE);
|
||||
byte[] decodedLicenseRequest = Base64.getUrlDecoder().decode(B64_LICENSE_REQUEST_WITH_GROUP_ID);
|
||||
|
||||
java.util.Map<String, String> configValues = new HashMap<>();
|
||||
|
||||
// Define the configuration that is to be used for WvPLCASEnvironment.
|
||||
configValues.put("drm_certificate_type", "dev");
|
||||
configValues.put("provider", "widevine_test");
|
||||
configValues.put("provider_iv", PROVIDER_IV);
|
||||
configValues.put("provider_key", PROVIDER_KEY);
|
||||
// Set the device certificate expiration 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.
|
||||
configValues.put("device_certificate_expiration", "315360000");
|
||||
|
||||
// Construct WvPLCASProxyEnvironment.
|
||||
WvPLCASProxyEnvironment environment = new WvPLCASProxyEnvironment(configValues);
|
||||
WvPLStatus status = environment.setServiceCertificate(
|
||||
decodedDrmServiceCertificate, decodedPrivateKey, passphraseBytes);
|
||||
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
||||
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
} else {
|
||||
System.out.println("Successfully loaded service certificate");
|
||||
}
|
||||
|
||||
// Get Device Certificate Status List Request.
|
||||
try {
|
||||
byte[] deviceCertificateStatusListRequest = environment.generateDeviceStatusListRequest();
|
||||
System.out.println(
|
||||
"generateDeviceStatusListRequest = "
|
||||
+ Arrays.toString(deviceCertificateStatusListRequest));
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GenerateDeviceStatusListRequest exception: code = "
|
||||
+ status.getStatusCode() + ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Get service certificate response.
|
||||
byte[] serviceCertificateResponse = environment.generateDrmServiceCertificateResponse();
|
||||
System.out.println(
|
||||
"Service certificate response = " + Arrays.toString(serviceCertificateResponse));
|
||||
|
||||
// Set device certificate statusList.
|
||||
String certificateStatusListFile =
|
||||
"sdk/testing/sampleTestCertificateStatusList.json";
|
||||
String certList = "";
|
||||
try {
|
||||
certList = loadCertificateStatusListFromFile(certificateStatusListFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("FileNotFoundException in reading input cert list.");
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException in reading input cert list.");
|
||||
}
|
||||
status = environment.setDeviceCertificateStatusList(certList.getBytes(UTF_8));
|
||||
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
||||
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
} else {
|
||||
System.out
|
||||
.println("Successfully set DeviceCertificateStatusList in WvPLCASProxyEnvironment.");
|
||||
}
|
||||
|
||||
// Construct a WVPLCASProxySession for a license request.
|
||||
WvPLCASProxySession session = null;
|
||||
try {
|
||||
session = environment.createSession(decodedLicenseRequest);
|
||||
} catch (WvPLStatusException e) {
|
||||
System.out.println("Message: " + e.getMessage());
|
||||
System.out.println("Status message: " + e.getStatus().getMessage());
|
||||
}
|
||||
System.out.println("Successful create WvPLCASProxySession in WvPLCASProxyEnvironment.");
|
||||
|
||||
System.out.println("Version of Cas Proxy SDK library: "
|
||||
+ WvPLCASProxySession.getVersionString());
|
||||
WvPLRequestType requestType = session.getRequestType();
|
||||
System.out.println("Message type : " + requestType.getMessageType());
|
||||
System.out.println("License type : " + requestType.getLicenseType());
|
||||
System.out.println("LicenseRequest type : " + requestType.getLicenseRequestType());
|
||||
|
||||
// Examine the license request by retrieving WvPLClientInfo.
|
||||
try {
|
||||
WvPLClientInfo clientInfo = session.getClientInfo();
|
||||
WvPLHdcp.HDCP maxHdcpVersion = clientInfo.getMaxHdcpVersion();
|
||||
System.out.println("WvPLClientInfo, max hdcp version = " + maxHdcpVersion.getHDCP()
|
||||
+ ", oem crypto api version = " + clientInfo.getOemCryptoApiVersion()
|
||||
+ ", provider client token = " + clientInfo.getProviderClientToken());
|
||||
Map<String, String> namesValues = clientInfo.getNamesValues();
|
||||
for (Map.Entry<String, String> nameValue : namesValues.entrySet()) {
|
||||
System.out.println("Key = " + nameValue.getKey() + ", Value = " + nameValue.getValue());
|
||||
}
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetClientInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Retrieve the content ID
|
||||
byte[] contentId = session.getContentId();
|
||||
System.out.println("Content ID: " + Arrays.toString(contentId));
|
||||
|
||||
// Examine the license request by retrieving WvPLDeviceInfo.
|
||||
try {
|
||||
WvPLDeviceInfo deviceInfo = session.getDeviceInfo();
|
||||
System.out.println("soc = " + deviceInfo.getSoc() + ", manufacturer = "
|
||||
+ deviceInfo.getManufacturer() + ", model = " + deviceInfo.getModel()
|
||||
+ ", device_type = " + deviceInfo.getDeviceType()
|
||||
+ ", system_id = " + deviceInfo.getSystemId());
|
||||
// Retrieve DRM Device Certificate serial number.
|
||||
byte[] drmDeviceCertificateSerialNumber =
|
||||
deviceInfo.getDrmCertificateSerialNumber();
|
||||
System.out.println("DrmDeviceCertificateSerialNumber = "
|
||||
+ Arrays.toString(drmDeviceCertificateSerialNumber));
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetDeviceInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Insert policy and keys for group license.
|
||||
groupLicenseRequestGeneration(session);
|
||||
|
||||
// Retrieve session pssh data.
|
||||
try {
|
||||
WvPLWidevinePsshData widevinePsshData = session.getPsshData();
|
||||
System.out.println("ContentId from Widevine Pssh = "
|
||||
+ Arrays.toString(widevinePsshData.getContentId()));
|
||||
if (!widevinePsshData.getKeyIds().isEmpty()) {
|
||||
for (byte[] keyId : widevinePsshData.getKeyIds()) {
|
||||
System.out.println("keyId from Widevine Pssh = " + Arrays.toString(keyId));
|
||||
}
|
||||
} else {
|
||||
System.out.println("KeyIds from Widevine Pssh is empty");
|
||||
}
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("Get WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Retrieve a CAS License request that is to be sent to Widevine License Service using HTTP(s)
|
||||
// POST.
|
||||
String licenseRequest = session.generateLicenseRequestAsJSON();
|
||||
System.out.println("License request is: " + licenseRequest);
|
||||
|
||||
try {
|
||||
WvPLClientCapabilities wvplClientCapabilities = session.getClientCapabilities();
|
||||
System.out.println("WvPLClientCapabilities = " + wvplClientCapabilities);
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetClientInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Destroy the created session.
|
||||
environment.destroySession(session);
|
||||
// Tear down the environment object.
|
||||
environment.close();
|
||||
}
|
||||
}
|
||||
386
ubuntu/example/WvPLCASProxyUsingMultiContentLicenseExample.java
Normal file
386
ubuntu/example/WvPLCASProxyUsingMultiContentLicenseExample.java
Normal file
@@ -0,0 +1,386 @@
|
||||
// Copyright 2021 Google LLC. All rights reserved.
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCASProxyEnvironment;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCASProxySession;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLCasKey;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLClientCapabilities;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLClientInfo;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLDeviceInfo;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLHdcp;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLKeyCategory;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLKeyCategorySpec;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLKeyType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLLicenseCategory;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLLicenseCategorySpec;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLMessageType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLOutputProtection;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLPlaybackPolicy;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLRequestType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLSessionInit;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatus;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatusException;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLTrackType;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLWidevinePsshData;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WvPLCASProxyUsingMultiContentLicenseExample {
|
||||
static final String B64_DRM_SERVICE_CERTIFICATE_WITH_CAS_PROXY_TYPE =
|
||||
"CrwCCAMSELBFY1_OQaWD87swUMHQjTMY0Ont7AUijgIwggEKAoIBAQCUNggP3JYvTaepEoHfiG32zOEbimIPtzmjTsu-"
|
||||
+ "3mOyXn3iA_d-aL6PnCqB0ORWvHld-xkRGHUUCSMAX0stvi-vTAd7e5fdMTXVtDbmj4o2fYDfp0klk3qj3OS7-X"
|
||||
+ "H-z2musgRkbzZTzpH8MzUnLRHz97TMx46bwYyL8SskrvnaWwyPBhkDfmAoNQKSVuLZNc6snfOAE4hNCdB4Qq-H"
|
||||
+ "TgC3FIl-1Kt4svUUPL4LYAzpKG5xH2r6ol0PQGSIKQ2qhJ-dyXLgDZcFLYdKd7hnKD1yUpvv8tGdHwcXawq7B-"
|
||||
+ "eLitKy0gRJx1nyMmLQ-RG31FBEfR6Gtatzcs2OTyoZuktzAgMBAAE6DXdpZGV2aW5lX3Rlc3RABBKAAwtMdfh-"
|
||||
+ "yBur-Ivq7rz_00RR8vA4MPJOPR3sZXDVFRQsATRvqUVPCTP88hh6Y7Y3IdHTEfXgcjiz2GZqEOvXzl3iuWkSjN"
|
||||
+ "QjNl5ghk955VIryOdzkIYBZJIv4_eEon2RRflExbv4y2GuWxTxHxMmIrFKXF-w2fLSvpiy1qT5daHPIcdvRBDH"
|
||||
+ "wIAVbmNmfv2EXoAqbvBWLhOdA8IRd5Lylqa8SWsUgkuyt9mglUdno6h_WCXZBm99eTfuN66ls-rJrlDgUNO3OU"
|
||||
+ "OXpMYMI8jE4Neo4GF8AKXoyt0lcckHwynzdlSYa04V6vbPMNycO-u1wpnUAPqkXYbnoYnbjm5gJ7Vav5wJtUM4"
|
||||
+ "wFAREefRmS_Dz_kqspC1CxQXo10KZQm3b4QXc_S0cqNXM_R9NGct0qjUdKec_k1RfC1j7MckdZMg4oU-mnqmwO"
|
||||
+ "ZS7jTNIaHS4ASTuicsDUsfX1Ac4eqGv1L3qEY4pipCOps-5mRJ3sCjz87cX8QnPsArgtFYSYPgAg==";
|
||||
static final String B64_PRIVATE_KEY_WITH_CAS_PROXY_TYPE =
|
||||
"MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI5Qd3AH24lskCAggAMB0GCWCGSAFlAwQBKgQQ9X4D3HPW"
|
||||
+ "x35HsgzSgMWCzASCBNBDZGDdRs_hyeRTrca0H4UERbrKRYFsoce9n6-cghmLtIzAn8pYdGH_jfj5Hc3HTo9aXx"
|
||||
+ "fJJz9Juckh9teStzVmA-8y2Qj7W8W243DjbyNyKKDzk9esQme5sVvNugEb8wiqraZ0q4KxfjcK60HsZrOK1Ise"
|
||||
+ "0TglQMvudrDzV3vTxtgP5LTer6wEnUjfGixzhL120X48me-1stTPeG2ji9zlsgmMCjYCEbe4ovMCZmVOaHnbQ3"
|
||||
+ "WNVVnMnVQCqCAmBg_0AKgYB9wvvy7vdRaFHv0EtmyCOegLToNE0I7L5LMcL4-HQ--bwQMHjVkDmIqB3s3XWyhN"
|
||||
+ "U_nneES3qpgAbKpObfPGs814BqjbKwGj6z8jrNJ9Lmlaj_7msphYCuOAEjc26CEmxMYG1dTe-XiluHGIVunau6"
|
||||
+ "iL7OguAdgbhkc2MQ7XJISjQ8j2sYuryUW33Pn2JSoKa4vVCWxTwg2t86Mc3FJ_daLM_z_kqTh5zel6o05tGXgH"
|
||||
+ "hn2UGRTjAs3PgxzExUX6M2_-6uSmdnS4oWxAqVd9ZREMjZaSBY6qPdXyM-Wd2RmUfLNSO3aazLxWu8uH2nbud_"
|
||||
+ "3vLyMSj_7lLjtAATqDKrcr1PyNlrn0MTQWIUZ4S5rsHHtprPB_v-7Ufh4OVPdyWfapBGJLx8Eg0Xscoxc_DpwA"
|
||||
+ "D9KoA62GGg2CPu4NvvHiFIvEkpsxNFGTEAbZfoXXw78GP370doSguKvbTI3INcguKM35pbpe7-gbU8BjSednsl"
|
||||
+ "bQMk4QKFg0YIQmTPDVXAC7FVnyP_dlNf2RXQRObGBGvA_oWv62iz8d3UhpIJOFHeyNic-qoQTj6wRFcxdFR61J"
|
||||
+ "hvqZ8rM_KHJl_pvazrhMJ4JAQJXWhQzOvp4rqAJ7Jfx1u_pF_ZRZ6AX2Rjec-xep4EaqRZPdfEUydKKlr10IIc"
|
||||
+ "_kNQwU15m0UEE_40wDJ3XqrhKuUnPfHpm4cziFYsQPrfuI36MCKklPvjdWS6VdSA-evN6KBZwD3RQh4jdzTxWf"
|
||||
+ "zN-0p9612jIwzUzZj8Zax-TRRaOaN-0-nuPsmR88Ps4Y8AE2-CocYykAD8jh5WbuZKJDEtrNsIfz6keNZVk5ji"
|
||||
+ "1JWcpwzbPk9L_A8MdZh5XBA7X-BLe2F6EIVgI3mwTUPSC8wpoGsc4Hu2VeePzOuuZ59IGSmDkyi68usMQzsVeq"
|
||||
+ "2VJyz4UpDgy5dC5EOcBHLf3_oiAoxuYu6MIXLk-srrO8-mikdRcey9EzmK9uqMV1e4b7Ts7hdIglBij1QwIKbD"
|
||||
+ "mMDMnmnPGX9X5KJojYuxkboe4WWwUgloyRkwxqKWIuEhLirO7E9eS-OOeqtz0idkcMNWziJRiUkVh768T4yfOf"
|
||||
+ "Z8ZvOCx59YN8bL390OZIIdaxSvj5mGeQX2-DTDspxDLpiluDJzTQmH7UZsSQ9DlQiXBtJwuaiFoRsyr0b1hh6n"
|
||||
+ "yE1TibcD_mWuwMOanUnvGF7OzRyneki4aB-v_PwpvplIDQuRqmkjn9i5P7tl6msEMUhp0yBE2tQIYPbQlIw57n"
|
||||
+ "3wRcGOz9ymOrREzEW1UhZQBibr8ZFNoWzRt-k0EVLYzNt96NDtHfHc7AlxJv8ERIDOZ4ai_nNeLgtV76-ybXnT"
|
||||
+ "RqRO9TXwqZhHQ_7gEs4Y01IJxvEQ==";
|
||||
static final String PASSPHRASE = "encryptallthekitties";
|
||||
static final String PROVIDER_IV = "d58ce954203b7c9a9a9d467f59839249";
|
||||
static final String PROVIDER_KEY = "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f9"
|
||||
+ "47ab9";
|
||||
static final String B64_LICENSE_REQUEST =
|
||||
"CAcSuQsKhAsIARLtCQquAggCEhCLiDL7eSGz5lQZxhEvltHOGOTt1OEFIo4CMIIBCgKCAQEApynnDkNRVwiBn-bGL5_C"
|
||||
+ "bqnyMAvVzKeRMbRpl8woIqhHmljqKHt9zq2mt3KQzQ3z96mL1OkZB2Mb_EBlr-k7CPlaV5n3ORJS3mo9Cg5QLc"
|
||||
+ "EWwOCFPIdeXr_4Q4WMMi8sBgF9QjmBp6QQcP-OrgwqwTVJEYfrInkHsRhey3bNPybrAlmj5sF3w1reLAeqJD0p"
|
||||
+ "WZ4lGmq027m-oAESe9OXZb1AobsjuIOxCrgprd4XMRuQKVBZVwk28O5exr2roL4Hrb_zBQVTfGfxAE2vRp5tdg"
|
||||
+ "Ak9vBwlWh_3jWmJlG1BL7qynkoLOgwAakU_dnvrOfm0VlZq-5TazxMtT5XOzkSjQIDAQABKJkgEoACMjGvs7ZD"
|
||||
+ "6n2zCV_co_6N9J4pnSsZ_p2nq18obvIXoIImvQ1TDpaD-7eO3syn2Lw_H5rAOlOo1IApwPSQpq8wG9onMW5ZIE"
|
||||
+ "CaWoiay6SVOdHZLAt4SxgdoRTzu0XtvHu6fN36blmVAOkvjA3RHs6-u4D-xzJz1cYgvzCzDAvhqQ8bhuqRNJc5"
|
||||
+ "2WG1ic4bG4PTHhNeSJt1KjJDGtG9botphtvQyYBzhytTSRH8jr-lKMYvaWm21LUHmmQLAvpZiczKxwjUEw5Ghg"
|
||||
+ "IPi1D56jj4JCQpNVX4L8kgrTP0E5i1Mv4B4otQ9201NJg1MocUlpurZ_aOs8wwqsXScf_z4bHJYhq2BQqwAggB"
|
||||
+ "EhAITWC8ZZN9tqx_mStB7PXyGKLTiowFIo4CMIIBCgKCAQEAmRs1e7cU3srB5w6qNtHQg03ySj0QNp-Qoic0o6"
|
||||
+ "1K68z8JDK91tzR_9dWmbpWCMRFeXLSfEerz_jIjNmQCTgmC4yFeVMnsq7zodsn6LliA5KE1gLGp0xqFDpnvmSh"
|
||||
+ "ahyPRPr62sJCzrbYrenE1FQuvT7p0qCnHrekzPkW4C8meTsME6SSHD7tScXJbNRVWY7eBAzkcrAVqa882oLEl5"
|
||||
+ "Kqf2u_v0ZnKTtE7HQpw5oDiRHOH-Riw16VwmTTYzQ8OtuUT6KqvboPthxAJ5dYXz37eW9s4dzzt5yYh76YFHDs"
|
||||
+ "vLBI5Z5WT8OtLEuGD3CqRo-2bEooR-7HVa3om9YiV0DJpQIDAQABKJkgMAESgAMhLeFBwTBXwZhyGN1_vC3J-E"
|
||||
+ "yC-R9bFj0DcMcGk4fHDJDDBg8FBFc8bgvTrLmE_Dq3siGnfTczMk1nCppe6mRpHVZmqbZ902eAPNV1O9depyOb"
|
||||
+ "7AwAgpdpV3HOIDxgiY1PJkrVXT0ByW9m1vtsU9GSimCtBA19SOnIPWhJwkjkXA-Vu7jNCx_u5EWMXGCrDVLh-w"
|
||||
+ "-O6Ydmr5z5MwdXhlfoAPGk7T9qAOiVGyFY9Fz8wvfl5cw9fwTqK-NKqN1J69eMYYwUBOMIJX5QKqyN8A1SqJhT"
|
||||
+ "Ab_l5ueE13sLxSyTWosYP7Wv7SWlhVp3_PJxXJB2EWJKWLA32BmFe6uSa-5NVgJ3CJ77Bw-z9ThdHd4eSG2PMt"
|
||||
+ "JT3oaS4wmONbMZJkfnlUTPD7KLNiEz6UKXeBzz9olgUxZn7nTnAmvXITfrHd0FeDTPHavo1wafiKy0t6QCRw8o"
|
||||
+ "ASZLtJw7_uJPxkCkY3TWwQvH0rlgeS0R2lCGq4zP9GGAwkPDldIvGp5PawIaEwoMY29tcGFueV9uYW1lEgN3d3"
|
||||
+ "caEQoKbW9kZWxfbmFtZRIDd3d3GiAKDHByb2R1Y3RfbmFtZRIQV2lkZXZpbmVDYXNUZXN0cxomChFhcmNoaXRl"
|
||||
+ "Y3R1cmVfbmFtZRIRYXJjaGl0ZWN0dXJlX25hbWUaGgoLZGV2aWNlX25hbWUSC2RldmljZV9uYW1lMgIoDhIgCh"
|
||||
+ "4KHBoNd2lkZXZpbmVfdGVzdCIJQ2FzVHNGYWtlWAIYASDk7dThBTAVONOi-_4CGoACBXDXgJopfGQLxWI0z-o2"
|
||||
+ "h-dH3L-ObMMm3moRAv7MQ-xnTALlyNMRCaGsfyy1L0SmsrQQptJjK7hB6tZDe-UQ76fIpQLeHnNOBXuaxl7sY2"
|
||||
+ "Gvrztx8HT_N0KFgAZ9hW1L--zvFw0R1ctjG88xGTpmFWsGoWEZ0NGTgc1XyssK62tuWz5CfIEXvhN7ZiMyoagP"
|
||||
+ "SOWZZ1Mltbiv1AEPeFC6My-njq8N3u9whokMzhlGMePSBctFmn4f8RtUeR7zlLdPuKcp0BBLAOF7ngXF1C-skj"
|
||||
+ "-Y1DrtxwqwczA56yLzXGlh5FhwhaFMSprOHbAFCIQ-ee66aDIbVZ-9_fBMiIE83Q==";
|
||||
|
||||
public static String loadCertificateStatusListFromFile(String certificateStatusListFile)
|
||||
throws IOException {
|
||||
BufferedReader br = Files.newBufferedReader(Paths.get(certificateStatusListFile), UTF_8);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
sb.append(line);
|
||||
sb.append(System.lineSeparator());
|
||||
line = br.readLine();
|
||||
}
|
||||
br.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void multiContentLicenseRequestGeneration(WvPLCASProxySession session) {
|
||||
WvPLPlaybackPolicy policy = new WvPLPlaybackPolicy();
|
||||
policy.setLicenseDurationSeconds(604800);
|
||||
policy.setPlaybackDurationSeconds(86400);
|
||||
session.setPolicy(policy);
|
||||
System.out.println(
|
||||
"License Duration Seconds = " + session.getPolicy().getLicenseDurationSeconds());
|
||||
System.out.println(
|
||||
"Playback duration Seconds = " + session.getPolicy().getPlaybackDurationSeconds());
|
||||
|
||||
// Add keys for each single content shown in this multi content license.
|
||||
// Assume key1 and key2 are entitlement keys created for single content.
|
||||
WvPLCasKey key1 = new WvPLCasKey();
|
||||
|
||||
byte[] oddKeyId = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
|
||||
key1.setOddKeyId(oddKeyId);
|
||||
byte[] oddKeyBytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key1.setOddKeyBytes(oddKeyBytes);
|
||||
byte[] evenKeyId = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
|
||||
key1.setEvenKeyId(evenKeyId);
|
||||
byte[] evenKeyBytes = {16, 15, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key1.setEvenKeyBytes(evenKeyBytes);
|
||||
key1.setTrackType(WvPLTrackType.TrackType.VIDEO_HD);
|
||||
key1.setKeyType(WvPLKeyType.KeyType.ENTITLEMENT);
|
||||
WvPLOutputProtection requiredOutputProtection = new WvPLOutputProtection();
|
||||
|
||||
// Set required output protection fields.
|
||||
requiredOutputProtection.setSecuredataPath(true);
|
||||
requiredOutputProtection.setDisableAnalogOutput(true);
|
||||
|
||||
// Set output protection on the Cas key.
|
||||
key1.setOutputProtection(requiredOutputProtection);
|
||||
|
||||
// Config key for one single content.
|
||||
WvPLKeyCategorySpec keyCategorySpec = new WvPLKeyCategorySpec();
|
||||
keyCategorySpec.setKeyCategory(WvPLKeyCategory.KeyCategory.SINGLE_CONTENT_KEY_DEFAULT);
|
||||
// Content id instead of group id needs to fill in since this is a key for
|
||||
// SINGLE_CONTENT_KEY_DEFAULT.
|
||||
String contentId1 = "content_1";
|
||||
keyCategorySpec.setContentOrGroupId(contentId1.getBytes(UTF_8));
|
||||
key1.setKeyCategorySpec(keyCategorySpec);
|
||||
|
||||
// Add WvPLCasKey to WvPLSession.
|
||||
WvPLStatus status = session.addKey(key1);
|
||||
|
||||
// Add key for another single content.
|
||||
// Adding a TrackType.VIDEO_SD with even key and even keyId.
|
||||
WvPLCasKey key2 = new WvPLCasKey();
|
||||
evenKeyId = new byte[] {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
evenKeyBytes = new byte[] {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
key2.setEvenKeyId(evenKeyId);
|
||||
key2.setEvenKeyBytes(evenKeyBytes);
|
||||
key2.setTrackType(WvPLTrackType.TrackType.VIDEO_SD);
|
||||
|
||||
WvPLKeyCategorySpec keyCategorySpec2 = new WvPLKeyCategorySpec();
|
||||
keyCategorySpec2.setKeyCategory(WvPLKeyCategory.KeyCategory.SINGLE_CONTENT_KEY_DEFAULT);
|
||||
// Content id instead of group id needs to fill in since this is a key for
|
||||
// SINGLE_CONTENT_KEY_DEFAULT.
|
||||
String contentId2 = "content_2";
|
||||
keyCategorySpec2.setContentOrGroupId(contentId2.getBytes(UTF_8));
|
||||
key2.setKeyCategorySpec(keyCategorySpec2);
|
||||
|
||||
status = session.addKey(key2);
|
||||
|
||||
List<WvPLCasKey> wvplCasKeys = session.getKeys();
|
||||
|
||||
// Validate setting/getting sessionInit values.
|
||||
WvPLSessionInit sessionInit = new WvPLSessionInit();
|
||||
String testSessionId = "TestSessionId";
|
||||
String testPurchaseId = "TestPurchaseId";
|
||||
String testProviderClientToken = "TestProviderClientToken";
|
||||
byte[] testMasterSigningKeys = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
boolean testOverrideProviderClientToken = true;
|
||||
|
||||
sessionInit.setSessionId(testSessionId);
|
||||
sessionInit.setPurchaseId(testPurchaseId);
|
||||
sessionInit.setMasterSigningKey(testMasterSigningKeys);
|
||||
sessionInit.setProviderClientToken(testProviderClientToken);
|
||||
sessionInit.setOverrideProviderClientToken(testOverrideProviderClientToken);
|
||||
// Set licenseCategorySpec in sessionInit where License Category should be
|
||||
// MULTI_CONTENT_LICENSE.
|
||||
WvPLLicenseCategorySpec licenseCategorySpec = new WvPLLicenseCategorySpec();
|
||||
licenseCategorySpec
|
||||
.setLicenseCategory(WvPLLicenseCategory.LicenseCategory.MULTI_CONTENT_LICENSE);
|
||||
String groupId = "user_group_1";
|
||||
licenseCategorySpec.setContentOrGroupId(groupId.getBytes(UTF_8));
|
||||
sessionInit.setLicenseCategorySpec(licenseCategorySpec);
|
||||
session.setSessionInit(sessionInit);
|
||||
|
||||
WvPLSessionInit retrievedSessionInit = session.getSessionInit();
|
||||
System.out.println(
|
||||
"retrieved session init fields: sessionId = " + retrievedSessionInit.getSessionId()
|
||||
+ ", purchaseId = " + retrievedSessionInit.getPurchaseId()
|
||||
+ ", masterSigningKey = " + Arrays.toString(retrievedSessionInit.getMasterSigningKey())
|
||||
+ ", providerClientToken = " + retrievedSessionInit.getProviderClientToken()
|
||||
+ ", overrideProviderClientToken = "
|
||||
+ retrievedSessionInit.getOverrideProviderClientToken()
|
||||
+ ", licenseCategorySpec= " + retrievedSessionInit.getLicenseCategorySpec().toString());
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
byte[] passphraseBytes = PASSPHRASE.getBytes(UTF_8);
|
||||
byte[] decodedDrmServiceCertificate =
|
||||
Base64.getUrlDecoder().decode(B64_DRM_SERVICE_CERTIFICATE_WITH_CAS_PROXY_TYPE);
|
||||
byte[] decodedPrivateKey = Base64.getUrlDecoder().decode(B64_PRIVATE_KEY_WITH_CAS_PROXY_TYPE);
|
||||
byte[] decodedLicenseRequest = Base64.getUrlDecoder().decode(B64_LICENSE_REQUEST);
|
||||
java.util.Map<String, String> configValues = new HashMap<>();
|
||||
|
||||
// Define the configuration that is to be used for WvPLCASEnvironment.
|
||||
configValues.put("drm_certificate_type", "dev");
|
||||
configValues.put("provider", "widevine_test");
|
||||
configValues.put("provider_iv", PROVIDER_IV);
|
||||
configValues.put("provider_key", PROVIDER_KEY);
|
||||
// Set the device certificate expiration 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.
|
||||
configValues.put("device_certificate_expiration", "315360000");
|
||||
|
||||
// Construct WvPLCASProxyEnvironment.
|
||||
WvPLCASProxyEnvironment environment = new WvPLCASProxyEnvironment(configValues);
|
||||
WvPLStatus status = environment.setServiceCertificate(
|
||||
decodedDrmServiceCertificate, decodedPrivateKey, passphraseBytes);
|
||||
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
||||
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
} else {
|
||||
System.out.println("Successfully loaded service certificate");
|
||||
}
|
||||
|
||||
// Get Device Certificate Status List Request.
|
||||
try {
|
||||
byte[] deviceCertificateStatusListRequest = environment.generateDeviceStatusListRequest();
|
||||
System.out.println(
|
||||
"generateDeviceStatusListRequest = "
|
||||
+ Arrays.toString(deviceCertificateStatusListRequest));
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GenerateDeviceStatusListRequest exception: code = "
|
||||
+ status.getStatusCode() + ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Get service certificate response.
|
||||
byte[] serviceCertificateResponse = environment.generateDrmServiceCertificateResponse();
|
||||
System.out.println(
|
||||
"Service certificate response = " + Arrays.toString(serviceCertificateResponse));
|
||||
|
||||
// Set device certificate statusList.
|
||||
String certificateStatusListFile =
|
||||
"sdk/testing/sampleTestCertificateStatusList.json";
|
||||
String certList = "";
|
||||
try {
|
||||
certList = loadCertificateStatusListFromFile(certificateStatusListFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("FileNotFoundException in reading input cert list.");
|
||||
} catch (IOException e) {
|
||||
System.out.println("IOException in reading input cert list.");
|
||||
}
|
||||
status = environment.setDeviceCertificateStatusList(certList.getBytes(UTF_8));
|
||||
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
||||
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
} else {
|
||||
System.out
|
||||
.println("Successfully set DeviceCertificateStatusList in WvPLCASProxyEnvironment.");
|
||||
}
|
||||
|
||||
// Construct a WVPLCASProxySession for a license request.
|
||||
WvPLCASProxySession session = null;
|
||||
try {
|
||||
session = environment.createSession(decodedLicenseRequest);
|
||||
} catch (WvPLStatusException e) {
|
||||
System.out.println("Message: " + e.getMessage());
|
||||
System.out.println("Status message: " + e.getStatus().getMessage());
|
||||
}
|
||||
System.out.println("Successful create WvPLCASProxySession in WvPLCASProxyEnvironment.");
|
||||
|
||||
System.out.println("Version of Cas Proxy SDK library: "
|
||||
+ WvPLCASProxySession.getVersionString());
|
||||
WvPLRequestType requestType = session.getRequestType();
|
||||
System.out.println("Message type : " + requestType.getMessageType());
|
||||
System.out.println("License type : " + requestType.getLicenseType());
|
||||
System.out.println("LicenseRequest type : " + requestType.getLicenseRequestType());
|
||||
|
||||
// Examine the license request by retrieving WvPLClientInfo.
|
||||
try {
|
||||
WvPLClientInfo clientInfo = session.getClientInfo();
|
||||
WvPLHdcp.HDCP maxHdcpVersion = clientInfo.getMaxHdcpVersion();
|
||||
System.out.println("WvPLClientInfo, max hdcp version = " + maxHdcpVersion.getHDCP()
|
||||
+ ", oem crypto api version = " + clientInfo.getOemCryptoApiVersion()
|
||||
+ ", provider client token = " + clientInfo.getProviderClientToken());
|
||||
Map<String, String> namesValues = clientInfo.getNamesValues();
|
||||
for (Map.Entry<String, String> nameValue : namesValues.entrySet()) {
|
||||
System.out.println("Key = " + nameValue.getKey() + ", Value = " + nameValue.getValue());
|
||||
}
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetClientInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Retrieve the content ID
|
||||
byte[] contentId = session.getContentId();
|
||||
System.out.println("Content ID: " + Arrays.toString(contentId));
|
||||
|
||||
// Examine the license request by retrieving WvPLDeviceInfo.
|
||||
try {
|
||||
WvPLDeviceInfo deviceInfo = session.getDeviceInfo();
|
||||
System.out.println("soc = " + deviceInfo.getSoc() + ", manufacturer = "
|
||||
+ deviceInfo.getManufacturer() + ", model = " + deviceInfo.getModel()
|
||||
+ ", device_type = " + deviceInfo.getDeviceType()
|
||||
+ ", system_id = " + deviceInfo.getSystemId());
|
||||
// Retrieve DRM Device Certificate serial number.
|
||||
byte[] drmDeviceCertificateSerialNumber =
|
||||
deviceInfo.getDrmCertificateSerialNumber();
|
||||
System.out.println("DrmDeviceCertificateSerialNumber = "
|
||||
+ Arrays.toString(drmDeviceCertificateSerialNumber));
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetDeviceInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Insert policy and keys for multi_content_license.
|
||||
multiContentLicenseRequestGeneration(session);
|
||||
|
||||
// Retrieve session pssh data.
|
||||
try {
|
||||
WvPLWidevinePsshData widevinePsshData = session.getPsshData();
|
||||
System.out.println("ContentId from Widevine Pssh = "
|
||||
+ Arrays.toString(widevinePsshData.getContentId()));
|
||||
if (!widevinePsshData.getKeyIds().isEmpty()) {
|
||||
for (byte[] keyId : widevinePsshData.getKeyIds()) {
|
||||
System.out.println("keyId from Widevine Pssh = " + Arrays.toString(keyId));
|
||||
}
|
||||
} else {
|
||||
System.out.println("KeyIds from Widevine Pssh is empty");
|
||||
}
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("Get WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// Retrieve a CAS License request that is to be sent to Widevine License Service using HTTP(s)
|
||||
// POST.
|
||||
String licenseRequest = session.generateLicenseRequestAsJSON();
|
||||
System.out.println("License request is: " + licenseRequest);
|
||||
|
||||
try {
|
||||
WvPLClientCapabilities wvplClientCapabilities = session.getClientCapabilities();
|
||||
System.out.println("WvPLClientCapabilities = " + wvplClientCapabilities);
|
||||
} catch (WvPLStatusException e) {
|
||||
status = e.getStatus();
|
||||
System.out.println("GetClientInfo WvPLStatus: code = " + status.getStatusCode()
|
||||
+ ", message = " + status.getMessage());
|
||||
}
|
||||
|
||||
// Destroy the created session.
|
||||
environment.destroySession(session);
|
||||
// Tear down the environment object.
|
||||
environment.close();
|
||||
}
|
||||
}
|
||||
BIN
ubuntu/example/wvpl_cas_proxy_sdk_entitlement_rotation_example
Normal file
BIN
ubuntu/example/wvpl_cas_proxy_sdk_entitlement_rotation_example
Normal file
Binary file not shown.
BIN
ubuntu/example/wvpl_cas_proxy_sdk_example
Normal file
BIN
ubuntu/example/wvpl_cas_proxy_sdk_example
Normal file
Binary file not shown.
241
ubuntu/example/wvpl_cas_proxy_sdk_example.cc
Normal file
241
ubuntu/example/wvpl_cas_proxy_sdk_example.cc
Normal file
@@ -0,0 +1,241 @@
|
||||
// Copyright 2019 Google LLC. All rights reserved.
|
||||
|
||||
// Example of how to use WvPL CAS API.
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "example//wvpl_cas_proxy_sdk_example_data.h"
|
||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h"
|
||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
||||
#include "sdk/external/common/wvpl/wvpl_types.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using video_widevine_server::wv_pl_sdk::ENTITLEMENT;
|
||||
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::kProvider;
|
||||
using video_widevine_server::wv_pl_sdk::kProviderIv;
|
||||
using video_widevine_server::wv_pl_sdk::kProviderKey;
|
||||
using video_widevine_server::wv_pl_sdk::NEW;
|
||||
using video_widevine_server::wv_pl_sdk::RENEWAL;
|
||||
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::WvPLCasKey;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLCASProxySession;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLClientInfo;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLDeviceInfo;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLPlaybackPolicy;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLRequestType;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLSecurityProfile;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyBytes1;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyBytes2;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyBytes3;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyId1;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyId2;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyId3;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kNewCasRequest;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kPassphrase;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::
|
||||
kPrivateKeyForWidevineTestWithCASProxyType;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kRenewalCasRequest;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::
|
||||
kServiceCertificateForWidevineTestWithCASProxyType;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kValidCertList;
|
||||
|
||||
void LogAndExit(WvPLStatus status) {
|
||||
if (!status.ok()) {
|
||||
std::cerr << status.error_message() << ", exiting. Error code = "
|
||||
<< std::to_string(status.error_code()) << std::endl;
|
||||
exit(status.error_code());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::cout << "Version of Cas Proxy SDK library: "
|
||||
<< WvPLCASProxySession::GetVersionString() << std::endl;
|
||||
|
||||
// Define the configuration that is to be used for WvPLCASEnvironment.
|
||||
std::map<std::string, std::string> config_values;
|
||||
// kDeviceCertificateExpiration shows that the device certificate status list
|
||||
// will expire in 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_values[kDeviceCertificateExpiration] = "315360000";
|
||||
// Ignore this setting, because service certificate in this file used for dev.
|
||||
// Content provider does not need to set this fieldwith prod service
|
||||
// certificate.
|
||||
config_values[kDrmCertificateType] = "dev";
|
||||
config_values[kProvider] = "widevine_test";
|
||||
config_values[kProviderIv] = "d58ce954203b7c9a9a9d467f59839249";
|
||||
config_values[kProviderKey] =
|
||||
"1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
|
||||
|
||||
// Set parameters on the environment.
|
||||
WvPLCASProxyEnvironment cas_proxy_environment(config_values);
|
||||
WvPLStatus status = cas_proxy_environment.Initialize();
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Environment failed to initialize. Exiting." << std::endl;
|
||||
exit(status.error_code());
|
||||
}
|
||||
std::cout << "Environment created and initialized" << std::endl;
|
||||
|
||||
std::string service_certificate;
|
||||
absl::Base64Unescape(kServiceCertificateForWidevineTestWithCASProxyType,
|
||||
&service_certificate);
|
||||
std::string private_key;
|
||||
absl::Base64Unescape(kPrivateKeyForWidevineTestWithCASProxyType,
|
||||
&private_key);
|
||||
// Must set a valid drm service certificate with CAS Proxy SDK type, otherwise
|
||||
// it will failed to create session.
|
||||
status = cas_proxy_environment.SetDrmServiceCertificate(
|
||||
service_certificate, private_key, kPassphrase);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set DrmServiceCertificate. " << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
|
||||
status = cas_proxy_environment.SetDeviceCertificateStatusList(kValidCertList);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to update the certificate. " << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
WvPLCASProxySession* cas_proxy_session = nullptr;
|
||||
status = cas_proxy_environment.CreateSession(
|
||||
absl::HexStringToBytes(kNewCasRequest), &cas_proxy_session);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to create session for New Request. " << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
std::cout << "Created proxy session..." << std::endl;
|
||||
|
||||
// Set parameters on the created session.
|
||||
// Set policy parameters
|
||||
WvPLPlaybackPolicy policy;
|
||||
policy.set_license_duration_seconds(604800);
|
||||
policy.set_playback_duration_seconds(86400);
|
||||
cas_proxy_session->set_policy(policy);
|
||||
|
||||
// Set key parameters
|
||||
// Key bytes and key id must be in bytes.
|
||||
WvPLCasKey wvpl_cas_key1;
|
||||
wvpl_cas_key1.set_odd_key_id(kKeyId1);
|
||||
wvpl_cas_key1.set_odd_key_bytes(kKeyBytes1);
|
||||
wvpl_cas_key1.set_even_key_id(kKeyId2);
|
||||
wvpl_cas_key1.set_even_key_bytes(kKeyBytes2);
|
||||
wvpl_cas_key1.set_track_type(VIDEO_HD);
|
||||
wvpl_cas_key1.set_key_type(ENTITLEMENT);
|
||||
wvpl_cas_key1.mutable_output_protection()->set_hdcp(HDCP_V1);
|
||||
wvpl_cas_key1.mutable_output_protection()->set_secure_data_path(true);
|
||||
status = cas_proxy_session->AddCasKey(wvpl_cas_key1);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key #1. " << status.error_message();
|
||||
LogAndExit(status);
|
||||
}
|
||||
|
||||
WvPLCasKey wvpl_cas_key2;
|
||||
wvpl_cas_key2.set_even_key_id(kKeyId3);
|
||||
wvpl_cas_key2.set_even_key_bytes(kKeyBytes3);
|
||||
wvpl_cas_key2.set_track_type(VIDEO_SD);
|
||||
wvpl_cas_key2.mutable_output_protection()->set_hdcp(HDCP_V2);
|
||||
wvpl_cas_key2.mutable_output_protection()->set_secure_data_path(false);
|
||||
|
||||
status = cas_proxy_session->AddCasKey(wvpl_cas_key2);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to add key #2. " << status.error_message();
|
||||
LogAndExit(status);
|
||||
}
|
||||
|
||||
WvPLDeviceInfo device_info;
|
||||
status = cas_proxy_session->GetDeviceInfo(&device_info);
|
||||
if (status.ok()) {
|
||||
std::cout << "WvPLDeviceInfo, drm_certificate_serial_number:"
|
||||
<< device_info.drm_certificate_serial_number()
|
||||
<< ", soc:" << device_info.soc()
|
||||
<< ", manufacturer:" << device_info.manufacturer()
|
||||
<< ", model:" << device_info.model()
|
||||
<< ", model year:" << device_info.model_year()
|
||||
<< ", device type:" << device_info.device_type()
|
||||
<< ", system id:" << device_info.system_id()
|
||||
<< ", test device:" << device_info.test_device()
|
||||
<< ", service id:" << device_info.service_id()
|
||||
<< ", device secruity level:" << device_info.security_level()
|
||||
<< std::endl;
|
||||
}
|
||||
WvPLClientInfo client_info;
|
||||
status = cas_proxy_session->GetClientInfo(&client_info);
|
||||
if (status.ok()) {
|
||||
std::cout << "WvPLClientInfo, max dcp version:"
|
||||
<< client_info.max_hdcp_version() << ", oemcrypto api version:"
|
||||
<< client_info.oem_crypto_api_version()
|
||||
<< ", provider client token:"
|
||||
<< client_info.provider_client_token()
|
||||
<< ", cdm version:" << client_info.cdm_version()
|
||||
<< ", max hdcp version:"
|
||||
<< client_info.client_capabilities().max_hdcp_version()
|
||||
<< ", resource rating tier:"
|
||||
<< client_info.client_capabilities().resource_rating_tier()
|
||||
<< std::endl;
|
||||
}
|
||||
WvPLSecurityProfile::DrmInfo drm_info;
|
||||
if (cas_proxy_session->GetDrmInfo(&drm_info)) {
|
||||
std::cout << "DrmInfo for system_id: " << drm_info.system_id() << std::endl;
|
||||
}
|
||||
|
||||
WvPLRequestType request_type = cas_proxy_session->GetRequestType();
|
||||
if (request_type.license_request_type() != NEW) {
|
||||
std::cerr << "License request type should be NEW." << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
|
||||
std::string json_signed_cas_drm_request;
|
||||
status = cas_proxy_session->GenerateLicenseRequestAsJSON(
|
||||
&json_signed_cas_drm_request);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate NEW license request " << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
std::cout
|
||||
<< "NEW Request to POST over HTTP(s) to "
|
||||
"https://license.uat.widevine.com/cas/getlicense/widevine_test = "
|
||||
<< json_signed_cas_drm_request << std::endl;
|
||||
|
||||
// Test RENEWAL request.
|
||||
cas_proxy_session = nullptr;
|
||||
status = cas_proxy_environment.CreateSession(
|
||||
absl::HexStringToBytes(kRenewalCasRequest), &cas_proxy_session);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to create session for Renewal Request. " << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
request_type = cas_proxy_session->GetRequestType();
|
||||
if (request_type.license_request_type() != RENEWAL) {
|
||||
std::cerr << "License request type should be RENEWAL." << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
|
||||
json_signed_cas_drm_request.clear();
|
||||
status = cas_proxy_session->GenerateLicenseRequestAsJSON(
|
||||
&json_signed_cas_drm_request);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate RENEWAL license request " << std::endl;
|
||||
LogAndExit(status);
|
||||
}
|
||||
std::cout
|
||||
<< "RENEWAL Request to POST over HTTP(s) to "
|
||||
"https://license.uat.widevine.com/cas/getlicense/widevine_test = "
|
||||
<< json_signed_cas_drm_request << std::endl;
|
||||
|
||||
// Destroy the created session.
|
||||
cas_proxy_environment.DestroySession(cas_proxy_session);
|
||||
return 0;
|
||||
}
|
||||
151
ubuntu/example/wvpl_cas_proxy_sdk_example_data.h
Normal file
151
ubuntu/example/wvpl_cas_proxy_sdk_example_data.h
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2021 Google LLC. All rights reserved.
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_MEDIA_CAS_PROXY_SDK_EXAMPLE_WVPL_CAS_PROXY_SDK_EXAMPLE_DATA_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_MEDIA_CAS_PROXY_SDK_EXAMPLE_WVPL_CAS_PROXY_SDK_EXAMPLE_DATA_H_
|
||||
|
||||
namespace video_widevine_server {
|
||||
namespace wv_pl_sdk {
|
||||
namespace example_data {
|
||||
constexpr char kNewCasRequest[] =
|
||||
"080712b90b0a840b080112ed090aae02080212108b8832fb7921b3e65419c6112f96d1"
|
||||
"ce18e4edd4e105228e023082010a0282010100a729e70e43515708819fe6c62f9fc26e"
|
||||
"a9f2300bd5cca79131b46997cc2822a8479a58ea287b7dceada6b77290cd0df3f7a98b"
|
||||
"d4e91907631bfc4065afe93b08f95a5799f7391252de6a3d0a0e502dc116c0e0853c87"
|
||||
"5e5ebff843858c322f2c06017d423981a7a41070ff8eae0c2ac135491187eb227907b1"
|
||||
"185ecb76cd3f26eb0259a3e6c177c35ade2c07aa243d29599e251a6ab4dbb9bea00112"
|
||||
"7bd39765bd40a1bb23b883b10ab829adde17311b90295059570936f0ee5ec6bdaba0be"
|
||||
"07adbff30505537c67f1004daf469e6d760024f6f07095687fde35a62651b504beeaca"
|
||||
"79282ce83001a914fdd9eface7e6d15959abee536b3c4cb53e573b39128d0203010001"
|
||||
"2899201280023231afb3b643ea7db3095fdca3fe8df49e299d2b19fe9da7ab5f286ef2"
|
||||
"17a08226bd0d530e9683fbb78edecca7d8bc3f1f9ac03a53a8d48029c0f490a6af301b"
|
||||
"da27316e5920409a5a889acba49539d1d92c0b784b181da114f3bb45edbc7bba7cddfa"
|
||||
"6e599500e92f8c0dd11ecebebb80fec73273d5c620bf30b30c0be1a90f1b86ea913497"
|
||||
"39d961b589ce1b1b83d31e135e489b752a32431ad1bd6e8b6986dbd0c98073872b5349"
|
||||
"11fc8ebfa528c62f6969b6d4b5079a640b02fa5989cccac708d4130e4686020f8b50f9"
|
||||
"ea38f82424293555f82fc920ad33f41398b532fe01e28b50f76d35349835328714969b"
|
||||
"ab67f68eb3cc30aac5d271fff3e1b1c9621ab6050ab00208011210084d60bc65937db6"
|
||||
"ac7f992b41ecf5f218a2d38a8c05228e023082010a0282010100991b357bb714decac1"
|
||||
"e70eaa36d1d0834df24a3d10369f90a22734a3ad4aebccfc2432bdd6dcd1ffd75699ba"
|
||||
"5608c4457972d27c47abcff8c88cd9900938260b8c85795327b2aef3a1db27e8b96203"
|
||||
"9284d602c6a74c6a143a67be64a16a1c8f44fafadac242ceb6d8ade9c4d4542ebd3ee9"
|
||||
"d2a0a71eb7a4ccf916e02f26793b0c13a4921c3eed49c5c96cd455598ede040ce472b0"
|
||||
"15a9af3cda82c49792aa7f6bbfbf4667293b44ec7429c39a038911ce1fe462c35e95c2"
|
||||
"64d363343c3adb944fa2aabdba0fb61c402797585f3dfb796f6ce1dcf3b79c9887be98"
|
||||
"1470ecbcb048e59e564fc3ad2c4b860f70aa468fb66c4a2847eec755ade89bd6225740"
|
||||
"c9a502030100012899203001128003212de141c13057c1987218dd7fbc2dc9f84c82f9"
|
||||
"1f5b163d0370c7069387c70c90c3060f0504573c6e0bd3acb984fc3ab7b221a77d3733"
|
||||
"324d670a9a5eea64691d5666a9b67dd367803cd5753bd75ea7239bec0c008297695771"
|
||||
"ce203c60898d4f264ad55d3d01c96f66d6fb6c53d1928a60ad040d7d48e9c83d6849c2"
|
||||
"48e45c0f95bbb8cd0b1feee4458c5c60ab0d52e1fb0f8ee98766af9cf93307578657e8"
|
||||
"00f1a4ed3f6a00e8951b2158f45cfcc2f7e5e5cc3d7f04ea2be34aa8dd49ebd78c618c"
|
||||
"1404e308257e502aac8df00d52a8985301bfe5e6e784d77b0bc52c935a8b183fb5afed"
|
||||
"25a5855a77fcf2715c907611624a58b037d819857bab926bee4d560277089efb070fb3"
|
||||
"f5385d1dde1e486d8f32d253de8692e3098e35b3192647e79544cf0fb28b362133e942"
|
||||
"97781cf3f68960531667ee74e7026bd72137eb1ddd057834cf1dabe8d7069f88acb4b7"
|
||||
"a402470f2801264bb49c3bfee24fc640a46374d6c10bc7d2b960792d11da5086ab8ccf"
|
||||
"f46180c243c395d22f1a9e4f6b021a130a0c636f6d70616e795f6e616d651203777777"
|
||||
"1a110a0a6d6f64656c5f6e616d6512037777771a200a0c70726f647563745f6e616d65"
|
||||
"12105769646576696e6543617354657374731a260a116172636869746563747572655f"
|
||||
"6e616d6512116172636869746563747572655f6e616d651a1a0a0b6465766963655f6e"
|
||||
"616d65120b6465766963655f6e616d653202280e12200a1e0a1c1a0d7769646576696e"
|
||||
"655f746573742209436173547346616b655802180120e4edd4e105301538d3a2fbfe02"
|
||||
"1a80020570d7809a297c640bc56234cfea3687e747dcbf8e6cc326de6a1102fecc43ec"
|
||||
"674c02e5c8d31109a1ac7f2cb52f44a6b2b410a6d2632bb841ead6437be510efa7c8a5"
|
||||
"02de1e734e057b9ac65eec6361afaf3b71f074ff37428580067d856d4bfbecef170d11"
|
||||
"d5cb631bcf31193a66156b06a16119d0d19381cd57cacb0aeb6b6e5b3e427c8117be13"
|
||||
"7b662332a1a80f48e599675325b5b8afd4010f7850ba332fa78eaf0ddeef7086890cce"
|
||||
"194631e3d205cb459a7e1ff11b54791ef394b74fb8a729d0104b00e17b9e05c5d42fac"
|
||||
"923f98d43aedc70ab0733039eb22f35c6961e4587085a14c4a9ace1db00508843e79ee"
|
||||
"ba68321b559fbdfdf04c88813cdd";
|
||||
|
||||
constexpr char kRenewalCasRequest[] =
|
||||
"0807122612141a120a100a001208812d22c7c19b482f20022800180220be8c8ee90530"
|
||||
"15388bd8fdf9091a20e7cb15614a3fd2290f6527a1356fccb9a675492e421f7699d35d"
|
||||
"b52bc0d31119";
|
||||
|
||||
constexpr char kServiceCertificateForWidevineTestWithCASProxyType[] =
|
||||
"CrwCCAMSELBFY1/OQaWD87swUMHQjTMY0Ont7AUijgIwggEKAoIBAQCUNggP3JYvTaepEoHfiG"
|
||||
"32zOEbimIPtzmjTsu+3mOyXn3iA/d+aL6PnCqB0ORWvHld+xkRGHUUCSMAX0stvi+vTAd7e5fd"
|
||||
"MTXVtDbmj4o2fYDfp0klk3qj3OS7+XH+z2musgRkbzZTzpH8MzUnLRHz97TMx46bwYyL8Sskrv"
|
||||
"naWwyPBhkDfmAoNQKSVuLZNc6snfOAE4hNCdB4Qq+HTgC3FIl+1Kt4svUUPL4LYAzpKG5xH2r6"
|
||||
"ol0PQGSIKQ2qhJ+dyXLgDZcFLYdKd7hnKD1yUpvv8tGdHwcXawq7B+eLitKy0gRJx1nyMmLQ+R"
|
||||
"G31FBEfR6Gtatzcs2OTyoZuktzAgMBAAE6DXdpZGV2aW5lX3Rlc3RABBKAAwtMdfh+yBur+Ivq"
|
||||
"7rz/00RR8vA4MPJOPR3sZXDVFRQsATRvqUVPCTP88hh6Y7Y3IdHTEfXgcjiz2GZqEOvXzl3iuW"
|
||||
"kSjNQjNl5ghk955VIryOdzkIYBZJIv4/eEon2RRflExbv4y2GuWxTxHxMmIrFKXF+w2fLSvpiy"
|
||||
"1qT5daHPIcdvRBDHwIAVbmNmfv2EXoAqbvBWLhOdA8IRd5Lylqa8SWsUgkuyt9mglUdno6h/WC"
|
||||
"XZBm99eTfuN66ls+rJrlDgUNO3OUOXpMYMI8jE4Neo4GF8AKXoyt0lcckHwynzdlSYa04V6vbP"
|
||||
"MNycO+u1wpnUAPqkXYbnoYnbjm5gJ7Vav5wJtUM4wFAREefRmS/Dz/kqspC1CxQXo10KZQm3b4"
|
||||
"QXc/S0cqNXM/R9NGct0qjUdKec/k1RfC1j7MckdZMg4oU+mnqmwOZS7jTNIaHS4ASTuicsDUsf"
|
||||
"X1Ac4eqGv1L3qEY4pipCOps+5mRJ3sCjz87cX8QnPsArgtFYSYPgAg==";
|
||||
|
||||
constexpr char kPrivateKeyForWidevineTestWithCASProxyType[] =
|
||||
"MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI5Qd3AH24lskCAggAMB0GCWCGSA"
|
||||
"FlAwQBKgQQ9X4D3HPWx35HsgzSgMWCzASCBNBDZGDdRs/hyeRTrca0H4UERbrKRYFsoce9n6+c"
|
||||
"ghmLtIzAn8pYdGH/jfj5Hc3HTo9aXxfJJz9Juckh9teStzVmA+8y2Qj7W8W243DjbyNyKKDzk9"
|
||||
"esQme5sVvNugEb8wiqraZ0q4KxfjcK60HsZrOK1Ise0TglQMvudrDzV3vTxtgP5LTer6wEnUjf"
|
||||
"GixzhL120X48me+1stTPeG2ji9zlsgmMCjYCEbe4ovMCZmVOaHnbQ3WNVVnMnVQCqCAmBg/0AK"
|
||||
"gYB9wvvy7vdRaFHv0EtmyCOegLToNE0I7L5LMcL4+HQ++bwQMHjVkDmIqB3s3XWyhNU/nneES3"
|
||||
"qpgAbKpObfPGs814BqjbKwGj6z8jrNJ9Lmlaj/7msphYCuOAEjc26CEmxMYG1dTe+XiluHGIVu"
|
||||
"nau6iL7OguAdgbhkc2MQ7XJISjQ8j2sYuryUW33Pn2JSoKa4vVCWxTwg2t86Mc3FJ/daLM/z/k"
|
||||
"qTh5zel6o05tGXgHhn2UGRTjAs3PgxzExUX6M2/+6uSmdnS4oWxAqVd9ZREMjZaSBY6qPdXyM+"
|
||||
"Wd2RmUfLNSO3aazLxWu8uH2nbud/3vLyMSj/7lLjtAATqDKrcr1PyNlrn0MTQWIUZ4S5rsHHtp"
|
||||
"rPB/v+7Ufh4OVPdyWfapBGJLx8Eg0Xscoxc/DpwAD9KoA62GGg2CPu4NvvHiFIvEkpsxNFGTEA"
|
||||
"bZfoXXw78GP370doSguKvbTI3INcguKM35pbpe7+gbU8BjSednslbQMk4QKFg0YIQmTPDVXAC7"
|
||||
"FVnyP/dlNf2RXQRObGBGvA/oWv62iz8d3UhpIJOFHeyNic+qoQTj6wRFcxdFR61JhvqZ8rM/KH"
|
||||
"Jl/pvazrhMJ4JAQJXWhQzOvp4rqAJ7Jfx1u/pF/ZRZ6AX2Rjec+xep4EaqRZPdfEUydKKlr10I"
|
||||
"Ic/kNQwU15m0UEE/40wDJ3XqrhKuUnPfHpm4cziFYsQPrfuI36MCKklPvjdWS6VdSA+evN6KBZ"
|
||||
"wD3RQh4jdzTxWfzN+0p9612jIwzUzZj8Zax+TRRaOaN+0+nuPsmR88Ps4Y8AE2+CocYykAD8jh"
|
||||
"5WbuZKJDEtrNsIfz6keNZVk5ji1JWcpwzbPk9L/A8MdZh5XBA7X+BLe2F6EIVgI3mwTUPSC8wp"
|
||||
"oGsc4Hu2VeePzOuuZ59IGSmDkyi68usMQzsVeq2VJyz4UpDgy5dC5EOcBHLf3/oiAoxuYu6MIX"
|
||||
"Lk+srrO8+mikdRcey9EzmK9uqMV1e4b7Ts7hdIglBij1QwIKbDmMDMnmnPGX9X5KJojYuxkboe"
|
||||
"4WWwUgloyRkwxqKWIuEhLirO7E9eS+OOeqtz0idkcMNWziJRiUkVh768T4yfOfZ8ZvOCx59YN8"
|
||||
"bL390OZIIdaxSvj5mGeQX2+DTDspxDLpiluDJzTQmH7UZsSQ9DlQiXBtJwuaiFoRsyr0b1hh6n"
|
||||
"yE1TibcD/mWuwMOanUnvGF7OzRyneki4aB+v/PwpvplIDQuRqmkjn9i5P7tl6msEMUhp0yBE2t"
|
||||
"QIYPbQlIw57n3wRcGOz9ymOrREzEW1UhZQBibr8ZFNoWzRt+k0EVLYzNt96NDtHfHc7AlxJv8E"
|
||||
"RIDOZ4ai/nNeLgtV76+ybXnTRqRO9TXwqZhHQ/7gEs4Y01IJxvEQ==";
|
||||
|
||||
constexpr char kPassphrase[] = "encryptallthekitties";
|
||||
|
||||
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 kKeyBytes1[] =
|
||||
"\x69\xea\xa8\x02\xa6\x76\x3a\xf9\x79\xe8\xd1\x94\x0f\xb8\x83\x92\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\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 kKeyBytes3[] =
|
||||
"\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x01\x01"
|
||||
"\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
|
||||
constexpr char kKeyId3[] =
|
||||
"\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
|
||||
constexpr char kKeyBytes4[] =
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01";
|
||||
constexpr char kKeyId4[] =
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01";
|
||||
|
||||
} // namespace example_data
|
||||
} // namespace wv_pl_sdk
|
||||
} // namespace video_widevine_server
|
||||
|
||||
#endif // VIDEO_WIDEVINE_EXPORT_MEDIA_CAS_PROXY_SDK_EXAMPLE_WVPL_CAS_PROXY_SDK_EXAMPLE_DATA_H_
|
||||
BIN
ubuntu/example/wvpl_cas_proxy_sdk_using_group_license_example
Normal file
BIN
ubuntu/example/wvpl_cas_proxy_sdk_using_group_license_example
Normal file
Binary file not shown.
339
ubuntu/example/wvpl_cas_proxy_sdk_using_group_license_example.cc
Normal file
339
ubuntu/example/wvpl_cas_proxy_sdk_using_group_license_example.cc
Normal file
@@ -0,0 +1,339 @@
|
||||
// Copyright 2021 Google LLC. All rights reserved.
|
||||
|
||||
// Example of how to use WvPL CAS API to generate group license request.
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "example//wvpl_cas_proxy_sdk_example_data.h"
|
||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h"
|
||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
||||
#include "sdk/external/common/wvpl/wvpl_types.h"
|
||||
|
||||
using video_widevine_server::wv_pl_sdk::ENTITLEMENT;
|
||||
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::kProvider;
|
||||
using video_widevine_server::wv_pl_sdk::kProviderIv;
|
||||
using video_widevine_server::wv_pl_sdk::kProviderKey;
|
||||
using video_widevine_server::wv_pl_sdk::NEW;
|
||||
using video_widevine_server::wv_pl_sdk::RENEWAL;
|
||||
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::WvPLCasKey;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLCASProxySession;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLClientInfo;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLDeviceInfo;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLLicenseCategorySpec;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLPlaybackPolicy;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLRequestType;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLSecurityProfile;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLSessionInit;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kPassphrase;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::
|
||||
kPrivateKeyForWidevineTestWithCASProxyType;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::
|
||||
kServiceCertificateForWidevineTestWithCASProxyType;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kValidCertList;
|
||||
|
||||
namespace {
|
||||
// For using group license, request from Cas should come with group id shown in
|
||||
// the pssh data. See plugin update on CaPrivate data for details.
|
||||
constexpr char kNewCasRequestWithGroupId[] =
|
||||
"080712f10b0aa30b080112eb090aae0208021210a6b40340e0d9e82e5b3bffd81914a91918"
|
||||
"978dc8e605228e023082010a02820101009c8d4f148e228211abdd915187c1a4f160088698"
|
||||
"61fa255be3c2fb41833076ccc7bcf4c2c41c173e6c3f292b1f047ac9be254ea7f54ee77ce7"
|
||||
"b3490abdc1d48ea429711ad2065a5dddbfb644afadc087fa1f726dc42793e0640543e132e0"
|
||||
"6bd0bcb8866f87a0fd68ec6280d4d9ff679485013dc139622e2a868ae5ef924e888dd323d8"
|
||||
"6208df7094d8e5edc9f295c6c49527364d809c0b7294482a693dd044b1492aeb4306d918d9"
|
||||
"618b5d3bec2b75e9114c561366aea166b72821ef6ceae0c3a5a08d5b916627957cf13fa1b3"
|
||||
"5cb7773957a2e34876bbb608ad6d12841865098179260ab4e4ee35e387623eb28d83f2c415"
|
||||
"c4d5666aa7eeb250b10f759de283020301000128e83d1280022ab67dfa24e32eed524afe0f"
|
||||
"705d6819ca7a8dbc98fa7b4d1678f0faeeaf785ecee988aa50461cc6f62267c0a8245ce49e"
|
||||
"c1679b2be9f73d0fcd30604adf9e1e1c68297173b36231dbaa6edee2168e2325371ecb71c7"
|
||||
"92d9bea7cb7e42d007dd34082af64e4bf9b5d5b91c5f5f351ec83f40a27197a1d3555940e8"
|
||||
"6c3e68a972fb37cf9c1f1f4ac82efa4f605352421098e6bf47dfe40739e91ccb21ebb3c270"
|
||||
"eef92add78c4c9e6e779c24c3046ac03496fe8cb96f9263689a0f7aa613f7f14817ca0fa85"
|
||||
"307608a853a58c366f475b3aef1effe8d7e6a8828762941e4b0213e4eeb6fc1cb96f8d7f0c"
|
||||
"59181f5745b28609b0f8223b1b13a59a95725fdec1e61ab4050aae020801121065802c9b62"
|
||||
"5e5a319c33dc1cb7c3c6d418e3a5bdd005228e023082010a0282010100b80502043c2a8a0f"
|
||||
"d8d25c613e1e3e3b5e349f332f04516a7510d38021a5629b9aa027aead3c759b7afe70bed6"
|
||||
"5f3df6860ff5eb60b983a3ffa33fde06f3b73014dfc845ab371c6600562e9d904f842b8ba4"
|
||||
"a5d9200ffa3ed45d705520a5c372a889f9e314386234c6897ae655851fcd9adb4ef9126c78"
|
||||
"386ea93bcb25ba3ec475c55c608e771c763ab02506f9b07252d6abf7ea64b1ebde7b95c640"
|
||||
"7690533bd6890b9274c16066f74fc401ea355f0a02106814d49bf0c89e6e1f8db2a47841cd"
|
||||
"0dad793296a107c36223404f2bf1fca16fd0a4b982634db62407f8f14acae3b05a038bd3e4"
|
||||
"bbbae4391bbfa7a47fb9d01de857ea88e5e36ee36e245859fc0f020301000128e83d128003"
|
||||
"7e06581a019184ab572afdcaddd03f161ce68200f8e6f8ad161947360bc8d49c0d68009b1c"
|
||||
"4644f9b3f3fb6ddfd92ef92de62d41d459d29d81bfaef3970a3a39d25b2662ecb03b2da7b6"
|
||||
"8302faa6dd98d95a143cc8c1cb6adda76d2ee9c3723faf95a29cdc3e968b6821a91c051ca2"
|
||||
"80a86669710a1ad7a44bf9218027460df694e2e9270396df221963f21ee6aa220a5ee4a4d0"
|
||||
"feb3d53eb5732f8f91e9a96b3b8be284c51339ea284d4d0edd55b6ad56f7416420e05e059f"
|
||||
"9734a96be25aa44560dba8c38755a42a82bd7f88edd19df346a667b33b8114c76a8838c423"
|
||||
"d824a50b23251a088136d6e8f475299d2afd46cea51b5cbdf789a572125cd24fbb813b387a"
|
||||
"10cd2a30e3447634ab3408f96b9cf3d98896d405f3f540d9c57962760fcd177cdd101eb8a4"
|
||||
"148b9c29ced5ead645a95b698f1cdc6e1db6678b85074186080d68d13cd37e07b16de370cd"
|
||||
"9afb9b25564a73a30e2af8085ea37d310c474f0e67ac00ca992a5296faedad7aa06ecd790f"
|
||||
"1e3d426558fa98383e3cd2ed48301a130a0c636f6d70616e795f6e616d6512037777771a11"
|
||||
"0a0a6d6f64656c5f6e616d6512037777771a200a0c70726f647563745f6e616d6512105769"
|
||||
"646576696e6543617354657374731a260a116172636869746563747572655f6e616d651211"
|
||||
"6172636869746563747572655f6e616d651a1a0a0b6465766963655f6e616d65120b646576"
|
||||
"6963655f6e616d651a1f0a147769646576696e655f63646d5f76657273696f6e1207676f2d"
|
||||
"746573743202281012390a370a331a0d7769646576696e655f74657374220a436173547347"
|
||||
"726f757058016a0943617347726f7570316a0943617347726f7570321003180120c2bfd585"
|
||||
"06301538a4dae8870f1a80024a9b1c76c61420b61b00719b699844b7db798540196f59ce26"
|
||||
"76de56e398553e56ca6f83cc29290697efd38d0291972bbf81de990b47db25275e595235e3"
|
||||
"c65b261641266dff2a0ab01f798f190ce9825818f2453edc3a8a502fbc0a684de358a98289"
|
||||
"35ab0089cab3832f5046fd8602fd18b1458631b0c41c73c164addf7ad8d4aec00af526beb8"
|
||||
"5324165a3f591a5ba4d26bc1ea1c0c4ca5508823f0990134110dd95d95cc762e493b04fafd"
|
||||
"10807d78e103b13143c3062c0c49e84e85ca30ba3dd901a66de3cd2a6dabb0ac3800f38139"
|
||||
"ab9ea64a5d3e8e7edf9a8dc8890f26cee169e3cab4e62ba7fa3cfc083a9d94778a24e6a2e7"
|
||||
"605aa8d1fbbce9af434a14000000010000001400040010f0fa2d240000002d";
|
||||
|
||||
constexpr char kRenewalCasRequest[] =
|
||||
"0807122612141a120a100a001208812d22c7c19b482f20022800180220be8c8ee90530"
|
||||
"15388bd8fdf9091a20e7cb15614a3fd2290f6527a1356fccb9a675492e421f7699d35d"
|
||||
"b52bc0d31119";
|
||||
|
||||
// Assume {GroupKeyId1, GroupKeyBytes1}, {GroupKeyId2, GroupKeyBytes2},
|
||||
// {GroupKeyId3, GroupKeyBytes3} in this example are entitlement keys created
|
||||
// for group.
|
||||
const char kGroupKeyBytes1[] =
|
||||
"\x69\xea\xa8\x02\xa6\x76\x3a\xf9\x79\xe8\xd1\x94\x0f\xb8\x83\x92\x69\xea"
|
||||
"\xa8\x02\xa6\x76\x3a\xf9\x79\xe8\xd1\x94\x0f\xb8\x83\x92";
|
||||
const char kGroupKeyId1[] =
|
||||
"\xab\xba\x27\x1e\x8b\xcf\x55\x2b\xbd\x2e\x86\xa4\x34\xa9\xa5\xd9";
|
||||
const char kGroupKeyBytes2[] =
|
||||
"\xa4\x63\x1a\x15\x3a\x44\x3d\xf9\xee\xd0\x59\x30\x43\xdb\x75\x19\xa4\x63"
|
||||
"\x1a\x15\x3a\x44\x3d\xf9\xee\xd0\x59\x30\x43\xdb\x75\x19";
|
||||
const char kGroupKeyId2[] =
|
||||
"\xf3\xc5\xe0\x36\x1e\x66\x54\xb2\x8f\x80\x49\xc7\x78\xb2\x39\x46";
|
||||
const char kGroupKeyBytes3[] =
|
||||
"\xa4\x63\x1a\x15\x3a\x44\x3d\xf9\xee\xd0\x59\x30\x43\xdb\x75\x19\xa4\x63"
|
||||
"\x1a\x15\x2a\x44\x4d\xf9\xee\xd0\x59\x30\x43\xdb\x75\x19";
|
||||
const char kGroupKeyId3[] =
|
||||
"\xf3\xc5\xe0\x36\x1e\x66\x54\xb2\x7f\x80\x49\xc7\x78\xb2\x40\x46";
|
||||
|
||||
void LogErrorAndExit(absl::string_view error_description, WvPLStatus status) {
|
||||
std::cerr << error_description << ": " << status.error_message()
|
||||
<< ", exiting. Error code = "
|
||||
<< std::to_string(status.error_code()) << std::endl;
|
||||
exit(status.error_code());
|
||||
}
|
||||
|
||||
int GroupLicenseRequestGeneration(WvPLCASProxySession* cas_proxy_session) {
|
||||
// Set parameters on the created session.
|
||||
// Set policy parameters
|
||||
WvPLPlaybackPolicy policy;
|
||||
policy.set_license_duration_seconds(604800);
|
||||
policy.set_playback_duration_seconds(86400);
|
||||
cas_proxy_session->set_policy(policy);
|
||||
|
||||
// Add keys for one group.
|
||||
WvPLCasKey wvpl_cas_key1;
|
||||
wvpl_cas_key1.set_even_key_id(kGroupKeyId1);
|
||||
wvpl_cas_key1.set_even_key_bytes(kGroupKeyBytes1);
|
||||
wvpl_cas_key1.set_odd_key_id(kGroupKeyId2);
|
||||
wvpl_cas_key1.set_odd_key_bytes(kGroupKeyBytes2);
|
||||
wvpl_cas_key1.set_track_type(VIDEO_HD);
|
||||
wvpl_cas_key1.set_key_type(ENTITLEMENT);
|
||||
wvpl_cas_key1.mutable_output_protection()->set_hdcp(HDCP_V1);
|
||||
wvpl_cas_key1.mutable_output_protection()->set_secure_data_path(true);
|
||||
|
||||
WvPLStatus status = cas_proxy_session->AddCasKey(wvpl_cas_key1);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to add key #1", status);
|
||||
}
|
||||
|
||||
WvPLCasKey wvpl_cas_key2;
|
||||
wvpl_cas_key2.set_even_key_id(kGroupKeyId3);
|
||||
wvpl_cas_key2.set_even_key_bytes(kGroupKeyBytes3);
|
||||
wvpl_cas_key2.set_track_type(VIDEO_SD);
|
||||
wvpl_cas_key2.mutable_output_protection()->set_hdcp(HDCP_V2);
|
||||
wvpl_cas_key2.mutable_output_protection()->set_secure_data_path(false);
|
||||
|
||||
status = cas_proxy_session->AddCasKey(wvpl_cas_key2);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to add key #2", status);
|
||||
}
|
||||
|
||||
// Set License Category as GROUP_LICENSE in NEW request.
|
||||
WvPLLicenseCategorySpec license_category_spec;
|
||||
license_category_spec.set_license_category(
|
||||
video_widevine_server::wv_pl_sdk::GROUP_LICENSE);
|
||||
|
||||
// List group ids shown in pssh_data.
|
||||
video_widevine_server::wv_pl_sdk::WvPLWidevinePsshData pssh_data;
|
||||
cas_proxy_session->GetPsshData(&pssh_data);
|
||||
std::list<std::string> group_ids = pssh_data.group_ids();
|
||||
std::cout << "Group ids shown in pssh data are: ";
|
||||
for (absl::string_view id : group_ids) {
|
||||
std::cout << id << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Select one group id shown in group ids list in pssh_data.
|
||||
// Here assume group keys inserted are generated based on the first group
|
||||
// shown in the list.
|
||||
// Any group id which are not shown in the pssh_data will throw an error.
|
||||
license_category_spec.set_content_or_group_id(group_ids.front());
|
||||
WvPLSessionInit session_init = cas_proxy_session->session_init();
|
||||
session_init.set_license_category_spec(license_category_spec);
|
||||
cas_proxy_session->set_session_init(session_init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::cout << "Version of Cas Proxy SDK library: "
|
||||
<< WvPLCASProxySession::GetVersionString() << std::endl;
|
||||
|
||||
// Define the configuration that is to be used for WvPLCASEnvironment.
|
||||
std::map<std::string, std::string> config_values;
|
||||
// kDeviceCertificateExpiration shows that the device certificate status list
|
||||
// will expire in 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_values[kDeviceCertificateExpiration] = "315360000";
|
||||
// Ignore this setting, because service certificate in this file used for dev.
|
||||
// Content provider does not need to set this fieldwith prod service
|
||||
// certificate.
|
||||
config_values[kDrmCertificateType] = "dev";
|
||||
config_values[kProvider] = "widevine_test";
|
||||
config_values[kProviderIv] = "d58ce954203b7c9a9a9d467f59839249";
|
||||
config_values[kProviderKey] =
|
||||
"1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
|
||||
|
||||
// Set parameters on the environment.
|
||||
WvPLCASProxyEnvironment cas_proxy_environment(config_values);
|
||||
WvPLStatus status = cas_proxy_environment.Initialize();
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Environment failed to initialize", status);
|
||||
}
|
||||
// Use std::cout to print out log is appropriate in example code. SDK users
|
||||
// could esaily follow process or understand step here.
|
||||
std::cout << "Environment created and initialized." << std::endl;
|
||||
|
||||
std::string service_certificate;
|
||||
absl::Base64Unescape(kServiceCertificateForWidevineTestWithCASProxyType,
|
||||
&service_certificate);
|
||||
std::string private_key;
|
||||
absl::Base64Unescape(kPrivateKeyForWidevineTestWithCASProxyType,
|
||||
&private_key);
|
||||
// Must set a valid drm service certificate with CAS Proxy SDK type, otherwise
|
||||
// it will fail to create session.
|
||||
status = cas_proxy_environment.SetDrmServiceCertificate(
|
||||
service_certificate, private_key, kPassphrase);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to set DrmServiceCertificate", status);
|
||||
}
|
||||
|
||||
status = cas_proxy_environment.SetDeviceCertificateStatusList(kValidCertList);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to update the certificate", status);
|
||||
}
|
||||
|
||||
std::cout << "Created proxy session for group license..." << std::endl;
|
||||
WvPLCASProxySession* cas_proxy_session = nullptr;
|
||||
status = cas_proxy_environment.CreateSession(
|
||||
absl::HexStringToBytes(kNewCasRequestWithGroupId), &cas_proxy_session);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to create session for NEW Request", status);
|
||||
}
|
||||
|
||||
int result = GroupLicenseRequestGeneration(cas_proxy_session);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
WvPLDeviceInfo device_info;
|
||||
status = cas_proxy_session->GetDeviceInfo(&device_info);
|
||||
if (status.ok()) {
|
||||
std::cout << "WvPLDeviceInfo, drm_certificate_serial_number:"
|
||||
<< device_info.drm_certificate_serial_number()
|
||||
<< ", soc:" << device_info.soc()
|
||||
<< ", manufacturer:" << device_info.manufacturer()
|
||||
<< ", model:" << device_info.model()
|
||||
<< ", model year:" << device_info.model_year()
|
||||
<< ", device type:" << device_info.device_type()
|
||||
<< ", system id:" << device_info.system_id()
|
||||
<< ", test device:" << device_info.test_device()
|
||||
<< ", service id:" << device_info.service_id()
|
||||
<< ", device secruity level:" << device_info.security_level()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
WvPLClientInfo client_info;
|
||||
status = cas_proxy_session->GetClientInfo(&client_info);
|
||||
if (status.ok()) {
|
||||
std::cout << "WvPLClientInfo, max dcp version:"
|
||||
<< client_info.max_hdcp_version() << ", oemcrypto api version:"
|
||||
<< client_info.oem_crypto_api_version()
|
||||
<< ", provider client token:"
|
||||
<< client_info.provider_client_token()
|
||||
<< ", cdm version:" << client_info.cdm_version()
|
||||
<< ", max hdcp version:"
|
||||
<< client_info.client_capabilities().max_hdcp_version()
|
||||
<< ", resource rating tier:"
|
||||
<< client_info.client_capabilities().resource_rating_tier()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
WvPLSecurityProfile::DrmInfo drm_info;
|
||||
if (cas_proxy_session->GetDrmInfo(&drm_info)) {
|
||||
std::cout << "DrmInfo for system_id: " << drm_info.system_id() << std::endl;
|
||||
}
|
||||
|
||||
WvPLRequestType request_type = cas_proxy_session->GetRequestType();
|
||||
if (request_type.license_request_type() != NEW) {
|
||||
std::cerr << "License request type should be NEW." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string json_signed_cas_drm_request;
|
||||
status = cas_proxy_session->GenerateLicenseRequestAsJSON(
|
||||
&json_signed_cas_drm_request);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to generate NEW license request", status);
|
||||
}
|
||||
std::cout
|
||||
<< "NEW Request to POST over HTTP(s) to "
|
||||
"https://license.uat.widevine.com/cas/getlicense/widevine_test = "
|
||||
<< json_signed_cas_drm_request << std::endl;
|
||||
|
||||
// Test RENEWAL request. RENEWAL request format will follow the original one.
|
||||
cas_proxy_session = nullptr;
|
||||
status = cas_proxy_environment.CreateSession(
|
||||
absl::HexStringToBytes(kRenewalCasRequest), &cas_proxy_session);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to create session for RENEWAL Request", status);
|
||||
}
|
||||
request_type = cas_proxy_session->GetRequestType();
|
||||
if (request_type.license_request_type() != RENEWAL) {
|
||||
std::cerr << "License request type should be RENEWAL." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_signed_cas_drm_request.clear();
|
||||
status = cas_proxy_session->GenerateLicenseRequestAsJSON(
|
||||
&json_signed_cas_drm_request);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to generate RENEWAL license request", status);
|
||||
}
|
||||
std::cout
|
||||
<< "RENEWAL Request to POST over HTTP(s) to "
|
||||
"https://license.uat.widevine.com/cas/getlicense/widevine_test = "
|
||||
<< json_signed_cas_drm_request << std::endl;
|
||||
|
||||
// Destroy the created session.
|
||||
cas_proxy_environment.DestroySession(cas_proxy_session);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,272 @@
|
||||
// Copyright 2021 Google LLC. All rights reserved.
|
||||
|
||||
// Example of how to use WvPL CAS API to generate multi content license request.
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "example//wvpl_cas_proxy_sdk_example_data.h"
|
||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h"
|
||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
||||
#include "sdk/external/common/wvpl/wvpl_types.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using video_widevine_server::wv_pl_sdk::ENTITLEMENT;
|
||||
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::kProvider;
|
||||
using video_widevine_server::wv_pl_sdk::kProviderIv;
|
||||
using video_widevine_server::wv_pl_sdk::kProviderKey;
|
||||
using video_widevine_server::wv_pl_sdk::NEW;
|
||||
using video_widevine_server::wv_pl_sdk::RENEWAL;
|
||||
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::WvPLCasKey;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLCASProxySession;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLClientInfo;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLDeviceInfo;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLLicenseCategorySpec;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLPlaybackPolicy;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLRequestType;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLSecurityProfile;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLSessionInit;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyBytes1;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyBytes2;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyBytes3;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyId1;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyId2;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kKeyId3;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kNewCasRequest;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kPassphrase;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::
|
||||
kPrivateKeyForWidevineTestWithCASProxyType;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kRenewalCasRequest;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::
|
||||
kServiceCertificateForWidevineTestWithCASProxyType;
|
||||
using video_widevine_server::wv_pl_sdk::example_data::kValidCertList;
|
||||
|
||||
void LogErrorAndExit(absl::string_view error_description, WvPLStatus status) {
|
||||
std::cerr << error_description << ": " << status.error_message()
|
||||
<< ", exiting. Error code = "
|
||||
<< std::to_string(status.error_code()) << std::endl;
|
||||
exit(status.error_code());
|
||||
}
|
||||
|
||||
int MultiContentLicenseRequestGeneration(
|
||||
WvPLCASProxySession* cas_proxy_session) {
|
||||
// Set parameters on the created session.
|
||||
// Set policy parameters.
|
||||
WvPLPlaybackPolicy policy;
|
||||
policy.set_license_duration_seconds(604800);
|
||||
policy.set_playback_duration_seconds(86400);
|
||||
cas_proxy_session->set_policy(policy);
|
||||
|
||||
// Add keys for each single content shown in this multi content license.
|
||||
WvPLCasKey wvpl_cas_key1;
|
||||
wvpl_cas_key1.set_odd_key_id(kKeyId1);
|
||||
wvpl_cas_key1.set_odd_key_bytes(kKeyBytes1);
|
||||
wvpl_cas_key1.set_even_key_id(kKeyId2);
|
||||
wvpl_cas_key1.set_even_key_bytes(kKeyBytes2);
|
||||
wvpl_cas_key1.set_track_type(VIDEO_HD);
|
||||
wvpl_cas_key1.set_key_type(ENTITLEMENT);
|
||||
wvpl_cas_key1.mutable_output_protection()->set_hdcp(HDCP_V1);
|
||||
wvpl_cas_key1.mutable_output_protection()->set_secure_data_path(true);
|
||||
// Config key for one single content.
|
||||
video_widevine_server::wv_pl_sdk::WvPLKeyCategorySpec keyCategorySpec;
|
||||
keyCategorySpec.set_key_category(
|
||||
video_widevine_server::wv_pl_sdk::SINGLE_CONTENT_KEY_DEFAULT);
|
||||
// Content id instead of group id needs to fill in since this is a key for
|
||||
// SINGLE_CONTENT_KEY_DEFAULT.
|
||||
keyCategorySpec.set_content_or_group_id("content_1");
|
||||
wvpl_cas_key1.set_key_category_spec(keyCategorySpec);
|
||||
|
||||
WvPLStatus status = cas_proxy_session->AddCasKey(wvpl_cas_key1);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to add key #1", status);
|
||||
}
|
||||
|
||||
WvPLCasKey wvpl_cas_key2;
|
||||
wvpl_cas_key2.set_even_key_id(kKeyId3);
|
||||
wvpl_cas_key2.set_even_key_bytes(kKeyBytes3);
|
||||
wvpl_cas_key2.set_track_type(VIDEO_SD);
|
||||
wvpl_cas_key2.mutable_output_protection()->set_hdcp(HDCP_V2);
|
||||
wvpl_cas_key2.mutable_output_protection()->set_secure_data_path(false);
|
||||
|
||||
// Add key for another single content.
|
||||
keyCategorySpec.set_key_category(
|
||||
video_widevine_server::wv_pl_sdk::SINGLE_CONTENT_KEY_DEFAULT);
|
||||
// Content id instead of group id needs to fill in since this is a key for
|
||||
// SINGLE_CONTENT_KEY_DEFAULT.
|
||||
keyCategorySpec.set_content_or_group_id("content_2");
|
||||
wvpl_cas_key2.set_key_category_spec(keyCategorySpec);
|
||||
|
||||
status = cas_proxy_session->AddCasKey(wvpl_cas_key2);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to add key #2", status);
|
||||
}
|
||||
|
||||
// Set License Category as MULTI_CONTENT_LICENSE in NEW request.
|
||||
WvPLLicenseCategorySpec license_category_spec;
|
||||
license_category_spec.set_license_category(
|
||||
video_widevine_server::wv_pl_sdk::MULTI_CONTENT_LICENSE);
|
||||
// Group id is determined by operator given user's subscription/package.
|
||||
license_category_spec.set_content_or_group_id("user_group_1");
|
||||
WvPLSessionInit session_init = cas_proxy_session->session_init();
|
||||
session_init.set_license_category_spec(license_category_spec);
|
||||
cas_proxy_session->set_session_init(session_init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::cout << "Version of Cas Proxy SDK library: "
|
||||
<< WvPLCASProxySession::GetVersionString() << std::endl;
|
||||
|
||||
// Define the configuration that is to be used for WvPLCASEnvironment.
|
||||
std::map<std::string, std::string> config_values;
|
||||
// kDeviceCertificateExpiration shows that the device certificate status list
|
||||
// will expire in 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_values[kDeviceCertificateExpiration] = "315360000";
|
||||
// Ignore this setting, because service certificate in this file used for dev.
|
||||
// Content provider does not need to set this fieldwith prod service
|
||||
// certificate.
|
||||
config_values[kDrmCertificateType] = "dev";
|
||||
config_values[kProvider] = "widevine_test";
|
||||
config_values[kProviderIv] = "d58ce954203b7c9a9a9d467f59839249";
|
||||
config_values[kProviderKey] =
|
||||
"1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
|
||||
|
||||
// Set parameters on the environment.
|
||||
WvPLCASProxyEnvironment cas_proxy_environment(config_values);
|
||||
WvPLStatus status = cas_proxy_environment.Initialize();
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Environment failed to initialize", status);
|
||||
}
|
||||
std::cout << "Environment created and initialized" << std::endl;
|
||||
|
||||
std::string service_certificate;
|
||||
absl::Base64Unescape(kServiceCertificateForWidevineTestWithCASProxyType,
|
||||
&service_certificate);
|
||||
std::string private_key;
|
||||
absl::Base64Unescape(kPrivateKeyForWidevineTestWithCASProxyType,
|
||||
&private_key);
|
||||
// Must set a valid drm service certificate with CAS Proxy SDK type, otherwise
|
||||
// it will fail to create session.
|
||||
status = cas_proxy_environment.SetDrmServiceCertificate(
|
||||
service_certificate, private_key, kPassphrase);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to set DrmServiceCertificate", status);
|
||||
}
|
||||
|
||||
status = cas_proxy_environment.SetDeviceCertificateStatusList(kValidCertList);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to update the certificate", status);
|
||||
}
|
||||
|
||||
std::cout << "Created proxy session for multi_content_license..."
|
||||
<< std::endl;
|
||||
WvPLCASProxySession* cas_proxy_session = nullptr;
|
||||
status = cas_proxy_environment.CreateSession(
|
||||
absl::HexStringToBytes(kNewCasRequest), &cas_proxy_session);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to create session for NEW Request", status);
|
||||
}
|
||||
|
||||
int result = MultiContentLicenseRequestGeneration(cas_proxy_session);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
WvPLDeviceInfo device_info;
|
||||
status = cas_proxy_session->GetDeviceInfo(&device_info);
|
||||
if (status.ok()) {
|
||||
std::cout << "WvPLDeviceInfo, drm_certificate_serial_number:"
|
||||
<< device_info.drm_certificate_serial_number()
|
||||
<< ", soc:" << device_info.soc()
|
||||
<< ", manufacturer:" << device_info.manufacturer()
|
||||
<< ", model:" << device_info.model()
|
||||
<< ", model year:" << device_info.model_year()
|
||||
<< ", device type:" << device_info.device_type()
|
||||
<< ", system id:" << device_info.system_id()
|
||||
<< ", test device:" << device_info.test_device()
|
||||
<< ", service id:" << device_info.service_id()
|
||||
<< ", device secruity level:" << device_info.security_level()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
WvPLClientInfo client_info;
|
||||
status = cas_proxy_session->GetClientInfo(&client_info);
|
||||
if (status.ok()) {
|
||||
std::cout << "WvPLClientInfo, max dcp version:"
|
||||
<< client_info.max_hdcp_version() << ", oemcrypto api version:"
|
||||
<< client_info.oem_crypto_api_version()
|
||||
<< ", provider client token:"
|
||||
<< client_info.provider_client_token()
|
||||
<< ", cdm version:" << client_info.cdm_version()
|
||||
<< ", max hdcp version:"
|
||||
<< client_info.client_capabilities().max_hdcp_version()
|
||||
<< ", resource rating tier:"
|
||||
<< client_info.client_capabilities().resource_rating_tier()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
WvPLSecurityProfile::DrmInfo drm_info;
|
||||
if (cas_proxy_session->GetDrmInfo(&drm_info)) {
|
||||
std::cout << "DrmInfo for system_id: " << drm_info.system_id() << std::endl;
|
||||
}
|
||||
|
||||
WvPLRequestType request_type = cas_proxy_session->GetRequestType();
|
||||
if (request_type.license_request_type() != NEW) {
|
||||
std::cerr << "License request type should be NEW." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::string json_signed_cas_drm_request;
|
||||
status = cas_proxy_session->GenerateLicenseRequestAsJSON(
|
||||
&json_signed_cas_drm_request);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to generate NEW license request", status);
|
||||
}
|
||||
std::cout
|
||||
<< "NEW Request to POST over HTTP(s) to "
|
||||
"https://license.uat.widevine.com/cas/getlicense/widevine_test = "
|
||||
<< json_signed_cas_drm_request << std::endl;
|
||||
|
||||
// Test RENEWAL request. RENEWAL request format will follow the original one.
|
||||
cas_proxy_session = nullptr;
|
||||
status = cas_proxy_environment.CreateSession(
|
||||
absl::HexStringToBytes(kRenewalCasRequest), &cas_proxy_session);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to create session for RENEWAL Request", status);
|
||||
}
|
||||
request_type = cas_proxy_session->GetRequestType();
|
||||
if (request_type.license_request_type() != RENEWAL) {
|
||||
std::cerr << "License request type should be RENEWAL." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_signed_cas_drm_request.clear();
|
||||
status = cas_proxy_session->GenerateLicenseRequestAsJSON(
|
||||
&json_signed_cas_drm_request);
|
||||
if (!status.ok()) {
|
||||
LogErrorAndExit("Failed to generate RENEWAL license request", status);
|
||||
}
|
||||
std::cout
|
||||
<< "RENEWAL Request to POST over HTTP(s) to "
|
||||
"https://license.uat.widevine.com/cas/getlicense/widevine_test = "
|
||||
<< json_signed_cas_drm_request << std::endl;
|
||||
|
||||
// Destroy the created session.
|
||||
cas_proxy_environment.DestroySession(cas_proxy_session);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user