RDK Documentation (Open Sourced RDK Components)
processProtectionHls.cpp
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2018 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 /**
21 * \file processProtection.cpp
22 *
23 * Process protection is for handling process protection of open cdm drm
24 * for HSL Streaming
25 * Functionalities are parse the file , get the drm type , PSSH data.
26 * Create DRM Session in thread
27 *
28 */
29 #include "_base64.h"
30 #include "AampDRMSessionManager.h"
31 #include "AampDrmSession.h"
32 #include "fragmentcollector_hls.h"
33 
34 #include <cstdlib>
35 #include <string>
36 using namespace std;
37 
38 #ifdef AAMP_HLS_DRM
39 
40 extern void *CreateDRMSession(void *arg);
42 
43 /**
44  * Global aamp config data
45  */
47 DrmSessionDataInfo* ProcessContentProtection(PrivateInstanceAAMP *aamp, std::string attrName);
48 
49 /**
50  * Local APIs declarations
51  */
52 static int GetFieldValue(string &attrName, string keyName, string &valuePtr);
53 static int getKeyId(string attrName, string &keyId);
54 static int getPsshData(string attrName, string &psshData);
55 static shared_ptr<AampDrmHelper> getDrmHelper(string attrName , bool bPropagateUriParams);
56 static uint8_t getPsshDataVersion(string attrName);
57 
58 /**
59  * @brief Return the string value, from the input KEY="value"
60  * @param [in] attribute list to be searched
61  * @param [in] Key name to be checked to get the value
62  * @param [out] value of the key
63  * @return none
64  */
65 static int GetFieldValue(string &attrName, string keyName, string &valuePtr){
66 
67  int valueStartPos = 0;
68  int valueEndPos = attrName.length();
69  int keylen = keyName.length();
70  int status = DRM_API_FAILED;
71  int found = 0, foundpos = 0;
72 
73  AAMPLOG_TRACE("Entring..");
74 
75  while ( (foundpos = attrName.find(keyName,found)) != std::string::npos)
76  {
77  AAMPLOG_TRACE("keyName = %s",
78  keyName.c_str());
79 
80  valueStartPos = foundpos + keylen;
81  if (attrName.at(valueStartPos) == '=')
82  {
83  string valueTempPtr = attrName.substr(valueStartPos+1);
84 
85  AAMPLOG_TRACE("valueTempPtr = %s",
86  valueTempPtr.c_str());
87 
88  /* update start position based on substring */
89  valueStartPos = 0;
90  if (valueTempPtr.at(0) == '"')
91  {
92  valueTempPtr = valueTempPtr.substr(1);
93  valueEndPos = valueTempPtr.find('"');
94  }
95  else if ( (valueEndPos = valueTempPtr.find(',')) == std::string::npos)
96  {
97  /*look like end string*/
98  valueEndPos = valueTempPtr.length();
99  }
100 
101  valuePtr = valueTempPtr.substr(valueStartPos, valueEndPos);
102  AAMPLOG_INFO("Value found : %s for Key : %s",
103  valuePtr.c_str(), keyName.c_str());
104  status = DRM_API_SUCCESS;
105  break;
106  }
107  else
108  {
109  AAMPLOG_TRACE("Checking next occurence of %s= in %s",
110  keyName.c_str(), attrName.c_str());
111  found = valueStartPos+1;
112  }
113  }
114 
115  if(DRM_API_SUCCESS != status)
116  {
117  AAMPLOG_ERR("Could not able to find %s in %s",
118  keyName.c_str(), attrName.c_str());
119  }
120 
121  return status;
122 }
123 
124 /* Widevine Example
125 #EXT-X-KEY:METHOD=SAMPLE-AES-CTR,
126 KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
127 KEYFORMATVERSIONS="1",URI="data:text/plain;base64,AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIgZTI1ZmFkYjQ4YmZiNDkyMjljZTBhNGFmZGZlMDUxOTcaB3NsaW5ndHYiBUhHVFZEKgVTRF9IRA==",
128 KEYID=0xe25fadb48bfb49229ce0a4afdfe05197
129 */
130 /* PlayReady Example
131 #EXT-X-KEY:METHOD=SAMPLE-AES-CTR,
132 URI="data:text/plain;charset=UTF-16;base64,BgIAAAEAAQD8ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AbgA0AEkARABBAEsATwAxAHMARwByAGcAegBpAHkAOAA4AFgAcgBqAGYAQQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgB1AGkAbwA4AFcAVQBwAFQANAA0ADAAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=",
133 KEYFORMAT="com.microsoft.playready",
134 KEYFORMATVERSIONS="1"
135 */
136 
137 /**
138  * @brief API to get the Widevine PSSH Data from the manifest attribute list, getWVPsshData
139  * @param [in] Attribute list
140  * @param [out] keyId string as reference
141  * @return status of the API
142  */
143 static int getKeyId(string attrName, string &keyId){
144 
145  int status = GetFieldValue(attrName, "KEYID", keyId );
146  if(DRM_API_SUCCESS != status){
147  AAMPLOG_INFO("Could not able to get Key Id from manifest"
148  );
149  return status;
150  }
151 
152  /* Remove 0x from begining */
153  keyId = keyId.substr(2);
154 
155  return status;
156 }
157 
158 /**
159  * @brief API to get the PSSH Data from the manifest attribute list, getPsshData
160  * @param [in] Attribute list
161  * @param [out] pssData as reference
162  * @return status of the API
163  */
164 static int getPsshData(string attrName, string &psshData){
165 
166  int status = GetFieldValue(attrName, "URI", psshData );
167  if(DRM_API_SUCCESS != status){
168  AAMPLOG_ERR("Could not able to get psshData from manifest"
169  );
170  return status;
171  }
172  /* Split string based on , and get the PSSH Data */
173  psshData = psshData.substr(psshData.find(',')+1);
174 
175  return status;
176 }
177 
178 /**
179  * @brief API to get the DRM type from the manifest attribute list, getDrmType
180  * @param [in] Attribute list
181  *
182  * @return pssh Data version number, default is 0
183  */
184 static uint8_t getPsshDataVersion(string attrName){
185 
186  uint8_t psshDataVer = 0;
187  string psshDataVerStr = "";
188 
189  if(DRM_API_SUCCESS != GetFieldValue(attrName, "KEYFORMATVERSIONS", psshDataVerStr )){
190  AAMPLOG_WARN("Could not able to receive pssh data version from manifest"
191  "returning default value as 0"
192  );
193  }else {
194  psshDataVer = (uint8_t)std::atoi(psshDataVerStr.c_str());
195  }
196 
197  return psshDataVer;
198 }
199 
200 /**
201  * @brief API to get the DRM helper from the manifest attribute list, getDrmType
202  * @param [in] Attribute list
203  *
204  * @return AampDrmHelper - DRM Helper (nullptr in case of unexpected behaviour)
205  */
206 static std::shared_ptr<AampDrmHelper> getDrmHelper(string attrName , bool bPropagateUriParams){
207 
208  string systemId = "";
209 
210  if(DRM_API_SUCCESS != GetFieldValue(attrName, "KEYFORMAT", systemId )){
211  AAMPLOG_ERR("Could not able to receive key id from manifest"
212  );
213  return nullptr;
214  }
215 
216  /** Remove urn:uuid: from it */
217  if (systemId.find("urn:uuid:") != std::string::npos){
218  systemId = systemId.substr(strlen("urn:uuid:"));
219  }
220  DrmInfo drmInfo;
222  drmInfo.systemUUID=systemId;
223  drmInfo.bPropagateUriParams = bPropagateUriParams;
225 }
226 
227 /**
228  * @brief Process content protection of track
229  * @param TrackState object
230  * @param attribute list from manifest
231  * @return none
232  */
233 DrmSessionDataInfo* ProcessContentProtection(PrivateInstanceAAMP *aamp, std::string attrName)
234 {
235  /* StreamAbstractionAAMP_HLS* context; */
236  /* Pseudo code for ProcessContentProtection in HLS is below
237  * Get Aamp instance as aamp
238  * 1. Get DRM type from manifest (KEYFORMAT uuid)
239  * 2. Get pssh data from manifest (extract URI value)
240  * 3. Check whether keyID with last processed keyId
241  * 4. if not, Create DrmSessionParams instance and fill it
242  * 4.1 Create a thread with CreateDRMSession and DrmSessionParams as parameter
243  * 4.2 Reuse the thread function CreateDRMSession which is used in MPD for HLS also
244  * 5. Else delete keyId and return
245  */
246  AampLogManager *mLogObj = aamp->mConfig->GetLoggerInstance();
247  shared_ptr<AampDrmHelper> drmHelper;
248  unsigned char* data = NULL;
249  unsigned char* contentMetadata = NULL;
250  size_t dataLength = 0;
251  int status = DRM_API_FAILED;
252  string psshDataStr = "";
253  char* psshData = NULL;
254  unsigned char * keyId = NULL;
255  int keyIdLen = 0;
256  MediaType mediaType = eMEDIATYPE_VIDEO;
257  DrmSessionDataInfo *drmSessioData = NULL;
258  do{
259  drmHelper = getDrmHelper(attrName , ISCONFIGSET(eAAMPConfig_PropogateURIParam));
260  if (nullptr == drmHelper){
261  AAMPLOG_ERR("Failed to get DRM type/helper from manifest!");
262  break;
263  }
264 
265  status = getPsshData(attrName, psshDataStr);
266  if (DRM_API_SUCCESS != status){
267  AAMPLOG_ERR("Failed to get PSSH Data from manifest!");
268  break;
269  }
270  psshData = (char*) malloc(psshDataStr.length() + 1);
271  memset(psshData, 0x00 , psshDataStr.length() + 1);
272  strncpy(psshData, psshDataStr.c_str(), psshDataStr.length());
273 
274  if(drmHelper->friendlyName().compare("Verimatrix") == 0)
275  {
276  logprintf("%s:%d Verimatrix DRM.", __FUNCTION__, __LINE__);
277  data = (unsigned char *)psshData;
278  dataLength = psshDataStr.length();
279  }
280  else
281  {
282  data = base64_Decode(psshData, &dataLength);
283  /* No more use */
284  free(psshData);
285  psshData = NULL;
286  }
287 
288  if (dataLength == 0)
289  {
290  AAMPLOG_ERR("Could not able to retrive DRM data from PSSH");
291  break;
292  }
294  {
295  AAMPLOG_TRACE("content metadata from manifest; length %d",
296  dataLength);
297  printf("*****************************************************************\n");
298  for (int i = 0; i < dataLength; i++)
299  {
300  printf("%c", data[i]);
301  }
302  printf("\n*****************************************************************\n");
303  for (int i = 0; i < dataLength; i++)
304  {
305  printf("%02x ", data[i]);
306  }
307  printf("\n*****************************************************************\n");
308 
309  }
310  if (!drmHelper->parsePssh(data, dataLength))
311  {
312  AAMPLOG_ERR("Failed to get key Id from manifest");
313  break;
314  }
315 
316  MediaType mediaType = eMEDIATYPE_VIDEO;
317 
318  if (drmHelper){
319  /** Push Drm Information for later use do not free the memory here*/
320  //AAMPLOG_INFO("Storing DRM Info at keyId %s",
321  //keyId);
322 
323  /** Populate session data **/
324  DrmSessionParams* sessionParams = new DrmSessionParams;
325  sessionParams->initData = data;
326  sessionParams->initDataLen = dataLength;
327  sessionParams->stream_type = mediaType;
328  sessionParams->aamp = aamp;
329  sessionParams->drmHelper = drmHelper;
330 
331  /** populate pool data **/
332  drmSessioData = new DrmSessionDataInfo() ;
333  drmSessioData->isProcessedLicenseAcquire = false;
334  drmSessioData->sessionData = sessionParams;
335  drmSessioData->processedKeyIdLen = keyIdLen;
336  drmSessioData->processedKeyId = (unsigned char *) malloc(keyIdLen + 1);
337  memcpy(drmSessioData->processedKeyId, keyId, keyIdLen);
338  }
339 
340  if (keyId) {
341  free(keyId);
342  keyId = NULL;
343  }
344 
345  }while(0);
346  if(data)
347  {
348  free(data); //CID:128617 - Resource leak
349  }
350  return drmSessioData;
351 }
352 
353 #else
354 
355 void* ProcessContentProtection(PrivateInstanceAAMP *aamp, std::string attrName){
356  AAMPLOG_INFO("AAMP_HLS_DRM not enabled"
357  );
358  return NULL;
359 }
360 #endif /** AAMP_HLS_DRM */
361 
362 /**
363  * EOF
364  */
AampDRMSessionManager.h
Header file for DRM session manager.
AampLogManager::trace
bool trace
Definition: AampLogManager.h:156
AampConfig::logging
AampLogManager logging
Definition: AampConfig.h:462
DrmSessionDataInfo::isProcessedLicenseAcquire
bool isProcessedLicenseAcquire
Definition: AampDRMSessionManager.h:60
fragmentcollector_hls.h
This file handles HLS Streaming functionality for AAMP player
eMEDIATYPE_VIDEO
@ eMEDIATYPE_VIDEO
Definition: AampMediaType.h:39
AampDrmHelperEngine::getInstance
static AampDrmHelperEngine & getInstance()
Get an instance of the DRM Helper Engine.
Definition: AampDrmHelperFactory.cpp:37
DrmSessionDataInfo
Drm Session Data Information for storing in a pool from parser.
Definition: AampDRMSessionManager.h:58
DrmSessionParams
Holds data regarding drm session.
Definition: AampDRMSessionManager.h:101
logprintf
void logprintf(const char *format,...)
Print logs to console / log fil.
Definition: aamplogging.cpp:432
gpGlobalConfig
AampConfig * gpGlobalConfig
Global configuration.
Definition: main_aamp.cpp:48
ISCONFIGSET
#define ISCONFIGSET(x)
Definition: AampConfig.h:84
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
AampConfig
AAMP Config Class defn.
Definition: AampConfig.h:457
ReleaseDRMLicenseAcquireThread
void ReleaseDRMLicenseAcquireThread(PrivateInstanceAAMP *aamp)
Function to release the DrmSession if it running.
Definition: AampDRMSessionManager.cpp:1741
DrmInfo::systemUUID
std::string systemUUID
Definition: AampDrmInfo.h:89
DrmInfo
DRM information required to decrypt.
Definition: AampDrmInfo.h:47
MediaType
MediaType
Media types.
Definition: AampMediaType.h:37
DrmSessionDataInfo::sessionData
struct DrmSessionParams * sessionData
Definition: AampDRMSessionManager.h:59
DrmSessionDataInfo::processedKeyId
unsigned char * processedKeyId
Definition: AampDRMSessionManager.h:61
_base64.h
base64 source Encoder/Decoder
AAMPLOG_TRACE
#define AAMPLOG_TRACE(FORMAT,...)
AAMP logging defines, this can be enabled through setLogLevel() as per the need.
Definition: AampLogManager.h:83
eAAMPConfig_PropogateURIParam
@ eAAMPConfig_PropogateURIParam
Definition: AampConfig.h:152
PrivateInstanceAAMP
Class representing the AAMP player's private instance, which is not exposed to outside world.
Definition: priv_aamp.h:640
CreateDRMSession
void * CreateDRMSession(void *arg)
Thread function to create DRM Session which would be invoked in thread from HLS , PlayReady or from p...
Definition: AampDRMSessionManager.cpp:1803
DrmInfo::bPropagateUriParams
bool bPropagateUriParams
Definition: AampDrmInfo.h:82
DrmSessionDataInfo::processedKeyIdLen
int processedKeyIdLen
Definition: AampDRMSessionManager.h:62
eMEDIAFORMAT_HLS_MP4
@ eMEDIAFORMAT_HLS_MP4
Definition: AampDrmMediaFormat.h:37
DrmInfo::mediaFormat
MediaFormat mediaFormat
Definition: AampDrmInfo.h:80
DRM_API_SUCCESS
#define DRM_API_SUCCESS
Macros to track the value of API success or failure.
Definition: AampDRMutils.h:44
base64_Decode
unsigned char * base64_Decode(const char *src, size_t *len, size_t srcLen)
decode base64 encoded data to binary equivalent
Definition: _base64.cpp:91
AampDrmHelperEngine::createHelper
std::shared_ptr< AampDrmHelper > createHelper(const struct DrmInfo &drmInfo, AampLogManager *logObj=NULL) const
Build a helper class to support the identified DRM.
Definition: AampDrmHelperFactory.cpp:69
AampDrmSession.h
Header file for AampDrmSession.