517 lines
28 KiB
Java
Executable File
517 lines
28 KiB
Java
Executable File
////////////////////////////////////////////////////////////////////////////////
|
|
//// Copyright 2021 Google LLC
|
|
////
|
|
//// This software is licensed under the terms defined in the Widevine Master
|
|
//// License Agreement. For a copy of this agreement, please contact
|
|
//// widevine-licensing@google.com.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
package com.google.video.widevine.sdk.wvpl;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Base64;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/** Tests for {@link WvPLProxySession} Java API in Widevine Proxy Server SDK. */
|
|
public class WvPLProxyUsingDspExample {
|
|
/* Creates WvTestRunner to run wvpl proxy test */
|
|
public static String loadCertificateStatusListFromFile(String certificateStatusListFile)
|
|
throws IOException {
|
|
BufferedReader br = Files.newBufferedReader(Path.of(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();
|
|
}
|
|
|
|
static class WvTestRunner extends Thread {
|
|
private final int loops;
|
|
|
|
private final String threadName;
|
|
|
|
private final WvPLProxyEnvironment env;
|
|
private List<String> customProfileOwners;
|
|
private String contentOwner;
|
|
|
|
public WvTestRunner(WvPLProxyEnvironment env, ThreadGroup group, String threadName, int loops) {
|
|
super(group, threadName);
|
|
this.loops = loops;
|
|
this.threadName = threadName;
|
|
this.env = env;
|
|
}
|
|
|
|
public void setCustomProfileOwners(List<String> customProfileOwners) {
|
|
this.customProfileOwners = customProfileOwners;
|
|
}
|
|
|
|
public void setContentOwner(String contentOwner) {
|
|
this.contentOwner = contentOwner;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
System.out.println("Thread Started: " + threadName);
|
|
try {
|
|
Thread.sleep(2000);
|
|
} catch (InterruptedException e) {
|
|
System.out.println("Unexpected error when starting thread = " + threadName);
|
|
}
|
|
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;
|
|
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==";
|
|
byte[] decodedLicenseRequest = Base64.getUrlDecoder().decode(b64LicenseRequest);
|
|
for (int i = 0; i < loops; i++) {
|
|
try {
|
|
byte[] bad = {1, 2, 3, 4};
|
|
env.createSession(bad);
|
|
} catch (WvPLStatusException e) {
|
|
System.out.println("Message for bad session: " + e.getMessage());
|
|
System.out.println("Status message for bad session: " + e.getStatus().getMessage());
|
|
}
|
|
try {
|
|
byte[] serviceCertificateRequest = Base64.getUrlDecoder().decode("CAQ=");
|
|
env.createSession(serviceCertificateRequest);
|
|
} catch (WvPLStatusException e) {
|
|
System.out.println("Message for failed to create session with service certificate "
|
|
+ "request: " + e.getMessage());
|
|
assertEquals(WvPLStatus.StatusCode.SERVICE_CERTIFICATE_REQUEST_MESSAGE,
|
|
e.getStatus().getStatusCode());
|
|
try {
|
|
byte[] serviceCert = env.generateDrmServiceCertificateResponse();
|
|
System.out.println("Returning service certificate: "
|
|
+ Base64.getUrlEncoder().encodeToString(serviceCert));
|
|
} catch (WvPLStatusException wvplE) {
|
|
System.out.println("Failed to get the DRM Service Certifidate: "
|
|
+ wvplE.getStatus().getMessage());
|
|
}
|
|
}
|
|
WvPLProxySession session = null;
|
|
try {
|
|
session = env.createSession(decodedLicenseRequest);
|
|
} catch (WvPLStatusException e) {
|
|
System.out.println("Message: " + e.getMessage());
|
|
System.out.println("Status message: " + e.getStatus().getMessage());
|
|
}
|
|
System.out.println("Version: " + WvPLProxySession.getVersionString());
|
|
WvPLRequestType requestType = session.getRequestType();
|
|
System.out.println("Message type : " + requestType.getMessageType());
|
|
if (requestType.getMessageType() != WvPLMessageType.MessageType.LICENSE_REQUEST) {
|
|
System.out.println(
|
|
"Expected LICENSE_REQUEST, Unexpected message type : " + requestType.getMessageType());
|
|
System.exit(3);
|
|
}
|
|
System.out.println("License type : " + requestType.getLicenseType());
|
|
System.out.println("LicenseRequest type : " + requestType.getLicenseRequestType());
|
|
WvPLStatus status;
|
|
try {
|
|
WvPLClientInfo clientInfo = session.getClientInfo();
|
|
WvPLHdcp.HDCP maxHdcpVersion = clientInfo.getMaxHdcpVersion();
|
|
System.out.println("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());
|
|
}
|
|
|
|
// Set parameters on the created session.
|
|
// Validate setting/getting WvPLPlaybackPolicy for a session
|
|
WvPLPlaybackPolicy policy = new WvPLPlaybackPolicy();
|
|
policy.setLicenseDurationSeconds(10000000L);
|
|
session.setPolicy(policy);
|
|
assertEquals(
|
|
policy.getLicenseDurationSeconds(), session.getPolicy().getLicenseDurationSeconds());
|
|
|
|
// Optional. Check the qualified custom profiles for the content owner.
|
|
List<String> qualifiedProfileNames;
|
|
if (customProfileOwners.contains(contentOwner)) {
|
|
try {
|
|
qualifiedProfileNames = session.getQualifiedCustomDeviceSecurityProfiles(contentOwner);
|
|
if (!qualifiedProfileNames.isEmpty()) {
|
|
System.out.println(
|
|
"DRM qualifying custom profiles for owner <" + contentOwner + ">:");
|
|
for (String profileName : qualifiedProfileNames) {
|
|
System.out.printf("%s ", profileName);
|
|
}
|
|
System.out.println();
|
|
}
|
|
} catch (WvPLStatusException e) {
|
|
status = e.getStatus();
|
|
System.out.println(
|
|
"Failed to get qualifying custom profiles: "
|
|
+ status.getStatusCode()
|
|
+ ", message: "
|
|
+ status.getMessage()
|
|
+ " for owner: <"
|
|
+ contentOwner
|
|
+ ">");
|
|
}
|
|
}
|
|
// Content keys are generated based on the info from qualifying profiles.
|
|
// The qualified profiles can be used to determine the content keys allowed in the license.
|
|
// In this example, the following `key1` and `key2` are generated based on qualified custom
|
|
// profiles. Those keys would support SD and HD content.
|
|
// Adding a TrackType.VIDEO_SD key (without keyId)
|
|
WvPLKey key1 = new WvPLKey();
|
|
byte[] data1 = {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
|
key1.setKeyBytes(data1);
|
|
key1.setTrackType(WvPLTrackType.TrackType.VIDEO_SD);
|
|
status = session.addKey(key1);
|
|
assertEquals(WvPLStatus.StatusCode.OK, status.getStatusCode());
|
|
|
|
// Adding a TrackType.VIDEO_HD key
|
|
WvPLKey key2 = new WvPLKey();
|
|
byte[] data2 = {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
|
key2.setKeyId(data2);
|
|
key2.setKeyBytes(data2);
|
|
key2.setTrackType(WvPLTrackType.TrackType.VIDEO_HD);
|
|
|
|
// Validate setting/getting WvPLOutputProtection values
|
|
WvPLOutputProtection outputProtection = new WvPLOutputProtection();
|
|
outputProtection.setHdcp(WvPLHdcp.HDCP.HDCP_V2_2);
|
|
assertEquals(WvPLHdcp.HDCP.HDCP_V2_2, outputProtection.getHdcp());
|
|
outputProtection.setSecurityLevel(WvPLSecurityLevel.SecurityLevel.SW_SECURE_DECODE);
|
|
assertEquals(
|
|
WvPLSecurityLevel.SecurityLevel.SW_SECURE_DECODE, outputProtection.getSecurityLevel());
|
|
key2.setOutputProtection(outputProtection);
|
|
|
|
// Validate setting/getting WvPLVideoResolutionConstraints
|
|
WvPLVideoResolutionConstraint videoResolutionConstraint1 =
|
|
new WvPLVideoResolutionConstraint();
|
|
videoResolutionConstraint1.setMinResolutionPixels(300);
|
|
videoResolutionConstraint1.setMaxResolutionPixels(600);
|
|
videoResolutionConstraint1.setHdcp(WvPLHdcp.HDCP.HDCP_V2);
|
|
|
|
WvPLVideoResolutionConstraint videoResolutionConstraint2 =
|
|
new WvPLVideoResolutionConstraint();
|
|
videoResolutionConstraint2.setMinResolutionPixels(3000);
|
|
videoResolutionConstraint2.setMaxResolutionPixels(6000);
|
|
videoResolutionConstraint2.setHdcp(WvPLHdcp.HDCP.HDCP_V1);
|
|
|
|
// Validate adding constraints and output protection values to key2 (VIDEO_HD)
|
|
key2.addVideoResolutionConstraint(videoResolutionConstraint1);
|
|
key2.addVideoResolutionConstraint(videoResolutionConstraint2);
|
|
assertThat(key2.getVideoResolutionConstraint()).hasSize(2);
|
|
|
|
|
|
for (WvPLVideoResolutionConstraint vrc : key2.getVideoResolutionConstraint()) {
|
|
if (vrc.getHdcp() == WvPLHdcp.HDCP.HDCP_V2) {
|
|
assertEquals(videoResolutionConstraint1, vrc);
|
|
} else {
|
|
assertEquals(videoResolutionConstraint2, vrc);
|
|
}
|
|
}
|
|
|
|
WvPLOutputProtection requestedOutputProtection = new WvPLOutputProtection();
|
|
requestedOutputProtection.setHdcp(WvPLHdcp.HDCP.HDCP_V2);
|
|
key2.setRequestedOutputProtection(requestedOutputProtection);
|
|
status = session.addKey(key2);
|
|
assertEquals(WvPLStatus.StatusCode.OK, status.getStatusCode());
|
|
|
|
// Or we could call filterKey() to filter out the keys. Keys could be inserted
|
|
// with one security profile as required profile, as well as content owner. In
|
|
// filterkey() API it already contains the logic of checking the qualified security
|
|
// profiles for the content owner.
|
|
WvPLKey key3 = new WvPLKey();
|
|
byte[] data3 = {4, 4, 4, 4, 4, 4, 4, 4, 4, 10, 11, 12, 13, 14, 15, 16};
|
|
key3.setKeyBytes(data3);
|
|
key3.setTrackType(WvPLTrackType.TrackType.VIDEO_HD);
|
|
outputProtection.setHdcp(WvPLHdcp.HDCP.HDCP_NONE);
|
|
outputProtection.setSecuredataPath(true);
|
|
key3.setOutputProtection(outputProtection);
|
|
String requiredProfileName = "dsp_test";
|
|
key3.setRequiredProfile(requiredProfileName.getBytes(UTF_8));
|
|
key3.setContentOwner(contentOwner.getBytes(UTF_8));
|
|
WvPLCapabilityStatus capabilityStatus = session.filterKey(key3);
|
|
assertEquals(
|
|
WvPLCapabilityStatus.DeviceCapabilityStatus.CAPABILITY_OK,
|
|
capabilityStatus.getStatus());
|
|
|
|
// The following example `wvpl_key4` will be filtered out because the profile name the key
|
|
// associated with is not qualified.
|
|
WvPLKey key4 = new WvPLKey();
|
|
byte[] data4 = {6, 6, 6, 6, 6, 6, 6, 6, 6, 10, 11, 12, 13, 14, 15, 16};
|
|
key4.setKeyBytes(data4);
|
|
key3.setTrackType(WvPLTrackType.TrackType.VIDEO_HD);
|
|
outputProtection.setHdcp(WvPLHdcp.HDCP.HDCP_NONE);
|
|
outputProtection.setSecuredataPath(true);
|
|
key3.setOutputProtection(outputProtection);
|
|
requiredProfileName = "L3";
|
|
key3.setRequiredProfile(requiredProfileName.getBytes(UTF_8));
|
|
key3.setContentOwner(contentOwner.getBytes(UTF_8));
|
|
capabilityStatus = session.filterKey(key4);
|
|
assertEquals(
|
|
WvPLCapabilityStatus.DeviceCapabilityStatus.CAPABILITY_UNQUALIFIED_PROFILE,
|
|
capabilityStatus.getStatus());
|
|
|
|
// 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);
|
|
assertEquals(testSessionId, session.getSessionInit().getSessionId());
|
|
assertEquals(testPurchaseId, session.getSessionInit().getPurchaseId());
|
|
assertEquals(Arrays.toString(testMasterSigningKeys),
|
|
Arrays.toString(session.getSessionInit().getMasterSigningKey()));
|
|
assertEquals(testProviderClientToken, session.getSessionInit().getProviderClientToken());
|
|
assertEquals(testOverrideProviderClientToken,
|
|
session.getSessionInit().getOverrideProviderClientToken());
|
|
// Test getDeviceInfo() function.
|
|
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());
|
|
} catch (WvPLStatusException e) {
|
|
status = e.getStatus();
|
|
System.out.println("GetDeviceInfo WvPLStatus: code = " + status.getStatusCode()
|
|
+ ", message = " + status.getMessage());
|
|
}
|
|
try {
|
|
WvPLWidevinePsshData widevinePsshData = session.getPsshData();
|
|
if (!widevinePsshData.getKeyIds().isEmpty()) {
|
|
for (byte[] keyId : widevinePsshData.getKeyIds()) {
|
|
System.out.println("keyId from Widevine Pssh = " + Arrays.toString(keyId));
|
|
}
|
|
System.out.println("Content Id" + Arrays.toString(widevinePsshData.getContentId()));
|
|
} 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());
|
|
}
|
|
// Test generateEncodedLicenseRequest() function.
|
|
// TODO(yawenyu): Check if licenseRequest can be base64 decoded and parsed into the proto.
|
|
try {
|
|
String licenseRequest = session.generateLicenseRequest();
|
|
if (licenseRequest.length() == 0) {
|
|
System.out.println("Base64 encoded license request is empty");
|
|
System.exit(-1);
|
|
}
|
|
System.out.println("License request is : " + licenseRequest);
|
|
} catch (WvPLStatusException e) {
|
|
status = e.getStatus();
|
|
System.out.println("GenerateEncodedLicenseReques failed. WvPLStatus: code = "
|
|
+ status.getStatusCode() + ", message = " + status.getMessage());
|
|
}
|
|
// Test getResponseStatus.
|
|
String input =
|
|
"{\"status\":\"OK\",\"license\":\"CAISdgpKCiBBOEVEMDBBQUVEODM2RThFODMwNDAwMDAwMDAwMDAwMBIgQThFRDAwQUFFRDgzNkU4RTgzMDQwMDAwMDAwMDAwMDAaACABKAQSBggBEAEYARoWIANCEgoQa2MxMwAAAAAuNBxJAAAACCDe1eziBSgBUAMaIDn9npcVDpyEU7RpVHPvVCAmlTDVEbaBDUdi+LWCCWBL\"}";
|
|
try {
|
|
String responseStatus = session.getResponseStatus(input);
|
|
assertEquals("OK", responseStatus);
|
|
} catch (WvPLStatusException e) {
|
|
System.out.println("Failed to getResponseStatus.");
|
|
}
|
|
try {
|
|
session.getLicense(input);
|
|
} catch (WvPLStatusException e) {
|
|
System.out.println("getResponseStatus status = " + status.getStatusCode()
|
|
+ ", message = " + status.getMessage());
|
|
}
|
|
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());
|
|
}
|
|
try {
|
|
env.destroySession(session);
|
|
} catch (IOException e) {
|
|
System.out.println("IOException when closing: " + e.getMessage());
|
|
}
|
|
// TODO(yawenyu): Add more test cases for getResponseStatus.
|
|
}
|
|
System.out.println("Thread Ended: " + threadName);
|
|
}
|
|
}
|
|
|
|
public static void main(String[] argv) throws Exception {
|
|
int numberOfRunners = 10;
|
|
int numberOfLoops = 100;
|
|
String b64DrmServiceCertificate =
|
|
"CscCCAMSEGMj4kXUq6vl6Zu3yX-iATQY8YHR4wUijgIwggEKAoIBAQCQ4zD-Na1NJ-_R5EukD3ZwnkJUVijD5Bs70gBbvYrskXADVMSC-YnFgN5_lQ7Y1jqG1Vo_o2MBLNu4wCoGjD9Vfnw2uOVs5lccs5hKGgxqHPgKit3PvVJYe0fXRi571pE-bI9FKsKlt02VkC0OopgqCui-494J9mVvTfmkwg24F0BBn6JnzNMKKLYXqNmEVyL-xF5AprYbYQwQ2RsYx0xHJ5ggh5J9LOJHuCfePTykRmdvkJfh0bnoBRrcR9VJzU--6ZMwFhsD3SEmGnyjfh9_rD1De01xdMIU1tumBDR7CsFmWFB-s8GPFEy14lkG7LWRZYOUagSf2FPh2V8O3rK3AgMBAAE6GHdpZGV2aW5lLXRlc3QuZ29vZ2xlLmNvbUACEoADqy10oin03kb2QW1t7OiNAx9Y5leFlqUaBveD93qtip5BC-4TPmB2CqKEGr_uUoR7YSOfoSsc8XJy5aGK6s05ci-LNxcQsHMbZr6nieDVO56AQhk6KvP2tB9qvPBKxtg7FKpxDjF43Fv2IeVUHnTy8JzuToOHLwgGDhT90RYnEqCTpVcssalc7XF8iVNERyMCakuud4TH8EL_bCqmoVY4Emdqdiu1uSMsTSQuSGu5GeFlK3FXxEjmKCw2ItKCiB3z6HGwMB0VpvX-CCQThc46O2D8b4fnN529cBOAmqeBI7ELZXJjybjD9EiUXrLx6IKLiCpjp-aWiwsRK1hZN6yEH-cRfSiXX_8mON4qi-aUkdsyVlNSn4WNp5GpOoY5MSfTq4EisngTSBzoo_UgXMoS0xf-DOsj614TngSDgXRNPrKnf19K8KetqFTv7BTxLUQbFuNHqHWcqSnimmo4lIsYdDA4Ed76kRERtbMnqeyI__UNSbY0eEZ3uxO95OxZMgye";
|
|
String b64PrivateKey =
|
|
"MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIGRMrX1uPR0sCAggAMB0GCWCGSAFlAwQBKgQQ8yhCy0bstsUeTLwl7saOrwSCBNDLB7oZx7Ypfodc9OR5aolJ6yMmKcvrB0jxRGioPLsT5flz_kWe4JMp25xR1c8Y0_ZrugU12zBbw9siyvfXhenrW0JVzxoqNGysggA_p-ZLXMxeQKcGwXHemWRMxlvO7wZG7gPANQhhkPnHzEN2kevvmsVTWIT7JVYGFALDg2mYgNsRslkblkfY51HvFS8vMOkL3YOG72NHnmpV4jMpiz9m7qiOcJ39oG2IldUb57e39LfnMO5WWafgrak2DEwL9zH6T3dxETcLK9hX19A_JDmsSUZk1EDyMh_JVIcjeDJASko3obeLavPLDZky_Nrl6tuht7vKhv0f_2PKxTCzJWCA7dtzNUymhszcxwRecV76lDMn6OcQ6DJblae423fJ9iDBOIHLFUDMfDoQDkRgFTAr4AagXurjipwRGu059khs4p60dHtGgkh0Rk5JuGv4pha4lUKtBP60ENFMV8MXc5na9p4rHVdRU7mQ2uetKTQN6uVInGXFhBH2oyPvxzTWcqh-xgOBdDUH5cWOEDdvvKFuNAj-URND8ypQVbnJ-mOBv3hdNil_ZQfOxf9MEWksT9ApoM9g-zAblIrh9wRavz_NlRy8AarSnxTLmlvxsNPsd_lPmLce0HZSdyGrUYgKBjWCabKPN-bA9o2FINdFSsztJrmUeTsFLJqujSB5oMjMeotmXKAkZgbwjEG-Agi5a4UMPw8Krl1dUlGxC42tVLnaucrWRnlKiqfQc4rncgUJ05cDUr8n2KY1RqfQGk-EuTiiiLA8eU_HhDSqPazpDT_yL6ZUgbswLVhd52_bK0vCXX4NsUsa3jF31Qq5vE56mnr7qrKpwzHuHxrIFiXiYtaH_dnhzasuOpCJbTZPRAebjWWf2eXpikJN4jA_J4q2smvENR82D9laATxLHzF41baHfvCPYjchNGA08P183-_YBaYGiJvnaNcnL_H7FDOT99V_gcwk1MixDy7AaRsiUG8ZuJQEEPi8J03GpSX8UTy9yDXRzXrgsuJZ5REAh5_bCu8OgI-y_RJ9bPvSKRere4VIdLj6YvVN1L68C1R-Z6HhHTQ6H4vaTLsYskGXN4N6wR-he6RYPq0EhCHRg0zNEVxRAqOxmwdUZKQ7IetqMT0geO30AwiUnCmJOIpku-lsCCGj8ECIIK198HN25mBnHcFWYyQbHGe73Z0rDjgWuiivvGC7pvsa6WjHwCtLVF8hTxal6ViGBN7-5zQ6YFZsmA5t8BloZBcohc5-jZUS62lgfyETHBmHVY8etQOm9L5dja7I18xlurZybwgUeMQQBZiwV3ynb0s_B1wQriAAdboFuglRD-dVqyobGMOk_ECePQ5LWQv6D5fqLaXzVyqLUJ_gpPQ6JAYbTywy5SIxx4JpIbqk17cBqaoYRP-RRA4DQGU_qrdh-HGqCesOL_yYqq2o7Gc-M-PWMlqYiEv8T2QbSywtWutqIkkok4Kqlo6zKn7Cgynhe0QsdXNVAlbNDzpdBTm6scKHl2PzLfuHOdwRe7BFkQAJJnMQuyrsGOMq4uEsKg0LMJm2hYOJ7PtMgFtIdXmdHQdsRkgkmHYZ5ryen-kjd7rIUtU1UjH2WPG3ROhdgMFw84uZGtt-WpsT4SrTrreC_QV_PlsOmqlHPBJg8w==";
|
|
String passphrase = "encryptallthekitties";
|
|
byte[] passphraseBytes = passphrase.getBytes(UTF_8);
|
|
|
|
byte[] decodedDrmServiceCertificate = Base64.getUrlDecoder().decode(b64DrmServiceCertificate);
|
|
byte[] decodedPrivateKey = Base64.getUrlDecoder().decode(b64PrivateKey);
|
|
|
|
String providerIv = "d58ce954203b7c9a9a9d467f59839249";
|
|
String providerKey = "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
|
|
String b64SerializedSignedDsps =
|
|
"Cm0I45_P_"
|
|
+ "AUSLwoIZHNwX3Rlc3QQAhoECAAQACIGCAAQAyACKg13aWRldmluZV90ZXN0OgQIABAAEjQKC"
|
|
+ "GxpdmVkZW1vEAIaAggEIgIQASoNd2lkZXZpbmVfdGVzdDIFCNcIEAI6CAiDwrX6BRAAEoADb"
|
|
+ "oYJI5ouzml8W63DmiTBA7thzSl5OaKbyc1dAKGpHrMw-lTuUyrzULPm5nb_"
|
|
+ "st4YJk2w3F0k4Ly0lsRY_QweMSIechtcII5jO_9N2scy0y5V-lBRH_"
|
|
+ "7AtZFdfwD2wrseVCCarSyWDZN84-"
|
|
+ "6Wu3ekKbNO8vehiP8Tx2VWmkcIypJ09nPuTDxPT5CutLkgzlIS2q9HjwE5IK4nfC-"
|
|
+ "rx7seGgMxouyEb-QsTBtJ-Lx9O8D1GFMvOtHmfG-KfoD1L-"
|
|
+ "9lUT6j8W3TfyrUesnIDQy2bCCQzsbsNg60M9B-YZNvl6DX_-"
|
|
+ "PqE1CT2Lal7rp5TsZluOtwEj8TMBzyNl5kC5MAXZ3ETEFDag_9qEZrMJMIEsw194_lo_"
|
|
+ "o2ivjkiPNwCC00rJ91RI9gc2ctDlXUqtbqfz5-lx_v04VsI8AEYfuXmO8OBhFZwz4__"
|
|
+ "ZVwpI8fOtedm1KI46uCWZUwIi3yigYNJvgxoynzxVF8uMLTJi3iqiG5BAtrRImEt1iRVD8Ow"
|
|
+ "h4-GAI=";
|
|
|
|
|
|
// Define the configuration that is to be used for WvPLEnvironment.
|
|
Map<String, String> configValues = new HashMap<>();
|
|
configValues.put("drm_certificate_type", "dev");
|
|
configValues.put("allow_unknown_device", "1");
|
|
configValues.put("provider", "widevine_test");
|
|
configValues.put("provider_iv", providerIv);
|
|
configValues.put("provider_key", providerKey);
|
|
// Set the device certificate expiration time to 10 years (10 * 365 * 24 * 3600). Note that in
|
|
// practice, the expiration should not be 10 years long. Certificate status list should be
|
|
// updated periodically.
|
|
configValues.put("device_certificate_expiration", "315360000");
|
|
|
|
WvPLProxyEnvironment env = new WvPLProxyEnvironment(configValues);
|
|
WvPLStatus status = env.setServiceCertificate(
|
|
decodedDrmServiceCertificate, decodedPrivateKey, passphraseBytes);
|
|
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
|
System.out.println("setServiceCertificate status = " + status.getStatusCode()
|
|
+ ", message = " + status.getMessage());
|
|
}
|
|
|
|
// Get Service certificate response.
|
|
try {
|
|
byte[] serviceCertificateResponse = env.generateDrmServiceCertificateResponse();
|
|
System.out.println(
|
|
"Service certificate response = " + Arrays.toString(serviceCertificateResponse));
|
|
} catch (WvPLStatusException e) {
|
|
status = e.getStatus();
|
|
System.out.println("getServiceCertificateResponse exception Message: "
|
|
+ e.getMessage() + ", exception status message: " + e.getStatus().getMessage());
|
|
}
|
|
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.");
|
|
}
|
|
try {
|
|
status = env.setDeviceCertificateStatusList(certList.getBytes(UTF_8));
|
|
} catch (WvPLStatusException e) {
|
|
status = e.getStatus();
|
|
System.out.println("setDeviceCertificateStatusList exception Message: "
|
|
+ e.getMessage() + ", exception status message: " + e.getStatus().getMessage()
|
|
+ ", numeric code = " + e.getStatus().getNumericCode());
|
|
}
|
|
assertEquals(WvPLStatus.StatusCode.OK, status.getStatusCode());
|
|
System.out.println("Successful set DeviceCertificateStatusList in WvPLProxyEnvironment.");
|
|
|
|
// Set custom device security profile list.
|
|
// One time setup each time new DSPs are loaded.
|
|
byte[] signedDsp = Base64.getUrlDecoder().decode(b64SerializedSignedDsps);
|
|
status = env.setCustomDeviceSecurityProfiles(signedDsp);
|
|
if (status.getStatusCode() != WvPLStatus.StatusCode.OK) {
|
|
System.out.println("setCustomDeviceSecurityProfiles status = " + status.getStatusCode()
|
|
+ ", message = " + status.getMessage());
|
|
}
|
|
|
|
// Optional sannity check.
|
|
// Verify the custom profile owners match with list of expected content owners.
|
|
List<String> customProfileOwners = new ArrayList<>();
|
|
try {
|
|
customProfileOwners = env.getCustomDeviceSecurityProfileOwners();
|
|
} catch (WvPLStatusException e) {
|
|
status = e.getStatus();
|
|
System.out.println("getCustomDeviceSecurityProfileOwners exception Message: "
|
|
+ e.getMessage() + ", exception status message: " + e.getStatus().getMessage()
|
|
+ ", numeric code = " + e.getStatus().getNumericCode());
|
|
}
|
|
if (customProfileOwners.isEmpty()) {
|
|
System.out.println("Owner list is empty for custom device security profiles.");
|
|
return;
|
|
}
|
|
System.out.printf("Custom profile owners are :");
|
|
for (String owner : customProfileOwners) {
|
|
System.out.printf("%s, ", owner);
|
|
}
|
|
System.out.println();
|
|
|
|
String contentOwner = "widevine_test";
|
|
WvTestRunner[] runner = new WvTestRunner[numberOfRunners];
|
|
ThreadGroup group = new ThreadGroup("Test Runner");
|
|
for (int i = 0; i < runner.length; i++) {
|
|
runner[i] = new WvTestRunner(env, group, "thread_runner_" + i, numberOfLoops);
|
|
runner[i].setCustomProfileOwners(customProfileOwners);
|
|
runner[i].setContentOwner(contentOwner);
|
|
runner[i].start();
|
|
}
|
|
for (WvPLProxyUsingDspExample.WvTestRunner element : runner) {
|
|
element.join();
|
|
}
|
|
env.close();
|
|
}
|
|
}
|