diff --git a/cpp/PallyConCpixClient/CpixClient.cpp b/cpp/PallyConCpixClient/CpixClient.cpp index 7a8f084..1170041 100644 --- a/cpp/PallyConCpixClient/CpixClient.cpp +++ b/cpp/PallyConCpixClient/CpixClient.cpp @@ -11,11 +11,12 @@ namespace pallycon { #define UUID_SIZE_INCLUDING_NULL_CHAR 37 -#define WIDEVINE_SYSMTE_ID "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED" -#define PLAYREADY_SYSMTE_ID "9A04F079-9840-4286-AB92-E65BE0885F95" -#define FAIRPLAY_SYSMTE_ID "94CE86FB-07FF-4F43-ADB8-93D2FA968CA2" -#define NCG_SYSMTE_ID "D9E4411A-E886-4909-A380-A77F28D52335" -#define HLS_NCG_SYSMTE_ID "48582A1D-1FF4-426E-8CD5-06424FCC578C" +#define WIDEVINE_SYSTEM_ID "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED" +#define PLAYREADY_SYSTEM_ID "9A04F079-9840-4286-AB92-E65BE0885F95" +#define FAIRPLAY_SYSTEM_ID "94CE86FB-07FF-4F43-ADB8-93D2FA968CA2" +#define NCG_SYSTEM_ID "D9E4411A-E886-4909-A380-A77F28D52335" +#define HLS_NCG_SYSTEM_ID "48582A1D-1FF4-426E-8CD5-06424FCC578C" +#define WISEPLAY_SYSTEM_ID "3D5E6D35-9B9A-41E8-B843-DD3C6E72C42C" static const char* __encryption_scheme_str[] = { "cenc", "cbc1", "cens", "cbcs" }; static const TrackType AllTrackTypes[] = { AUDIO, SD, HD, UHD1, UHD2 }; @@ -165,7 +166,7 @@ namespace pallycon { XMLNode reqWidevineNode = reqDRMList.addChild("cpix:DRMSystem"); reqWidevineNode.addAttribute("kid", map.second.c_str()); - reqWidevineNode.addAttribute("systemId", WIDEVINE_SYSMTE_ID); + reqWidevineNode.addAttribute("systemId", WIDEVINE_SYSTEM_ID); } if (drmType & PLAYREADY) @@ -173,7 +174,7 @@ namespace pallycon { XMLNode reqPlayReadyNode = reqDRMList.addChild("cpix:DRMSystem"); reqPlayReadyNode.addAttribute("kid", map.second.c_str()); - reqPlayReadyNode.addAttribute("systemId", PLAYREADY_SYSMTE_ID); + reqPlayReadyNode.addAttribute("systemId", PLAYREADY_SYSTEM_ID); } if (drmType & FAIRPLAY) @@ -181,7 +182,7 @@ namespace pallycon { XMLNode reqFairPlayNode = reqDRMList.addChild("cpix:DRMSystem"); reqFairPlayNode.addAttribute("kid", map.second.c_str()); - reqFairPlayNode.addAttribute("systemId", FAIRPLAY_SYSMTE_ID); + reqFairPlayNode.addAttribute("systemId", FAIRPLAY_SYSTEM_ID); } if (drmType & NCG) @@ -189,7 +190,7 @@ namespace pallycon { XMLNode reqNcgNode = reqDRMList.addChild("cpix:DRMSystem"); reqNcgNode.addAttribute("kid", map.second.c_str()); - reqNcgNode.addAttribute("systemId", NCG_SYSMTE_ID); + reqNcgNode.addAttribute("systemId", NCG_SYSTEM_ID); } if (drmType & HLS_NCG) @@ -197,7 +198,15 @@ namespace pallycon { XMLNode reqHlsNcgNode = reqDRMList.addChild("cpix:DRMSystem"); reqHlsNcgNode.addAttribute("kid", map.second.c_str()); - reqHlsNcgNode.addAttribute("systemId", HLS_NCG_SYSMTE_ID); + reqHlsNcgNode.addAttribute("systemId", HLS_NCG_SYSTEM_ID); + } + + if (drmType & WISEPLAY) + { + XMLNode reqWisePlayNode = reqDRMList.addChild("cpix:DRMSystem"); + + reqWisePlayNode.addAttribute("kid", map.second.c_str()); + reqWisePlayNode.addAttribute("systemId", WISEPLAY_SYSTEM_ID); } } @@ -223,11 +232,12 @@ namespace pallycon { packInfo.contentId = responseRoot.getAttribute("id"); - std::string systemId_widevine = WIDEVINE_SYSMTE_ID; - std::string systemId_playready = PLAYREADY_SYSMTE_ID; - std::string systemId_fairplay = FAIRPLAY_SYSMTE_ID; - std::string systemId_ncg = NCG_SYSMTE_ID; - std::string systemId_hlsNcg = HLS_NCG_SYSMTE_ID; + std::string systemId_widevine = WIDEVINE_SYSTEM_ID; + std::string systemId_playready = PLAYREADY_SYSTEM_ID; + std::string systemId_fairplay = FAIRPLAY_SYSTEM_ID; + std::string systemId_ncg = NCG_SYSTEM_ID; + std::string systemId_hlsNcg = HLS_NCG_SYSTEM_ID; + std::string systemId_wiseplay = WISEPLAY_SYSTEM_ID; XMLNode resContentKeyList = responseRoot.getChildNode("cpix:ContentKeyList"); XMLNode resContentKeyUsageRuleList = responseRoot.getChildNode("cpix:ContentKeyUsageRuleList"); @@ -284,7 +294,7 @@ namespace pallycon { drmInfo.iv = resIv; } - XMLNode resWidevineNode, resPlayReadyNode, resFairPlayNode, resNcgNode, reqHlsNcgNode; + XMLNode resWidevineNode, resPlayReadyNode, resFairPlayNode, resNcgNode, resHlsNcgNode, resWisePlayNode; for (int i = 0; i < resDRMSystemList.nChildNode(); i++) { XMLNode resDrmNode = resDRMSystemList.getChildNode("cpix:DRMSystem", i); @@ -309,7 +319,11 @@ namespace pallycon { } else if (0 == strcmp(resSystemId, systemId_hlsNcg.c_str())) { - reqHlsNcgNode = resDrmNode.deepCopy(); + resHlsNcgNode = resDrmNode.deepCopy(); + } + else if (0 == strcmp(resSystemId, systemId_wiseplay.c_str())) + { + resWisePlayNode = resDrmNode.deepCopy(); } } } @@ -318,20 +332,26 @@ namespace pallycon { { drmInfo.widevinePSSHpayload = resWidevineNode.getChildNode("cpix:ContentProtectionData").getText(); drmInfo.widevinePSSH = resWidevineNode.getChildNode("cpix:PSSH").getText(); + drmInfo.widevineHlsSignalingDataMaster = resWidevineNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "master").getText(); + drmInfo.widevineHlsSignalingDataMedia = resWidevineNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "media").getText(); } if (!resPlayReadyNode.isEmpty()) { drmInfo.playreadyPSSHpayload = resPlayReadyNode.getChildNode("cpix:ContentProtectionData").getText(); drmInfo.playreadyPSSH = resPlayReadyNode.getChildNode("cpix:PSSH").getText(); + drmInfo.playreadySmoothStreamingData = resPlayReadyNode.getChildNode("cpix:SmoothStreamingProtectionHeaderData").getText(); + drmInfo.playreadyHlsSignalingDataMaster = resPlayReadyNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "master").getText(); + drmInfo.playreadyHlsSignalingDataMedia = resPlayReadyNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "media").getText(); } if (!resFairPlayNode.isEmpty()) { - drmInfo.fairplayHlsSignalingData = resFairPlayNode.getChildNode("cpix:HLSSignalingData").getText(); int outputLength = 0; std::shared_ptr keyUri = __Base64Decode(resFairPlayNode.getChildNode("cpix:URIExtXKey").getText(), &outputLength); std::string strKeyUri(keyUri.get(), keyUri.get() + outputLength); drmInfo.fairplayHlsKeyUri = strKeyUri; + drmInfo.fairplayHlsSignalingDataMaster = resFairPlayNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "master").getText(); + drmInfo.fairplayHlsSignalingDataMedia = resFairPlayNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "media").getText(); } if (!resNcgNode.isEmpty()) @@ -342,14 +362,22 @@ namespace pallycon { drmInfo.ncgCek = strCek.c_str(); } - if (!reqHlsNcgNode.isEmpty()) + if (!resHlsNcgNode.isEmpty()) { int outputLength = 0; - std::shared_ptr keyUri = __Base64Decode(reqHlsNcgNode.getChildNode("cpix:URIExtXKey").getText(), &outputLength); + std::shared_ptr keyUri = __Base64Decode(resHlsNcgNode.getChildNode("cpix:URIExtXKey").getText(), &outputLength); std::string strKeyUri(keyUri.get(), keyUri.get() + outputLength); drmInfo.ncgHlsKeyUri = strKeyUri.c_str(); } + if (!resWisePlayNode.isEmpty()) + { + drmInfo.wiseplayPSSHpayload = resWisePlayNode.getChildNode("cpix:ContentProtectionData").getText(); + drmInfo.wiseplayPSSH = resWisePlayNode.getChildNode("cpix:PSSH").getText(); + drmInfo.wiseplayHlsSignalingDataMaster = resWisePlayNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "master").getText(); + drmInfo.wiseplayHlsSignalingDataMedia = resWisePlayNode.getChildNodeWithAttribute("cpix:HLSSignalingData", "playlist", "media").getText(); + } + packInfo.multiDrmInfos.push_back(drmInfo); } diff --git a/cpp/PallyConCpixClient/CpixClient.h b/cpp/PallyConCpixClient/CpixClient.h index 84d56f4..ac6da0e 100644 --- a/cpp/PallyConCpixClient/CpixClient.h +++ b/cpp/PallyConCpixClient/CpixClient.h @@ -20,7 +20,8 @@ namespace pallycon PLAYREADY = (1 << 1), // 0000 0010 // 0x02 FAIRPLAY = (1 << 2), // 0000 0100 // 0x04 NCG = (1 << 3), // 0000 1000 // 0x08 - HLS_NCG = (1 << 4), // 0001 0000 // 0x10 + HLS_NCG = (1 << 4), // 0001 0000 // 0x16 + WISEPLAY = (1 << 5), // 0010 0000 // 0x32 }; enum TrackType { @@ -101,12 +102,22 @@ namespace pallycon std::string periodIndex; std::string widevinePSSH; std::string widevinePSSHpayload; + std::string widevineHlsSignalingDataMaster; + std::string widevineHlsSignalingDataMedia; std::string playreadyPSSH; std::string playreadyPSSHpayload; - std::string fairplayHlsSignalingData; + std::string playreadySmoothStreamingData; + std::string playreadyHlsSignalingDataMaster; + std::string playreadyHlsSignalingDataMedia; std::string fairplayHlsKeyUri; + std::string fairplayHlsSignalingDataMaster; + std::string fairplayHlsSignalingDataMedia; std::string ncgCek; std::string ncgHlsKeyUri; + std::string wiseplayPSSH; + std::string wiseplayPSSHpayload; + std::string wiseplayHlsSignalingDataMaster; + std::string wiseplayHlsSignalingDataMedia; }; struct ContentPackagingInfo diff --git a/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.cpp b/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.cpp index d310e23..d25d7a6 100644 --- a/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.cpp +++ b/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.cpp @@ -50,12 +50,22 @@ namespace PallyCon { drmInfo.PeriodIndex = gcnew String(multiDrmInfo.periodIndex.c_str()); drmInfo.WidevinePSSH = gcnew String(multiDrmInfo.widevinePSSH.c_str()); drmInfo.WidevinePSSHpayload = gcnew String(multiDrmInfo.widevinePSSHpayload.c_str()); + drmInfo.WidevineHlsSignalingDataMaster = gcnew String(multiDrmInfo.widevineHlsSignalingDataMaster.c_str()); + drmInfo.WidevineHlsSignalingDataMedia = gcnew String(multiDrmInfo.widevineHlsSignalingDataMedia.c_str()); drmInfo.PlayReadyPSSH = gcnew String(multiDrmInfo.playreadyPSSH.c_str()); drmInfo.PlayReadyPSSHpayload = gcnew String(multiDrmInfo.playreadyPSSHpayload.c_str()); - drmInfo.FairplayHlsSignalingData = gcnew String(multiDrmInfo.fairplayHlsSignalingData.c_str()); + drmInfo.PlayReadySmoothStreamingData = gcnew String(multiDrmInfo.playreadySmoothStreamingData.c_str()); + drmInfo.PlayReadyHlsSignalingDataMaster = gcnew String(multiDrmInfo.playreadyHlsSignalingDataMaster.c_str()); + drmInfo.PlayReadyHlsSignalingDataMedia = gcnew String(multiDrmInfo.playreadyHlsSignalingDataMedia.c_str()); drmInfo.FairplayHlsKeyUri = gcnew String(multiDrmInfo.fairplayHlsKeyUri.c_str()); + drmInfo.FairplayHlsSignalingDataMaster = gcnew String(multiDrmInfo.fairplayHlsSignalingDataMaster.c_str()); + drmInfo.FairplayHlsSignalingDataMedia = gcnew String(multiDrmInfo.fairplayHlsSignalingDataMedia.c_str()); drmInfo.NcgCek = gcnew String(multiDrmInfo.ncgCek.c_str()); drmInfo.NcgHlsKeyUri = gcnew String(multiDrmInfo.ncgHlsKeyUri.c_str()); + drmInfo.WiseplayPSSH = gcnew String(multiDrmInfo.wiseplayPSSH.c_str()); + drmInfo.WiseplayPSSHpayload = gcnew String(multiDrmInfo.wiseplayPSSHpayload.c_str()); + drmInfo.WiseplayHlsSignalingDataMaster = gcnew String(multiDrmInfo.wiseplayHlsSignalingDataMaster.c_str()); + drmInfo.WiseplayHlsSignalingDataMedia = gcnew String(multiDrmInfo.wiseplayHlsSignalingDataMedia.c_str()); packInfos.DrmInfos->Add(drmInfo); } diff --git a/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.h b/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.h index 1859d5a..5a4e667 100644 --- a/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.h +++ b/csharp-sample/PallyConCpixClientWrapper/CpixClientWrapper.h @@ -19,6 +19,7 @@ namespace PallyCon { FAIRPLAY = (1 << 2), NCG = (1 << 3), HLS_NCG = (1 << 4), + WISEPLAY = (1 << 5), }; public enum class TrackType { @@ -38,12 +39,22 @@ namespace PallyCon { String^ PeriodIndex; String^ WidevinePSSH; String^ WidevinePSSHpayload; + String^ WidevineHlsSignalingDataMaster; + String^ WidevineHlsSignalingDataMedia; String^ PlayReadyPSSH; String^ PlayReadyPSSHpayload; - String^ FairplayHlsSignalingData; + String^ PlayReadySmoothStreamingData; + String^ PlayReadyHlsSignalingDataMaster; + String^ PlayReadyHlsSignalingDataMedia; String^ FairplayHlsKeyUri; + String^ FairplayHlsSignalingDataMaster; + String^ FairplayHlsSignalingDataMedia; String^ NcgCek; String^ NcgHlsKeyUri; + String^ WiseplayPSSH; + String^ WiseplayPSSHpayload; + String^ WiseplayHlsSignalingDataMaster; + String^ WiseplayHlsSignalingDataMedia; }; public value struct ContentPackagingInfo { diff --git a/csharp-sample/PallyConCpixClientWrapper/include/CpixClient.h b/csharp-sample/PallyConCpixClientWrapper/include/CpixClient.h index 84d56f4..ac6da0e 100644 --- a/csharp-sample/PallyConCpixClientWrapper/include/CpixClient.h +++ b/csharp-sample/PallyConCpixClientWrapper/include/CpixClient.h @@ -20,7 +20,8 @@ namespace pallycon PLAYREADY = (1 << 1), // 0000 0010 // 0x02 FAIRPLAY = (1 << 2), // 0000 0100 // 0x04 NCG = (1 << 3), // 0000 1000 // 0x08 - HLS_NCG = (1 << 4), // 0001 0000 // 0x10 + HLS_NCG = (1 << 4), // 0001 0000 // 0x16 + WISEPLAY = (1 << 5), // 0010 0000 // 0x32 }; enum TrackType { @@ -101,12 +102,22 @@ namespace pallycon std::string periodIndex; std::string widevinePSSH; std::string widevinePSSHpayload; + std::string widevineHlsSignalingDataMaster; + std::string widevineHlsSignalingDataMedia; std::string playreadyPSSH; std::string playreadyPSSHpayload; - std::string fairplayHlsSignalingData; + std::string playreadySmoothStreamingData; + std::string playreadyHlsSignalingDataMaster; + std::string playreadyHlsSignalingDataMedia; std::string fairplayHlsKeyUri; + std::string fairplayHlsSignalingDataMaster; + std::string fairplayHlsSignalingDataMedia; std::string ncgCek; std::string ncgHlsKeyUri; + std::string wiseplayPSSH; + std::string wiseplayPSSHpayload; + std::string wiseplayHlsSignalingDataMaster; + std::string wiseplayHlsSignalingDataMedia; }; struct ContentPackagingInfo diff --git a/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient-debug.lib b/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient-debug.lib index 4748c76..d3186af 100644 Binary files a/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient-debug.lib and b/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient-debug.lib differ diff --git a/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient.lib b/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient.lib index 88b9b6c..11e5d98 100644 Binary files a/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient.lib and b/csharp-sample/PallyConCpixClientWrapper/lib/x64/PallyConCpixClient.lib differ diff --git a/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient-debug.lib b/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient-debug.lib index 40ece2b..6fd262f 100644 Binary files a/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient-debug.lib and b/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient-debug.lib differ diff --git a/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient.lib b/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient.lib index 1f856d2..a75c8b6 100644 Binary files a/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient.lib and b/csharp-sample/PallyConCpixClientWrapper/lib/x86/PallyConCpixClient.lib differ diff --git a/java/pom.xml b/java/pom.xml index f1cf60a..8380f22 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -6,7 +6,7 @@ com.pallycon pallycon-cpix-client-java - 1.2.0 + 1.4.0 17 diff --git a/java/src/main/java/com/pallycon/cpix/PallyConCpixClient.java b/java/src/main/java/com/pallycon/cpix/PallyConCpixClient.java index 6f4baa2..76fa761 100644 --- a/java/src/main/java/com/pallycon/cpix/PallyConCpixClient.java +++ b/java/src/main/java/com/pallycon/cpix/PallyConCpixClient.java @@ -33,22 +33,25 @@ import org.xml.sax.InputSource; import org.json.simple.parser.JSONParser; -public class PallyConCpixClient implements CpixClient{ +public class PallyConCpixClient implements CpixClient { + private static final String WIDEVINE_SYSTEM_ID = "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED"; private static final String PLAYREADY_SYSTEM_ID = "9A04F079-9840-4286-AB92-E65BE0885F95"; private static final String FAIRPLAY_SYSTEM_ID = "94CE86FB-07FF-4F43-ADB8-93D2FA968CA2"; private static final String NCG_SYSTEM_ID = "D9E4411A-E886-4909-A380-A77F28D52335"; private static final String HLS_NCG_SYSTEM_ID = "48582A1D-1FF4-426E-8CD5-06424FCC578C"; + private static final String WISEPLAY_SYSTEM_ID = "3D5E6D35-9B9A-41E8-B843-DD3C6E72C42C"; private String kmsUrl; public PallyConCpixClient(String kmsUrl) { this.kmsUrl = kmsUrl; } + @Override public ContentPackagingInfo GetContentKeyInfoFromPallyConKMS(String contentId, EnumSet drmTypes, EncryptionScheme encryptionScheme, - EnumSet trackTypes, long periodIndex) throws CpixClientException{ + EnumSet trackTypes, long periodIndex) throws CpixClientException { Map keyMap = buildKeyMap(trackTypes); @@ -57,16 +60,16 @@ public ContentPackagingInfo GetContentKeyInfoFromPallyConKMS(String contentId, String responseXml = makeHttpRequest(kmsUrl, requestXml); if (responseXml != null) { - if(isValidResponse(responseXml)) { + if (isValidResponse(responseXml)) { return parseResponse(responseXml); - } - else{ + } else { throw new CpixClientException(responseXml); } } else { throw new CpixClientException("Error occurred while getting content key info."); } } + private Map buildKeyMap(EnumSet trackTypes) { Map keyMap = new HashMap<>(); if (trackTypes.contains(TrackType.ALL_TRACKS)) { @@ -113,7 +116,8 @@ private String buildRequestXml(String contentId, Map keyMap, for (TrackType track : keyMap.keySet()) { Element reqContentKey = doc.createElement("cpix:ContentKey"); reqContentKey.setAttribute("kid", keyMap.get(track)); - reqContentKey.setAttribute("commonEncryptionScheme", encryptionScheme.name().toLowerCase()); + reqContentKey.setAttribute("commonEncryptionScheme", + encryptionScheme.name().toLowerCase()); reqContentKeyList.appendChild(reqContentKey); String keyPeriodId = "keyPeriod_" + UUID.randomUUID().toString(); @@ -125,8 +129,8 @@ private String buildRequestXml(String contentId, Map keyMap, Element reqContentKeyUsageRule = doc.createElement("cpix:ContentKeyUsageRule"); reqContentKeyUsageRule.setAttribute("intendedTrackType", track.name()); reqContentKeyUsageRule.setAttribute("kid", keyMap.get(track)); - if(periodIndex > 0){ - Element reqKeyPeriodFilter = doc.createElement("cpix:KeyPeriodFilter"); + if (periodIndex > 0) { + Element reqKeyPeriodFilter = doc.createElement("cpix:KeyPeriodFilter"); reqKeyPeriodFilter.setAttribute("periodId", keyPeriodId); reqContentKeyUsageRule.appendChild(reqKeyPeriodFilter); } @@ -150,6 +154,8 @@ private String buildRequestXml(String contentId, Map keyMap, case HLS_NCG: systemId = HLS_NCG_SYSTEM_ID; break; + case WISEPLAY: + systemId = WISEPLAY_SYSTEM_ID; } if (systemId != null) { @@ -163,8 +169,9 @@ private String buildRequestXml(String contentId, Map keyMap, reqRoot.appendChild(reqContentKeyList); reqRoot.appendChild(reqDrmSystemList); - if(periodIndex > 0) + if (periodIndex > 0) { reqRoot.appendChild(reqContentKeyPeriodList); + } reqRoot.appendChild(reqContentKeyUsageRuleList); doc.appendChild(reqRoot); @@ -193,7 +200,8 @@ private String convertDocumentToString(Document doc) { return null; } } - private String makeHttpRequest(String url, String requestData) throws CpixClientException{ + + private String makeHttpRequest(String url, String requestData) throws CpixClientException { try { URL urlObj = new URL(url); HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection(); @@ -209,38 +217,42 @@ private String makeHttpRequest(String url, String requestData) throws CpixClient // Read the response StringBuilder responseBuilder = new StringBuilder(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + BufferedReader in = new BufferedReader( + new InputStreamReader(conn.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { responseBuilder.append(inputLine); } in.close(); } else { - throw new CpixClientException("HTTP Request Error: " + conn.getResponseCode() + " - " + conn.getResponseMessage()); + throw new CpixClientException( + "HTTP Request Error: " + conn.getResponseCode() + " - " + + conn.getResponseMessage()); } conn.disconnect(); return responseBuilder.toString(); - }catch (CpixClientException ex) { + } catch (CpixClientException ex) { throw ex; } catch (Exception ex) { throw new CpixClientException("Error occurred during HTTP request.", ex); } } + private Boolean isValidResponse(String responseData) { // This is because if the KMS server returns a custom error code, it will respond in JSON format. Boolean result = false; - try{ + try { JSONParser jsonParser = new JSONParser(); jsonParser.parse(responseData); - }catch (Exception e){ + } catch (Exception e) { result = true; } return result; } - private ContentPackagingInfo parseResponse(String responseXml) throws CpixClientException{ + private ContentPackagingInfo parseResponse(String responseXml) throws CpixClientException { try { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); @@ -261,7 +273,7 @@ private ContentPackagingInfo parseResponse(String responseXml) throws CpixClient drmInfo.setTrackType(trackType); drmInfo.setKeyId(keyId); - if(contentKeyPeriodList.getLength() > 0) { + if (contentKeyPeriodList.getLength() > 0) { Element keyPeriodFilter = (Element) contentKeyUsageRule.getElementsByTagName( "cpix:KeyPeriodFilter").item(0); String periodId = keyPeriodFilter.getAttribute("periodId"); @@ -280,7 +292,8 @@ private ContentPackagingInfo parseResponse(String responseXml) throws CpixClient Element contentKey = (Element) contentKeyList.item(i); String keyId = contentKey.getAttribute("kid"); String explicitIV = contentKey.getAttribute("explicitIV"); - String keyValue = contentKey.getElementsByTagName("pskc:PlainValue").item(0).getTextContent(); + String keyValue = contentKey.getElementsByTagName("pskc:PlainValue").item(0) + .getTextContent(); for (MultiDrmInfo drmInfo : multiDrmInfos) { if (drmInfo.getKeyId().equals(keyId)) { @@ -298,38 +311,117 @@ private ContentPackagingInfo parseResponse(String responseXml) throws CpixClient for (MultiDrmInfo drmInfo : multiDrmInfos) { if (drmInfo.getKeyId().equals(keyId)) { + Element hlsSignalingDataMasterElement = null; + Element hlsSignalingDataMediaElement = null; + if (!systemId.equals(NCG_SYSTEM_ID) + && !systemId.equals(HLS_NCG_SYSTEM_ID)) { + NodeList hlsSignalingDataNodes = drmSystem.getElementsByTagName( + "cpix:HLSSignalingData"); + + for (int j = 0; j < hlsSignalingDataNodes.getLength(); j++) { + Element element = (Element) hlsSignalingDataNodes.item(j); + if ("master".equals(element.getAttribute("playlist"))) { + hlsSignalingDataMasterElement = element; + } + if ("media".equals(element.getAttribute("playlist"))) { + hlsSignalingDataMediaElement = element; + } + } + } + switch (systemId) { case WIDEVINE_SYSTEM_ID: - String psshWidevine = drmSystem.getElementsByTagName("cpix:PSSH").item(0).getTextContent(); - String contentProtectionDataWidevine = drmSystem.getElementsByTagName("cpix:ContentProtectionData").item(0).getTextContent(); + String psshWidevine = drmSystem.getElementsByTagName("cpix:PSSH") + .item(0).getTextContent(); + String contentProtectionDataWidevine = drmSystem.getElementsByTagName( + "cpix:ContentProtectionData").item(0).getTextContent(); + drmInfo.setWidevinePssh(psshWidevine); drmInfo.setWidevinePsshPayload(contentProtectionDataWidevine); + if(hlsSignalingDataMasterElement != null) { + drmInfo.setWidevineHlsSignalingDataMaster( + StringUtil.decodeBase64( + hlsSignalingDataMasterElement.getTextContent())); + } + if(hlsSignalingDataMediaElement != null) { + drmInfo.setWidevineHlsSignalingDataMedia( + StringUtil.decodeBase64( + hlsSignalingDataMediaElement.getTextContent())); + } break; case PLAYREADY_SYSTEM_ID: - String psshPlayReady = drmSystem.getElementsByTagName("cpix:PSSH").item(0).getTextContent(); - String contentProtectionDataPlayReady = drmSystem.getElementsByTagName("cpix:ContentProtectionData").item(0).getTextContent(); + String psshPlayReady = drmSystem.getElementsByTagName("cpix:PSSH") + .item(0).getTextContent(); + String contentProtectionDataPlayReady = drmSystem.getElementsByTagName( + "cpix:ContentProtectionData").item(0).getTextContent(); + String smoothStreamingDataPlayReady = drmSystem.getElementsByTagName( + "cpix:SmoothStreamingProtectionHeaderData").item(0) + .getTextContent(); + drmInfo.setPlayreadyPssh(psshPlayReady); drmInfo.setPlayreadyPsshPayload(contentProtectionDataPlayReady); + drmInfo.setPlayreadySmoothStreamingData( + smoothStreamingDataPlayReady); + if(hlsSignalingDataMasterElement != null) { + drmInfo.setPlayreadyHlsSignalingDataMaster( + StringUtil.decodeBase64( + hlsSignalingDataMasterElement.getTextContent())); + } + if(hlsSignalingDataMediaElement != null) { + drmInfo.setPlayreadyHlsSignalingDataMedia( + StringUtil.decodeBase64( + hlsSignalingDataMediaElement.getTextContent())); + } break; case FAIRPLAY_SYSTEM_ID: - Element uriExtXKeyElement = (Element) drmSystem.getElementsByTagName("cpix:URIExtXKey").item(0); + Element uriExtXKeyElement = (Element) drmSystem.getElementsByTagName( + "cpix:URIExtXKey").item(0); String fairplayHlsKeyUri = uriExtXKeyElement.getTextContent(); - drmInfo.setFairplayHlsKeyUri(StringUtil.decodeBase64(fairplayHlsKeyUri)); - Element hlsSignalingDataElement = (Element) drmSystem.getElementsByTagName("cpix:HLSSignalingData").item(0); - String fairplayHlsSignalingData = hlsSignalingDataElement.getTextContent(); - drmInfo.setFairplayHlsSignalingData(StringUtil.decodeBase64(fairplayHlsSignalingData)); + drmInfo.setFairplayHlsKeyUri( + StringUtil.decodeBase64(fairplayHlsKeyUri)); + if(hlsSignalingDataMasterElement != null) { + drmInfo.setFairplayHlsSignalingDataMaster( + StringUtil.decodeBase64( + hlsSignalingDataMasterElement.getTextContent())); + } + if(hlsSignalingDataMediaElement != null) { + drmInfo.setFairplayHlsSignalingDataMedia( + StringUtil.decodeBase64( + hlsSignalingDataMediaElement.getTextContent())); + } break; case NCG_SYSTEM_ID: - Element uriExtXKeyElementNCG = (Element) drmSystem.getElementsByTagName("cpix:URIExtXKey").item(0); + Element uriExtXKeyElementNCG = (Element) drmSystem.getElementsByTagName( + "cpix:URIExtXKey").item(0); String ncgCek = uriExtXKeyElementNCG.getTextContent(); drmInfo.setNcgCek(ncgCek); break; case HLS_NCG_SYSTEM_ID: - Element uriExtXKeyElementHLSNCG = (Element) drmSystem.getElementsByTagName("cpix:URIExtXKey").item(0); + Element uriExtXKeyElementHLSNCG = (Element) drmSystem.getElementsByTagName( + "cpix:URIExtXKey").item(0); String ncgHlsKeyUri = uriExtXKeyElementHLSNCG.getTextContent(); drmInfo.setNcgHlsKeyUri(StringUtil.decodeBase64(ncgHlsKeyUri)); break; + case WISEPLAY_SYSTEM_ID: + String psshWiseplay = drmSystem.getElementsByTagName("cpix:PSSH") + .item(0).getTextContent(); + String contentProtectionDataWiseplay = drmSystem.getElementsByTagName( + "cpix:ContentProtectionData").item(0).getTextContent(); + + drmInfo.setWiseplayPssh(psshWiseplay); + drmInfo.setWiseplayPsshPayload(contentProtectionDataWiseplay); + if(hlsSignalingDataMasterElement != null) { + drmInfo.setWiseplayHlsSignalingDataMaster( + StringUtil.decodeBase64( + hlsSignalingDataMasterElement.getTextContent())); + } + if(hlsSignalingDataMediaElement != null) { + drmInfo.setWiseplayHlsSignalingDataMedia( + StringUtil.decodeBase64( + hlsSignalingDataMediaElement.getTextContent())); + } + break; } break; } diff --git a/java/src/main/java/com/pallycon/cpix/dto/DrmType.java b/java/src/main/java/com/pallycon/cpix/dto/DrmType.java index 7df478c..59a7123 100644 --- a/java/src/main/java/com/pallycon/cpix/dto/DrmType.java +++ b/java/src/main/java/com/pallycon/cpix/dto/DrmType.java @@ -5,5 +5,6 @@ public enum DrmType { PLAYREADY, FAIRPLAY, NCG, - HLS_NCG + HLS_NCG, + WISEPLAY } diff --git a/java/src/main/java/com/pallycon/cpix/dto/MultiDrmInfo.java b/java/src/main/java/com/pallycon/cpix/dto/MultiDrmInfo.java index cf69962..5da0b0f 100644 --- a/java/src/main/java/com/pallycon/cpix/dto/MultiDrmInfo.java +++ b/java/src/main/java/com/pallycon/cpix/dto/MultiDrmInfo.java @@ -1,6 +1,7 @@ package com.pallycon.cpix.dto; public class MultiDrmInfo { + private String trackType; private String key; private String keyId; @@ -8,12 +9,22 @@ public class MultiDrmInfo { private String periodIndex; private String widevinePssh; private String widevinePsshPayload; + private String widevineHlsSignalingDataMaster; + private String widevineHlsSignalingDataMedia; private String playreadyPssh; private String playreadyPsshPayload; - private String fairplayHlsSignalingData; + private String playreadySmoothStreamingData; + private String playreadyHlsSignalingDataMaster; + private String playreadyHlsSignalingDataMedia; private String fairplayHlsKeyUri; + private String fairplayHlsSignalingDataMaster; + private String fairplayHlsSignalingDataMedia; private String ncgCek; private String ncgHlsKeyUri; + private String wiseplayPssh; + private String wiseplayPsshPayload; + private String wiseplayHlsSignalingDataMaster; + private String wiseplayHlsSignalingDataMedia; public String getTrackType() { return trackType; @@ -71,6 +82,22 @@ public void setWidevinePsshPayload(String widevinePsshPayload) { this.widevinePsshPayload = widevinePsshPayload; } + public String getWidevineHlsSignalingDataMaster() { + return widevineHlsSignalingDataMaster; + } + + public void setWidevineHlsSignalingDataMaster(String widevineHlsSignalingDataMaster) { + this.widevineHlsSignalingDataMaster = widevineHlsSignalingDataMaster; + } + + public String getWidevineHlsSignalingDataMedia() { + return widevineHlsSignalingDataMedia; + } + + public void setWidevineHlsSignalingDataMedia(String widevineHlsSignalingDataMedia) { + this.widevineHlsSignalingDataMedia = widevineHlsSignalingDataMedia; + } + public String getPlayreadyPssh() { return playreadyPssh; } @@ -87,12 +114,28 @@ public void setPlayreadyPsshPayload(String playreadyPsshPayload) { this.playreadyPsshPayload = playreadyPsshPayload; } - public String getFairplayHlsSignalingData() { - return fairplayHlsSignalingData; + public String getPlayreadySmoothStreamingData() { + return playreadySmoothStreamingData; + } + + public void setPlayreadySmoothStreamingData(String playreadySmoothStreamingData) { + this.playreadySmoothStreamingData = playreadySmoothStreamingData; } - public void setFairplayHlsSignalingData(String fairplayHlsSignalingData) { - this.fairplayHlsSignalingData = fairplayHlsSignalingData; + public String getPlayreadyHlsSignalingDataMaster() { + return playreadyHlsSignalingDataMaster; + } + + public void setPlayreadyHlsSignalingDataMaster(String playreadyHlsSignalingDataMaster) { + this.playreadyHlsSignalingDataMaster = playreadyHlsSignalingDataMaster; + } + + public String getPlayreadyHlsSignalingDataMedia() { + return playreadyHlsSignalingDataMedia; + } + + public void setPlayreadyHlsSignalingDataMedia(String playreadyHlsSignalingDataMedia) { + this.playreadyHlsSignalingDataMedia = playreadyHlsSignalingDataMedia; } public String getFairplayHlsKeyUri() { @@ -103,6 +146,22 @@ public void setFairplayHlsKeyUri(String fairplayHlsKeyUri) { this.fairplayHlsKeyUri = fairplayHlsKeyUri; } + public String getFairplayHlsSignalingDataMaster() { + return fairplayHlsSignalingDataMaster; + } + + public void setFairplayHlsSignalingDataMaster(String fairplayHlsSignalingDataMaster) { + this.fairplayHlsSignalingDataMaster = fairplayHlsSignalingDataMaster; + } + + public String getFairplayHlsSignalingDataMedia() { + return fairplayHlsSignalingDataMedia; + } + + public void setFairplayHlsSignalingDataMedia(String fairplayHlsSignalingDataMedia) { + this.fairplayHlsSignalingDataMedia = fairplayHlsSignalingDataMedia; + } + public String getNcgCek() { return ncgCek; } @@ -118,4 +177,36 @@ public String getNcgHlsKeyUri() { public void setNcgHlsKeyUri(String ncgHlsKeyUri) { this.ncgHlsKeyUri = ncgHlsKeyUri; } + + public String getWiseplayPssh() { + return wiseplayPssh; + } + + public void setWiseplayPssh(String wiseplayPssh) { + this.wiseplayPssh = wiseplayPssh; + } + + public String getWiseplayPsshPayload() { + return wiseplayPsshPayload; + } + + public void setWiseplayPsshPayload(String wiseplayPsshPayload) { + this.wiseplayPsshPayload = wiseplayPsshPayload; + } + + public String getWiseplayHlsSignalingDataMaster() { + return wiseplayHlsSignalingDataMaster; + } + + public void setWiseplayHlsSignalingDataMaster(String wiseplayHlsSignalingDataMaster) { + this.wiseplayHlsSignalingDataMaster = wiseplayHlsSignalingDataMaster; + } + + public String getWiseplayHlsSignalingDataMedia() { + return wiseplayHlsSignalingDataMedia; + } + + public void setWiseplayHlsSignalingDataMedia(String wiseplayHlsSignalingDataMedia) { + this.wiseplayHlsSignalingDataMedia = wiseplayHlsSignalingDataMedia; + } } diff --git a/python/src/content_packaging_data.py b/python/src/content_packaging_data.py index c4c06da..078d2a1 100644 --- a/python/src/content_packaging_data.py +++ b/python/src/content_packaging_data.py @@ -10,12 +10,22 @@ class MultiDrmInfo: period_index: str = "" widevine_pssh: str = "" widevine_pssh_payload: str = "" + widevine_hls_signaling_data_master: str = "" + widevine_hls_signaling_data_media: str = "" playready_pssh: str = "" playready_pssh_payload: str = "" - fairplay_hls_signaling_data: str = "" + playready_smoothstreaming_data: str = "" + playready_hls_signaling_data_master: str = "" + playready_hls_signaling_data_media: str = "" fairplay_hls_key_uri: str = "" + fairplay_hls_signaling_data_master: str = "" + fairplay_hls_signaling_data_media: str = "" ncg_cek: str = "" ncg_hls_key_uri: str = "" + wiseplay_pssh: str = "" + wiseplay_pssh_payload: str = "" + wiseplay_hls_signaling_data_master: str = "" + wiseplay_hls_signaling_data_media: str = "" @dataclass diff --git a/python/src/cpix_client.py b/python/src/cpix_client.py index 518dc34..c452b7c 100644 --- a/python/src/cpix_client.py +++ b/python/src/cpix_client.py @@ -14,6 +14,7 @@ _fairplay_system_id = "94CE86FB-07FF-4F43-ADB8-93D2FA968CA2" _ncg_system_id = "D9E4411A-E886-4909-A380-A77F28D52335" _hls_ncg_system_id = "48582A1D-1FF4-426E-8CD5-06424FCC578C" +_wiseplay_system_id = "3D5E6D35-9B9A-41E8-B843-DD3C6E72C42C" def get_request_data(content_id, drm_type, encryption_scheme, track_type, period_index): @@ -68,6 +69,8 @@ def get_request_data(content_id, drm_type, encryption_scheme, track_type, period SubElement(req_drm_system_list, "cpix:DRMSystem", {"kid": key_map[track], "systemId": _ncg_system_id}) if DrmType.HLS_NCG in drm_type: SubElement(req_drm_system_list, "cpix:DRMSystem", {"kid": key_map[track], "systemId": _hls_ncg_system_id}) + if DrmType.WISEPLAY in drm_type: + SubElement(req_drm_system_list, "cpix:DRMSystem", {"kid": key_map[track], "systemId": _wiseplay_system_id}) return tostring(req_root, encoding='utf8', method="xml") @@ -120,21 +123,56 @@ def parse_response(response_data): multidrm_info.widevine_pssh = res_drm_system.find("cpix:PSSH", namespaces).text multidrm_info.widevine_pssh_payload \ = res_drm_system.find("cpix:ContentProtectionData", namespaces).text + multidrm_info.widevine_hls_signaling_data_master \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='master']", namespaces).text).decode( + 'utf-8') + multidrm_info.widevine_hls_signaling_data_media \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='media']", namespaces).text).decode( + 'utf-8') elif system_id == _playready_system_id: multidrm_info.playready_pssh = res_drm_system.find("cpix:PSSH", namespaces).text multidrm_info.playready_pssh_payload \ = res_drm_system.find("cpix:ContentProtectionData", namespaces).text + multidrm_info.playready_smoothstreaming_data = res_drm_system.find( + "cpix:SmoothStreamingProtectionHeaderData", namespaces).text + multidrm_info.playready_hls_signaling_data_master \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='master']", namespaces).text).decode( + 'utf-8') + multidrm_info.playready_hls_signaling_data_media \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='media']", namespaces).text).decode( + 'utf-8') elif system_id == _fairplay_system_id: multidrm_info.fairplay_hls_key_uri \ = base64.b64decode(res_drm_system.find("cpix:URIExtXKey", namespaces).text).decode('utf-8') - multidrm_info.fairplay_hls_signaling_data \ - = base64.b64decode(res_drm_system.find("cpix:HLSSignalingData", namespaces).text).decode( + multidrm_info.fairplay_hls_signaling_data_master \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='master']", namespaces).text).decode( + 'utf-8') + multidrm_info.fairplay_hls_signaling_data_media \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='media']", namespaces).text).decode( 'utf-8') elif system_id == _ncg_system_id: multidrm_info.ncg_cek = res_drm_system.find("cpix:URIExtXKey", namespaces).text elif system_id == _hls_ncg_system_id: multidrm_info.ncg_hls_key_uri \ = base64.b64decode(res_drm_system.find("cpix:URIExtXKey", namespaces).text).decode('utf-8') + elif system_id == _wiseplay_system_id: + multidrm_info.wiseplay_pssh = res_drm_system.find("cpix:PSSH", namespaces).text + multidrm_info.wiseplay_pssh_payload \ + = res_drm_system.find("cpix:ContentProtectionData", namespaces).text + multidrm_info.wiseplay_hls_signaling_data_master \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='master']", namespaces).text).decode( + 'utf-8') + multidrm_info.wiseplay_hls_signaling_data_media \ + = base64.b64decode( + res_drm_system.find("cpix:HLSSignalingData[@playlist='media']", namespaces).text).decode( + 'utf-8') pack_info = ContentPackagingInfo(res_root.get("id")) pack_info.multidrm_infos = multidrm_infos diff --git a/python/src/drm_type.py b/python/src/drm_type.py index 679df41..76a312b 100644 --- a/python/src/drm_type.py +++ b/python/src/drm_type.py @@ -7,3 +7,4 @@ class DrmType(Flag): FAIRPLAY = auto() NCG = auto() HLS_NCG = auto() + WISEPLAY = auto()