RDK Documentation (Open Sourced RDK Components)
admanager_mpd.cpp
Go to the documentation of this file.
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 admanager_mpd.cpp
22  * @brief Client side DAI manger for MPEG DASH
23  */
24 
25 #include "admanager_mpd.h"
26 #include "AampUtils.h"
27 #include "fragmentcollector_mpd.h"
28 #include <inttypes.h>
29 
30 #include <algorithm>
31 
32 static void *AdFulfillThreadEntry(void *arg)
33 {
35  if(aamp_pthread_setname(pthread_self(), "aampADFulfill"))
36  {
37  AAMPLOG_ERR("aamp_pthread_setname failed");
38  }
39  _this->FulFillAdObject();
40  return NULL;
41 }
42 
43 /**
44  * @brief CDAIObjectMPD Constructor
45  */
46 CDAIObjectMPD::CDAIObjectMPD(AampLogManager *logObj, PrivateInstanceAAMP* aamp): CDAIObject(logObj, aamp), mPrivObj(new PrivateCDAIObjectMPD(logObj, aamp))
47 {
48 
49 }
50 
51 /**
52  * @brief CDAIObjectMPD destructor.
53  */
55 {
56  SAFE_DELETE(mPrivObj);
57 }
58 
59 /**
60  * @brief Setting the alternate contents' (Ads/blackouts) URL
61  *
62  */
63 void CDAIObjectMPD::SetAlternateContents(const std::string &periodId, const std::string &adId, const std::string &url, uint64_t startMS, uint32_t breakdur)
64 {
65  mPrivObj->SetAlternateContents(periodId, adId, url, startMS, breakdur);
66 }
67 
68 
69 /**
70  * @brief PrivateCDAIObjectMPD constructor
71  */
72 PrivateCDAIObjectMPD::PrivateCDAIObjectMPD(AampLogManager* logObj, PrivateInstanceAAMP* aamp) : mLogObj(logObj),mAamp(aamp),mDaiMtx(), mIsFogTSB(false), mAdBreaks(), mPeriodMap(), mCurPlayingBreakId(), mAdObjThreadID(0), mAdFailed(false), mCurAds(nullptr),
73  mCurAdIdx(-1), mContentSeekOffset(0), mAdState(AdState::OUTSIDE_ADBREAK),mPlacementObj(), mAdFulfillObj(),mAdtoInsertInNextBreak(), mAdObjThreadStarted(false)
74 {
76 }
77 
78 /**
79  * @brief PrivateCDAIObjectMPD destructor
80  */
82 {
84  {
85  int rc = pthread_join(mAdObjThreadID, NULL);
86  if (rc != 0)
87  {
88  AAMPLOG_ERR("***pthread_join failed, returned %d", rc);
89  }
90  mAdObjThreadStarted = false;
91  }
93 }
94 
95 /**
96  * @brief Method to insert period into period map
97  */
99 {
100  const std::string &prdId = period->GetId();
101  if(!isPeriodExist(prdId))
102  {
103  mPeriodMap[prdId] = Period2AdData();
104  }
105 }
106 
107 /**
108  * @brief Method to check the existence of period in the period map
109  */
110 bool PrivateCDAIObjectMPD::isPeriodExist(const std::string &periodId)
111 {
112  return (mPeriodMap.end() != mPeriodMap.find(periodId))?true:false;
113 }
114 
115 /**
116  * @brief Method to check the existence of Adbreak object in the AdbreakObject map
117  */
118 inline bool PrivateCDAIObjectMPD::isAdBreakObjectExist(const std::string &adBrkId)
119 {
120  return (mAdBreaks.end() != mAdBreaks.find(adBrkId))?true:false;
121 }
122 
123 /**
124  * @brief Method to remove expired periods from the period map
125  */
126 void PrivateCDAIObjectMPD::PrunePeriodMaps(std::vector<std::string> &newPeriodIds)
127 {
128  //Erase all adbreaks other than new adbreaks
129  for (auto it = mAdBreaks.begin(); it != mAdBreaks.end();) {
130  if ((mPlacementObj.pendingAdbrkId != it->first) && (mCurPlayingBreakId != it->first) &&//We should not remove the pending/playing adbreakObj
131  (newPeriodIds.end() == std::find(newPeriodIds.begin(), newPeriodIds.end(), it->first))) {
132  auto &adBrkObj = *it;
133  AAMPLOG_INFO("[CDAI] Removing the period[%s] from mAdBreaks.",adBrkObj.first.c_str());
134  auto adNodes = adBrkObj.second.ads;
135  for(AdNode &ad: *adNodes)
136  {
137  SAFE_DELETE(ad.mpd);
138  }
139  it = mAdBreaks.erase(it);
140  } else {
141  ++it;
142  }
143  }
144 
145  //Erase all periods other than new periods
146  for (auto it = mPeriodMap.begin(); it != mPeriodMap.end();) {
147  if (newPeriodIds.end() == std::find(newPeriodIds.begin(), newPeriodIds.end(), it->first)) {
148  it = mPeriodMap.erase(it);
149  } else {
150  ++it;
151  }
152  }
153 }
154 
155 /**
156  * @brief Method to reset the state of the CDAI state machine
157  */
159 {
160  //TODO: Vinod, maybe we can move these playback state variables to PrivateStreamAbstractionMPD
161  mIsFogTSB = false;
162  mCurPlayingBreakId = "";
163  mAdFailed = false;
164  mCurAds = nullptr;
165  std::lock_guard<std::mutex> lock(mDaiMtx);
166  mCurAdIdx = -1;
167  mContentSeekOffset = 0;
169 }
170 
171 /**
172  * @brief Method to clear the maps in the CDAI object
173  */
175 {
176  std::unordered_map<std::string, AdBreakObject> tmpMap;
177  std::swap(mAdBreaks,tmpMap);
178  for(auto &adBrkObj: tmpMap)
179  {
180  auto adNodes = adBrkObj.second.ads;
181  for(AdNode &ad: *adNodes)
182  {
183  SAFE_DELETE(ad.mpd);
184  }
185  }
186 
187  mPeriodMap.clear();
188 }
189 
190 /**
191  * @brief Method to create a bidirectional between the ads and the underlying content periods
192  */
193 void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
194 {
195  bool placed = false;
196  //Populate the map to specify the period boundaries
197  if(mpd && (-1 != mPlacementObj.curAdIdx) && "" != mPlacementObj.pendingAdbrkId && isAdBreakObjectExist(mPlacementObj.pendingAdbrkId)) //Some Ad is still waiting for the placement
198  {
200  vector<IPeriod *> periods = mpd->GetPeriods();
201  if(!abObj.adjustEndPeriodOffset) // not all ads are placed
202  {
203  bool openPrdFound = false;
204 
205  for(int iter = 0; iter < periods.size(); iter++)
206  {
207  if(abObj.adjustEndPeriodOffset)
208  {
209  // placement done no need to run for loop now
210  break;
211  }
212 
213  auto period = periods.at(iter);
214  const std::string &periodId = period->GetId();
215  //We need to check, open period is available in the manifest. Else, something wrong
216  if(mPlacementObj.openPeriodId == periodId)
217  {
218  openPrdFound = true;
219  }
220  else if(openPrdFound)
221  {
222  if(aamp_GetPeriodDuration(mpd, iter, 0) > 0)
223  {
224  //Previous openPeriod ended. New period in the adbreak will be the new open period
225  mPeriodMap[mPlacementObj.openPeriodId].filled = true;
226  mPlacementObj.openPeriodId = periodId;
228  }
229  else
230  {
231  continue; //Empty period may come early; excluding them
232  }
233  }
234 
235  if(openPrdFound && -1 != mPlacementObj.curAdIdx)
236  {
237  double periodDelta = aamp_GetPeriodNewContentDuration(mpd, period, mPlacementObj.curEndNumber);
238  Period2AdData& p2AdData = mPeriodMap[periodId];
239 
240  if("" == p2AdData.adBreakId)
241  {
242  //New period opened
245  }
246 
247  p2AdData.duration += periodDelta;
248 
249  while(periodDelta > 0)
250  {
251  AdNode &curAd = abObj.ads->at(mPlacementObj.curAdIdx);
252  if("" == curAd.basePeriodId)
253  {
254  //Next ad started placing
255  curAd.basePeriodId = periodId;
256  curAd.basePeriodOffset = p2AdData.duration - periodDelta;
257  int offsetKey = curAd.basePeriodOffset;
258  offsetKey = offsetKey - (offsetKey%OFFSET_ALIGN_FACTOR);
259  p2AdData.offset2Ad[offsetKey] = AdOnPeriod{mPlacementObj.curAdIdx,0}; //At offsetKey of the period, new Ad starts
260  }
261  if(periodDelta < (curAd.duration - mPlacementObj.adNextOffset))
262  {
263  mPlacementObj.adNextOffset += periodDelta;
264  periodDelta = 0;
265  }
266  else if((mPlacementObj.curAdIdx < (abObj.ads->size()-1)) //If it is not the last Ad, we can start placement immediately.
267  || periodDelta >= OFFSET_ALIGN_FACTOR) //Making sure that period has sufficient space to fallback
268  {
269  //Current Ad completely placed. But more space available in the current period for next Ad
270  curAd.placed = true;
271  periodDelta -= (curAd.duration - mPlacementObj.adNextOffset);
273  if(mPlacementObj.curAdIdx < abObj.ads->size())
274  {
275  mPlacementObj.adNextOffset = 0; //New Ad's offset
276  }
277  else
278  {
279  //Place the end markers of adbreak
280  abObj.endPeriodId = periodId; //If it is the exact period boundary, end period will be the next one
281  abObj.endPeriodOffset = p2AdData.duration - periodDelta;
282  abObj.adjustEndPeriodOffset = true; // marked for later adjustment
283  break;
284  }
285  }
286  else
287  {
288  //No more ads to place & No sufficient space to finalize. Wait for next period/next mpd refresh.
289  break;
290  }
291  }
292  }
293  }
294  }
295  if(abObj.adjustEndPeriodOffset) // make endPeriodOffset adjustment
296  {
297  bool endPeriodFound = false;
298  int iter =0;
299 
300  for(iter = 0; iter < periods.size(); iter++)
301  {
302  auto period = periods.at(iter);
303  const std::string &periodId = period->GetId();
304  //We need to check, end period is available in the manifest. Else, something wrong
305  if(abObj.endPeriodId == periodId)
306  {
307  endPeriodFound = true;
308  break;
309  }
310  }
311 
312  if(false == endPeriodFound) // something wrong keep the end-period positions same and proceed.
313  {
314  abObj.adjustEndPeriodOffset = false;
315  AAMPLOG_WARN("[CDAI] Couldn't adjust offset [endPeriodNotFound] ");
316  }
317  else
318  {
319  //Inserted Ads finishes in < 4 seconds of new period (inside the adbreak) : Play-head goes to the period’s beginning.
321  {
322  abObj.adjustEndPeriodOffset = false; // done with Adjustment
323  abObj.endPeriodOffset = 0;//Aligning the last period
324  mPeriodMap[abObj.endPeriodId] = Period2AdData(); //Resetting the period with small out-lier.
325  AAMPLOG_INFO("[CDAI] Adjusted endperiodOffset");
326  }
327  else
328  {
329  // get current period duration
330  uint64_t currPeriodDuration = aamp_GetPeriodDuration(mpd, iter, 0);
331 
332  // Are we too close to current period end?
333  //--> Inserted Ads finishes < 2 seconds behind new period : Channel play-back starts from new period.
334  int diff = currPeriodDuration - abObj.endPeriodOffset;
335  // if diff is negative or < OFFSET_ALIGN_FACTOR we have to wait for it to catch up
336  // and either period will end with diff < OFFSET_ALIGN_FACTOR then adjust to next period start
337  // or diff will be more than OFFSET_ALIGN_FACTOR then don't do any adjustment
338  if(diff < OFFSET_ALIGN_FACTOR)
339  {
340  //check if next period available
341  iter++;
342  if( iter < periods.size() )
343  {
344  auto nextPeriod = periods.at(iter);
345  abObj.adjustEndPeriodOffset = false; // done with Adjustment
346  abObj.endPeriodOffset = 0;//Aligning to next period start
347  abObj.endPeriodId = nextPeriod->GetId();
349  AAMPLOG_INFO("[CDAI] [%d] close to period end [%lld],Aligning to next-period:%s",
350  diff,currPeriodDuration,abObj.endPeriodId.c_str());
351  }
352  else
353  {
354  AAMPLOG_INFO("[CDAI] [%d] close to period end [%lld],but next period not available,waiting",
355  diff,currPeriodDuration);
356  }
357  }// --> Inserted Ads finishes >= 2 seconds behind new period : Channel playback starts from that position in the current period.
358  // OR //--> Inserted Ads finishes in >= 4 seconds of new period (inside the adbreak) : Channel playback starts from that position in the period.
359  else
360  {
361  AAMPLOG_INFO("[CDAI] [%d] NOT close to period end", diff);
362  abObj.adjustEndPeriodOffset = false; // done with Adjustment
363  }
364  }
365  }
366 
367  if(!abObj.adjustEndPeriodOffset) // placed all ads now print the placement data and set mPlacementObj.curAdIdx = -1;
368  {
369  mPlacementObj.curAdIdx = -1;
370  //Printing the placement positions
371  std::stringstream ss;
372  ss<<"{AdbreakId: "<<mPlacementObj.pendingAdbrkId;
373  ss<<", duration: "<<abObj.adsDuration;
374  ss<<", endPeriodId: "<<abObj.endPeriodId;
375  ss<<", endPeriodOffset: "<<abObj.endPeriodOffset;
376  ss<<", #Ads: "<<abObj.ads->size() << ",[";
377  for(int k=0;k<abObj.ads->size();k++)
378  {
379  AdNode &ad = abObj.ads->at(k);
380  ss<<"\n{AdIdx:"<<k <<",AdId:"<<ad.adId<<",duration:"<<ad.duration<<",basePeriodId:"<<ad.basePeriodId<<", basePeriodOffset:"<<ad.basePeriodOffset<<"},";
381  }
382  ss<<"],\nUnderlyingPeriods:[ ";
383  for(auto it = mPeriodMap.begin();it != mPeriodMap.end();it++)
384  {
385  if(it->second.adBreakId == mPlacementObj.pendingAdbrkId)
386  {
387  ss<<"\n{PeriodId:"<<it->first<<", duration:"<<it->second.duration;
388  for(auto pit = it->second.offset2Ad.begin(); pit != it->second.offset2Ad.end() ;pit++)
389  {
390  ss<<", offset["<<pit->first<<"]=> Ad["<<pit->second.adIdx<<"@"<<pit->second.adStartOffset<<"]";
391  }
392  }
393  }
394  ss<<"]}";
395  AAMPLOG_WARN("[CDAI] Placement Done: %s.", ss.str().c_str());
396 
397  }
398  }
399  if(-1 == mPlacementObj.curAdIdx)
400  {
401  if(-1 == mAdtoInsertInNextBreak.curAdIdx)
402  {
407  }
408  else
409  {
410  mPlacementObj = mAdtoInsertInNextBreak;
411  mAdtoInsertInNextBreak.curAdIdx = -1;
412  }
413  }
414  }
415 }
416 
417 /**
418  * @brief Checking to see if a period is the begining of the Adbreak or not.
419  *
420  * @return Ad index, if the period has an ad over it. Else -1
421  */
422 int PrivateCDAIObjectMPD::CheckForAdStart(const float &rate, bool init, const std::string &periodId, double offSet, std::string &breakId, double &adOffset)
423 {
424  int adIdx = -1;
425  auto pit = mPeriodMap.find(periodId);
426  if(mPeriodMap.end() != pit && !(pit->second.adBreakId.empty()))
427  {
428  //mBasePeriodId belongs to an Adbreak. Now we need to see whether any Ad is placed in the offset.
429  Period2AdData &curP2Ad = pit->second;
430  if(isAdBreakObjectExist(curP2Ad.adBreakId))
431  {
432  breakId = curP2Ad.adBreakId;
433  AdBreakObject &abObj = mAdBreaks[breakId];
434  bool seamLess = init?false:(AAMP_NORMAL_PLAY_RATE == rate);
435  if(seamLess)
436  {
437  int floorKey = (int)(offSet * 1000);
438  floorKey = floorKey - (floorKey%OFFSET_ALIGN_FACTOR);
439  auto adIt = curP2Ad.offset2Ad.find(floorKey);
440  if(curP2Ad.offset2Ad.end() == adIt)
441  {
442  //Need in cases like the current offset=29.5sec, next adAdSart=30.0sec
443  int ceilKey = floorKey + OFFSET_ALIGN_FACTOR;
444  adIt = curP2Ad.offset2Ad.find(ceilKey);
445  }
446 
447  if((curP2Ad.offset2Ad.end() != adIt) && (0 == adIt->second.adStartOffset))
448  {
449  //Considering only Ad start
450  adIdx = adIt->second.adIdx;
451  adOffset = 0;
452  }
453  }
454  else //Discrete playback
455  {
456  uint64_t key = (uint64_t)(offSet * 1000);
457  uint64_t start = 0;
458  uint64_t end = curP2Ad.duration;
459  if(periodId == abObj.endPeriodId)
460  {
461  end = abObj.endPeriodOffset; //No need to look beyond the adbreakEnd
462  }
463 
464  if(key >= start && key <= end)
465  {
466  //Yes, Key is in Adbreak. Find which Ad.
467  for(auto it = curP2Ad.offset2Ad.begin(); it != curP2Ad.offset2Ad.end(); it++)
468  {
469  if(key >= it->first)
470  {
471  adIdx = it->second.adIdx;
472  adOffset = (double)((key - it->first)/1000);
473  }
474  else
475  {
476  break;
477  }
478  }
479  }
480  }
481 
482  if(rate >= AAMP_NORMAL_PLAY_RATE && -1 == adIdx && abObj.endPeriodId == periodId && (uint64_t)(offSet*1000) >= abObj.endPeriodOffset)
483  {
484  breakId = ""; //AdState should not stick to IN_ADBREAK after Adbreak ends.
485  }
486  }
487  }
488  return adIdx;
489 }
490 
491 /**
492  * @brief Checking to see if the position in a period corresponds to an end of Ad playback or not
493  */
495 {
496  uint64_t fragOffset = (uint64_t)(currOffset * 1000);
497  if(fragOffset >= (mCurAds->at(mCurAdIdx).duration + OFFSET_ALIGN_FACTOR))
498  {
499  //Current Ad is playing beyond the AdBreak + OFFSET_ALIGN_FACTOR
500  return true;
501  }
502  return false;
503 }
504 
505 /**
506  * @brief Checking to see if a period has Adbreak
507  */
508 bool PrivateCDAIObjectMPD::isPeriodInAdbreak(const std::string &periodId)
509 {
510  return !(mPeriodMap[periodId].adBreakId.empty());
511 }
512 
513 /**
514  * @brief Method for downloading and parsing Ad's MPD
515  *
516  * @return Pointer to the MPD object
517  */
518 MPD* PrivateCDAIObjectMPD::GetAdMPD(std::string &manifestUrl, bool &finalManifest, bool tryFog)
519 {
520  MPD* adMpd = NULL;
521  GrowableBuffer manifest;
522  bool gotManifest = false;
523  long http_error = 0;
524  double downloadTime = 0;
525  std::string effectiveUrl;
526  memset(&manifest, 0, sizeof(manifest));
527  gotManifest = mAamp->GetFile(manifestUrl, &manifest, effectiveUrl, &http_error, &downloadTime, NULL, eCURLINSTANCE_DAI);
528  if (gotManifest)
529  {
530  AAMPLOG_TRACE("PrivateCDAIObjectMPD:: manifest download success");
531  }
532  else if (mAamp->DownloadsAreEnabled())
533  {
534  AAMPLOG_ERR("PrivateCDAIObjectMPD:: manifest download failed");
535  }
536 
537  if (gotManifest)
538  {
539  finalManifest = true;
540  xmlTextReaderPtr reader = xmlReaderForMemory(manifest.ptr, (int) manifest.len, NULL, NULL, 0);
541  if(tryFog && !mAamp->mConfig->IsConfigSet(eAAMPConfig_PlayAdFromCDN) && reader && mIsFogTSB) //Main content from FOG. Ad is expected from FOG.
542  {
543  std::string channelUrl = mAamp->GetManifestUrl(); //TODO: Get FOG URL from channel URL
544  std::string encodedUrl;
545  UrlEncode(effectiveUrl, encodedUrl);
546  int ipend = 0;
547  for(int slashcnt=0; ipend < channelUrl.length(); ipend++)
548  {
549  if(channelUrl[ipend] == '/')
550  {
551  slashcnt++;
552  if(slashcnt >= 3)
553  {
554  break;
555  }
556  }
557  }
558 
559  effectiveUrl.assign(channelUrl.c_str(), 0, ipend);
560  effectiveUrl.append("/adrec?clientId=FOG_AAMP&recordedUrl=");
561  effectiveUrl.append(encodedUrl.c_str());
562  GrowableBuffer fogManifest;
563  memset(&fogManifest, 0, sizeof(manifest));
564  http_error = 0;
565  mAamp->GetFile(effectiveUrl, &fogManifest, effectiveUrl, &http_error, &downloadTime, NULL, eCURLINSTANCE_DAI);
566  if(200 == http_error || 204 == http_error)
567  {
568  manifestUrl = effectiveUrl;
569  if(200 == http_error)
570  {
571  //FOG already has the manifest. Releasing the one from CDN and using FOG's
572  xmlFreeTextReader(reader);
573  reader = xmlReaderForMemory(fogManifest.ptr, (int) fogManifest.len, NULL, NULL, 0);
574  aamp_Free(&manifest);
575  manifest = fogManifest;
576  fogManifest.ptr = NULL;
577  }
578  else
579  {
580  finalManifest = false;
581  }
582  }
583 
584  if(fogManifest.ptr)
585  {
586  aamp_Free(&fogManifest);
587  }
588  }
589  if (reader != NULL)
590  {
591  if (xmlTextReaderRead(reader))
592  {
593  Node* root = aamp_ProcessNode(&reader, manifestUrl, true);
594  if (NULL != root)
595  {
596  std::vector<Node*> children = root->GetSubNodes();
597  for (size_t i = 0; i < children.size(); i++)
598  {
599  Node* child = children.at(i);
600  const std::string& name = child->GetName();
601  AAMPLOG_INFO("PrivateCDAIObjectMPD:: child->name %s", name.c_str());
602  if (name == "Period")
603  {
604  AAMPLOG_INFO("PrivateCDAIObjectMPD:: found period");
605  std::vector<Node *> children = child->GetSubNodes();
606  bool hasBaseUrl = false;
607  for (size_t i = 0; i < children.size(); i++)
608  {
609  if (children.at(i)->GetName() == "BaseURL")
610  {
611  hasBaseUrl = true;
612  }
613  }
614  if (!hasBaseUrl)
615  {
616  // BaseUrl not found in the period. Get it from the root and put it in the period
617  children = root->GetSubNodes();
618  for (size_t i = 0; i < children.size(); i++)
619  {
620  if (children.at(i)->GetName() == "BaseURL")
621  {
622  Node* baseUrl = new Node(*children.at(i));
623  child->AddSubNode(baseUrl);
624  hasBaseUrl = true;
625  break;
626  }
627  }
628  }
629  if (!hasBaseUrl)
630  {
631  std::string baseUrlStr = Path::GetDirectoryPath(manifestUrl);
632  Node* baseUrl = new Node();
633  baseUrl->SetName("BaseURL");
634  baseUrl->SetType(Text);
635  baseUrl->SetText(baseUrlStr);
636  AAMPLOG_INFO("PrivateCDAIObjectMPD:: manual adding BaseURL Node [%p] text %s",
637  baseUrl, baseUrl->GetText().c_str());
638  child->AddSubNode(baseUrl);
639  }
640  break;
641  }
642  }
643  adMpd = root->ToMPD();
644  SAFE_DELETE(root);
645  }
646  else
647  {
648  AAMPLOG_WARN("Could not create root node");
649  }
650  }
651  else
652  {
653  AAMPLOG_ERR("xmlTextReaderRead failed");
654  }
655  xmlFreeTextReader(reader);
656  }
657  else
658  {
659  AAMPLOG_ERR("xmlReaderForMemory failed");
660  }
661 
663  {
664  aamp_AppendNulTerminator(&manifest); // make safe for cstring operations
665  AAMPLOG_WARN("Ad manifest: %s", manifest.ptr);
666  }
667  aamp_Free(&manifest);
668  }
669  else
670  {
671  AAMPLOG_ERR("[CDAI]: Error on manifest fetch");
672  }
673  return adMpd;
674 }
675 
676 /**
677  * @brief Method for fullfilling the Ad
678  */
680 {
681  bool adStatus = false;
682  uint64_t startMS = 0;
683  uint32_t durationMs = 0;
684  bool finalManifest = false;
685  std::lock_guard<std::mutex> lock( mDaiMtx );
686  MPD *ad = GetAdMPD(mAdFulfillObj.url, finalManifest, true);
687  if(ad)
688  {
689  auto periodId = mAdFulfillObj.periodId;
690  if(ad->GetPeriods().size() && isAdBreakObjectExist(periodId)) // Ad has periods && ensuring that the adbreak still exists
691  {
692  auto &adbreakObj = mAdBreaks[periodId];
693  std::shared_ptr<std::vector<AdNode>> adBreakAssets = adbreakObj.ads;
694  durationMs = aamp_GetDurationFromRepresentation(ad);
695 
696  startMS = adbreakObj.adsDuration;
697  uint32_t availSpace = adbreakObj.brkDuration - startMS;
698  if(availSpace < durationMs)
699  {
700  AAMPLOG_WARN("Adbreak's available space[%u] < Ad's Duration[%u]. Trimming the Ad.", availSpace, durationMs);
701  durationMs = availSpace;
702  }
703  adbreakObj.adsDuration += durationMs;
704 
705  std::string bPeriodId = ""; //BasePeriodId will be filled on placement
706  int bOffset = -1; //BaseOffset will be filled on placement
707  if(0 == adBreakAssets->size())
708  {
709  //First Ad placement is doing now.
710  if(isPeriodExist(periodId))
711  {
712  mPeriodMap[periodId].offset2Ad[0] = AdOnPeriod{0,0};
713  }
714  //If current ad index is -1 (that is no ads are pushed into the map yet), current ad placement can take place from here itself.
715  //Otherwise, the Player need to wait until the current ad placement is done.
716 
717  if(mPlacementObj.curAdIdx == -1 )
718  {
719  mPlacementObj.pendingAdbrkId = periodId;
720  mPlacementObj.openPeriodId = periodId; //May not be available Now.
724  bPeriodId = periodId;
725  bOffset = 0;
726  }
727  else
728  {
729  mAdtoInsertInNextBreak.pendingAdbrkId = periodId;
730  mAdtoInsertInNextBreak.openPeriodId = periodId; //May not be available Now.
731  mAdtoInsertInNextBreak.curEndNumber = 0;
732  mAdtoInsertInNextBreak.curAdIdx = 0;
733  mAdtoInsertInNextBreak.adNextOffset = 0;
734  }
735  }
736  if(!finalManifest)
737  {
738  AAMPLOG_INFO("Final manifest to be downloaded from the FOG later. Deleting the manifest got from CDN.");
739  SAFE_DELETE(ad);
740  }
741  adBreakAssets->emplace_back(AdNode{false, false, mAdFulfillObj.adId, mAdFulfillObj.url, durationMs, bPeriodId, bOffset, ad});
742  AAMPLOG_WARN("New Ad successfully added[Id=%s, url=%s].", mAdFulfillObj.adId.c_str(),mAdFulfillObj.url.c_str());
743 
744  adStatus = true;
745  }
746  else
747  {
748  AAMPLOG_WARN("AdBreadkId[%s] not existing. Dropping the Ad.", periodId.c_str());
749  SAFE_DELETE(ad);
750  }
751  }
752  else
753  {
754  AAMPLOG_ERR("Failed to get Ad MPD[%s].", mAdFulfillObj.url.c_str());
755  }
756  mAamp->SendAdResolvedEvent(mAdFulfillObj.adId, adStatus, startMS, durationMs);
757 }
758 
759 /**
760  * @brief Setting the alternate contents' (Ads/blackouts) URL
761  */
762 void PrivateCDAIObjectMPD::SetAlternateContents(const std::string &periodId, const std::string &adId, const std::string &url, uint64_t startMS, uint32_t breakdur)
763 {
764  if("" == adId || "" == url)
765  {
766  std::lock_guard<std::mutex> lock(mDaiMtx);
767  //Putting a place holder
768  if(!(isAdBreakObjectExist(periodId)))
769  {
770  auto adBreakAssets = std::make_shared<std::vector<AdNode>>();
771  mAdBreaks.emplace(periodId, AdBreakObject{breakdur, adBreakAssets, "", 0, 0}); //Fix the duration after getting the Ad
772  Period2AdData &pData = mPeriodMap[periodId];
773  pData.adBreakId = periodId;
774  }
775  }
776  else
777  {
779  {
780  //Clearing the previous thread
781  int rc = pthread_join(mAdObjThreadID, NULL);
782  if(rc != 0) //CID:101068 - Resolving the local variable rc initialized but not used
783  {
784  AAMPLOG_ERR("pthread_join(mAdObjThreadID) failed , errno = %d, %s , Rejecting promise.",errno,strerror(errno));
785  }
786  mAdObjThreadStarted = false;
787  }
788  if(isAdBreakObjectExist(periodId))
789  {
790  auto &adbreakObj = mAdBreaks[periodId];
791  int ret = 0;
792  if(adbreakObj.brkDuration <= adbreakObj.adsDuration)
793  {
794  AAMPLOG_WARN("No more space left in the Adbreak. Rejecting the promise.");
795  ret = -1;
796  }
797  else
798  {
799  mAdFulfillObj.periodId = periodId;
800  mAdFulfillObj.adId = adId;
801  mAdFulfillObj.url = url;
802  int ret = pthread_create(&mAdObjThreadID, NULL, &AdFulfillThreadEntry, this);
803  if(ret != 0)
804  {
805  AAMPLOG_ERR(" pthread_create(FulFillAdObject) failed, errno = %d, %s. Rejecting promise.", errno, strerror(errno));
806  }
807  else
808  {
809  mAdObjThreadStarted = true;
810  }
811  }
812  if(ret != 0)
813  {
815  }
816  }
817  }
818 }
PrivateCDAIObjectMPD::CheckForAdStart
int CheckForAdStart(const float &rate, bool init, const std::string &periodId, double offSet, std::string &breakId, double &adOffset)
Checking to see if a period is the begining of the Adbreak or not.
Definition: admanager_mpd.cpp:422
CDAIObjectMPD::SetAlternateContents
virtual void SetAlternateContents(const std::string &periodId, const std::string &adId, const std::string &url, uint64_t startMS=0, uint32_t breakdur=0) override
Setting the alternate contents' (Ads/blackouts) URL.
Definition: admanager_mpd.cpp:63
PrivateCDAIObjectMPD::PrivateCDAIObjectMPD
PrivateCDAIObjectMPD(AampLogManager *logObj, PrivateInstanceAAMP *aamp)
PrivateCDAIObjectMPD constructor.
Definition: admanager_mpd.cpp:72
AampLogManager::trace
bool trace
Definition: AampLogManager.h:156
aamp_Free
void aamp_Free(void *ptr)
wrapper for g_free, used for segment allocation
Definition: AampMemoryUtils.cpp:56
PrivateCDAIObjectMPD::PlaceAds
void PlaceAds(dash::mpd::IMPD *mpd)
Method to create a bidirectional between the ads and the underlying content periods.
Definition: admanager_mpd.cpp:193
PrivateCDAIObjectMPD::mIsFogTSB
bool mIsFogTSB
Definition: admanager_mpd.h:284
PrivateInstanceAAMP::SendAdResolvedEvent
void SendAdResolvedEvent(const std::string &adId, bool status, uint64_t startMS=0, uint64_t durationMs=0)
Send status of Ad manifest downloading & parsing.
Definition: priv_aamp.cpp:8884
PrivateCDAIObjectMPD::ResetState
void ResetState()
Method to reset the state of the CDAI state machine.
Definition: admanager_mpd.cpp:158
PrivateCDAIObjectMPD
Private Client Side DAI object for DASH.
Definition: admanager_mpd.h:278
AampConfig::logging
AampLogManager logging
Definition: AampConfig.h:462
PrivateCDAIObjectMPD::ClearMaps
void ClearMaps()
Method to clear the maps in the CDAI object.
Definition: admanager_mpd.cpp:174
fragmentcollector_mpd.h
Fragment collector MPEG DASH declarations.
PrivateCDAIObjectMPD::mPeriodMap
std::unordered_map< std::string, Period2AdData > mPeriodMap
Definition: admanager_mpd.h:286
PrivateCDAIObjectMPD::mContentSeekOffset
double mContentSeekOffset
Definition: admanager_mpd.h:296
PrivateCDAIObjectMPD::~PrivateCDAIObjectMPD
~PrivateCDAIObjectMPD()
PrivateCDAIObjectMPD destructor.
Definition: admanager_mpd.cpp:81
AdOnPeriod
Individual Ad's object placed over the period.
Definition: admanager_mpd.h:208
AdBreakObject
AdBreak's metadata object.
Definition: admanager_mpd.h:172
PrivateCDAIObjectMPD::mAdFulfillObj
AdFulfillObj mAdFulfillObj
Definition: admanager_mpd.h:293
PlacementObj::openPeriodId
std::string openPeriodId
Definition: admanager_mpd.h:258
AdState::OUTSIDE_ADBREAK
@ OUTSIDE_ADBREAK
PlacementObj::curAdIdx
int curAdIdx
Definition: admanager_mpd.h:260
PrivateInstanceAAMP::CurlInit
void CurlInit(AampCurlInstance startIdx, unsigned int instanceCount=1, std::string proxyName="")
Curl initialization function.
Definition: priv_aamp.cpp:3252
gpGlobalConfig
AampConfig * gpGlobalConfig
Global configuration.
Definition: main_aamp.cpp:48
PrivateCDAIObjectMPD::mAdState
AdState mAdState
Definition: admanager_mpd.h:297
PrivateCDAIObjectMPD::mCurPlayingBreakId
std::string mCurPlayingBreakId
Definition: admanager_mpd.h:287
GrowableBuffer::len
size_t len
Definition: AampMemoryUtils.h:42
UrlEncode
void UrlEncode(std::string inStr, std::string &outStr)
Encode URL.
Definition: AampUtils.cpp:678
AdFulfillObj::adId
std::string adId
Definition: admanager_mpd.h:239
AdNode::duration
uint64_t duration
Definition: admanager_mpd.h:118
AdBreakObject::adsDuration
uint32_t adsDuration
Definition: admanager_mpd.h:177
AdBreakObject::ads
std::shared_ptr< std::vector< AdNode > > ads
Definition: admanager_mpd.h:174
admanager_mpd.h
Client side DAI manger for MPEG DASH.
AdBreakObject::endPeriodId
std::string endPeriodId
Definition: admanager_mpd.h:175
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
PrivateInstanceAAMP::GetManifestUrl
std::string & GetManifestUrl(void)
Get manifest URL.
Definition: priv_aamp.h:1890
PrivateCDAIObjectMPD::isPeriodExist
bool isPeriodExist(const std::string &periodId)
Method to check the existence of period in the period map.
Definition: admanager_mpd.cpp:110
CDAIObjectMPD::~CDAIObjectMPD
virtual ~CDAIObjectMPD()
CDAIObjectMPD destructor.
Definition: admanager_mpd.cpp:54
aamp_AppendNulTerminator
void aamp_AppendNulTerminator(struct GrowableBuffer *buffer)
Append nul character to buffer.
Definition: AampMemoryUtils.cpp:156
PrivateCDAIObjectMPD::GetAdMPD
MPD * GetAdMPD(std::string &url, bool &finalManifest, bool tryFog=false)
Method for downloading and parsing Ad's MPD.
Definition: admanager_mpd.cpp:518
PrivateCDAIObjectMPD::mCurAds
std::shared_ptr< std::vector< AdNode > > mCurAds
Definition: admanager_mpd.h:291
PrivateInstanceAAMP::GetNetworkProxy
std::string GetNetworkProxy()
To get the network proxy.
Definition: priv_aamp.cpp:9079
PrivateCDAIObjectMPD::isAdBreakObjectExist
bool isAdBreakObjectExist(const std::string &adBrkId)
Method to check the existence of Adbreak object in the AdbreakObject map.
Definition: admanager_mpd.cpp:118
Period2AdData
Meta info corresponding to each period.
Definition: admanager_mpd.h:218
PrivateCDAIObjectMPD::CheckForAdTerminate
bool CheckForAdTerminate(double fragmentTime)
Checking to see if the position in a period corresponds to an end of Ad playback or not.
Definition: admanager_mpd.cpp:494
AdState
AdState
Ad playback states.
Definition: AdManagerBase.h:35
PrivateCDAIObjectMPD::mAamp
PrivateInstanceAAMP * mAamp
Definition: admanager_mpd.h:282
AdNode
Individual Ad's meta info.
Definition: admanager_mpd.h:113
GrowableBuffer::ptr
char * ptr
Definition: AampMemoryUtils.h:41
PrivateCDAIObjectMPD::InsertToPeriodMap
void InsertToPeriodMap(IPeriod *period)
Method to insert period into period map.
Definition: admanager_mpd.cpp:98
PrivateCDAIObjectMPD::mPlacementObj
PlacementObj mPlacementObj
Definition: admanager_mpd.h:294
PrivateCDAIObjectMPD::mAdBreaks
std::unordered_map< std::string, AdBreakObject > mAdBreaks
Definition: admanager_mpd.h:285
Period2AdData::offset2Ad
std::map< int, AdOnPeriod > offset2Ad
Definition: admanager_mpd.h:222
PrivateCDAIObjectMPD::mAdObjThreadStarted
bool mAdObjThreadStarted
Definition: admanager_mpd.h:289
AdNode::adId
std::string adId
Definition: admanager_mpd.h:116
PrivateCDAIObjectMPD::isPeriodInAdbreak
bool isPeriodInAdbreak(const std::string &periodId)
Checking to see if a period has Adbreak.
Definition: admanager_mpd.cpp:508
eAAMPConfig_PlayAdFromCDN
@ eAAMPConfig_PlayAdFromCDN
Definition: AampConfig.h:128
AdFulfillObj::periodId
std::string periodId
Definition: admanager_mpd.h:238
PrivateCDAIObjectMPD::mDaiMtx
std::mutex mDaiMtx
Definition: admanager_mpd.h:283
AAMPLOG_TRACE
#define AAMPLOG_TRACE(FORMAT,...)
AAMP logging defines, this can be enabled through setLogLevel() as per the need.
Definition: AampLogManager.h:83
GrowableBuffer
Structure of GrowableBuffer.
Definition: AampMemoryUtils.h:39
PrivateInstanceAAMP
Class representing the AAMP player's private instance, which is not exposed to outside world.
Definition: priv_aamp.h:640
eCURLINSTANCE_DAI
@ eCURLINSTANCE_DAI
Definition: priv_aamp.h:163
PrivateInstanceAAMP::CurlTerm
void CurlTerm(AampCurlInstance startIdx, unsigned int instanceCount=1)
Terminate curl contexts.
Definition: priv_aamp.cpp:3333
PrivateCDAIObjectMPD::PrunePeriodMaps
void PrunePeriodMaps(std::vector< std::string > &newPeriodIds)
Method to remove expired periods from the period map.
Definition: admanager_mpd.cpp:126
PlacementObj::curEndNumber
uint64_t curEndNumber
Definition: admanager_mpd.h:259
AdBreakObject::adjustEndPeriodOffset
bool adjustEndPeriodOffset
Definition: admanager_mpd.h:178
OFFSET_ALIGN_FACTOR
#define OFFSET_ALIGN_FACTOR
Definition: admanager_mpd.h:107
PlacementObj::adNextOffset
uint32_t adNextOffset
Definition: admanager_mpd.h:261
AdNode::basePeriodId
std::string basePeriodId
Definition: admanager_mpd.h:119
PlacementObj::pendingAdbrkId
std::string pendingAdbrkId
Definition: admanager_mpd.h:257
CDAIObject
Base class for the client side DAI object.
Definition: AdManagerBase.h:57
PrivateInstanceAAMP::DownloadsAreEnabled
bool DownloadsAreEnabled(void)
Check if downloads are enabled.
Definition: priv_aamp.cpp:6752
AdBreakObject::endPeriodOffset
uint64_t endPeriodOffset
Definition: admanager_mpd.h:176
AampConfig::IsConfigSet
bool IsConfigSet(AAMPConfigSettings cfg)
Gets the boolean configuration value.
Definition: AampConfig.cpp:649
PrivateCDAIObjectMPD::FulFillAdObject
void FulFillAdObject()
Method for fullfilling the Ad.
Definition: admanager_mpd.cpp:679
PrivateCDAIObjectMPD::SetAlternateContents
void SetAlternateContents(const std::string &periodId, const std::string &adId, const std::string &url, uint64_t startMS, uint32_t breakdur=0)
Setting the alternate contents' (Ads/blackouts) URL.
Definition: admanager_mpd.cpp:762
Period2AdData::duration
uint64_t duration
Definition: admanager_mpd.h:221
PrivateCDAIObjectMPD::mAdFailed
bool mAdFailed
Definition: admanager_mpd.h:290
Period2AdData::adBreakId
std::string adBreakId
Definition: admanager_mpd.h:220
AdNode::placed
bool placed
Definition: admanager_mpd.h:115
PrivateCDAIObjectMPD::mCurAdIdx
int mCurAdIdx
Definition: admanager_mpd.h:292
CDAIObjectMPD::CDAIObjectMPD
CDAIObjectMPD(AampLogManager *logObj, PrivateInstanceAAMP *aamp)
CDAIObjectMPD Constructor.
Definition: admanager_mpd.cpp:46
PrivateInstanceAAMP::GetFile
bool GetFile(std::string remoteUrl, struct GrowableBuffer *buffer, std::string &effectiveUrl, long *http_error=NULL, double *downloadTime=NULL, const char *range=NULL, unsigned int curlInstance=0, bool resetBuffer=true, MediaType fileType=eMEDIATYPE_DEFAULT, long *bitrate=NULL, int *fogError=NULL, double fragmentDurationSec=0, class CMCDHeaders *pCMCDMetrics=NULL)
Download a file from the CDN.
Definition: priv_aamp.cpp:3585
AdNode::basePeriodOffset
int basePeriodOffset
Definition: admanager_mpd.h:120
aamp_GetDurationFromRepresentation
uint64_t aamp_GetDurationFromRepresentation(dash::mpd::IMPD *mpd)
Get duration though representation iteration.
Definition: fragmentcollector_mpd.cpp:4874
PrivateCDAIObjectMPD::mAdObjThreadID
pthread_t mAdObjThreadID
Definition: admanager_mpd.h:288
aamp_ProcessNode
Node * aamp_ProcessNode(xmlTextReaderPtr *reader, std::string url, bool isAd)
Get xml node form reader.
Definition: fragmentcollector_mpd.cpp:2914
aamp_GetPeriodDuration
double aamp_GetPeriodDuration(dash::mpd::IMPD *mpd, int periodIndex, uint64_t mpdDownloadTime)
Get Period Duration.
Definition: fragmentcollector_mpd.cpp:3966
CDAIObjectMPD::mPrivObj
class PrivateCDAIObjectMPD * mPrivObj
Definition: admanager_mpd.h:46
AdFulfillObj::url
std::string url
Definition: admanager_mpd.h:240