34 #include "AampUtils.h"
44 #define LICENCE_REQUEST_HEADER_ACCEPT "Accept:"
46 #define LICENCE_REQUEST_HEADER_CONTENT_TYPE "Content-Type:"
48 #define LICENCE_RESPONSE_JSON_LICENCE_KEY "license"
49 #define DRM_METADATA_TAG_START "<ckm:policy xmlns:ckm=\"urn:ccp:ckm\">"
50 #define DRM_METADATA_TAG_END "</ckm:policy>"
51 #define SESSION_TOKEN_URL "http://localhost:50050/authService/getSessionToken"
53 #define INVALID_SESSION_SLOT -1
54 #define DEFUALT_CDM_WAIT_TIMEOUT_MS 2000
56 #define CURL_EASY_SETOPT(curl, CURLoption, option)\
57 if (curl_easy_setopt(curl, CURLoption, option) != 0) {\
58 AAMPLOG_WARN("Failed at curl_easy_setopt ");\
59 } //CID:128208 - checked return
61 static const char *sessionTypeName[] = {
"video",
"audio",
"subtitle",
"aux-audio"};
63 static pthread_mutex_t drmSessionMutex = PTHREAD_MUTEX_INITIALIZER;
65 KeyID::KeyID() : creationTime(0), isFailedKeyId(false), isPrimaryKeyId(false), data()
74 #if defined(USE_SECCLIENT) || defined(USE_SECMANAGER)
81 static string getFormattedLicenseServerURL(
string url)
85 endpos = len = url.size();
87 if (memcmp(url.data(),
"https://", 8) == 0)
91 else if (memcmp(url.data(),
"http://", 7) == 0)
98 endpos = url.find(
'/', startpos);
99 if (endpos != string::npos)
101 len = endpos - startpos;
105 return url.substr(startpos, len);
113 cachedKeyIDs(NULL), accessToken(NULL),
115 cachedKeyMutex(PTHREAD_MUTEX_INITIALIZER)
116 ,curlSessionAbort(false), mEnableAccessAtrributes(true)
117 ,mDrmSessionLock(), licenseRequestAbort(false)
118 ,mMaxDRMSessions(maxDrmSessions)
120 #ifdef USE_SECMANAGER
121 ,mSessionId(AAMP_SECMGR_INVALID_SESSION_ID)
124 if(maxDrmSessions < 1)
128 else if(maxDrmSessions > MAX_DASH_DRM_SESSIONS)
130 mMaxDRMSessions = MAX_DASH_DRM_SESSIONS;
133 cachedKeyIDs =
new KeyID[mMaxDRMSessions];
134 AAMPLOG_INFO(
"AampDRMSessionManager MaxSession:%d",mMaxDRMSessions);
135 pthread_mutex_init(&mDrmSessionLock, NULL);
145 SAFE_DELETE_ARRAY(drmSessionContexts);
146 SAFE_DELETE_ARRAY(cachedKeyIDs);
147 pthread_mutex_destroy(&mDrmSessionLock);
148 pthread_mutex_destroy(&accessTokenMutex);
149 pthread_mutex_destroy(&cachedKeyMutex);
157 AAMPLOG_WARN(
" AampDRMSessionManager:: Clearing session data");
158 for(
int i = 0 ; i < mMaxDRMSessions; i++)
160 if (drmSessionContexts != NULL && drmSessionContexts[i].drmSession != NULL)
162 #ifdef USE_SECMANAGER
164 if (drmSessionContexts[i].drmSession->getSessionId() != AAMP_SECMGR_INVALID_SESSION_ID)
169 SAFE_DELETE(drmSessionContexts[i].drmSession);
173 if (cachedKeyIDs != NULL)
175 cachedKeyIDs[i] =
KeyID();
185 sessionMgrState = state;
193 return sessionMgrState;
200 curlSessionAbort = isAbort;
207 return curlSessionAbort;
216 licenseRequestAbort = isAbort;
224 pthread_mutex_lock(&cachedKeyMutex);
225 for(
int i = 0 ; i < mMaxDRMSessions; i++)
227 if(cachedKeyIDs[i].isFailedKeyId)
229 if(!cachedKeyIDs[i].data.empty())
231 cachedKeyIDs[i].data.clear();
233 cachedKeyIDs[i].isFailedKeyId =
false;
234 cachedKeyIDs[i].creationTime = 0;
236 cachedKeyIDs[i].isPrimaryKeyId =
false;
238 pthread_mutex_unlock(&cachedKeyMutex);
259 for(
int i = 0 ; i < mMaxDRMSessions; i++)
262 if((cachedKeyIDs[i].isFailedKeyId || forceClearSession) && drmSessionContexts != NULL)
264 AampMutexHold sessionMutex(drmSessionContexts[i].sessionMutex);
265 if (drmSessionContexts[i].drmSession != NULL)
267 AAMPLOG_WARN(
"AampDRMSessionManager:: Clearing failed Session Data Slot : %d", i);
268 #ifdef USE_SECMANAGER
270 if (drmSessionContexts[i].drmSession->getSessionId() != AAMP_SECMGR_INVALID_SESSION_ID)
275 SAFE_DELETE(drmSessionContexts[i].drmSession);
282 void AampDRMSessionManager::setVideoWindowSize(
int width,
int height)
284 #ifdef USE_SECMANAGER
285 AAMPLOG_WARN(
"In AampDRMSessionManager:: setting video windor size w:%d x h:%d mMaxDRMSessions=%d mSessionId=[%" PRId64
"]",width,height,mMaxDRMSessions,mSessionId);
286 if(mSessionId != AAMP_SECMGR_INVALID_SESSION_ID)
288 AAMPLOG_WARN(
"In AampDRMSessionManager:: valid session ID");
295 void AampDRMSessionManager::setPlaybackSpeedState(
int speed,
double position,
bool delayNeeded)
297 #ifdef USE_SECMANAGER
298 AAMPLOG_WARN(
"In AampDRMSessionManager::after calling setPlaybackSpeedState speed=%d position=%f mSessionId=[%" PRId64
"]",speed, position, mSessionId);
299 if(mSessionId != AAMP_SECMGR_INVALID_SESSION_ID)
301 AAMPLOG_WARN(
"In AampDRMSessionManager::valid session ID");
320 logprintf(
"Aborting DRM curl operation.. - CURLE_ABORTED_BY_CALLBACK");
334 size_t nmemb,
void *userdata)
338 size_t numBytesForBlock = size * nmemb;
341 logprintf(
"Aborting DRM curl operation.. - CURLE_ABORTED_BY_CALLBACK");
342 numBytesForBlock = 0;
347 else if (data->
getData().empty())
349 data->
setData((
unsigned char *)ptr, numBytesForBlock);
353 data->
addData((
unsigned char *)ptr, numBytesForBlock);
357 logprintf(
" wrote %zu number of blocks", numBytesForBlock);
359 return numBytesForBlock;
372 int startPos = parentStr.find(startStr);
373 if(string::npos != startPos)
375 int offset = strlen(startStr.c_str());
376 int endPos = parentStr.find(endStr, startPos + offset + 1);
377 if(string::npos != endPos)
379 ret = parentStr.substr(startPos + offset, endPos - (startPos + offset));
390 if(accessToken == NULL)
394 callbackData->data = tokenReply;
395 callbackData->mDRMSessionManager =
this;
399 CURL *curl = curl_easy_init();;
400 CURL_EASY_SETOPT(curl, CURLOPT_NOSIGNAL, 1L);
404 CURL_EASY_SETOPT(curl, CURLOPT_PROGRESSDATA,
this);
405 CURL_EASY_SETOPT(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
406 CURL_EASY_SETOPT(curl, CURLOPT_FOLLOWLOCATION, 1L);
407 CURL_EASY_SETOPT(curl, CURLOPT_NOPROGRESS, 0L);
408 CURL_EASY_SETOPT(curl, CURLOPT_WRITEDATA, callbackData);
410 CURL_EASY_SETOPT(curl, CURLOPT_SSL_VERIFYPEER, 0L);
412 CURL_EASY_SETOPT(curl, CURLOPT_URL, SESSION_TOKEN_URL);
414 res = curl_easy_perform(curl);
418 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
419 if (httpCode == 200 || httpCode == 206)
421 string tokenReplyStr = tokenReply->
getData();
423 if(tokenStatusCode.length() == 0)
428 if(tokenStatusCode.length() == 1 && tokenStatusCode.c_str()[0] ==
'0')
431 size_t len = token.length();
434 accessToken = (
char*)malloc(len+1);
437 accessTokenLen = len;
438 memcpy( accessToken, token.c_str(), len );
439 accessToken[len] = 0x00;
440 AAMPLOG_WARN(
" Received session token from auth service ");
444 AAMPLOG_WARN(
"accessToken is null");
449 AAMPLOG_WARN(
" Could not get access token from session token reply");
455 AAMPLOG_ERR(
" Missing or invalid status code in session token reply");
461 AAMPLOG_ERR(
" Get Session token call failed with http error %d", httpCode);
462 error_code = httpCode;
467 AAMPLOG_ERR(
" Get Session token call failed with curl error %d", res);
470 SAFE_DELETE(tokenReply);
471 SAFE_DELETE(callbackData);
472 curl_easy_cleanup(curl);
475 tokenLen = accessTokenLen;
485 pthread_mutex_lock(&cachedKeyMutex);
486 for (
int sessionSlot = 0; sessionSlot < mMaxDRMSessions; sessionSlot++)
488 auto keyIDSlot = cachedKeyIDs[sessionSlot].data;
489 if (!keyIDSlot.empty() && keyIDSlot.end() != std::find(keyIDSlot.begin(), keyIDSlot.end(), keyIdArray))
492 AAMPLOG_INFO(
"Session created/inprogress with same keyID %s at slot %d", debugStr.c_str(), sessionSlot);
496 pthread_mutex_unlock(&cachedKeyMutex);
502 #if defined(USE_SECCLIENT) || defined(USE_SECMANAGER)
504 DrmData * AampDRMSessionManager::getLicenseSec(
const AampLicenseRequest &licenseRequest, std::shared_ptr<AampDrmHelper> drmHelper,
507 DrmData *licenseResponse =
nullptr;
508 const char *mediaUsage =
"stream";
509 string contentMetaData = drmHelper->getDrmMetaData();
510 char *encodedData =
base64_Encode(
reinterpret_cast<const unsigned char*
>(contentMetaData.c_str()), contentMetaData.length());
511 char *encodedChallengeData =
base64_Encode(
reinterpret_cast<const unsigned char*
>(challengeInfo.
data->getData().c_str()), challengeInfo.
data->getDataLength());
513 size_t encodedDataLen = ((contentMetaData.length() + 2) /3) * 4;
514 size_t encodedChallengeDataLen = ((challengeInfo.
data->getDataLength() + 2) /3) * 4;
516 const char *keySystem = drmHelper->ocdmSystemId().c_str();
517 const char *secclientSessionToken = challengeInfo.
accessToken.empty() ? NULL : challengeInfo.
accessToken.c_str();
519 char *licenseResponseStr = NULL;
520 size_t licenseResponseLength = 2;
521 uint32_t refreshDuration = 3;
522 const char *requestMetadata[1][2];
523 uint8_t numberOfAccessAttributes = 0;
524 const char *accessAttributes[2][2] = {NULL, NULL, NULL, NULL};
525 std::string serviceZone, streamID;
528 if (aampInstance->GetEnableAccessAtrributesFlag())
532 if (!serviceZone.empty())
534 accessAttributes[numberOfAccessAttributes][0] = VSS_SERVICE_ZONE_KEY_STR;
535 accessAttributes[numberOfAccessAttributes][1] = serviceZone.c_str();
536 numberOfAccessAttributes++;
538 if (!streamID.empty())
540 accessAttributes[numberOfAccessAttributes][0] = VSS_VIRTUAL_STREAM_ID_KEY_STR;
541 accessAttributes[numberOfAccessAttributes][1] = streamID.c_str();
542 numberOfAccessAttributes++;
545 AAMPLOG_INFO(
"accessAttributes : {\"%s\" : \"%s\", \"%s\" : \"%s\"}", accessAttributes[0][0], accessAttributes[0][1], accessAttributes[1][0], accessAttributes[1][1]);
547 std::string moneytracestr;
548 requestMetadata[0][0] =
"X-MoneyTrace";
549 aampInstance->GetMoneyTraceString(moneytracestr);
550 requestMetadata[0][1] = moneytracestr.c_str();
552 AAMPLOG_WARN(
"[HHH] Before calling SecClient_AcquireLicense-----------");
553 AAMPLOG_WARN(
"destinationURL is %s (drm server now used)", licenseRequest.url.c_str());
554 AAMPLOG_WARN(
"MoneyTrace[%s]", requestMetadata[0][1]);
560 int32_t businessStatus;
563 ((numberOfAccessAttributes == 0) ? NULL : accessAttributes),
564 encodedData, encodedDataLen,
565 encodedChallengeData, encodedChallengeDataLen,
568 secclientSessionToken, challengeInfo.
accessToken.length(),
570 &licenseResponseStr, &licenseResponseLength,
571 &statusCode, &reasonCode, &businessStatus);
574 AAMPLOG_WARN(
"acquireLicense via SecManager SUCCESS!");
577 *httpExtStatusCode = 0;
578 if (licenseResponseStr)
580 licenseResponse =
new DrmData((
unsigned char *)licenseResponseStr, licenseResponseLength);
581 free(licenseResponseStr);
586 eventHandle->SetVerboseErrorCode( statusCode, reasonCode, businessStatus);
587 AAMPLOG_WARN(
"Verbose error set with class : %d, Reason Code : %d Business status: %d ", statusCode, reasonCode, businessStatus);
588 *httpCode = statusCode;
589 *httpExtStatusCode = reasonCode;
591 AAMPLOG_ERR(
"acquireLicense via SecManager FAILED!, httpCode %d, httpExtStatusCode %d", *httpCode, *httpExtStatusCode);
601 int32_t sec_client_result = SEC_CLIENT_RESULT_FAILURE;
602 SecClient_ExtendedStatus statusInfo;
603 unsigned int attemptCount = 0;
606 if(sleepTime<=0) sleepTime = 100;
607 while (attemptCount < MAX_LICENSE_REQUEST_ATTEMPTS)
610 sec_client_result = SecClient_AcquireLicense(licenseRequest.url.c_str(), 1,
611 requestMetadata, numberOfAccessAttributes,
612 ((numberOfAccessAttributes == 0) ? NULL : accessAttributes),
615 encodedChallengeData, strlen(encodedChallengeData), keySystem, mediaUsage,
616 secclientSessionToken,
617 &licenseResponseStr, &licenseResponseLength, &refreshDuration, &statusInfo);
619 if (((sec_client_result >= 500 && sec_client_result < 600)||
620 (sec_client_result >= SEC_CLIENT_RESULT_HTTP_RESULT_FAILURE_TLS && sec_client_result <= SEC_CLIENT_RESULT_HTTP_RESULT_FAILURE_GENERIC ))
621 && attemptCount < MAX_LICENSE_REQUEST_ATTEMPTS)
623 AAMPLOG_ERR(
" acquireLicense FAILED! license request attempt : %d; response code : sec_client %d", attemptCount, sec_client_result);
624 if (licenseResponseStr) SecClient_FreeResource(licenseResponseStr);
625 AAMPLOG_WARN(
" acquireLicense : Sleeping %d milliseconds before next retry.", sleepTime);
635 AAMPLOG_TRACE(
"licenseResponse len is %zd", licenseResponseLength);
636 AAMPLOG_TRACE(
"accessAttributesStatus is %d", statusInfo.accessAttributeStatus);
639 if (sec_client_result != SEC_CLIENT_RESULT_SUCCESS)
641 AAMPLOG_ERR(
" acquireLicense FAILED! license request attempt : %d; response code : sec_client %d extStatus %d", attemptCount, sec_client_result, statusInfo.statusCode);
643 eventHandle->ConvertToVerboseErrorCode( sec_client_result, statusInfo.statusCode);
645 *httpCode = sec_client_result;
646 *httpExtStatusCode = statusInfo.statusCode;
648 AAMPLOG_WARN(
"Converted the secclient httpCode : %d, httpExtStatusCode: %d to verbose error with class : %d, Reason Code : %d Business status: %d ", *httpCode, *httpExtStatusCode, eventHandle->getSecManagerClassCode(), eventHandle->getSecManagerReasonCode(), eventHandle->getBusinessStatus());
652 AAMPLOG_WARN(
" acquireLicense SUCCESS! license request attempt %d; response code : sec_client %d", attemptCount, sec_client_result);
653 eventHandle->setAccessStatusValue(statusInfo.accessAttributeStatus);
654 licenseResponse =
new DrmData((
unsigned char *)licenseResponseStr, licenseResponseLength);
656 if (licenseResponseStr) SecClient_FreeResource(licenseResponseStr);
662 free(encodedChallengeData);
663 return licenseResponse;
676 double totalTime = 0;
677 struct curl_slist *headers = NULL;
680 callbackData->data = keyInfo;
681 callbackData->mDRMSessionManager =
this;
682 long challengeLength = 0;
683 long long downloadTimeMS = 0;
687 for (
auto& header : licenseRequest.headers)
689 std::string customHeaderStr = header.first;
690 customHeaderStr.push_back(
' ');
693 customHeaderStr.append(header.second.at(0));
694 headers = curl_slist_append(headers, customHeaderStr.c_str());
697 AAMPLOG_WARN(
" CustomHeader :%s",customHeaderStr.c_str());
701 AAMPLOG_WARN(
" Sending license request to server : %s ", licenseRequest.url.c_str());
704 CURL_EASY_SETOPT(curl, CURLOPT_VERBOSE, 1L);
708 CURL_EASY_SETOPT(curl, CURLOPT_PROGRESSDATA,
this);
709 CURL_EASY_SETOPT(curl, CURLOPT_TIMEOUT, 5L);
710 CURL_EASY_SETOPT(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
711 CURL_EASY_SETOPT(curl, CURLOPT_FOLLOWLOCATION, 1L);
712 CURL_EASY_SETOPT(curl, CURLOPT_URL, licenseRequest.url.c_str());
713 CURL_EASY_SETOPT(curl, CURLOPT_WRITEDATA, callbackData);
715 CURL_EASY_SETOPT(curl, CURLOPT_SSL_VERIFYPEER, 0L);
719 CURL_EASY_SETOPT(curl, CURLOPT_SSL_VERIFYPEER, 1L);
722 CURL_EASY_SETOPT(curl, CURLOPT_HTTPHEADER, headers);
726 challengeLength = licenseRequest.payload.size();
727 CURL_EASY_SETOPT(curl, CURLOPT_POSTFIELDSIZE, challengeLength);
728 CURL_EASY_SETOPT(curl, CURLOPT_POSTFIELDS,(uint8_t * )licenseRequest.payload.data());
732 CURL_EASY_SETOPT(curl, CURLOPT_HTTPGET, 1L);
735 if (!licenseProxy.empty())
737 CURL_EASY_SETOPT(curl, CURLOPT_PROXY, licenseProxy.c_str());
739 CURL_EASY_SETOPT(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
741 unsigned int attemptCount = 0;
742 bool requestFailed =
true;
744 while(attemptCount < MAX_LICENSE_REQUEST_ATTEMPTS && !licenseRequestAbort)
746 bool loopAgain =
false;
748 long long tStartTime = NOW_STEADY_TS_MS;
749 res = curl_easy_perform(curl);
750 long long tEndTime = NOW_STEADY_TS_MS;
751 long long downloadTimeMS = tEndTime - tStartTime;
753 if(licenseRequestAbort)
755 AAMPLOG_ERR(
" Aborting License acquisition");
757 *httpCode = CURLE_ABORTED_BY_CALLBACK;
763 if (res != CURLE_ABORTED_BY_CALLBACK && res != CURLE_WRITE_ERROR)
765 if (res == CURLE_OPERATION_TIMEDOUT || res == CURLE_COULDNT_CONNECT)
770 SAFE_DELETE(keyInfo);
771 SAFE_DELETE(callbackData);
774 callbackData->data = keyInfo;
775 callbackData->mDRMSessionManager =
this;
776 CURL_EASY_SETOPT(curl, CURLOPT_WRITEDATA, callbackData);
778 AAMPLOG_ERR(
" curl_easy_perform() failed: %s", curl_easy_strerror(res));
779 AAMPLOG_ERR(
" acquireLicense FAILED! license request attempt : %d; response code : curl %d", attemptCount, res);
785 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, httpCode);
786 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &totalTime);
787 if (*httpCode != 200 && *httpCode != 206)
789 int licenseRetryWaitTime;
791 AAMPLOG_ERR(
" acquireLicense FAILED! license request attempt : %d; response code : http %d", attemptCount, *httpCode);
792 if(*httpCode >= 500 && *httpCode < 600
793 && attemptCount < MAX_LICENSE_REQUEST_ATTEMPTS && licenseRetryWaitTime > 0)
795 SAFE_DELETE(keyInfo);
796 SAFE_DELETE(callbackData);
799 callbackData->data = keyInfo;
800 callbackData->mDRMSessionManager =
this;
801 CURL_EASY_SETOPT(curl, CURLOPT_WRITEDATA, callbackData);
802 AAMPLOG_WARN(
"acquireLicense : Sleeping %d milliseconds before next retry.",licenseRetryWaitTime);
808 AAMPLOG_WARN(
" DRM Session Manager Received license data from server; Curl total time = %.1f", totalTime);
809 AAMPLOG_WARN(
" acquireLicense SUCCESS! license request attempt %d; response code : http %d", attemptCount, *httpCode);
810 requestFailed =
false;
814 double total, connect, startTransfer, resolve, appConnect, preTransfer, redirect, dlSize;
816 double totalPerformRequest = (double)(downloadTimeMS)/1000;
818 curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &resolve);
819 curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &connect);
820 curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &appConnect);
821 curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &preTransfer);
822 curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &startTransfer);
823 curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, &redirect);
824 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &dlSize);
825 curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &reqSize);
828 std::string appName, timeoutClass;
834 if (CURLE_OPERATION_TIMEDOUT == res || CURLE_PARTIAL_FILE == res || CURLE_COULDNT_CONNECT == res)
838 timeoutClass =
"(" + to_string(reqSize > 0) +
")";
840 AAMPLOG_WARN(
"HttpRequestEnd: %s%d,%d,%ld%s,%2.4f,%2.4f,%2.4f,%2.4f,%2.4f,%2.4f,%2.4f,%2.4f,%g,%ld,%.500s",
841 appName.c_str(), mediaType, streamType, *httpCode, timeoutClass.c_str(), totalPerformRequest, totalTime, connect, startTransfer, resolve, appConnect,
842 preTransfer, redirect, dlSize, reqSize, licenseRequest.url.c_str());
850 AAMPLOG_WARN(
" Updating Curl Abort Response Code");
852 *httpCode = CURLE_ABORTED_BY_CALLBACK;
855 if(requestFailed && keyInfo != NULL)
857 SAFE_DELETE(keyInfo);
860 SAFE_DELETE(callbackData);
861 curl_slist_free_all(headers);
876 const char* systemId,
MediaFormat mediaFormat,
const unsigned char * initDataPtr,
877 uint16_t initDataLen,
MediaType streamType,
879 bool isPrimarySession)
882 std::shared_ptr<AampDrmHelper> drmHelper;
892 AAMPLOG_ERR(
" Failed to locate DRM helper");
898 if(contentMetadataPtr)
900 std::string contentMetadataPtrString =
reinterpret_cast<const char*
>(contentMetadataPtr);
901 drmHelper->setDrmMetaData(contentMetadataPtrString);
904 if (!drmHelper->parsePssh(initDataPtr, initDataLen))
906 AAMPLOG_ERR(
" Failed to Parse PSSH from the DRM InitData");
923 if (!drmHelper || !eventHandle || !aampInstance)
927 AAMPLOG_ERR(
" Failed to create DRM Session invalid parameters ");
939 AAMPLOG_ERR(
" SessionManager state inactive, aborting request");
943 int selectedSlot = INVALID_SESSION_SLOT;
945 AAMPLOG_INFO(
"StreamType :%d keySystem is %s",streamType, drmHelper->ocdmSystemId().c_str());
950 code =
getDrmSession(drmHelper, selectedSlot, eventHandle, aampInstance);
957 return drmSessionContexts[selectedSlot].drmSession;
960 if ((code !=
KEY_INIT) || (selectedSlot == INVALID_SESSION_SLOT))
962 AAMPLOG_WARN(
" Unable to get DrmSession : Key State %d ", code);
966 std::vector<uint8_t> keyId;
967 drmHelper->getKey(keyId);
972 AAMPLOG_INFO(
"App registered the ContentProtectionDataEvent to send new drm config");
973 ContentProtectionDataUpdate(aampInstance, keyId, streamType);
980 AAMPLOG_WARN(
" Unable to initialize DrmSession : Key State %d ", code);
982 cachedKeyIDs[selectedSlot].isFailedKeyId =
true;
986 if(aampInstance->mIsFakeTune)
990 cachedKeyIDs[selectedSlot].isFailedKeyId =
true;
994 code =
acquireLicense(drmHelper, selectedSlot, cdmError, eventHandle, aampInstance, streamType);
997 AAMPLOG_WARN(
" Unable to get Ready Status DrmSession : Key State %d ", code);
999 cachedKeyIDs[selectedSlot].isFailedKeyId =
true;
1003 #ifdef USE_SECMANAGER
1005 if (mSessionId != AAMP_SECMGR_INVALID_SESSION_ID)
1007 AAMPLOG_WARN(
" Setting sessionId[%" PRId64
"] to current drmSession", mSessionId);
1008 drmSessionContexts[selectedSlot].drmSession->setSessionId(mSessionId);
1012 return drmSessionContexts[selectedSlot].drmSession;
1022 bool keySlotFound =
false;
1023 bool isCachedKeyId =
false;
1024 unsigned char *keyId = NULL;
1026 std::vector<uint8_t> keyIdArray;
1027 std::map<int, std::vector<uint8_t>> keyIdArrays;
1028 drmHelper->getKeys(keyIdArrays);
1030 drmHelper->getKey(keyIdArray);
1033 if (keyIdArray.empty())
1039 if (keyIdArrays.empty())
1042 keyIdArrays[0] = keyIdArray;
1051 int sessionSlot = 0;
1056 for (; sessionSlot < mMaxDRMSessions; sessionSlot++)
1058 auto keyIDSlot = cachedKeyIDs[sessionSlot].data;
1059 if (!keyIDSlot.empty() && keyIDSlot.end() != std::find(keyIDSlot.begin(), keyIDSlot.end(), keyIdArray))
1061 AAMPLOG_INFO(
"Session created/inprogress with same keyID %s at slot %d", keyIdDebugStr.c_str(), sessionSlot);
1062 keySlotFound =
true;
1063 isCachedKeyId =
true;
1075 for (
int index = 0; index < mMaxDRMSessions; index++)
1077 if (!cachedKeyIDs[index].isPrimaryKeyId)
1079 keySlotFound =
true;
1080 sessionSlot = index;
1087 AAMPLOG_WARN(
" Unable to find keySlot for keyId %s ", keyIdDebugStr.c_str());
1092 for (
int index= sessionSlot + 1; index< mMaxDRMSessions; index++)
1094 if (cachedKeyIDs[index].creationTime < cachedKeyIDs[sessionSlot].creationTime)
1096 sessionSlot = index;
1099 AAMPLOG_WARN(
" Selected slot %d for keyId %s", sessionSlot, keyIdDebugStr.c_str());
1104 if(cachedKeyIDs[sessionSlot].isFailedKeyId)
1106 AAMPLOG_WARN(
" Found FailedKeyId at sesssionSlot :%d, return key error",sessionSlot);
1114 if(cachedKeyIDs[sessionSlot].data.size() != 0)
1116 cachedKeyIDs[sessionSlot].data.clear();
1118 cachedKeyIDs[sessionSlot].isFailedKeyId =
false;
1120 std::vector<std::vector<uint8_t>> data;
1121 for(
auto& keyId : keyIdArrays)
1124 AAMPLOG_INFO(
"Insert[%d] - slot:%d keyID %s", keyId.first, sessionSlot, debugStr.c_str());
1125 data.push_back(keyId.second);
1128 cachedKeyIDs[sessionSlot].data = data;
1131 cachedKeyIDs[sessionSlot].isPrimaryKeyId = isPrimarySession;
1134 selectedSlot = sessionSlot;
1135 const std::string systemId = drmHelper->ocdmSystemId();
1136 AampMutexHold sessionMutex(drmSessionContexts[sessionSlot].sessionMutex);
1137 if (drmSessionContexts[sessionSlot].drmSession != NULL)
1139 if (drmHelper->ocdmSystemId() != drmSessionContexts[sessionSlot].drmSession->
getKeySystem())
1141 AAMPLOG_WARN(
"changing DRM session for %s to %s", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str(), drmHelper->ocdmSystemId().c_str());
1143 else if (cachedKeyIDs[sessionSlot].data.end() != std::find(cachedKeyIDs[sessionSlot].data.begin(), cachedKeyIDs[sessionSlot].data.end() ,drmSessionContexts[sessionSlot].data))
1145 KeyState existingState = drmSessionContexts[sessionSlot].drmSession->
getState();
1148 AAMPLOG_WARN(
"Found drm session READY with same keyID %s - Reusing drm session", keyIdDebugStr.c_str());
1149 #ifdef USE_SECMANAGER
1152 if (drmSessionContexts[sessionSlot].drmSession->getSessionId() != AAMP_SECMGR_INVALID_SESSION_ID &&
1153 mSessionId == AAMP_SECMGR_INVALID_SESSION_ID)
1156 mSessionId = drmSessionContexts[sessionSlot].drmSession->getSessionId();
1164 AAMPLOG_WARN(
"Found drm session in INIT state with same keyID %s - Reusing drm session", keyIdDebugStr.c_str());
1169 if (drmSessionContexts[sessionSlot].drmSession->waitForState(
KEY_READY, drmHelper->keyProcessTimeout()))
1171 AAMPLOG_WARN(
"Waited for drm session READY with same keyID %s - Reusing drm session", keyIdDebugStr.c_str());
1174 AAMPLOG_WARN(
"key was never ready for %s ", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str());
1175 cachedKeyIDs[selectedSlot].isFailedKeyId =
true;
1180 AAMPLOG_WARN(
"existing DRM session for %s has error state %d", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str(), existingState);
1181 cachedKeyIDs[selectedSlot].isFailedKeyId =
true;
1187 AAMPLOG_WARN(
"existing DRM session for %s has different key in slot %d", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str(), sessionSlot);
1189 AAMPLOG_WARN(
"deleting existing DRM session for %s ", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str());
1190 #ifdef USE_SECMANAGER
1192 if (drmSessionContexts[sessionSlot].drmSession->getSessionId() != AAMP_SECMGR_INVALID_SESSION_ID)
1197 SAFE_DELETE(drmSessionContexts[sessionSlot].drmSession);
1203 if (drmSessionContexts[sessionSlot].drmSession != NULL)
1205 AAMPLOG_INFO(
"Created new DrmSession for DrmSystemId %s", systemId.c_str());
1206 drmSessionContexts[sessionSlot].data = keyIdArray;
1207 code = drmSessionContexts[sessionSlot].drmSession->
getState();
1213 drmHelper->setOutputProtectionFlag(
true);
1218 AAMPLOG_WARN(
"Unable to Get DrmSession for DrmSystemId %s", systemId.c_str());
1222 #if defined(USE_OPENCDM_ADAPTER)
1223 drmSessionContexts[sessionSlot].drmSession->setKeyId(keyIdArray);
1236 std::vector<uint8_t> drmInitData;
1237 drmHelper->createInitData(drmInitData);
1239 AampMutexHold sessionMutex(drmSessionContexts[sessionSlot].sessionMutex);
1241 AAMPLOG_INFO(
"DRM session Custom Data - %s ", customData.empty()?
"NULL":customData.c_str());
1242 drmSessionContexts[sessionSlot].drmSession->
generateAampDRMSession(drmInitData.data(), drmInitData.size(), customData);
1244 code = drmSessionContexts[sessionSlot].drmSession->
getState();
1247 AAMPLOG_ERR(
"DRM session was not initialized : Key State %d ", code);
1250 AAMPLOG_ERR(
"DRM session ID is empty: Key State %d ", code);
1268 shared_ptr<DrmData> licenseResponse;
1269 int32_t httpResponseCode = -1;
1270 int32_t httpExtendedStatusCode = -1;
1272 if (drmHelper->isExternalLicense())
1276 if(drmHelper->friendlyName().compare(
"Verimatrix") == 0)
1278 licenseResponse = std::make_shared<DrmData>();
1279 drmHelper->transformLicenseResponse(licenseResponse);
1285 AampMutexHold sessionMutex(drmSessionContexts[sessionSlot].sessionMutex);
1290 AAMPLOG_INFO(
"Request to generate license challenge to the aampDRMSession(CDM)");
1293 challengeInfo.
data.reset(drmSessionContexts[sessionSlot].drmSession->aampGenerateKeyRequest(challengeInfo.
url, drmHelper->licenseGenerateTimeout()));
1294 code = drmSessionContexts[sessionSlot].drmSession->
getState();
1298 AAMPLOG_ERR(
"Error in getting license challenge : Key State %d ", code);
1306 bool usingAppDefinedAuthToken = !aampInstance->
mSessionToken.empty();
1310 if (!(drmHelper->getDrmMetaData().empty() || anonymouslicReq))
1315 long tokenError = 0;
1316 char *sessionToken = NULL;
1317 if(!usingAppDefinedAuthToken)
1320 AAMPLOG_WARN(
"Access Token from AuthServer");
1326 AAMPLOG_WARN(
"Got Access Token from External App");
1328 if (NULL == sessionToken)
1332 AAMPLOG_WARN(
"failed to get access token, Anonymous request not enabled");
1334 eventHandle->setResponseCode(tokenError);
1335 if(!licenseRequestAbort)
1343 AAMPLOG_INFO(
"access token is available");
1344 challengeInfo.
accessToken = std::string(sessionToken, tokenLen);
1347 if(licenseRequestAbort)
1349 AAMPLOG_ERR(
"Error!! License request was aborted. Resetting session slot %d", sessionSlot);
1351 eventHandle->setResponseCode(CURLE_ABORTED_BY_CALLBACK);
1358 licenseRequest.licenseAnonymousRequest = anonymouslicReq;
1359 drmHelper->generateLicenseRequest(challengeInfo, licenseRequest);
1362 AAMPLOG_ERR(
"Error!! License challenge was not generated by the CDM : Key State %d", code);
1370 std::string licenseServerProxy;
1376 AAMPLOG_WARN(
"Request License from the Drm Server %s", licenseRequest.url.c_str());
1379 #if defined(USE_SECCLIENT) || defined(USE_SECMANAGER)
1380 if (isContentMetadataAvailable)
1382 eventHandle->setSecclientError(
true);
1383 licenseResponse.reset(getLicenseSec(licenseRequest, drmHelper, challengeInfo, aampInstance, &httpResponseCode, &httpExtendedStatusCode, eventHandle));
1385 bool sec_accessTokenExpired = aampInstance->mConfig->
IsConfigSet(
eAAMPConfig_UseSecManager) && SECMANGER_DRM_FAILURE == httpResponseCode && SECMANGER_ACCTOKEN_EXPIRED == httpExtendedStatusCode;
1387 if (((412 == httpResponseCode && 401 == httpExtendedStatusCode) || sec_accessTokenExpired) && !usingAppDefinedAuthToken)
1389 AAMPLOG_INFO(
"License Req failure by Expired access token httpResCode %d statusCode %d", httpResponseCode, httpExtendedStatusCode);
1397 long tokenError = 0;
1399 if (NULL != sessionToken)
1401 AAMPLOG_INFO(
"Requesting License with new access token");
1402 challengeInfo.
accessToken = std::string(sessionToken, tokenLen);
1403 httpResponseCode = httpExtendedStatusCode = -1;
1404 licenseResponse.reset(getLicenseSec(licenseRequest, drmHelper, challengeInfo, aampInstance, &httpResponseCode, &httpExtendedStatusCode, eventHandle));
1411 if(usingAppDefinedAuthToken)
1413 AAMPLOG_WARN(
"Ignore AuthToken Provided for non-ContentMetadata DRM license request");
1415 eventHandle->setSecclientError(
false);
1416 licenseResponse.reset(
getLicense(licenseRequest, &httpResponseCode, streamType, aampInstance, isContentMetadataAvailable, licenseServerProxy));
1425 code = handleLicenseResponse(drmHelper, sessionSlot, cdmError, httpResponseCode, httpExtendedStatusCode, licenseResponse, eventHandle, aampInstance);
1432 KeyState AampDRMSessionManager::handleLicenseResponse(std::shared_ptr<AampDrmHelper> drmHelper,
int sessionSlot,
int &cdmError, int32_t httpResponseCode, int32_t httpExtendedStatusCode, shared_ptr<DrmData> licenseResponse, DrmMetaDataEventPtr eventHandle,
PrivateInstanceAAMP* aamp)
1434 if (!drmHelper->isExternalLicense())
1436 if ((licenseResponse != NULL) && (licenseResponse->getDataLength() != 0))
1440 #if !defined(USE_SECCLIENT) && !defined(USE_SECMANAGER)
1441 if (!drmHelper->getDrmMetaData().empty())
1448 string jsonStr(licenseResponse->getData().c_str(), licenseResponse->getDataLength());
1454 std::vector<uint8_t> keyData;
1457 AAMPLOG_WARN(
"Unable to retrieve license from JSON response", jsonStr.c_str());
1461 licenseResponse = make_shared<DrmData>(keyData.data(), keyData.size());
1466 AAMPLOG_WARN(
"Failed to parse JSON response", jsonStr.c_str());
1470 AAMPLOG_INFO(
"license acquisition completed");
1471 drmHelper->transformLicenseResponse(licenseResponse);
1478 AAMPLOG_ERR(
"Error!! Invalid License Response was provided by the Server");
1480 bool SecAuthFailure =
false, SecTimeout =
false;
1487 eventHandle->setResponseCode(httpResponseCode);
1488 eventHandle->setSecManagerReasonCode(httpExtendedStatusCode);
1489 if(SECMANGER_DRM_FAILURE == httpResponseCode && SECMANGER_ENTITLEMENT_FAILURE == httpExtendedStatusCode)
1495 AAMPLOG_WARN(
"DRM session for %s, Authorisation failed", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str());
1497 else if(SECMANGER_DRM_FAILURE == httpResponseCode && SECMANGER_SERVICE_TIMEOUT == httpExtendedStatusCode)
1506 else if (412 == httpResponseCode)
1512 AAMPLOG_WARN(
"DRM session for %s, Authorisation failed", drmSessionContexts[sessionSlot].drmSession->getKeySystem().c_str());
1515 else if (CURLE_OPERATION_TIMEDOUT == httpResponseCode)
1519 else if(CURLE_ABORTED_BY_CALLBACK == httpResponseCode || CURLE_WRITE_ERROR == httpResponseCode)
1523 eventHandle->setResponseCode(httpResponseCode);
1528 eventHandle->setResponseCode(httpResponseCode);
1534 return processLicenseResponse(drmHelper, sessionSlot, cdmError, licenseResponse, eventHandle, aamp);
1538 KeyState AampDRMSessionManager::processLicenseResponse(std::shared_ptr<AampDrmHelper> drmHelper,
int sessionSlot,
int &cdmError,
1539 shared_ptr<DrmData> licenseResponse, DrmMetaDataEventPtr eventHandle,
PrivateInstanceAAMP* aampInstance)
1546 AAMPLOG_INFO(
"Updating the license response to the aampDRMSession(CDM)");
1548 cdmError = drmSessionContexts[sessionSlot].drmSession->
aampDRMProcessKey(licenseResponse.get(), drmHelper->keyProcessTimeout());
1560 if (cdmError == HDCP_OUTPUT_PROTECTION_FAILURE || cdmError == HDCP_COMPLIANCE_CHECK_FAILURE)
1572 AAMPLOG_ERR(
" Failed to get DRM keys");
1588 string contentMetaData = drmHelper->getDrmMetaData();
1589 bool isContentMetadataAvailable = !contentMetaData.empty();
1591 if (!contentMetaData.empty())
1593 if (!licenseRequest.url.empty())
1595 #if defined(USE_SECCLIENT) || defined(USE_SECMANAGER)
1596 licenseRequest.url = getFormattedLicenseServerURL(licenseRequest.url);
1604 std::unordered_map<std::string, std::vector<std::string>> customHeaders;
1607 if (!customHeaders.empty())
1610 licenseRequest.headers = customHeaders;
1613 if (isContentMetadataAvailable)
1615 std::string customData;
1616 if (customHeaders.empty())
1619 licenseRequest.headers.clear();
1623 if (!customData.empty())
1625 licenseRequest.headers.insert({LICENCE_REQUEST_HEADER_ACCEPT, {customData.c_str()}});
1630 if (!customData.empty())
1632 licenseRequest.headers.insert({LICENCE_REQUEST_HEADER_CONTENT_TYPE, {customData.c_str()}});
1639 return isContentMetadataAvailable;
1647 #ifdef USE_SECMANAGER
1648 if(AAMP_SECMGR_INVALID_SESSION_ID != mSessionId)
1653 mSessionId = AAMP_SECMGR_INVALID_SESSION_ID;
1658 void AampDRMSessionManager::ContentProtectionDataUpdate(
PrivateInstanceAAMP* aampInstance, std::vector<uint8_t> keyId,
MediaType streamType)
1660 std::string contentType = sessionTypeName[streamType];
1662 bool DRM_Config_Available =
false;
1664 while (iter1 < aampInstance->vDynamicDrmData.size())
1666 DynamicDrmInfo dynamicDrmCache = aampInstance->vDynamicDrmData.at(iter1);
1667 if(keyId == dynamicDrmCache.keyID)
1669 AAMPLOG_WARN(
"DrmConfig already present in cached data in slot : %d applying config",iter1);
1670 std::map<std::string,std::string>::iterator itr;
1671 for(itr = dynamicDrmCache.licenseEndPoint.begin();itr!=dynamicDrmCache.licenseEndPoint.end();itr++)
1673 if(strcasecmp(
"com.microsoft.playready",itr->first.c_str())==0)
1677 if(strcasecmp(
"com.widevine.alpha",itr->first.c_str())==0)
1681 if(strcasecmp(
"org.w3.clearkey",itr->first.c_str())==0)
1688 DRM_Config_Available =
true;
1693 if(!DRM_Config_Available) {
1694 ContentProtectionDataEventPtr eventData = std::make_shared<ContentProtectionDataEvent>(keyId, contentType);
1696 pthread_mutex_lock(&aampInstance->mDynamicDrmUpdateLock);
1697 int pthreadReturnValue = 0;
1699 int drmUpdateTimeout;
1701 AAMPLOG_WARN(
"Timeout Wait for DRM config message from application :%d",drmUpdateTimeout);
1703 AAMPLOG_INFO(
"Found new KeyId %s and not in drm config cache, sending ContentProtectionDataEvent to App", keyIdDebugStr.c_str());
1705 pthreadReturnValue = pthread_cond_timedwait(&aampInstance->mWaitForDynamicDRMToUpdate, &aampInstance->mDynamicDrmUpdateLock, &ts);
1706 if (ETIMEDOUT == pthreadReturnValue)
1708 AAMPLOG_WARN(
"pthread_cond_timedwait returned TIMEOUT, Applying Default config");
1710 std::map<std::string,std::string>::iterator itr;
1711 for(itr = dynamicDrmCache.licenseEndPoint.begin();itr!=dynamicDrmCache.licenseEndPoint.end();itr++) {
1712 if(strcasecmp(
"com.microsoft.playready",itr->first.c_str())==0) {
1715 if(strcasecmp(
"com.widevine.alpha",itr->first.c_str())==0) {
1718 if(strcasecmp(
"org.w3.clearkey",itr->first.c_str())==0) {
1725 else if (0 != pthreadReturnValue)
1727 AAMPLOG_WARN(
"pthread_cond_timedwait returned %s ", strerror(pthreadReturnValue));
1730 AAMPLOG_WARN(
"%s:%d [WARN] pthread_cond_timedwait(dynamicDrmUpdate) returned success!", __FUNCTION__, __LINE__);
1732 pthread_mutex_unlock(&aampInstance->mDynamicDrmUpdateLock);
1743 if(aamp->drmSessionThreadStarted)
1745 void *value_ptr = NULL;
1746 int rc = pthread_join(aamp->createDRMSessionThreadID, &value_ptr);
1749 AAMPLOG_WARN(
"pthread_join returned %d for createDRMSession Thread",
1752 aamp->drmSessionThreadStarted =
false;
1753 AAMPLOG_WARN(
"DRMSession Thread Released");
1765 int iState = DRM_API_FAILED;
1769 if (NULL == drmData){
1770 AAMPLOG_ERR(
"Could not able to process with the NULL Drm data"
1776 AAMPLOG_INFO(
"Creating thread with sessionData = 0x%08x",
1778 if(0 == pthread_create(&aamp->createDRMSessionThreadID, NULL,\
1782 aamp->drmSessionThreadStarted =
true;
1788 AAMPLOG_ERR(
"pthread_create failed for CreateDRMSession : error code %d, %s",
1789 errno, strerror(errno));
1805 if(aamp_pthread_setname(pthread_self(),
"aampfMP4DRM"))
1807 AAMPLOG_ERR(
"aamp_pthread_setname failed");
1811 if(sessionParams ==
nullptr) {
1812 AAMPLOG_ERR(
"sessionParams is null");
1815 if(sessionParams->aamp ==
nullptr) {
1816 AAMPLOG_ERR(
"no aamp in sessionParams");
1820 #if defined(USE_SECCLIENT) || defined(USE_SECMANAGER)
1821 bool isSecClientError =
true;
1823 bool isSecClientError =
false;
1831 const char * systemId;
1833 if (sessionParams->aamp ==
nullptr) {
1834 AAMPLOG_ERR(
"no aamp in sessionParams");
1838 if (sessionParams->aamp->mDRMSessionManager ==
nullptr) {
1839 AAMPLOG_ERR(
"no aamp->mDrmSessionManager in sessionParams");
1844 if (sessionParams->drmHelper ==
nullptr)
1847 AAMPLOG_ERR(
"Failed DRM Session Creation, no helper");
1856 std::vector<uint8_t> data;
1857 systemId = sessionParams->drmHelper->getUuid().c_str();
1858 sessionParams->drmHelper->createInitData(data);
1859 sessionParams->aamp->mStreamSink->
QueueProtectionEvent(systemId, data.data(), data.size(), sessionParams->stream_type);
1860 drmSession = sessionManger->
createDrmSession(sessionParams->drmHelper, e, sessionParams->aamp, sessionParams->stream_type);
1862 if(NULL == drmSession)
1864 AAMPLOG_ERR(
"Failed DRM Session Creation for systemId = %s", systemId);
1866 long responseCode = e->getResponseCode();
1884 if(e->getAccessStatusValue() != 3)
1886 AAMPLOG_INFO(
"Sending DRMMetaData");
1892 if(sessionParams->aamp->mIsFakeTune)