// Copyright 2018 Google LLC. All rights reserved. package com.google.video.widevine.sdk.wvpl; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.video.widevine.protos.LicenseProtocol.License; import com.google.video.widevine.protos.LicenseProtocol.SignedMessage; 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.Map; /** Example of how to use WvPL API. */ public class WvPLExample { /* Creates WvTestRunner to run wvpl test */ static class WvTestRunner extends Thread { private final int loops; private final String threadName; private final WvPLEnvironment env; public WvTestRunner(WvPLEnvironment 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("InterruptedException in thread."); } 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="; String testSessionId = "TestSessionId"; String testPurchaseId = "TestPurchaseId"; String testProviderClientToken = "TestProviderClientToken"; boolean testOverrideProviderClientToken = true; byte[] decodedLicenseRequest = Base64.getUrlDecoder().decode(b64LicenseRequest); byte[] testMasterSigningKeyBytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 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()); } WvPLSession session = null; try { session = env.createSession(decodedLicenseRequest); } catch (WvPLStatusException e) { System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } byte[] contentId = null; try { contentId = session.getContentId(); System.out.println("ContentId:" + new String(contentId, UTF_8)); } catch (WvPLStatusException e) { System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } System.out.println("Version: " + WvPLSession.getVersionString()); // VMP Status try { System.out.println( "VMP Status: " + session.verifyPlatform().getPlatformVerificationStatus()); } catch (WvPLStatusException e) { System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } // Set parameters on the created session. WvPLPlaybackPolicy policy = new WvPLPlaybackPolicy(); policy.setLicenseDurationSeconds(10000000L); session.setPolicy(policy); 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); session.addKey(key1); 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); session.addKey(key2); 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); WvPLOutputProtection outputProtection = new WvPLOutputProtection(); outputProtection.setHdcp(WvPLHdcp.HDCP.HDCP_V2_2); outputProtection.setSecurityLevel(WvPLSecurityLevel.SecurityLevel.SW_SECURE_DECODE); outputProtection.setDisableAnalogOutput(true); outputProtection.setCgms(WvPLCgms.Cgms.COPY_FREE); System.out.println( "SecurityLevel for outputProtection = " + outputProtection.getSecurityLevel()); 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); key3.addVideoResolutionConstraint(videoResolutionConstraint1); key3.addVideoResolutionConstraint(videoResolutionConstraint2); System.out.println( "Number of video resolutions in key3 = " + key3.getVideoResolutionConstraint().size()); for (WvPLVideoResolutionConstraint vrc : key3.getVideoResolutionConstraint()) { System.out.println("min resolution in pixels = " + vrc.getMinResolutionPixels() + ", max resolution in pixels = " + vrc.getMaxResolutionPixels() + ", hdcp = " + vrc.getHdcp()); } key3.setOutputProtection(outputProtection); WvPLOutputProtection requestedOutputProtection = new WvPLOutputProtection(); requestedOutputProtection.setHdcp(WvPLHdcp.HDCP.HDCP_V2); key3.setRequestedOutputProtection(requestedOutputProtection); session.addKey(key3); WvPLKey key4 = new WvPLKey(); byte[] data4 = {10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; key4.setKeyBytes(data4); key4.setTrackType(WvPLTrackType.TrackType.VIDEO_UHD1); session.addKey(key4); System.out.println("Is device ChromeCDM = " + session.isChromeCDM()); WvPLSessionInit sessionInit = new WvPLSessionInit(); sessionInit.setSessionId(testSessionId); sessionInit.setPurchaseId(testPurchaseId); sessionInit.setMasterSigningKey(testMasterSigningKeyBytes); sessionInit.setProviderClientToken(testProviderClientToken); sessionInit.setOverrideProviderClientToken(testOverrideProviderClientToken); session.setSessionInit(sessionInit); try { byte[] license = session.generateLicense(); System.out.println( "License Duration Seconds = " + session.getPolicy().getLicenseDurationSeconds()); System.out.print("License Response = "); if (license.length > 0) { printSignedMessage(license); } else { System.out.println("Empty"); } } catch (WvPLStatusException e) { System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } try { // GetProvisionedDeviceInfo is deprecated, use getDeviceInfo instead. WvPLDeviceInfo deviceInfo = session.getDeviceInfo(); System.out.println("DeviceInfo = " + deviceInfo); WvPLDeviceSecurityLevel.DeviceSecurityLevel deviceSecurityLevel = deviceInfo.getDeviceSecurityLevel(); // Expect a L1 device for the license request in use. System.out.println( "Device Security level = " + deviceSecurityLevel.getDeviceSecurityLevel()); } catch (WvPLStatusException e) { System.out.println("Failed to get deviceInfo."); System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } 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) { System.out.println("Failed to get clientInfo from license request."); System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } WvPLWidevinePsshData widevinePsshData = null; try { widevinePsshData = session.getPsshData(); } catch (WvPLStatusException e) { System.out.println("Failed to get psshData from license request."); System.out.println("Message: " + e.getMessage()); System.out.println("Status message: " + e.getStatus().getMessage()); } if (widevinePsshData.getContentId().length > 0) { System.out.println( "ContentId from Widevine Pssh = " + Arrays.toString(widevinePsshData.getContentId())); } else { System.out.println("ContentId from Widevine Pssh is empty"); } 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"); } WvPLStatus errorStatus = new WvPLStatus(WvPLStatus.StatusCode.SERVICE_CERTIFICATE_REQUEST_MESSAGE, ""); byte[] error = env.generateErrorResponse(errorStatus); System.out.print("Service Certificate Response = "); if (error.length > 0) { printSignedMessage(error); } else { System.out.println("Empty"); } // license counter with flushData set boolean flushData = true; byte[] statsBytes = env.getStatsAsBytes(flushData); System.out.print("stats as bytes with flush set = "); if (statsBytes.length > 0) { System.out.println(Arrays.toString(statsBytes)); } else { System.out.println("Empty"); } String statsString = env.getStatsAsString(flushData); System.out.print("stats as std::string with flush set = "); if (statsString.length() > 0) { System.out.println(statsString); } else { System.out.println("Empty"); } // license counter with flushData unset flushData = false; statsBytes = env.getStatsAsBytes(flushData); System.out.print("stats as bytes with flush unset = "); if (statsBytes.length > 0) { System.out.println(Arrays.toString(statsBytes)); } else { System.out.println("Empty"); } statsString = env.getStatsAsString(flushData); System.out.print("stats as String with flush unset = "); if (statsString.length() > 0) { System.out.println(statsString); } else { System.out.println("Empty"); } 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()); try { policy.close(); key1.close(); key2.close(); outputProtection.close(); key3.close(); session.close(); } catch (IOException e) { System.out.println("IOException when closing: " + e.getMessage()); } System.out.println("Thread Name: " + threadName + ", Loop Complete: " + i); try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println("InterruptedException in thread."); } } System.out.println("Thread Ended: " + threadName); } } public static void printSignedMessage(byte[] bytes) { try { SignedMessage licenseMessage = SignedMessage.parseFrom(bytes); System.out.println(licenseMessage); if (licenseMessage.getType() == SignedMessage.MessageType.LICENSE || licenseMessage.getType() == SignedMessage.MessageType.SERVICE_CERTIFICATE) { License licenseResponse = License.parseFrom(licenseMessage.getMsg()); System.out.println(licenseResponse); } } catch (Exception e) { System.out.print(" FAILED"); } } 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 { int numberOfRunners = 10; int numberOfLoops = 100; // TODO(yawenyu): Remove loadCertificateStatusListFromFile function. Add three flags to the // main function for certificateStatusListFile,b64DrmServiceCertificate and b64PrivateKey. String certificateStatusListFile = "sdk/testing/sampleProdCertificateStatusList.json"; String b64DrmServiceCertificate = "CsYCCAMSEIrKPCL3PObh7uUsPogH1bwY-PDksQUijgIwggEKAoIBAQDP6G_52lmYxLv2m2qL3B2L" + "tUUjCcHWvy4cxBe4_9TJLHkqaZe8InB4mmn_V0IV0f8-1jXu9cwxHycp0c2FzUe40KcK5Y1Tjqp2" + "EgFzC_e7z_KnTv0_ar1E7HANAAJbfOZEsTPDiLqRyD0kS85lCCxHICPrruORnKvgogDm4Gr4ACNO" + "NMG8WeH1mgVeIUNPpg1FVeeWYr1zMAmJmSHjPz6ymHW9lMNFLZayJZNjA9L-g4Ncv8mI03Qt0fmi" + "hJLa5p9EHrqDuhbEgmD3fmEvxwyitR111NbXPAzJPk_4jfMqztIiqDoEXqBEpnFgdTBPwx9FmC3C" + "en_0SGMMtpmC8sfJAgMBAAE6GWF0cy53di5zYW5kYm94Lmdvb2dsZS5jb20SgAN1Hma3aCJos4A_" + "aa-JyanEIZ12SpZpkQissZxSI0JTwRgW8bnYMgMFqJAdxKQ60kDjwzlqi30bpqXgFa6dvfWjswlR" + "cRQovHhR0UAnI04LmmXuH4LN1Exclh9TxKnMtYW9tkCKD-Ykrl1gbaBSYkTLTvn9zV8z7sHePDzz" + "tNMZH0MFR2YWLc0X5TSPJETftB_iGgm0SoQy7CpFYEswBV4kTlTEtEbdH3D1tPvp2VT9--sT45b2" + "rH2smhm-iiOi20sr42Dhcsl6TkIrmvuKcXv7oVjNHEUo4F25qmjFaNTVmBjxwfYPxTANqnnNJVIO" + "bAqfQVMCJT0sUd5C0LWcYIaUOxRI2hJCp3rpEyIWPjexk8hRwZ1S2Sdiiiwlh_ms3PlSkyoMWIHa" + "VllH3OV_8S1LFMy3ZgCOgx0rnFjNVpFayCSLWFhtE0waV2dQ1bhtYhGDxn17fO0EXUyNJhPa2rfy" + "r1VDonJVG7CyyzwF88_0KEZISCQykw3oCF82PDKF2tU="; String b64PrivateKey = "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQItfwZJLNOj2MCAggAMBQGCCqGSIb3" + "DQMHBAiwSBxfbxJvkwSCBMi6EkXgJBbGDayLfDbm1EFCucR6OiGAJoH_1ePza9mGREhI_r4YqCZx" + "opY8D5aFJIeKjR4KCiOoGZnn9xHu5JBhs_asGFWuSFry95fXFzfgYCFqzI2Za9TZkDpqDrh2d8on" + "CGBIYgz9PaxXKrxAQxhLfKaZ8lB-pRi5SRTV-6nxG37ZfDMRIrHFQcxhlnjTSQ97Ix2iaK66UYDJ" + "sqjapH3cYwk_B_xaxpbYUDlmuJBh14SzSpjG_HXlBWRxCKBRljXo6wjBoBFyKviu4p3Otcpfa7Rf" + "1nF4gQHHW6HvMvQTaY0lC6D5NzyV7KWosBdYX0am7uvQKs9MqulhL0NpBFMywyb9CTDvccoDyanO" + "U4nkSsax6ILS2trA7JKrb_4CX5W6qkmFgCqzgx8cNWI-1NABCJzBtF85BGoArQKW_sQqh96ulfTb" + "MpyQKQ2Uvkqtfv3G7Q5Hz3A6qAJqf6A6a9ADsk4ry9-ZZshlxFw4iNa6kNQKKSO4EElIHXe47TAF" + "658nb9aA2cSlLQnr7d9h-AyGghP6cztTazwgjiS7lXo4GwOQQ2jWuVJ4RI0750WdC5t1yS1p-qIC" + "2Ckh71OF8d3DSDQYTMYjn5iOODQqqM9mx_VMIairNfrCsX9GvOHSw0My3OshKCuPXhdt3TkThp2T" + "Mr4TlunHiPG5C7S1tSr0Brvy_c6XpejpLxmnUd-_J53GfbHLXeZiifMVCu7c7BKSkoDSLQwfk7lz" + "Idu0BE9GtIrB1NmQasYaeE9L31TL4KegvROFksyK7mZnC6NEXZKsZdsfV3TcB0OZ52BE5L2X7CMO" + "X-n_BQeH-cB-pbIuFqKtbjEcqRUag-m4MYZ2GkMwBJP3Sh_jewjh2TKPlkwvJI9FX5n7VGGuBvN5" + "CmUqqgQAqu9ieVuz-VVylSIOwdEdSyPGQia45OlYd9HsTD7NdGPyseBjlVLWq2BI1lG5KqJqCH7w" + "NxrIYl0PWOo6WrClWJW1CkJXRmoKzl5PTx-PL8W0KO3pZg94RMHVsZ8sRE62MPPu9Ltnl6x0Zjc8" + "YQItP7eR-aF0wlQQ-8__TBTBah3hLMBsAEKV6xD2bTvHBW-3vd-WCxX3hM7FACULlxgbT5wkXb0K" + "hUOWwim3zLRjbFhOI-MynVt6aM83bWrSRdbr52eyT4Ybx3EZ8tLVtzumgLVMWbJXcUnOU6I5y6W-" + "tzzUHsDba5AtG4-u9UitUQlDd4Hh4GlUaRdCqX8PwQLl-efjJysBuNu5xobxp3df9SqRgxCdaC-J" + "CS2Hi_hciIrcJNwxTJFUjilGOMDAqM0GdH8QMkbFjPAsAvz_fMYHoB4vyRYeURbwyiFb8hVOjgdB" + "8M_oRlmeYIcS8DzR84WdV-yUV_hsakjIqr5KznmGqhDSgrv609vjxKLO3PUnXq1J5TcTH5hN-bHr" + "WS-9zV0iA81aCVxk7HbCAj_ODuQjFYu_B31gvpkgICvgb-PMxCU-GJ5-bcYLWm-8apHdQ15SMbma" + "TrW7k7JZLMMqSjc7aJ25NyIbAtBg70EjebAnJI1JqmnPV-lUzfeqW0ulRv1fQZH057BXCyaPhNDY" + "rFf_lzyz-aX21HuL59l1B6rEJPU3qxdctT6kmi6L78fTvSP0V5aNd0box0Y="; String passphrase = "encryptallthekitties"; byte[] passphraseBytes = passphrase.getBytes(UTF_8); byte[] decodedDrmServiceCertificate = Base64.getUrlDecoder().decode(b64DrmServiceCertificate); byte[] decodedPrivateKey = Base64.getUrlDecoder().decode(b64PrivateKey); 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."); } 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("allow_unknown_device", "1"); 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"); java.util.Map preProvKeys = new java.util.HashMap<>(); preProvKeys.put(100, "f7008b38acc00ec68c732ac665c55c65"); try (WvPLEnvironment env = new WvPLEnvironment(configValues)) { env.setPreProvisioningKeys(preProvKeys); WvPLStatus status; 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()); } status = env.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"); } 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 (WvPLExample.WvTestRunner element : runner) { element.join(); } env.close(); } } }