fragmentcollector_mpd.cpp
/**
 * @brief Update MPD manifest
 *
 * @param[in] retrievePlaylistFromCache  True to try to get from cache
 *
 * @retval true on success
 */
@brief Update MPD manifest
@param[in] retrievePlaylistFromCache  True to try to get from cache

@retval true on success
@brief Update MPD manifest @param [ in ] retrievePlaylistFromCache True to try to get from cache @retval true on success
AAMPStatusType PrivateStreamAbstractionMPD::UpdateMPD(bool retrievePlaylistFromCache)
{
	GrowableBuffer manifest;
	AAMPStatusType ret = AAMPStatusType::eAAMPSTATUS_OK;
	int downloadAttempt = 0;
	char *manifestUrl = aamp->GetManifestUrl();
	bool gotManifest = false;
	bool retrievedPlaylistFromCache = false;
	bool harvestManifest = (gpGlobalConfig->mpdHarvestLimit && strstr(manifestUrl, "ccr.mm-"));
	if (retrievePlaylistFromCache)
	{
		memset(&manifest, 0, sizeof(manifest));
		if (aamp->RetrieveFromPlaylistCache(manifestUrl, &manifest, manifestUrl))
		{
			logprintf("PrivateStreamAbstractionMPD::%s:%d manifest retrieved from cache\n", __FUNCTION__, __LINE__);
			retrievedPlaylistFromCache = true;
		}
	}
	while( downloadAttempt < 2)
	{
		if (!retrievedPlaylistFromCache)
		{
			long http_error = 0;
			downloadAttempt++;
			memset(&manifest, 0, sizeof(manifest));
			aamp->profiler.ProfileBegin(PROFILE_BUCKET_MANIFEST);
			gotManifest = aamp->GetFile(manifestUrl, &manifest, manifestUrl, &http_error, NULL, 0, true, eMEDIATYPE_MANIFEST);
			if (gotManifest)
			{
				aamp->profiler.ProfileEnd(PROFILE_BUCKET_MANIFEST);
				if (mContext->mNetworkDownDetected)
				{
					mContext->mNetworkDownDetected = false;
				}
			}
			else if (aamp->DownloadsAreEnabled())
			{
				if(downloadAttempt < 2 && 404 == http_error)
				{
					continue;
				}
				aamp->profiler.ProfileError(PROFILE_BUCKET_MANIFEST);
				if (this->mpd != NULL && (CURLE_OPERATION_TIMEDOUT == http_error || CURLE_COULDNT_CONNECT == http_error))
				{
					mContext->mNetworkDownDetected = true;
					logprintf("PrivateStreamAbstractionMPD::%s Ignore curl timeout\n", __FUNCTION__);
					ret = AAMPStatusType::eAAMPSTATUS_OK;
					break;
				}
				aamp->SendDownloadErrorEvent(AAMP_TUNE_MANIFEST_REQ_FAILED, http_error);
				logprintf("PrivateStreamAbstractionMPD::%s - manifest download failed\n", __FUNCTION__);
				ret = AAMPStatusType::eAAMPSTATUS_MANIFEST_DOWNLOAD_ERROR;
				break;
			}
		}
		else
		{
			gotManifest = true;
		}
		if (gotManifest)
		{
#ifdef AAMP_HARVEST_SUPPORT_ENABLED
		char fileName[1024] = {'\0'};
		strcat(fileName, HARVEST_BASE_PATH);
		strcat(fileName, "manifest.mpd");
		WriteFile( fileName, manifest.ptr, manifest.len);
#endif
			xmlTextReaderPtr reader = xmlReaderForMemory(manifest.ptr, (int) manifest.len, NULL, NULL, 0);
			if(harvestManifest)
			{
				static unsigned int counter = 0;
				string fileSuffix = to_string((counter % gpGlobalConfig->mpdHarvestLimit) + 1);
				counter++;
#ifdef WIN32
				string fullPath = "c:/tmp";
#elif defined(__APPLE__)
				string fullPath = getenv("HOME");
#else
				string fullPath = "/opt/logs";
#endif
				fullPath = fullPath + "/HarvestedMPD.txt" + fileSuffix;
				logprintf("Saving manifest to %s\n",fullPath.c_str());
				FILE *outputFile = fopen(fullPath.c_str(), "w");
				fwrite(manifest.ptr, manifest.len, 1, outputFile);
				fclose(outputFile);
			}
			if (reader != NULL)
			{
				if (xmlTextReaderRead(reader))
				{
					Node *root = ProcessNode(&reader, manifestUrl);
					if(root != NULL)
					{
						uint32_t fetchTime = Time::GetCurrentUTCTimeInSec();
						MPD* mpd = root->ToMPD();
						if (mpd)
						{
							mpd->SetFetchTime(fetchTime);
							FindTimedMetadata(mpd, root);
							if (this->mpd)
							{
								delete this->mpd;
							}
							this->mpd = mpd;
	                        aamp->mEnableCache = (mpd->GetType() == "static");
	                        if (aamp->mEnableCache && !retrievedPlaylistFromCache)
	                        {
	                            aamp->InsertToPlaylistCache(aamp->GetManifestUrl(), &manifest, aamp->GetManifestUrl());
	                        }
						}
						else
						{
						    ret = AAMPStatusType::eAAMPSTATUS_MANIFEST_CONTENT_ERROR;
						}
						delete root;
					}
					else
					{
						logprintf("Error while processing MPD, Process Node returned NULL\n");
						if(downloadAttempt < 2)
						{
							retrievedPlaylistFromCache = false;
							continue;
						}
						ret = AAMPStatusType::eAAMPSTATUS_MANIFEST_PARSE_ERROR;
					}
				}
				xmlFreeTextReader(reader);
			}
			if (gpGlobalConfig->logging.trace)
			{
				aamp_AppendNulTerminator(&manifest); 
				logprintf("%s\n", manifest.ptr);
			}
			aamp_Free(&manifest.ptr);
			mLastPlaylistDownloadTimeMs = aamp_GetCurrentTimeMS();
		}
		else
		{
			logprintf("aamp: error on manifest fetch\n");
			ret = AAMPStatusType::eAAMPSTATUS_MANIFEST_DOWNLOAD_ERROR;
		}
		break;
	}
	if( ret == eAAMPSTATUS_MANIFEST_PARSE_ERROR || ret == eAAMPSTATUS_MANIFEST_CONTENT_ERROR)
	{
	    if(NULL != manifest.ptr && NULL != manifestUrl)
	    {
            int tempDataLen = (MANIFEST_TEMP_DATA_LENGTH - 1);
            char temp[MANIFEST_TEMP_DATA_LENGTH];
            strncpy(temp, manifest.ptr, tempDataLen);
            temp[tempDataLen] = 0x00;
	        logprintf("ERROR: Invalid Playlist URL: %s ret:%d\n", manifestUrl,ret);
	        logprintf("ERROR: Invalid Playlist DATA: %s \n", temp);
	    }
        aamp->SendErrorEvent(AAMP_TUNE_INVALID_MANIFEST_FAILURE);
	}
	return ret;
}
AAMPStatusType PrivateStreamAbstractionMPD :: UpdateMPD ( bool retrievePlaylistFromCache ) { GrowableBuffer manifest ; AAMPStatusType ret = AAMPStatusType :: eAAMPSTATUS_OK ; int downloadAttempt = 0 ; char * manifestUrl = aamp -> GetManifestUrl ( ) ; bool gotManifest = false ; bool retrievedPlaylistFromCache = false ; bool harvestManifest = ( gpGlobalConfig -> mpdHarvestLimit && strstr ( manifestUrl , " " ) ) ; if ( retrievePlaylistFromCache ) { memset ( & manifest , 0 , sizeof ( manifest ) ) ; if ( aamp -> RetrieveFromPlaylistCache ( manifestUrl , & manifest , manifestUrl ) ) { logprintf ( " \n " , __FUNCTION__ , __LINE__ ) ; retrievedPlaylistFromCache = true ; } } while ( downloadAttempt < 2 ) { if ( ! retrievedPlaylistFromCache ) { long http_error = 0 ; downloadAttempt ++ ; memset ( & manifest , 0 , sizeof ( manifest ) ) ; aamp -> profiler . ProfileBegin ( PROFILE_BUCKET_MANIFEST ) ; gotManifest = aamp -> GetFile ( manifestUrl , & manifest , manifestUrl , & http_error , NULL , 0 , true , eMEDIATYPE_MANIFEST ) ; if ( gotManifest ) { aamp -> profiler . ProfileEnd ( PROFILE_BUCKET_MANIFEST ) ; if ( mContext -> mNetworkDownDetected ) { mContext -> mNetworkDownDetected = false ; } } else if ( aamp -> DownloadsAreEnabled ( ) ) { if ( downloadAttempt < 2 && 404 == http_error ) { continue ; } aamp -> profiler . ProfileError ( PROFILE_BUCKET_MANIFEST ) ; if ( this -> mpd != NULL && ( CURLE_OPERATION_TIMEDOUT == http_error || CURLE_COULDNT_CONNECT == http_error ) ) { mContext -> mNetworkDownDetected = true ; logprintf ( " \n " , __FUNCTION__ ) ; ret = AAMPStatusType :: eAAMPSTATUS_OK ; break ; } aamp -> SendDownloadErrorEvent ( AAMP_TUNE_MANIFEST_REQ_FAILED , http_error ) ; logprintf ( " \n " , __FUNCTION__ ) ; ret = AAMPStatusType :: eAAMPSTATUS_MANIFEST_DOWNLOAD_ERROR ; break ; } } else { gotManifest = true ; } if ( gotManifest ) { #ifdef AAMP_HARVEST_SUPPORT_ENABLED char fileName [ 1024 ] = { ' \0 ' } ; strcat ( fileName , HARVEST_BASE_PATH ) ; strcat ( fileName , " " ) ; WriteFile ( fileName , manifest . ptr , manifest . len ) ; #endif xmlTextReaderPtr reader = xmlReaderForMemory ( manifest . ptr , ( int ) manifest . len , NULL , NULL , 0 ) ; if ( harvestManifest ) { static unsigned int counter = 0 ; string fileSuffix = to_string ( ( counter % gpGlobalConfig -> mpdHarvestLimit ) + 1 ) ; counter ++ ; #ifdef WIN32 string fullPath = " " ; #elif defined ( __APPLE__ ) string fullPath = getenv ( " " ) ; #else string fullPath = " " ; #endif fullPath = fullPath + " " + fileSuffix ; logprintf ( " \n " , fullPath . c_str ( ) ) ; FILE * outputFile = fopen ( fullPath . c_str ( ) , " " ) ; fwrite ( manifest . ptr , manifest . len , 1 , outputFile ) ; fclose ( outputFile ) ; } if ( reader != NULL ) { if ( xmlTextReaderRead ( reader ) ) { Node * root = ProcessNode ( & reader , manifestUrl ) ; if ( root != NULL ) { uint32_t fetchTime = Time :: GetCurrentUTCTimeInSec ( ) ; MPD * mpd = root -> ToMPD ( ) ; if ( mpd ) { mpd -> SetFetchTime ( fetchTime ) ; FindTimedMetadata ( mpd , root ) ; if ( this -> mpd ) { delete this -> mpd ; } this -> mpd = mpd ; aamp -> mEnableCache = ( mpd -> GetType ( ) == " " ) ; if ( aamp -> mEnableCache && ! retrievedPlaylistFromCache ) { aamp -> InsertToPlaylistCache ( aamp -> GetManifestUrl ( ) , & manifest , aamp -> GetManifestUrl ( ) ) ; } } else { ret = AAMPStatusType :: eAAMPSTATUS_MANIFEST_CONTENT_ERROR ; } delete root ; } else { logprintf ( " \n " ) ; if ( downloadAttempt < 2 ) { retrievedPlaylistFromCache = false ; continue ; } ret = AAMPStatusType :: eAAMPSTATUS_MANIFEST_PARSE_ERROR ; } } xmlFreeTextReader ( reader ) ; } if ( gpGlobalConfig -> logging . trace ) { aamp_AppendNulTerminator ( & manifest ) ; logprintf ( " \n " , manifest . ptr ) ; } aamp_Free ( & manifest . ptr ) ; mLastPlaylistDownloadTimeMs = aamp_GetCurrentTimeMS ( ) ; } else { logprintf ( " \n " ) ; ret = AAMPStatusType :: eAAMPSTATUS_MANIFEST_DOWNLOAD_ERROR ; } break ; } if ( ret == eAAMPSTATUS_MANIFEST_PARSE_ERROR || ret == eAAMPSTATUS_MANIFEST_CONTENT_ERROR ) { if ( NULL != manifest . ptr && NULL != manifestUrl ) { int tempDataLen = ( MANIFEST_TEMP_DATA_LENGTH - 1 ) ; char temp [ MANIFEST_TEMP_DATA_LENGTH ] ; strncpy ( temp , manifest . ptr , tempDataLen ) ; temp [ tempDataLen ] = 0x00 ; logprintf ( " \n " , manifestUrl , ret ) ; logprintf ( " \n " , temp ) ; } aamp -> SendErrorEvent ( AAMP_TUNE_INVALID_MANIFEST_FAILURE ) ; } return ret ; }
@brief Update MPD manifest
 @param[in] retrievePlaylistFromCache  True to try to get from cache
@brief Update MPD manifest @param [ in ] retrievePlaylistFromCache True to try to get from cache
//Skip this for first ever update mpd request // parse xml //Dump the DAI vod manifest to /opt/logs if mpdHarvestLimit is set //mpds will be save with a numeric suffix, which would be going from 1 to mpdHarvestLimit //old mpds will get overwritten after a cycle // make safe for cstring operations