//////////////////////////////////////////////////////////////////////////////// //// Copyright 2018 Google LLC //// //// This software is licensed under the terms defined in the Widevine Master //// License Agreement. For a copy of this agreement, please contact //// widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// package com.google.video.widevine.sdk.wvpl; 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.Arrays; import java.util.Base64; import java.util.Map; /** Tests for {@link WvPLProxySession} Java API in Widevine Proxy Server SDK. */ public class WvPLProxyExample { /* 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 int loops; private String threadName; private WvPLProxyEnvironment env; public WvTestRunner(WvPLProxyEnvironment env, ThreadGroup group, String threadName, int loops) { super(group, threadName); this.loops = loops; this.threadName = threadName; this.env = env; } @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 = "CAES9AwKlQwIARLtCQquAggCEhDEmqLqtzGkARd0kTEo0I1IGJSf2qkFIo4CMIIBCgKCAQEA0NXBS5-DGcEt_vnp" + "kWgiYUrrlKjddGnSLPuloU5fNHN-TTtF2HwCbKHxv-71EeYwl4omrd36XZ7N6cRPE78G1BQoJy57z2wgCJZ8_3" + "jPsMnQSadynMxDdvVBqQde87T66-KqqBMTBOI3dC_LtX1Ydj04OR3yIKSlmTGGPwW37BfvsmNWGAHOHa0i7kP3" + "C1HkUyBixNJLArnNmQSfLi5jf8EyRu6-yJwFRyY1EcXXcDouUgJbWFGey6oK26-HI87rs4bEJyjxk3fr0BJcfh" + "QSVm-Awmyp4TU0J_A_PLoatG0yzjvPLT0ymsujLta0ZT6xHLSSeD3JfDyrlyS196GS2QIDAQABKIchEoACUqrZ" + "8CzIzCe-j4BI0cqjvQ7C_spcMjwdlO9E5pb-FIcP5fDdOSa8Op6gpkB7HwEv-HC8ITXjdQ3MRl5BcLB8elBDBw" + "Tl-nfw4AUqVRwSyPKfpOTU9w7MloiFBD8j2zP0Fbb3gub_G-JCMBYlpi8ObTiE5a3olWIl__trUgj-huLSKkIs" + "dH7dtaK55vvHIM7h7UcwomnxjJN1phHxB0c4iyHBAQfGaVSIUz3N7nXqsW__QO7qRIa7XCA-uiXpYF17wwTc4w" + "_X_fOKoYJ8mly85Sunm-XvxKZGzzcjyJuOsO_cK_KUiqt-TzeVmiohpmrEDK68ozm6LMFIFO3yBFpNgxq2BQqw" + "AggBEhDbPKzP3nYDjtzFHkw5JPr6GMLSg44FIo4CMIIBCgKCAQEAuVISqq1KZKOCyoJdYCxsMcBmzUvOotSUG2" + "c3VlJz_7Kq4MY65zff4_8AXtnsT4q4WWiREgiewPWe0n8x8_FI8z3r5cLKzwh_wRUwHlV5Sn2dw4I8VTzdPMH5" + "bfmgtCpM1NV5NhzT-YagPth3xrcwCnIP54oCLuKCDxG_rKcmKcHiyMVZnqdYHDNO5b8Tn21EV3JHZsLjpEfo_J" + "Og6mv1Z0r-vP6VJQT43KSJns5VSKx-RAHoff2ZTBuDWU2YOqFZpi_oeupPiHT_prwF9bIZiGhbEFNK-2T_t2BG" + "SzBpGNkQPb3VLek7WcctcqZTZ-eFQrzboRV0L5O8pho2cjVTswIDAQABKIchMAESgAMB8IopgGaBVAPSQnh6PI" + "VhD9nt9H_BgEMsW_pXJ5ij4PMltfdr8y03yF2GHJ_ZTeRYJpL_Mn8Mh5sLCaNF44S3nxSw5dT7bH35ZIFiB-uC" + "OH60js6UKadq099NZkPUtLCJAX5U_ggkSq2UMAMeRCyTo7XghUEaf_JyECh6rI5fKAjzIX7MfTLU32yHeiGkjN" + "Aj2_SoUnZH91Kb_wbStm6GSQdnw7G2kyKp6I6MJclgQZn7fJVCmRJugC57fDiBVv-sfl3Zp2SYQ9hwRBR9byMn" + "Vp5KLedB_v-9nnHniMLgSiDK-HASpZA-5C0OO27jHcdvdMgVjXoyJY05YYW1BcKKnGHit82fMY5zEDVG5mfmgq" + "d8ZYVlLAxJLWHZ7XCs1pIcAG1LjEy5rKzQtlT2DdwBzsF5mdybWKCLr-fbEqFo_ftp9HIc6EL70pZ07ofHbl0e" + "-PCkn5mJJYPbTNv7UxZgUU_2IqUJTxtwZD2GannSnwAPjd6D7u0W6CwFk-rhBe4aFAoMY29tcGFueV9uYW1lEg" + "Rhc3VzGhUKCm1vZGVsX25hbWUSB05leHVzIDcaIAoRYXJjaGl0ZWN0dXJlX25hbWUSC2FybWVhYmktdjdhGhIK" + "C2RldmljZV9uYW1lEgNkZWIaFgoMcHJvZHVjdF9uYW1lEgZyYXpvcmcaRQoKYnVpbGRfaW5mbxI3Z29vZ2xlL3" + "Jhem9yZy9kZWI6TU5DL01BU1RFUi8xODU1NjM3OnVzZXJkZWJ1Zy9kZXYta2V5cxotCglkZXZpY2VfaWQSIEpR" + "NVpJWkVMVUpBQlBVQzNLMkg1Q0NXNklVAAAAAAAAGiYKFHdpZGV2aW5lX2NkbV92ZXJzaW9uEg52My4wLjAtYW" + "5kcm9pZDIIEAEgBCgJMAASSgpICiIIARoNd2lkZXZpbmVfdGVzdCIPc3RyZWFtaW5nX2NsaXAxEAEaIDE3NEQ4" + "MkUyRjA0QzZGQkEwNjAwMDAwMDAwMDAwMDAwGAEgmZ_aqQUwFTij79WWBRqAAsguK-RkA18-zOzwX38JDpT877" + "woGiL-kUhQ9w2NuDxolgFovFqp-VNEESpG9GG-dp8sFXAABy4Xk3YJnyVvAtI6MtiSPjDLt87QPSie6WCLgqvL" + "zHoGSGuo4ij4HBX23QM0jZNDz_u_1rdZLKfV-nIWQ1sVI2u-QYnTYCztRmpMd1Gp1mZzLpcOL9PNGIYbuJSmQe" + "fi3FDGdwfmKLRYg8peJXj2OPHKNyyJCfRMZ42PmBvg4bxI36Ets_TU_6m2RMKARnTLYoGq0bw0fl9GeV_27mDU" + "Kvl0SIWXh0Jup8xxCO_iFQzw_7rCyW2FtrzXqq2qEmPRK5HjY-_c_0XVWh0="; 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 namesValues = clientInfo.getNamesValues(); for (Map.Entry 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()); WvPLKey key1 = new WvPLKey(); byte[] data1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; key1.setKeyId(data1); key1.setKeyBytes(data1); key1.setTrackType(WvPLTrackType.TrackType.AUDIO); status = session.addKey(key1); assertEquals(WvPLStatus.StatusCode.OK, status.getStatusCode()); // Adding a TrackType.VIDEO_SD key (without keyId) WvPLKey key2 = new WvPLKey(); byte[] data2 = {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; key2.setKeyBytes(data2); key2.setTrackType(WvPLTrackType.TrackType.VIDEO_SD); status = session.addKey(key2); assertEquals(WvPLStatus.StatusCode.OK, status.getStatusCode()); // Adding a TrackType.VIDEO_HD key WvPLKey key3 = new WvPLKey(); byte[] data3 = {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; key3.setKeyId(data3); key3.setKeyBytes(data3); key3.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()); key3.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 key3 (VIDEO_HD) key3.addVideoResolutionConstraint(videoResolutionConstraint1); key3.addVideoResolutionConstraint(videoResolutionConstraint2); assertEquals(2, key3.getVideoResolutionConstraint().size()); for (WvPLVideoResolutionConstraint vrc : key3.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); key3.setRequestedOutputProtection(requestedOutputProtection); status = session.addKey(key3); assertEquals(WvPLStatus.StatusCode.OK, status.getStatusCode()); // We also could use filterKey to filter out the key. WvPLKey filteredKey1 = new WvPLKey(); byte[] filteredKeyData1 = {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; filteredKey1.setKeyId(filteredKeyData1); filteredKey1.setKeyBytes(filteredKeyData1); filteredKey1.setTrackType(WvPLTrackType.TrackType.VIDEO_HD); WvPLCapabilityStatus capabilityStatus = session.filterKey(filteredKey1); assertEquals( WvPLCapabilityStatus.DeviceCapabilityStatus.CAPABILITY_OK, 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); java.util.Map configValues = new java.util.HashMap(); String providerIv = "d58ce954203b7c9a9a9d467f59839249"; String providerKey = "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9"; // Define the configuration that is to be used for WvPLEnvironment. 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."); 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].start(); } for (int i = 0; i < runner.length; i++) { runner[i].join(); } env.close(); } }